[HN Gopher] Writing a Minecraft server from scratch in Bash (2022)
       ___________________________________________________________________
        
       Writing a Minecraft server from scratch in Bash (2022)
        
       Author : LorenDB
       Score  : 317 points
       Date   : 2024-03-02 14:42 UTC (1 days ago)
        
 (HTM) web link (sdomi.pl)
 (TXT) w3m dump (sdomi.pl)
        
       | pvg wrote:
       | Discussion at the time
       | https://news.ycombinator.com/item?id=30347501 92 comments
        
         | dang wrote:
         | Thanks! Macroexpanded:
         | 
         |  _My thoughts on writing a Minecraft server from scratch in
         | Bash_ - https://news.ycombinator.com/item?id=30347501 - Feb
         | 2022 (90 comments)
        
       | dinkleberg wrote:
       | Now this is a proper hacker site. This is great.
        
       | TeaVMFan wrote:
       | As someone who's done a lot of work with scriptable Minecraft
       | servers for both Java and Bedrock (ScraM), this is impressive.
       | Bonus points for using "duckduckgoing" in a sentence.
        
       | SunlitCat wrote:
       | Just wondering, but is writing custom servers for commercial
       | games still a thing?
        
         | petee wrote:
         | I think it will always be a thing for those who play games &
         | like to dabble with tech, either to fix a bug, learn a
         | language, or just see how the sausage is made.
        
         | madeofpalk wrote:
         | For Minecraft, very much so. Minecraft, especially the Java
         | version, is in a comparatively odd place in that it receives
         | significant free content updates AND officially supports
         | running any historical version AND has an extremely vibrant
         | modding community.
         | 
         | Minecraft (Java) is as much of a game engine for others to
         | build on as it is a game itself.
        
           | Filligree wrote:
           | The four great game engines: Unreal, Unity, Minecraft and
           | Godot.
           | 
           | I don't think Minecraft is number four on the list. It might
           | be number two.
        
             | jasonjayr wrote:
             | Roblox is somewhere on that list too ....
        
               | Filligree wrote:
               | How many thousand mods does it have?
        
               | BalinKing wrote:
               | Isn't each server its own mod, in effect?
        
           | themoonisachees wrote:
           | This is because in addition to being the most sold video game
           | of all time, minecraft is effectively open source. It's not
           | literally open source, but you can decompile java bytecode
           | with standard tooling, and symbols are available, either
           | community-reversed, or official.
        
             | teaearlgraycold wrote:
             | Frustrating how game studios can see Minecraft's success
             | here and not change a thing about their development
             | practices.
        
               | Aurornis wrote:
               | There's actually a very large and vibrant community for
               | modding Unity games like this.
               | 
               | More competitive games can't afford any type of easy
               | reverse engineering due to the cheating factor.
        
               | darknavi wrote:
               | Mods are the (amazing) end game for Lethal Company. So
               | many fun, new tweaks and content.
        
               | noah91734 wrote:
               | For the curious: https://thunderstore.io/c/lethal-
               | company/
               | 
               | Click on any mod, and you can see the decompiled source.
               | The mods use function hooking to run before or after
               | certain functions are called rather than the event based
               | system you see in Minecraft plugins.
        
               | ryukoposting wrote:
               | I think Minecraft's position today has as much to do with
               | the content of the game itself as it has to do with its
               | architecture/Mojang's engineering choices.
               | 
               | The nearly-infinite expandability and modularity of
               | Minecraft is partially due to the simplicity of the art,
               | core game mechanics, and lack of storyline. Good mods are
               | harder to make when the world they must integrate into is
               | more complex.
               | 
               | I think this means a lot of games wouldn't see the kind
               | of sustained success Minecraft has seen, even with more
               | "open" development practices.
               | 
               | I hypothesize that the "open world" craze of years past
               | was an attempt to capture Minecraft magic, but those
               | games lacked the _thematic_ open-endedness that really
               | facilitates Minecraft 's longevity.
        
             | LtWorf wrote:
             | minetest is open source for real though
        
           | LtWorf wrote:
           | Minetest is much more of a game engine.
           | 
           | I've heard from someone I know that played both extensively
           | that minetest is less prone to losing everything for data
           | corruption (never happened once in minetest, regularly in
           | minecraft after a while. But sample size is 1).
        
             | tehbeard wrote:
             | Is that sample size of one from the java edition or bedrock
             | edition of minecraft?
        
               | LtWorf wrote:
               | java
        
             | chungy wrote:
             | I don't think I've ever witnessed data corruption in
             | Minecraft, and that's even playing since Alpha 1.0.11 and
             | multiple data format migrations... well, my sample size is
             | 1, too.
             | 
             | I've also been on ZFS nearly the whole time. Are you
             | certain Minecraft actually corrupted your data file, or do
             | you suffer underlying hardware failure?
        
         | firtoz wrote:
         | AFAIK yes, the RE scene is still active.
        
         | haunter wrote:
         | Not just servers but for some games clients too
         | https://runelite.net/
        
           | static_motion wrote:
           | I find RuneLite a fascinatingly well-built piece of software.
           | The lead dev, Adam, did a fantastic job with it, and good on
           | Jagex for allowing its use, even as far as advertising it on
           | their own front page.
        
             | hoten wrote:
             | It really papers over (some of) the tedium of the game and
             | let's you enjoy the rest easier. Love it.
        
           | SunlitCat wrote:
           | Although writing game servers for commercial games is already
           | "difficult", isn't writing game clients for commercial games
           | a huge issue copyright wise?
        
       | BearOso wrote:
       | A negative power, i.e. 2^(-n) is just 1/(2^n). I'm surprised the
       | author didn't remember that with their own 2^-1 = 0.5 example and
       | eventually reached out to awk for it.
        
         | tryauuum wrote:
         | I don't understand how this would help the author. Since the
         | bash doesn't support floating point numbers anyway
        
           | anthk wrote:
           | This. Also, gawk has netwoki support, so you can write an mc
           | server with just gawk.
        
             | BearOso wrote:
             | I had the same thought. bc would have been a lighter
             | choice.
             | 
             | And tryauuum, I think the author only needed powers of two
             | to emulate floating point in the first place. So they could
             | just divide said number by 2 a number of times.
        
       | taviso wrote:
       | They should have used my (dumb?) library, ctypes.sh:
       | 
       | https://github.com/taviso/ctypes.sh
       | 
       | Then they can access libm, poll(), select() and so on from bash
       | :)
        
         | lagniappe wrote:
         | woah that's cool :) also hello tavis
        
         | MrBuddyCasino wrote:
         | I'm not sure you should have done that, but it is impressive
         | for the sheer chuzpa of it. Like reanimating Frankenstein.
        
         | jethro_tell wrote:
         | Lol, holy shit what did I just read?
         | 
         | Amazing, installing now. I want to be part of the problem.
        
         | Brian_K_White wrote:
         | Awesome, but beside the point of writing something in bash that
         | never needed to be in bash for any technical reason.
         | 
         | Meaning if it requires bash plus some specially installed
         | compiled c code, then it might as well require c or python or
         | anything else and there is no point in calling it "written in
         | bash", or writing it in mostly-bash-plus-special-plugin.
         | 
         | I do know who I'm speaking to so please assume I say this
         | respectfully. :) I have no problem with a "pointless" project
         | like that as I'll show in a second.
         | 
         | That said, this minecraft project itself relies on externals
         | like xxd when it doesn't need to, so using ctypes.sh would be
         | no worse in this case, so you are right, in this case they
         | might as well have.
         | 
         | But for the record it is possible to read, store, manipulate,
         | do math on, and output binary in pure bash without anything
         | like dd or xxd.
         | 
         | The only byte that is a problem is null, and there is a way to
         | deal with that. You can't directly store a null, but you can
         | detect that you read one and store that info, and reconstruct
         | it on output later, or do math on it, use it's numerical value
         | as an array index or byte offset or whatever the byte is for.
         | 
         | For a minimal example, just copying a binary file: while LANG=C
         | IFS= read -d '' -r -n 1 x ;do printf '%c' "$x" ;done <bin1
         | >bin2
         | 
         | That's a bit too minimal since it doesn't show what other kinds
         | of things you can do that are more useful than cat-without-cat.
         | 
         | A bit more generic and useful:
         | https://gist.github.com/bkw777/c1413d0e3de6c54524ddae890fe8d...
         | 
         | The LANG=C, IFS= , and -d'' all combine to render all bytes
         | accessible except 0x00, and then the return value from read()
         | tells you the difference between "we read a 0x00" and "we
         | didn't read anything" and "input ended"
         | 
         | And it doesn't have to use < and > on the overall while()
         | comand either. You can exec 3<>file_or_fifo_or_tty and read -u3
         | / printf >&3 etc inside the loop instead.
         | 
         | An example reading from a serial port:
         | https://gist.github.com/bkw777/ddde771cc85fdd888c7ec74953193...
         | 
         | Used in anger: https://github.com/bkw777/pdd.sh see tpdd_read,
         | tpdd_write, file_to_fhex, str_to_shex reading and writing both
         | a serial port and local files and doing all kinds of processing
         | on the data.
         | 
         | And these loops are not even subshells let alone externals. You
         | can manipulate variables inside the loop and you are still in
         | the same original context. I'd say parent shell but there are
         | no childern.
         | 
         | Those all read a single byte at a time with read -n 1, but they
         | don't have to.
         | 
         | You can read without the -n1 and each iteration of the loop
         | will collect as much as it can between nulls instead of always
         | one byte. That would consume less ram and less loop iterations.
         | 
         | But the things I'm using them for want to slice & dice the
         | individual bytes and byte-ranges at numerical offsets anyway
         | and the data is always small (by todays standards) so the
         | array-of-hex-pairs is just too convenient where a[n] == byte n,
         | and all bytes are treated the same whether printable, non-
         | printable, or null, and aside from merely storing and
         | regenerating the bytes with printf you can also use the
         | numerical values directly as well by simply prepending 0x, so
         | 0x$n or 0x${a[n]} almost anywhere you would normally have a
         | simple integer. So you can do math on them and use them as
         | array indexes and byte offsets etc.
         | 
         | Read the 2nd byte of h[] as a length of the payload to follow,
         | and clip out that payload: ${h[@]:2:0x${h[1]}}
        
         | captainbland wrote:
         | I mean if it's good enough for python...
        
         | synergy20 wrote:
         | would love to see how poll() and select() etc work this way
        
           | taviso wrote:
           | Here are some examples!
           | 
           | https://github.com/taviso/ctypes.sh/blob/master/test/select..
           | ..
           | https://github.com/taviso/ctypes.sh/blob/master/test/poll.sh
           | 
           | Yes, it is crazy :)
        
       | bilekas wrote:
       | So that happened... Jesus. I've read a lot of articles about the
       | way they implement stuff but this takes the cake. Hands down one
       | of, if not the best write up of something wild I've ever read.
       | Top shelf.
        
       | osigurdson wrote:
       | While I am not good at bash programming, I am surprised how
       | capable / non horrible it actually is.
        
       | fddrdplktrew wrote:
       | Minecraft, one of greatest game since Quake
        
       | synergy20 wrote:
       | bash is one of my favorite, as favorite as vim and lua.
       | 
       | a single binary that is less than 2M bytes, universal, way more
       | capable than many people think.
       | 
       | with shellcheck and good habits, bash can be readable and safe as
       | well.
       | 
       | if you want something extra, you can always use C/C++ to add
       | those utilities without using more involved FFI etc, and without
       | pip/npm/etc to load who knows how many dependencies.
        
         | inetknght wrote:
         | > _with shellcheck and good habits, bash can be readable and
         | safe as well._
         | 
         | My favorite thing to do with shellcheck: add it to CI.
         | Developers hate this one trick!
         | 
         | A lot of times CI and Dockerfiles have inline bash scripts. My
         | next favorite thing to do is to move all of that inlined bash
         | to their own script files. Now that CI has shellcheck: all that
         | stuff gets checked too! Developers seem to hate this though
         | because it's "less readable". Less readable my ass, it's way
         | more safe.
         | 
         | Next problem: the same bash scripts are now in the same files
         | in multiple repositories (a distributed build). I'm open to
         | ideas for improvements here.
        
         | yodsanklai wrote:
         | I dislike bash because I'm not good with it. It sucks but is
         | still often the best solution available. Actually, one of my
         | regret was not to invest more time on it when I was a student
         | (a while ago) because it's one of these rare tools that
         | accompanied me my whole career.
        
           | inetknght wrote:
           | It's true. The nice thing is that there are many _many_
           | examples of how to use bash. Just open a script file in
           | random repositories. Most scripts are super SUPER simple. But
           | just copy-paste to shellcheck and it will give some feedback
           | if you 're looking to get in some really quick commits and
           | PRs :)
        
       ___________________________________________________________________
       (page generated 2024-03-03 23:01 UTC)