2023-04-17 Emacs news

| emacs, emacs-news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, lobste.rs, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

Updating my Minecraft command book using Emacs, TRAMP, and mcf.el

| minecraft, play, emacs

I wanted to see what else people have done in terms of combining Minecraft and Emacs. It turns out that you can control Minecraft from Emacs via mcf if you set enable-rcon=true in your server.properties (also a good idea to set rcon.password) and you configure variables like mcf-rcon-password on the Emacs side. It needed a little tweaking to get it to connect to a remote server, so I've submitted a pull request. Anyway, since Emacs can talk to Minecraft and I can write sequences of Minecraft commands as functions, I thought about turning my Minecraft command books into something that I could update right from Emacs.

Creating my own datapack was pretty straightforward once I figured out the directory structure. I needed to put functions in <world-name>/datapacks/sachac/data/sachac/functions. Inside <world-name>/datapacks/sachac, I created pack.mcmeta with the following contents:

{
    "pack": {
        "pack_format": 10,
        "description": "sachac's tweaks"
    }
}

Inside <world-name>/datapacks/sachac/data/sachac/functions, I created a command_book.mcfunction file with the command to give me the book. I updated my command book function to remove the / from the beginning.

I used /reload to reload my Minecraft configuration and /datapack list to confirm that my datapack was loaded. Then /function sachac:command_book ran the function to give me the command book, so that all worked out. I replaced the command in the command block with the function call.

The next step was to update it directly from Emacs, including reloading. First, I needed a function to give me the filename of a function file.

(defun my-minecraft-datapack-function-file-name (world datapack-name function-name)
  "Return the filename for a mcfunction file given WORLD, DATAPACK-NAME, and FUNCTION-NAME."
  (seq-reduce
   (lambda (path subdir) (expand-file-name subdir path))
   (list "datapacks"
         datapack-name
         "data"
         datapack-name
         "functions"
         (concat function-name ".mcfunction"))
   world))

I used C-c C-x p (org-set-property) to add a WORLD property to my Org subtree. For example, my snapshot world is at /ssh:desktop:~/.minecraft/saves/Snapshot. Then I can get the correct value within the subtree by using org-entry-get-with-inheritance. This is how I wrote the command book function for my snapshot world:

#+begin_src emacs-lisp :var body=mc-snapshot :var team=mc-team :var quick=mc-quick :var effects=mc-effects :var items=mc-items :results silent
(with-temp-file
    (my-minecraft-datapack-function-file-name
     (org-entry-get-with-inheritance "WORLD")
     "sachac"
     "command_book")
  (insert (my-minecraft-book "Commands 8.5" "Mom" (append team quick body effects items))))
(mcf-eval "reload")
#+end_src

So now I can use C-c C-c to execute the Emacs Lisp block and have my Minecraft world updated. Then I just need to right-click on my command block's button or run the function in order to get the new version.

I'm looking forward to learning more about mcfunctions so that I can write a function that automatically replaces the book in everyone's inventories. Could be fun.

2023-04-10 Emacs news

| emacs, emacs-news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, lobste.rs, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

Using Org Mode tables and Emacs Lisp to create Minecraft Java JSON command books

| minecraft, org, emacs, play
  • [2023-04-12 Wed]: Remove / from the beginning so that I can use this in a function. Split book function into JSON and command. Updated effects to hide particles.
  • [2023-04-10 Mon]: Separated trident into channeling and riptide.

A+ likes playing recent Minecraft snapshots because of the new features. The modding systems haven't been updated for the snaphots yet, so we couldn't use mods like JourneyMap to teleport around. I didn't want to be the keeper of coordinates and be in charge of teleporting people to various places.

It turns out that you can make clickable books using JSON. I used the Minecraft book editor to make a prototype book and figure out the syntax. Then I used a command block to give it to myself in order to work around the length limits on commands in chat. A+ loved being able to carry around a book that could teleport her to either of us or to specified places, change the time of day, clear the weather, and change game mode. That also meant that I no longer had to type all the commands to give her water breathing, night vision, or slow falling, or give her whatever tools she forgot to pack before she headed out. It was so handy, W- and I got our own copies too.

Manually creating the clickable targets was annoying, especially since we wanted the book to have slightly different content depending on the instance we were in. I wanted to be able to specify the contents using Org Mode tables and generate the JSON for the book using Emacs.

Here's a screenshot:

2023-04-09_10-09-48.png
Figure 1: Screenshot of command book

This is the code to make it:

(defun my-minecraft-remove-markup (s)
  (if (string-match "^[=~]\\(.+?\\)[=~]$" s)
      (match-string 1 s)
    s))

(defun my-minecraft-book-json (title author book)
  "Generate the JSON for TITLE AUTHOR BOOK.
BOOK should be a list of lists of the form (text click-command color)."
  (json-encode
   `((pages . 
            ,(apply 'vector
                    (mapcar
                     (lambda (page)
                       (json-encode
                        (apply 'vector 
                               (seq-mapcat
                                (lambda (command)
                                  (let ((text (my-minecraft-remove-markup (or (elt command 0) "")))
                                        (click (my-minecraft-remove-markup (or (elt command 1) "")))
                                        (color (or (elt command 2) "")))
                                    (unless (or (string-match "^<.*>$" text)
                                                (string-match "^<.*>$" click)
                                                (string-match "^<.*>$" color))
                                      (list
                                       (append
                                        (list (cons 'text text))
                                        (unless (string= click "")
                                          `((clickEvent 
                                             (action . "run_command")
                                             (value . ,(concat "/" click)))))                                    
                                        (unless (string= color "")
                                          (list (cons 'color
                                                      color))))
                                       (if (string= color "")
                                           '((text . "\n"))
                                         '((text . "\n")
                                           (color . "reset")))))))
                                page))))
                     (seq-partition book 14)
                     )))
     (author . ,author)
     (title . ,title))))

(defun my-minecraft-book (title author book)
  "Generate a command to put into a command block in order to get a book.
Label it with TITLE and AUTHOR.
BOOK should be a list of lists of the form (text click-command color).
Copy the command text to the kill ring for pasting into a command block."
  (let ((s (concat "item replace entity @p weapon.mainhand with written_book"
                   (my-minecraft-book-json title author book))))
    (kill-new s)
    s))

With this code, I can generate a simple book like this:

(my-minecraft-book "Simple book" "sachac"
                   '(("Daytime" "set time 0800")
                     ("Creative" "gamemode creative" "#0000cd")))
item replace entity @p weapon.mainhand with written_book{"pages":["[{\"text\":\"Daytime\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/set time 0800\"}},{\"text\":\"\\n\"},{\"text\":\"Creative\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/gamemode creative\"},\"color\":\"#0000cd\"},{\"text\":\"\\n\",\"color\":\"reset\"}]"],"author":"sachac","title":"Simple book"}

To place it in the world:

  1. I changed my server.properties to set enable-command-block=true.
  2. In the game, I used /gamemode creative to switch to creative mode.
  3. I used /give @p minecraft:command_block to give myself a command block.
  4. I right-clicked an empty place to set the block there.
  5. I right-clicked on the command block and pasted in the command.
  6. I added a button.

Then I clicked on the button and it replaced whatever I was holding with the book. I used item replace instead of give so that it's easy to replace old versions.

On the Org Mode side, it's much nicer to specify commands in a named table. For example, if I name the following table with #+name: mc-quick, I can refer to it with :var quick=mc-quick in the Emacs Lisp source block. (You can check the Org source for this post if that makes it easier to understand.)

Daytime time set 0800  
Clear weather weather clear  
Creative gamemode creative #0000cd
Survival gamemode survival #ff4500
Spectator gamemode spectator #228b22
(my-minecraft-book "Book from table" "sachac" quick)
item replace entity @p weapon.mainhand with written_book{"pages":["[{\"text\":\"Daytime\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/time set 0800\"}},{\"text\":\"\\n\"},{\"text\":\"Clear weather\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/weather clear\"}},{\"text\":\"\\n\"},{\"text\":\"Creative\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/gamemode creative\"},\"color\":\"#0000cd\"},{\"text\":\"\\n\",\"color\":\"reset\"},{\"text\":\"Survival\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/gamemode survival\"},\"color\":\"#ff4500\"},{\"text\":\"\\n\",\"color\":\"reset\"},{\"text\":\"Spectator\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/gamemode spectator\"},\"color\":\"#228b22\"},{\"text\":\"\\n\",\"color\":\"reset\"}]"],"author":"sachac","title":"Book from table"}

Then I can define several named tables and append them together. Here's one for different effects:

Water breathing effect give @p minecraft:water_breathing infinite 255 true  
Night vision effect give @p minecraft:night_vision infinite 255 true  
Regeneration effect give @p minecraft:regeneration infinite 255 true  
Haste effect give @p minecraft:haste infinite 2 true  
Health boost effect give @p minecraft:health_boost infinite 255 true  
Slow falling effect give @p minecraft:slow_falling infinite 255 true  
Fire resist effect give @p minecraft:fire_resistance infinite 255 true  
Resistance effect give @p minecraft:resistance infinite 255 true  
Clear effects effect clear @p  

Some commands are pretty long. Specifying a width like <20> in the first row lets me use C-c TAB to toggle width.

Pickaxe give @p minecraft:diamond_pickaxe{Enchantments:[{id:"minecraft:fortune",lvl:4s},{id:"minecraft:mending",lvl:1s},{id:"minecraft:efficiency",lvl:4s}]}  
Silk touch pickaxe give @p minecraft:diamond_pickaxe{Enchantments:[{id:"minecraft:silk_touch",lvl:1s},{id:"minecraft:mending",lvl:1s}]}  
Sword give @p minecraft:diamond_sword{Enchantments:[{id:"minecraft:looting",lvl:4s},{id:"minecraft:mending",lvl:1s}]}  
Axe give @p minecraft:diamond_axe{Enchantments:[{id:"minecraft:looting",lvl:4s},{id:"minecraft:mending",lvl:1s}]}  
Shovel give @p minecraft:diamond_shovel{Enchantments:[{id:"minecraft:fortune",lvl:4s},{id:"minecraft:mending",lvl:1s},{id:"minecraft:efficiency",lvl:4s}]}  
Bow give @p minecraft:bow{Enchantments:[{id:"minecraft:infinity",lvl:1s},{id:"minecraft:mending",lvl:1s}]}  
Arrows give @p minecraft:arrow 64  
Torches give @p minecraft:torch 64  
Fishing give @p minecraft:fishing_rod{Enchantments:[{id:"minecraft:lure",lvl:4s},{id:"minecraft:luck_of_the_sea",lvl:4s},{id:"minecraft:mending",lvl:1s}]}  
Riptide trident give @p minecraft:trident{Enchantments:[{id:"minecraft:loyalty",lvl:4s},{id:"minecraft:mending",lvl:1s},{id:"minecraft:riptide",lvl:4s}]}  
Channeling trident give @p minecraft:trident{Enchantments:[{id:"minecraft:loyalty",lvl:4s},{id:"minecraft:mending",lvl:1s},{id:"minecraft:channeling",lvl:1s}]}  
Weather rain weather rain  
Weather thunder weather thunder  
Birch signs give @p minecraft:birch_sign 16  
Bucket of water give @p minecraft:water_bucket  
Bucket of milk give @p minecraft:milk_bucket  
Bucket of lava give @p minecraft:lava_bucket  
Water bottles give @p minecraft:potion{Potion:"minecraft:water"} 3  
Blaze powder give @p minecraft:blaze_powder 16  
Brewing stand give @p minecraft:brewing_stand  
Magma cream give @p minecraft:magma_cream  

Here's what that table looks like in Org Mode:

2023-04-10_09-55-57.png
Figure 2: With column width

Here's how to combine multiple tables:

#+begin_src emacs-lisp :results silent :var quick=mc-quick :var effects=mc-effects :var items=mc-items :exports code
(my-minecraft-book "Book from multiple tables" "sachac" (append quick effects items))
#+end_src

Now producing instance-specific books is just a matter of including the sections I want, like a table that has coordinates for different bases in that particular instance.

I thought about making an Org link type for click commands and some way of exporting that will convert to JSON and keep the whitespace. That way, I might be able to write longer notes and export them to Minecraft book JSON for in-game references, such as notes on villager blocks or potion ingredients. The table + Emacs Lisp approach is already quite useful for quick shortcuts, though, and it was easy to write. We'll see if we need more fanciness!

View org source for this post

2023-04-03 Emacs news

| emacs, emacs-news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, lobste.rs, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

2023-03-27 Emacs news

| emacs, emacs-news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, lobste.rs, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

Preparing for middle age

| life, planning

My peer group's not yet at the point of discussing maintenance meds, but they often discuss brain fog, fatigue, and strategies for dealing with perimenopause. Since I'll be turning 40 in a few months, I figured it would be a good idea to start anticipating some of the changes that come with age. If I look for ways to improve my systems, workflows, and habits, I might be able to age more gracefully. Here's are some age-related changes and quick thoughts about what I can do about them.

  • Changing relationships, losing people: Throughout the years, I'll need to deal with the loss of people close to me, whether it's because of natural development (like A+ going off and living her own life), changing situations (drifting in and out of playgroups based on her interests), or old age and death. I can prepare for that by making the most of the time I do have with people, learning more life skills, staying engaged, and laying the groundwork for more relationships that might turn into old friendships.

    It's a little complicated because I think I'll continue to be cautious about spending a lot of time indoors around other people. Fortunately, there are a lot of outdoor socialization opportunities. Eventually, when A+'s off and doesn't want her mom hanging around when she's out with her friends, I can join some of the walking clubs out of the nearby park.

    I like the Emacs community, and I'm looking forward to maturing into some sort of community grandmother. I imagine it'll be mostly about oohing and aahing over people's cool projects and suggesting that they go talk to so-and-so who was curious about something similar.

  • Brain fog, slower processing: I got a sneak preview of this during the early years of parenting, and I still have many days where I either feel slower or I don't have lots of focused time. I think dealing with this is about being kind to myself (since there's no point in wasting even more energy on beating myself up), managing my expectations, and managing my tasks so that when I do have some focused time, I can do whatever I needed to do at the time that it's good to do it.

    I've gotten a lot of use out of speed-reading, but in case that slows down, I can also get a lot from reading more slowly. I can take more sketchnotes and try to make more connections to other things I know.

    Summarization seems to be one of the things that current natural language processing systems are getting pretty good at, so that might also be useful.

  • Fading memories: I hope habits of journaling, taking pictures, and drawing sketches will help me appreciate these moments that fill my years so that things don't feel like as much of a blur. Backups are important, of course. Also, converting thoughts and memories into a form that other people can bump into means that it's not limited to my brain: blog posts about things I've been learning, photo albums that A+ can flip through whenever she likes, things like that. Retrieving memories and organizing them into narratives/stories helps make sense of them too.
  • Less working memory: Working memory is useful for being able to see the connections between things and solving problems quickly. I'm beginning to appreciate the difficulty of keeping lots of things in my head, especially when someone's trying to talk to me at the same time. That's cool. I can reduce multitasking and minimize commitments. I can refile information so that it's close to related information. I can chunk information differently and then spread them out side-by-side, like the way index cards and sketchnotes help me build up thoughts and Org Mode helps me compare shopping choices. External monitors help, and I can print things out if I need to. Remembrance agents might be able to suggest related things, too.
  • Lower recall of words, details: It doesn't matter much if the memory is there, if I don't have a way of getting back to it. Stuff inside my brain is likely to get lost. Maintaining a centralized note-taking habit (especially if information is fragmented over different apps and devices) will probably help with this. Mnemonic techniques can help with making things more vivid. I hope that natural language search will be useful too, and I'm looking forward to seeing what large-language models for artificial intelligence can do when applied to personal datasets. Episodic search might become more viable, too, if I can use things I remember to narrow down where to find something. Recognition is easier than recall, so even having something suggest a few options might be enough to unstick my brain. If I take pictures or notes of where I've stored infrequently-used things, that might make searching easier too.
  • Inattention: I occasionally get brain hiccups, and stress or low sleep makes it worse. Slowing down and not rushing helps. Processes, checklists, and repeating TODOs helps. Organizing our physical space so that there's a home for things helps when I'm on autopilot, although I still get attentional blips and put things in the wrong place. Keeping an oops fund helps.

    Cubing might be a way for me to track this. Sometimes I make a mistake and my solve time goes way up, so that's a way to check how often my attention wanders when I mean to be paying attention.

  • Less energy: I'm becoming more protective of my sleep, and I've got a good mix of things I can do even when I have low energy. Walking is good, and I can ramp up to other forms of exercise slowly. There are lots of long-term hobbies I can enjoy well into old age, so there's plenty to explore.
  • Hormonal disruption: I think this is mostly about getting a sense of what to expect, having good relationships with doctors and other health professionals, and being open to adapting my lifestyle as things change. My friends have mentioned a fair bit of sleep disruption, so that's probably something to watch out for too.
  • Changing priorities and perspectives: This is one of the good benefits of all of this. Constraints make things clearer. Looking forward to growing wiser.

I'll also keep assistive technology in mind, since there are all sorts of interesting ways tech might be able to help with age-related cognitive or physical decline.

Going to happen anyway, if all goes well. Might as well have fun!