Into Avalonia I Go

For all the praises I’ve sung to Apple’s Swift programming language, you’d think I would have thrown C# under the bus. And while I do think Swift’s package management is a lot better, I’m still quite fond of C#. That being said, my biggest problem with .NET in the past has been working with GUI frameworks. Although I’m very good at writing command line applications, it’s not where my heart is at.

My first successful desktop application was a simple game launcher designed with Windows Forms, Blue Rose. It was created for an open source project that was still in the alpha stage. When leadership changed hands, we were stuck with downloading rapid-fire builds manually. Getting tired of the madness, I reluctantly put together a quick launcher to fill in the gap because no one else would. It worked flawlessly and everyone used it. So when the lead programmer and I had a falling out (for the dumbest reason), you can imagine how I felt having to give up all that hard work.

After that, I basically bounced from framework to framework. My only requirement is that it has support for Linux. Closet I got to something I liked was Tauri, an Electron-like framework, because it had support for C# in the form of Blazor. The downside is that while it a lot more faster than Electron because it uses the operating system’s built-in renderer, it still complicated by the fact it uses Rust as the backend. (See my thoughts on Rust here) Aside from that, I basically wanted to stick Terminal interfaces.

Barkdown Editor

My biggest beef with Microsoft is their flagship UI framework, MAUI, lacks Linux support. Despite literary standing for “Multiplatform,” it only targets macOS, iOS, and Android but not desktop Linux. So, yeah, they’re not lying but since .NET as a whole supports Linux (it’s what. got me to soften up in the first place), you can imagine my disappointment. It wasn’t until I rediscovered Avalonia, a similar framework that does support Linux, that I reconsidered. So I followed their quick starter tutorial and quickly warmed to it. The tutorial was a simple temperature converter that updated in real time.

After trying it out with a few other projects and with the intended goal of porting over Blue Rose, I pondered… “Wait. This can’t just another niche one shot. I want this to full fill a need like Blue Rose but it needs to be general purpose yet still easy enough to tinker with to the end of time.” Then I remembered a long time ago when I made a website in an early version Blazor that rendered Markdown from content read from a JSON file I created. I could make a Markdown editor! I already knew this would work because I already seen the exact API I needed in action before. And it’s the most simplistic thing in the world. All you need is an input box one side and web view on the other. No wonder there dime a dozen editors out there in the wild. It’s a great progression progression from the tutorial! So I did just that.

After I quickly scraping together and remembering what I had use previously, I spun up the Barkdown project and voila! Worked exactly as I knew it would. As much I love the name, it does imply that it is a variant of Markdown when that’s not the case. It’s just a filler. xD I already read up that it’s possible to hook in support for varies filetype, etc., into Avalonia. So that makes it even better.

Unwrapping Swift

I recently rewritten my toy program that prints the ISO week, e.g. 2026-W18-04, from Rust to Swift. The previous version was approaching roughly 100 lines of code (excluding the self updater portions) and imported dozens of third-party libraries compared to the newer version that’s roughly 30 lines that only pulls from Swift’s build-in standard library, Foundation. Granted, this doesn’t include all the options from the original but --utc was reintroduced.

Adding UTC support proved a bit tricky. Swift 6 brought native support for concurrency and protection against data races. This brought with it unwrapping and the concept of ownership. Ya’ know. The very thing I threw a fit over Rust about, but there are some differences.

The TimeZone struct, included in Foundation, provided the solution to this but also introduced a new problem in regards to implementation. I needed to unwrap it in order to properly get the value needed to change the calendar’s time zone property. Luckily, this proved to be rather easier than I thought. All I had to do was apply timeZone ?? .autoupdatingCurrent to the property.

While the actual implementation is fairly straight forward, there is a lot going on under the hood that resulted in using this fairly simple solution. Because time zone abbreviations aren’t standardized and may have contradicting meanings, it is possible to not return no value at all. In order to account for this, we fall back to the user’s “current” (i.e. local) time zone.

When I had to use Rust, unwrapping often invoking the unwrap() method or using Some() struct for more complex routines. In my experience, using the unwrap method can cause trouble in it’s own right because it expects there to be a value. It’s basically the equivalent of adding the exclamation mark at the end of the field in order to override the safety checks. (That’s actually what I originally did in my first attempt with time zone switcher.) The Some() is used in if statements in order to test for the right value, which is to say but that can lead to the Pyramid of Doom if not done right. You could do a simple if statement using Ok() and Err() (the raw version of vlaue1 ?? value2), which is basically to saying, “okay, this is true, but if it isn’t you can throw an error,” but that too can easily lead down the same path of doom.

To be fair, there is no right or wrong way of handling concurrency. In fact, both Rust, and Swift do overlap in some places. It’s just the way Swift does it tends to behave more like C#’s error checking than Rust’s verbose way of doing things.

Decentralized Package Management

One thing that has always given me a more favourable view of Swift is how Apple choose to go about handling package management from the very beginning. Similar to Go, the majority of packages are referenced using Git repositories. Swift differs in that you usually have to specify a snapshotted version using the tag feature instead of pulling everything from a certain branch. Not that you can’t do that, don’t get me wrong, it’s just not recommended in production.

While this method is not without its drawbacks, it does eliminate a lot of security concerns. Plenty of my toy Rust and .NET applications had relied on dependent bot to frequently update varies dependencies. Swift takes this approach a step further by having a minimum version baseline. You can really fine-tone this by simply updating every minor patch or major release. 

Really the biggest drawback is that you are building a lot of external dependencies all at once. Sure it removes DLL hell but it does increase the build time and processing resources by quite a bit. Trade offs. It’s essentially bad with languages like Rust because it exists in such weird middle ground between bare bones and having a feature complete standard library. Like, I had to write an extension for a time and date library just so I can get basic support for printing ISO weeks that I could use for my little toy program that was inspired by Tom Scott. I just created DLC for DLC just so my silly little program worked. Like, WTF!? Luckily, Swift isn’t that bad since Foundation is built into the language, regardless of the platform you’re on, and you know they’re going to optimize the shit out of it for experience. But I digress. xD

All that being said, this is how it’s always been done. Many C/C++ programs bundle libraries needed to successfully build their project. It’s basically why many of their classic projects have such big and monolithic repositories. When Git came along, plenty of new projects pulled from submodules instead. Even older .NET applications did this before NuGet came along. Modern programming languages, such as Go and Swift, just adopted a form of this submodule practice by baking it into the package manager and having those be referenced from a cache instead.

Really the biggest benefit is decentralization. Even if Apple attempted to were throw a wrench into the ecosystem, they’d likely miss. The majority of that ecosystem is just open source Git repositories that anyone fork. This is also means that you’re not limited to a central repository or host. Like, there is this one library I discovered a few days ago in the Swift Package Index they recently moved from GitHub to their own personal Git and it still functions all the same.

Compare this something like .NET, where everything is centralized on NuGet. While this isn’t necessarily a bad thing and it has certainly help evaluate the platform, Microsoft really has their grip on the wheel. All their recent .NET talks is just about AI this and AI that. Meanwhile, Apple is over here creating new open source libraries and features. Like the recent @c annotation that exports functions as C headers or their new Configuration library. I love the .NET guys. I really do. The two Scotts are my favourite. I just hate the leadership. (Not that Apple is any better.)

From Rust to Swift

As the Rust programming language continues to spread through the open source community, I find myself wanting to leave it. I haven’t touched it since the pandemic. The borrow checker is just so annoying to use. Like, the compiler could hit on you upside the head for the most benign things. It’s so frustrating. xD I’ve yearned for something that was just as safe without sacrificing damn near everything. My first attempt was with Zig and, as much I really liked it, the language still has some teething issues.

Now, I’ve been keeping track of Swift on and off for a long time. Roughly since it’s debut in 2014. Helps that I’m a Mac user. Despite suffering similar teething problems as Zig, it evolved rapidly and matured a lot since 5.0. I decided to give it another shot when I was setting up my Linux laptop. The RAM is very small by today’s standards so putting something like Rust’s complicated build system wasn’t much of an option. So I created a series of command line applications after I discovered that’s what “tool” option meant. My first attempt was creating a simple program that generates a desktop entry for Linux. It was quite simple to make. Like, the whole program is roughly a 100 lines of code. (Although, if you focus on the actual logic portion, it’s probably way tiny.) And although I haven’t properly tested it on a distro yet, the dry runs are working flawlessly.

I have a number of other tools written in not only Rust but C# that could do with a proper rewrite. The most complex are written in C# while the simpler ones are in Rust. My most simplistic is a D&D dice roller. I had planned to add support for modifiers but my issue with the borrowing checker forced me to abandon it. On the C# side, my tool used to used to streamlines building an EPUB using Pandoc is slightly more complex.

I decided to start simple and rewrote that dice roller. While it shares a roughly similar architecture as the original, there are some notable differences that make the two incompatible. Like instead of typing in any number using the --roll option, you can specify “d2” to “d100” as argument and add an additional --modifier option that you can type a number into. This new version functions more like an actual dice roller you’d use in D&D or any other tabletop game and less like random number generator dressed up as a one. Next up is allowing for multiple dice to be rolled so you can create different builds.

All that being said, Swift is turning out to be a joy to develop for and I may use it to create more tools in the future. Regardless of what some people may say, programming shouldn’t be a chore to do. I stuck with C# and tried out Zig preciously because it didn’t punish me for programming the way I was taught.

And don’t get me wrong, Rust is a great programming language. Once you get the hang of it, it is powerful tool to use like anything else. Rust has earned its spot to be adopted into the kernel and other Linux distros. The language was designed to handle loads like this. But it isn’t for me anymore.

Project Liger Zero

Recently, I just got started working on Project Liger Zero (or TSO LZ), a prototype aimed at recreating The Sims Online using Godot. In order to make this all work I’m using 2dog, a library that uses libgodot in order to reverse the workflow, letting .NET take control of the engine. You can still make use of GDScript or C# for scripting but this brings with it more advanced capabilities of .NET to Godot. Which is useful for both complex games like this or simple ones.

Unlike past projects, I’m taking a slightly different approach to this. Since Godot has a basic multiplayer framework already built-in, I’m going to focus on creating a foundation for testing networking with a simple map view and later lot using Kenny’s game assets as a substitute. That way I won’t be going in completely blind when it comes too finally using TSO’s contents. Not that it doesn’t do that already to a slightly lesser degree.

You see, Godot is rather strict about file I/O. That’s good, don’t get me wrong, but it does make creating a project like this rather tricky. In order to get around that, I figured you can simply place or put a symlink to TSOClient in the game’s user data directory. The first thing I did was to see if this even works is to have it show the TSO version you have on the login screen. Map mode does something similar, if TSO is found it’ll play music from the game. So it is completely possible.

Behind the Name

It’s been a while since I’ve used a code name for a Sims project. Mostly just been reusing the classics cause I couldn’t think of anything better. But this project is certainly different from the rest. While 2dog is just as bleeding edge as my failed attempt with Zig, I at least know C# and Godot.

So when it came to time to come up for name, this needed to be special. Then I remembered Zoids: New Century. It was one of the many animes I grew up with and have been itching to see it again. As a kid, I wanted to be in the mecha the main character had soo bad. So I named this project after it: Liger Zero.

That brief backstory aside, it’s just a cool name to give a game client.

Not Just for TSO

I’ve seen a few recreation projects that eventually grew up to become their own thing. They all reached the point where the game evolved into a versatile engine. Probably the best example is OpenTTD.

So even if all else fails, all this effort doesn’t go to waste. That’s my plan for Liger Zero.