A working Minecraft 1.8.9 server implemented entirely in Excel VBA. Real client with a real protocol and no server software. The process listening on port 25565 is EXCEL.EXE.
It handles the server list ping, login, world data and keep-alives. You join, you spawn on grass, you can walk around and place blocks. Your position updates a cell in the spreadsheet as you move, because at some point I decided 'that would be a fun little thing'.
Why
People have built Minecraft in Excel before. SethBling's version is from 2014 and it's great. Those are all clones of Minecraft though, running inside the spreadsheet, not a server.
I couldn't find anyone that has made Excel speak the actual protocol so a real client can connect to it. So now someone has. And if I'm not the first, it'd be interesting to see what came before.
What it does
Server list ping with MOTD, player count and a favicon
Offline-mode login, no encryption
Flat world, 5x5 chunks of bedrock, dirt and grass
Creative mode, so you can fly and place things
Keep-alives, so the session survives longer than 20 seconds
Live player position written into the sheet
What it doesn't do
Almost everything else. No block updates on the server side, no entities, no mobs, no real physics, no chat commands, no second player. Blocks you place exist only in your client. Walk away and come back and they're still there, because nothing is telling your client otherwise.
It's a server in the sense that a client connects to it and receives a world. Set your expectations accordingly.
Requirements
Windows, 64-bit Excel with VBA. Not Excel for Mac, its VBA is sandboxed and can't open sockets
Minecraft Java 1.8.9, protocol 47
Setup
Download ExcelMCServer.bas
New workbook, save as .xlsm
Alt+F11 for the VB Editor, then File > Import File, select the .bas
Ctrl+G for the Immediate window, type SetupWorkbook, Enter
Back in Excel, click START and allow the firewall prompt
Connect to the machine's IP on port 25565
Optional: I resized the Excel icon in paint on the VM so it's not going in here so put a 64x64 PNG called favicon.png in the same folder as the workbook and it'll show up in the server list. Must be exactly 64x64 or the client drops it.
How it works
The Declare PtrSafe block at the top binds to ws2_32.dll, which is Windows' sockets library. Every program on Windows that touches the network goes through it, Java included.
Everything else is written from nothing, because no VBA library for any of this exists:
VarInts. The protocol's variable width integer format. Needs an unsigned right shift, which VBA doesn't have, so URShift7 fakes it.
Packet framing. Length, then packet ID, then payload. TCP is a stream and not a sequence of messages, so packets arrive split across reads or several at once. DrainPackets buffers until a whole packet is present.
Endianness. The protocol is big-endian, x86 is little-endian, so every multi-byte number gets reversed. Doubles and floats go through CopyMemory because there's no other way to see their bytes in VBA.
State machine. Handshake, then either status or login, then play.
Chunks. The reason this targets 1.8.9 and not a current version. In 1.8, a chunk section is a flat array of (id << 4) | meta shorts, then block light, then sky light. 12,544 bytes for one section plus biome data, and you can send it uncompressed. Modern versions use palette-encoded, bit packed longs and expect zlib. VBA has no zlib. That's a whole different project.
Things that went wrong, for the benefit of anyone attempting this
CInt(25565 - 65536) overflows. VBA's Integer stops at -32768, and 25565 already fits in one, so the wrapping I'd written for high port numbers was both unnecessary and fatal.
VBA's \ operator truncates toward zero, so building big-endian bytes by division silently mangles negative numbers. Every chunk at a negative coordinate went to the wrong place.
A 12KB packet does not fit in a non-blocking socket's send buffer. The first version sent whatever fitted and threw away the rest, which was a fun one to debug.
Building a byte array by repeatedly concatenating it is fine at 30 bytes and unusable at 12,544. The chunk body is built once into a preallocated array and reused.
And many hours lost to macOS, which blocks apps from reaching the local network until you grant permission, and reports the refusal as NoRouteToHost. Every test from Terminal worked, because Terminal already had permission. I thought it was a code bug... wasn't a code bug.
Running it from a Mac
Windows in a VM. If Minecraft can't reach the VM and everything else can, that's the macOS local network permission, and the quickest fix is relaying through Terminal, which already has the grant:
socat TCP-LISTEN:25565,fork,reuseaddr TCP::25565
Then connect to localhost:25565.
Licence
MIT. Do what you like with it.