Monthly Archives: December 2017

Gearing up

It’s time to start work on Animated Chatroom. It is a monumental project; the largest project to date that I have ever desired to undertake.

My resources are somewhat scarce, but it could be worse. The two resources which I am in great scarcity of are developers (human resources) and energy (something which tends to be inversely proportional to time). The developers I seek are either not competent enough to produce modular code, or they live in a very different time zone that complicates any coordinative effort. My energy is drained from playing with my brother or doing real-life tasks which I have been postponing for too long, such as cleaning some things up.

There is another question that compounds a desire to do everything other than work on Animated Chatroom: where do I even start?

Well, let’s see what Torvalds has to say about his success:

Nobody should start to undertake a large project. You start with a small trivial project, and you should never expect it to get large. If you do, you’ll just overdesign and generally think it is more important than it likely is at that stage. Or worse, you might be scared away by the sheer size of the work you envision. So start small, and think about the details. Don’t think about some big picture and fancy design. If it doesn’t solve some fairly immediate need, it’s almost certainly over-designed. And don’t expect people to jump in and help you. That’s not how these things work. You need to get something half-way useful first, and then others will say “hey, that almost works for me”, and they’ll get involved in the project.

Okay, Benevolent Dictator Linus…

You start with a small trivial project, and you should never expect it to get large. If you do, you’ll just overdesign and generally think it is more important than it likely is at that stage.

All right, so we started with a small trivial project. It was called Attorney Online 2. It was good. And then it tanked because of poor design. I want Animated Chatroom to not go through that pain again.

Or worse, you might be scared away by the sheer size of the work you envision.

Which I am.All right, so what features do we not need? Let’s cut nodes until we get something less overwhelming.

Better. That’s almost the bare minimum that I need.

In list format:

  1. Core animation engine.
  2. Asset loader.
  3. Basic network.
  4. Basic UI.

That’s all, I guess I don’t care about anything else right now. So let’s cut it down even further.

Okay. So version 0.1 will barely have a UI. It’s just figuring out how stuff should work.

It’s clear that VNVM is at the center of this entire project. If I can design VNVM correctly, then this project has a chance; otherwise, a poor execution will lead to a shaky foundation.

The Visual Novel Virtual Machine

What is the purpose of the Visual Novel Virtual Machine project? The purpose is to bring sequences of animations and dialogue sequences, the bread and butter of visual novels, to a portable environment. From reverse engineering performed by others, it turns out that major visual novels also use a bytecode to control dialogue and game events. In the VNVM world, this is called VNASM (Visual Novel Assembly).

Within characters, emotes are simply small bits of VNASM, which are then called by the parent game (which also runs in the VNVM). Recording a game is just a matter of storing what code was emitted and when. The point is that essentially all VNASM is compiled or emitted by a front-end, rendering it unnecessary to understand VNASM to write a character. (But, it would kinda be nice to be able to inline it, wouldn’t it?)

This makes VNVM satisfactory for both scripted and network environments. In a network situation, where the execution is left open, there is a simple wait loop that awaits the next instruction from the network buffer. New clients simply retrieve the full execution state of the VNVM to get going. The server controls what kinds of commands can be sent to it; most likely, an in-character chat will look something like this as a request made to the server:

{ emote: "thinking", message: "Hmm... \p{2} I wonder if I can get this to work right..." }

The \p marker denotes a pause of 2 seconds, which the server parses out to emit a delay of 2 seconds (of course, limiting the number to a reasonable amount). The server then pushes the reference to the character who wants to talk, as well as the message to be said, and calls char_0b7aa8::thinking where 0b7aa8 is the character’s ID. This denotes that the named subroutine thinking is located in a segment of VNVM code named char_0b7aa8.

More to follow later.

Rethinking Attorney Online assets

It seems fairly obvious that FanatSors was not expecting a complex level of gameplay when he released the Delphi-made Attorney Online back in 2012.

Yet AO still exists, with about 150-200 daily players who frequent the couple dozen servers, with the most popular being /aog/’s Attorney Online Vidya. OmniTroid’s Qt-based, open-source AO2 client is now the de facto client, touting “advanced” features such as color, Unicode support, and parametrized preanimations. Likewise, the open-source tsuserver3 and esoteric-but-still-open-source serverD are the two choices of hosting for AO. Today, however, the legends of FanatSors and OmniTroid have faded away.

https://i.imgur.com/V30YtuL.png
An overview of the Attorney Online family.

Most players and case-writers are regularly impacted by the technical limits and quirks of the engine. Configuration of each character is all done in a single INI file, defining each emote as an octothorpe-delimited sequence of animations to be played. Each animation refers to a GIF file prefixed by an (a) or (b); that is, the format and naming scheme must be precise in the file system level.

This is not the main challenge, however. The challenge is managing assets.

Every server asks their users to download an archive, spanning up to 7 GB in size, containing character sprites, music tracks, backgrounds, evidence images, and sound effects that may be needed during gameplay. Assets are only identified by their folder name; this is the only unique identifier attached to an asset. These are the problems with using an internal name as the sole identifier:

  • Two servers may offer different content, but under the same internal name, causing a hard clash. Content could be isolated per-server, but this causes a serious redundancy problem.
  • Two servers may offer the same content, but under different internal names. This causes excessive redundancy.
  • Two servers may offer just about the same content, with a small difference. In this case, there is no hierarchy established as to which one is derived from the other one.

Upon requesting a character list for my proposed new standard base, nuVanilla (and receiving a monumental list!), it felt that the amount of dimensions that the assets needed to be examined in were too many to use a conventional spreadsheet for, so I opted for a full-blown database. My choice was split between MySQL/MariaDB and PostgreSQL, but I remembered that I wanted to learn Postgres, as the performance and versatility claimed to be far greater than MariaDB could offer.

One immediate issue is the sheer number of many-to-many relationships that manifest, causing an effective decoupling of many columns:

  • Multiple packs can include the same asset.
  • The same asset could be under different internal names.
  • Multiple assets can have the same internal name.
  • Multiple assets can represent the same character.
  • Assets of the same character can come from different games.
  • Assets can be in different formats, such as 256×192 or even 1280×720 (yes, some people resize their sprites to match their theme’s viewport size).

How do I represent uniqueness of assets, then? I can’t even hash the char.ini, because the char.ini contains the internal name of the asset. What’s more, there is no standard way to hash multiple files at a time; in this case, I would want to hash all of the emote images at the same time. (For now, however, I am hashing the char.ini until I find an adequate solution.)

One solution would be to give every asset a UUID. This would, in theory, add an additional layer of “uniqueness” into each asset. However, this still does not resolve the original problem: two assets with the same content but different internal names would still be detected as “different” upon submission, since the hash of each char.ini would be different. And this would compound a new problem on top of the old one: modifiers of an asset would be burdened with updating the UUID of the asset they are editing; forgetting to update it could only cause an error when uploading it to some centralized database.

What modifications can be done to an asset?

  • A small correction to frame data – minimal change
  • Emote additions – significant change
  • Internal name change – minimal change
  • SFX name change – minimal change

Three out of four of these changes are minimal changes. Thus, it would not make sense to consider them completely different assets. We can try to establish a hierarchy of assets, to see which asset succeeded the other, but that is no substitute for a diff. The data stored remains redundant.

Therefore, I can conclude Attorney Online assets cannot be accurately uniquely identified for management, and attempting to set up a database to manage them would take me nowhere.

I should then refocus my efforts to designing asset structure in Animated Chatroom.

Each asset would have a definition file (such as char.json), which would state the name of the character, its ancestors, and a reference to the sprite file. The format of the definition file would probably be JSON, while the sprite file would then be written in something like Spritelang.

The asset is then bundled using tar and signed using GPG. This verifies the identity of the packager of the asset (for increased trust, the packager’s key can be cross-signed by a responsible admin, who in turned is cross-signed by the Animated Chatroom Root Key. All of these keys can be uploaded onto a general-purpose key server, like pgp.mit.edu. The signature of a package need not be specifically signed by the AC official root key; just a key that is cross-signed by someone on the keychain. The absence of a signature does not mean that the asset contains malicious content and therefore cannot be trusted; rather, the purpose of the signature is to assure that the contents of an asset have not been modified, and to seal the credits of an asset. After the tar has been signed, the tar can then be compressed in a desired format such as xz (which is basically 7-Zip but using a byte stream as opposed to an embedded archive). In this case, the unique identifier of the asset is the key ID of the GPG signature. This is the strongest possible hash: not only is the data factored in, but also the identity of the individual who authored the asset.

Now that we have established a strong, unique identifier to our data, we need to solve the data redundancy problem.

Children of ancestors use an incremental tar file, which minimizes the content stored in the child. Even deleted content can be tracked if incremental tars are applied correctly. We may also employ a similar scheme as the Docker Image Specification (version 1), but it’s clear that someone did not read into tar’s ability to do incremental archiving out of the box. (“NOTE: For this reason, it is not possible to create an image root filesystem which contains a file or directory with a name beginning with .wh.. ” It requires little thinking to realize that this is a tremendously absurd limitation, just to add the ability of identifying deleted objects. If anything, deleted files should have been put in a separate file, for the sake of not introducing an artificial limitation to the file system.)

Incremental versioning has a major implication for authoring assets: authored assets are immutable. No, sir, the Animated Chatroom authoring tool will not allow you to modify an asset that has already been successfully packaged and signed, unless you choose one of the following options:

  • Create an asset that is a child of the asset you want to modify. This is not a favorable option if you have not published the parent asset. However, the authoring tool will set the hierarchy up for you.
  • Create a new asset, derived from the data of the parent asset. There is no hierarchy established, it’s just a hard copy of the parent asset. This is favorable only when the parent asset has not been published.

Acquiring modified versions of an asset would be simple under this system:

  • The desired version of the asset is downloaded and unzipped. (We don’t need to untar the entire asset yet.)
  • The signature is verified, and a warning is displayed if the signature is invalid.
  • The definition file is untarred and checked for an ancestor. If an ancestor exists, a recursive download request is made on the ancestor.
  • The asset contents are untarred on the target folder.

Asset servers for Animated Chatroom web clients can establish this hierarchy – without the expected redundancy! – by using symbolic links to represent files that are identical to the parent.

Finally, we can track what assets we have downloaded and what asset repositories we are currently using, by storing local data in an SQLite database file.

Instead of a name-based character list, servers use character IDs to disambiguate between different versions of the same character. A server can then offer download sources for specific characters, such as if a character was made “in-house,” so to speak.

What are the improvements over this design over the old design devised by FanatSors?

  • Authorship is immutable. This is important mostly for original content: repository owners will refuse to publish assets that refuse to identify the original creator of content. However, in the case of ripped content, it is desirable to preserve information about who ripped it, but ultimately, it is all copyrighted by the publisher of the game (Capcom, Chunsoft, etc.).
  • Downloading is automatic. Under the old system, players were too lazy to download zip files to play on new servers, and server owners were too lazy to compose zip files for players to download every time new content is suggested. Now, server admins need only do a graphical lookup of the assets they want to add on the server, confirm the additions, and the new content is immediately requested for download by clients, all seamlessly and in the background.
  • Name clashing is no more, since we established that internal names are no good as a unique identifier.
  • Asset content is deduplicated (to the best of the ability of this system).
  • Asset management is decentralized. I don’t own the database – in fact, nobody does. You can host part of the repertoire of Animated Chatroom content, but you can never host all of it.
    • On a similar note, this makes Animated Chatroom effectively immune to cease-and-desist notifications. I can take down the offending content on my servers, but due to technical restrictions, I cannot be responsible for the content hosted by other servers. The cease-and-desist notifications would have to be sent to each offending server.

This concludes an overview of the proposed design of asset management in Animated Chatroom. I hope you found this design enlightening for any future adventures in software development.

Reverse engineering LIMG

LIMG is the custom image format used in Professor Layton and the Unwound Future. Like many Level-5 shenanigans, it’s a custom format for absolutely no reason other than to serve as a deterrent for future reverse engineers (no pun intended).

After taking Tinke and applying it to the game’s image, we can easily find that the animations are CANIs, which get decompressed via LZ10 and passed through a QuickBMS script to get split into LIMGs. But what now? Tinke does not recognize the LIMG format, and all we get is an incoherent mess, which we can explore by opening the file as either a tile or a map. This process works best with small images.

We can, for instance, open up /lt3/menu/level5_a.limg, and expect the Level-5 wordmark. We can achieve getting the wordmark with an offset of 0x680, a 128×16 size image, horizontal image pattern, and 8×8 tile size, with still some artifacts and wrong color.

We can then take a look at the LIMG in hexadecimal, and try to find these values. We start off with the FourCC (LIMG), then what seems to be the 32-bit base offset value, … and then what?

That’s where I’m stuck. I need to know where the palette data is, etc.

Aesthetics

It’s that season again when girls dress in cozy jackets with skintight leggings and “cute” boots. Juxtapose this thought, for one brief moment, with the image of guys with gym shorts coming in the bathroom, slamming the toilet seat down, sitting for a good long while on the toilet, and then letting the door slam on the way out; and then another doing some shaving or something, playing a bunch of country music all about getting some girl or otherwise generally romantic.

How does that make me feel? Not very masculine.

Sometimes I imagine myself fighting someone off and succeeding, and then finally looking at myself to see what monstrous body I have inherited. A body strong enough to kill. A voice deep enough to hold ground. An uncontrollable amount of hair.

And sometimes I have dreamed of being in a store, eyeing these leggings, and trying to put them on. And I’ve had the same dream for years. Why?

It is not something easily explicable. If someone asks me if I look at women, I would say yes – it’s not exactly easily resistible. But I don’t think I do it for the same reasons as other men do it: I don’t lust them. I am not interested in sex. But I do look at curvatures and those physical and expressive qualities that make someone simply seem touchable and huggable, even if I never ultimately end up touching or hugging them (in fact, this never happens). But I think about it anyway: how it feels to cuddle with someone, to enjoy life with them, to simply propulse encouragement off one another and live life to the fullest, notwithstanding what others think or feel except for these two people, who are so tightly wrapped within one another.

And what do they expect of me? Some call me strong. Others have suggested I start lifting weights – not fully aware of what little self-esteem I have. Do they expect a sedate friendship or a deep connection? And what do I expect of them? To support me in my personal projects/delusions? To feel comfortable if I wrap my arms around them, or if I rest my head on their lap?

Maybe I should try sleeping for something longer than 7.5 hours.