Hi, I'm *squid*

Moongate V2 Dev Log #3: Player Portal, Maps, Books, and a .NET Bug I Didn't Own

Moongate logo

Before I get into this week's work, I want to start with a thank you.

Last week I posted Moongate on Hacker News as a Show HN: Show HN: Moongate - Ultima Online server emulator in .NET 10 with Lua scripting.!

For a while, it ended up getting way more attention than I expected, and according to the screenshot I saved it was the most-read story on Hacker News for about 24 hours. Whether you clicked through because you still remember Ultima Online, because you care about emulators, or just because the combination of .NET 10, Lua scripting, and an MMO server sounded weird enough to inspect, thank you!

The response was honestly bigger than I expected.

Hacker news

The thread itself was also one of the best kinds of internet feedback loops: a mix of nostalgia, technical curiosity, old UO stories, and genuinely useful questions about architecture and direction. That kind of attention does not build the project for you, obviously, but it does give a lot of energy back when you are deep in the part of the work that is usually invisible.

And then, almost immediately after that, this week started with one of those bugs that makes you question your own sanity.

I lost almost two days chasing an issue that looked like it had to be in my code. It wasn't. It turned out to be a .NET/runtime problem on the debugger side, which I reported here: dotnet/runtime#125484.

That kind of thing is frustrating for the obvious reason: the time is still gone, even when the bug is not yours. But it also gave me a useful reminder. A lot of engineering time is not spent fixing your own mistakes. Sometimes it is spent proving that the problem lives somewhere else.

And that distinction matters more than it sounds. If you misdiagnose a platform bug as an application bug, you can spend days "improving" code that was never the problem in the first place. This week I had to do the opposite kind of work: reduce the problem carefully enough that I could stop blaming Moongate for behavior Moongate did not actually own.

Even with that detour, this ended up being a very solid week for Moongate. The biggest step forward was the new player portal, but there was also meaningful progress on maps, content authoring, mobile state, protocol work, and a few engine fixes that were worth doing before they became bigger problems.

The player portal is real now

The headline feature this week is the new player portal.

Moongate now has a proper player-facing web surface where an account can log in, move through profile navigation, change its password, and inspect character-related data without dropping straight into admin-only tooling or raw backend internals.

The most useful addition here is that the portal is no longer just a shell. It is actually becoming a place where a player can verify game state. I added views for character inventory and bank contents, which turns the portal from a cosmetic extra into something operationally useful.

Portal

That matters because one of the recurring problems in projects like this is that world state exists, but it is hard to inspect from the outside. If a player reports "I think I lost an item" or "I don't remember what was in my bank," having a direct way to check account-adjacent data is a much better experience than treating the game server as a black box.

It also changes the feel of the project. A lot of emulator and server work is real progress that does not look like progress until you build an interface around it. The portal gives that work somewhere to land. It takes systems that would otherwise only be visible through logs, database rows, or internal tools and puts them behind a path a normal player can actually navigate.

This also came with some presentation work. I added profile navigation, branding, localization support, and pushed the visual direction further into the dark fantasy style I want for the project.

That design work was not just decoration. Once you decide a portal is meant to be used and not merely demonstrated, structure starts to matter more. Navigation matters. Labels matter. The difference between "there is a page for this" and "this feels like part of a coherent player surface" is mostly in those details.

Also, in the interest of honesty: a good chunk of the UI work was done with Codex, because I absolutely hate doing frontend work myself. I can do it when I need to, but it drains me fast, and I would much rather spend that energy on runtime behavior, protocol work, and game-server systems. Using Codex for the portal UI let me keep momentum on the parts I care about without leaving the web surface half-baked.

Portal 2

Portal 3

Bank

The broader point is simple: Moongate is starting to grow real player-facing surfaces, not just server internals. That is the kind of progress I care about because it forces the backend, data model, and UI to meet in the same place.

Better tools for seeing the world

Another area that moved forward this week was world visibility.

I added a maps page with zoom and pan support, a coordinate crosshair that shows UO map coordinates on hover, and online player markers on top of the world map. Those features are useful as UI on their own, but they are also part of a larger pattern: making the world easier to observe while it is running.

Map view

That kind of visibility pays for itself quickly. It helps with debugging, it helps with admin workflows, and it helps turn "I think the world is doing X" into something you can verify in a few seconds.

The map viewer is a good example of the kind of feature I like in infrastructure-heavy projects: useful for players and operators, but also secretly a debugging tool. As soon as you can inspect a world spatially, a lot of vague state problems become concrete. You can see where people are, whether your coordinate assumptions are wrong, and whether the live world matches the mental model in your head.

Moongate has a lot of systems work under the hood, and that can easily become invisible progress. The map tools make some of that progress legible. They also complement the portal nicely: one surface helps you inspect player-owned state, the other helps you inspect the world those players live in.

Books and content authoring got much better

I also spent time improving the content side of the project.

Books now support both readonly and writable flows, including the client 7 writable book path. I also fixed some of the rough edges around book tooltips and page requests so the whole feature behaves more like a real system and less like a partially-wired experiment.

On top of that, I added text template rendering for gumps and support for hash comments in text templates. That is not as flashy as a new UI page, but it matters a lot for the long-term direction of the project. It means more game content can be authored and iterated on without pushing every small change through hardcoded server logic.

Books

This is one of the recurring themes in Moongate right now: moving from "the server can technically do this" to "this is actually a usable content pipeline."

That distinction is easy to underestimate. It is one thing to prove that content can be represented. It is another to make the authoring path resilient enough that you would actually want to build on top of it. Writable books, readonly books, template rendering, and the little compatibility fixes around them all push in that direction.

Mobile state and protocol work kept catching up with the features

A lot of visible progress this week depended on less visible model and protocol work.

I added typed mobile state, effective modifiers, persisted skills, and a more modern player status packet path. I also expanded the packet coverage documentation, including a pragmatic coverage matrix and POL reference notes.

That kind of work does not usually produce a screenshot, but it is part of what makes the project feel less fragile over time. Features are easier to trust when the underlying state model is explicit, persisted correctly, and mapped to protocol behavior in a way that is easier to reason about.

I think this is one of the places where game-server projects either mature or stay permanently slippery. If state stays implicit for too long, every new feature becomes a negotiation with hidden behavior. If state gets typed, persisted, and documented properly, new features start to compose instead of collide.

A few engine and runtime fixes were still necessary

There was also some less glamorous but important cleanup this week.

I fixed more linked-door behavior, persisted and applied door facing metadata, and refactored some hot paths to use pooled buffers and reference lists instead of paying unnecessary allocation costs. None of that is the kind of thing that makes a flashy headline, but this kind of polish is what keeps a project from slowing down under its own weight.

There were also smaller fixes around debugger startup on macOS, container/item inspection, and various places where recent work needed to be tightened up so the project could keep moving without accumulating avoidable friction.

And that loops back to the opening .NET issue. Sometimes the visible progress of a week is not just what you shipped. It is what you shipped while also surviving platform friction, debugging detours, and the normal background noise of engine work.

Closing

So the short version of this week is:

That is the kind of week I want more of.

Moongate is still very much a work in progress, but it is starting to connect three things that matter at the same time: player-facing UX, operational visibility, and flexible content systems. That combination is much more interesting to me than shipping isolated features with no connective tissue between them.

This was also the kind of week that makes the shape of the project easier to see. The portal is not an isolated web add-on. The maps work is not just a debugging toy. The books and templates work is not just content polish. They all point in the same direction: a server that is easier to use, easier to inspect, and easier to build on top of.

Three Bugs That Forced an Architecture Upgrade


#devlog #dotnet #gamedev #moongate #ultima-online