Sponge is not the place to ask this question (at least not a good one). You are better off asking Forge (luckily I’m here). Sponge is not an implementation of a minecraft server, rather an implementation of SpongeAPI layered atop Forge, which is atop of Minecraft server (so none of the people at Sponge actually know how to make a server except for SpaceManiac).
I’m a TridentSDK developer. Since Trident is clean reimplementation of the minecraft server, I would be the most qualified to answer at the moment, so don’t call me out for trolling because I am not.
Trident was developed around game order. At first, we figured that we needed a base the server runs on. This means connections, world loading, processes, and plugins. We started out with connections because it is the easiest. Netty was the backend, and we open a server bootstrap bound to IP 127.0.0.1 and port 25565. This allows clients to connect to the target at the external IP that is redirected through the connection made by the server bootstrap on localhost. This is started using 2 NioEventLoops.
Next, we did loggin/CLI options. As we have not had the chance to fully control the server yet, we held back on command implementation until world loading finishes. Currently, JOptSimple parses /help and the other runtime parameters.
Then, the server object is constructed. This loads in all of the processes, including server task executor, scheduling, connection listeners, and various API libraries.
The most important is protocol. We were highly focused on protocol because that’s what makes a server, a a server. The ability to communicate with clients (after connection pools are initialized). Basically, we had to replicate all of the packets on the protocol spec on wiki.vg, and correct the encoding a tiny bit. I won’t go into much detail, but we also handled client logins and encryption, along with the decoders/encoders along the netty IO connections. This was the hardest part to figure out in my personal opinion. There is a nice protocol order on the protocol FAQ on wiki.vg, that was a good reference for player joining, which came next.
All of the packets have an action method that can be overridden to perform an action when the packet is reviewed by the server. Once the join game packet is sent by the client, the server can now send the world chunks, block lighting, entities, metadata, and other players. Also note that you need to listen for the player’s update packet (which I am pretty sure has KeepAlice somewhere in there) which prompts you to update the world and send tick modifications to the client.
We haven’t gotten to world loading as we are discussing API design and when to make decisions, so I don’t know much about that. What we have started is RegionFile decoding, which allows us to parse world folders of default minecraft maps, which is extremely cool (but difficult). We have the NBT decoding done, and are looking on Minecraft wiki for information on the world file format (heh clean room :P).
I was in charge of multithreading. This is central to the server, as the existing minecraft server did not have very advanced multithreading capabilities. Task handling is based on ConcurrentTaskExecutor which is a thread pool that only loops and has a set pool size, in order to utilize the CPU consistently. We discussed the amount of threads to use to be around 16, because most processors cannot support more than 16 threads at a single time. More threads, and they would compete for CPU cycles, which may degrade performance instead of increasing it. I am currently looking at a separate performance concurrent queue because the current one takes 500ns to take the last item out. I’ve also reimplemented the scheduler (but tests show that it is 2x slower than the Bukkit scheduler… Yeesh) which originally had synchronized everywhere, even on atomic variables (hehe, not to blame the other developer for that - he had a cool tick class though).
All in all, just start with the connections/protocol.