Tutorial 1 - Background

Published 1 month, 1 week ago


In this tutorial I'll go over some important background information you'll need before you can start developing mods.

Contents

1 Preface

The AER modding framework is very new. Expect to encounter a lot of bugs while developing your mods. If you do run into any bugs, please mention them on the official Discord server or post an issue on the Github repository. Furthermore, while I've done my best to analyze and understand as many pieces of the HLD executable as I can, there is still a whole lot that I don't understand about it. That means there aren't going to be cut-and-dry solutions for many of things you might want your mod to do; you'll likely have to get creative at some points. Please reach out for help on the Discord if you're not sure how to approach a problem!

AER mods are created using the C programming language. This language can be a bit unforgiving at times, so I've tried my best to make the mod development process as straightforward as I reasonably can. Also keep in mind that that HLD is a 32-bit game (even when running on 64-bit machines). As a result, you'll be using 32-bit types.

The AER framework tries to be agnostic when it comes to the IDE or code editor you use to create your mods. If you already have a C development workflow that you're comfortable with, you shouldn't have any issues writing mods using that workflow. For those who haven't worked with C as much or don't have a development workflow, I've created a template mod project called the AER Mod Development Kit (MDK) you can use. It should hopefully make the modding process significantly easier. I'll discuss this more in the next tutorial.

Lastly, the AER mod runtime environment (the C library that your mod will call functions from) will strictly follow Semantic Versioning. That means if you write a mod for a fictional version of the MRE, v2.3.4, then that same mod is guaranteed to be compatible with all newer releases with the same major version number (2 in this case).

2 HLD's Engine

HLD was created by Heart Machine using an early version of the Game Maker Engine. As of the time this tutorial was written, YoYo Games has released two versions of this engine. At the time of HLD's development, Game Maker was just starting the transition from the first version of the engine to the second. As a result, HLD's executable contains most of the original engine's functionality, but a few notable sections have been deprecated and no longer function.

The goal of this modding framework is to give mod developers the ability to tap into key engine functionality to manipulate HLD's game state in creative, novel, and useful ways. With this in mind, you'll need a basic understanding of this engine before you can start developing your first mod. Throughout these tutorials, I'll be referencing the official engine (v1) documentation.

2.1 Objects

(Go here for the official AER Object API.)

At the very heart of the engine is the concept of objects. If you're familiar with object-oriented programming, then you could think of an object as a class. An object is basically a "blueprint" for a specific type of entity. Objects have the ability to "inherit" functionality from other objects. This forms the "object inheritance tree".

2.2 Instances

(Go here for the official AER Instance API.)

If objects are like blueprints, then instances are the actual things created using those blueprints. Instances are effectively the engine's version of "entities". All of the things on the screen from the player character to enemies to bullets to even menus are all instances of some object. That is to say that Heart Machine created special objects for every "kind" of entity that can appear in the game, and they then create multiple instances of these objects to interact with each other.

In the context of the AER modding framework, instances have three key categories of properties:

2.2.1 Attributes

Attributes are the hard-wired properties that every instance has no matter which object "blueprint" it was created from. These include things like sprite, position, movement speed and ID. Note that just because an instance has a particular attribute, that doesn't mean it has to use it.

2.2.2 HLD Locals

While it might seem easy to just give every single instance a bunch of attributes for every conceivable situation, it would start to become impractical once each instance has hundreds of values to keep track of (only some of which it actually uses). To solve this problem, the engine provided Heart Machine with a way to assign custom attributes to specific instances. These are referred to as HLD locals in the modding framework.

2.2.3 Mod Locals

For the sake of performance, the engine made special optimizations to the HLD locals. An unfortunate side effect is that while the AER framework allows you to lookup and modify these HLD locals, you can't actually give new HLD locals to instances. To get around this, the framework provides the concept of mod locals. These mod locals behave almost exactly the same as HLD locals, but they are managed by the AER framework instead of the engine and you can freely create and destroy them.

2.3 Sprites

(Go here for the official AER Sprite API.)

So far I've only discussed internal logic related to HLD. To bring life to that logic, the engine uses the concept of sprites. Broadly speaking, sprites are the actual visual representations of instances. An instance can only have one sprite at a time (or no sprite at all), but it can change which sprite it renders itself as whenever it chooses.

Sprites aren't limited to static images; they can (optionally) be animated with an arbitrary number of animation frames. The speed at which this animation occurs is controlled by an attribute on the instance being rendered. Technically, the engine allows sprites to be rendered on their own without being attached to an instance. The AER framework, however, only allows sprites to be rendered via instances (for the time being).

2.4 Events

(Go here for the official AER Event API.)

So now you see how the HLD engine represents in-game instances and how it displays them, but what controls how those instances interact with each other? The answer is events. Game Maker is a fundamentally event-driven engine. This means that for a great number of situations (such as when an instance of an object is created, when it's destroyed, when it collides with another instance of some object and even when its sprite animation is finished), the engine triggers an event.

To handle an event, the engine first determines the object that the target instance was created from. It then checks if Heart Machine attached an "event listener" to that specific event on that specific object. An event listener is just a piece of code that does any number of things in response to the event. If the object does have a listener, then the engine executes it with the particular instance(s) that triggered the event. Finally, the engine executes the corresponding event listener on that object's parent object, and then the "grandparent" object, all the way until it gets to the base object from which all objects either directly or indirectly inherit.

This is where the AER framework truly shines; it provides mod developers with a very robust method of tapping into this event system in a clean and compatibility-minded way.

2.5 Rooms

(Go here for the official AER Room API.)

Additionally, the game needs environments in which instances can interact with each other. That's where rooms come into play. Unfortunately, rooms haven't been a focus of the HLD analysis effort, so the current version of the AER framework doesn't provide many tools for manipulating in-game rooms. Hopefully this will change in the future.

2.6 Steps

Finally, the engine must simulate all of this in discrete intervals many times per second. Most games call these intervals "ticks", but Game Maker chooses to call them steps. A step corresponds to one iteration of the main game loop, and HLD has 60 steps per second.

 

#dev #moddevtut