24 December 2024 - Entity Actions, and The Lack of a Player Entity
<<< Previous Post
Next Post >>>
A lot of my recent posts have been complaints and problems. So let's change up the vibe a bit and talk about progress! I'll even say it's for holiday spirit so I get some +rep with Santa.
Anyway, in this post I want to talk about the Entity Action system. This is a sort-of-complex system that works with the main Entity system to allow entities to actually do things, without actually having to know how to do it. The entity just says "I want to do this", and the action handles the details and the procedure.
I think a lot of people will find this exciting, especially those that enjoy the ability to roleplay in games. You'll see why. But first, we have to break it down.
What Is It?
The term "entity" in a game is basically representative of "a thing in the world that is doing something with code". This could be an NPC, a machine, or a vehicle. Blocks in the world are not entities, because they are just geometry. That should make sense, right?
Most games have a distinct entity type for the player. This is incredibly common as it allows assigning special functionality to players that NPCs wouldn't typically have, like a link to the save file, an inventory, and other assorted goodies. It also makes it easy for NPCs to know that they are interacting with a player. You see, I actually chose to not do this.
In my game, entities have a piece of data known as an input provider. This is basically the interface layer that links some arbitrary technique of control to the entity. This control could be an AI (like, the traditional game kind, not deep learning), or it could be your keyboard+mouse/gamepad. What matters is that it provides instructions for what the entity should be doing.
By extension of this, players are identified with the player controller. Consider this and the lack of a specific player entity type, and you (hopefully) guessed it: the player can be any (living) entity in the game! The game is designed with this in mind. And modders, don't worry, there is a very convenient, well-defined AbstractEntity.IsPlayer
property available to you.
I think this opens the door for a lot of potential with new gameplay created by users. This was heavily inspired by Risk of Rain 2's RoR2::CharacterBody
class. You can actually play as anything in the game, not just the survivors, and I thought that was really cool. It was also inspired by Rain World's Safari Mode, where you can take control of random creatures around the map and play with the ecosystem.
Most importantly, I think this is an outstanding immersive tool. Games often treat the player differently, and it kind of breaks the immersion if your goal is to tell your own story where you might not want to be the flashy main character. If you spawn in as a Novan, NPCs will see you as just a plain Novan like they would any other, not as "the player".
So, How Does it Work?
A data type in the game's code called EntityAction
declares a thing an entity can do. This is about as arbitrary as it sounds. It could be the action of placing a block in the world, the action of swinging a melee attack, the action of shooting a gun, the action of smelling the air to find something, the action of casting a spell. If it is an action and, discretely, is not movement (because movement and jumping has its own system), and is not an interaction with a usable object (because interactions have their own type as well, but this may very well change!) it's an Entity Action.
Actions are entirely arbitrary, and must be created on game startup (you can't create new action types during runtime (read: after mod initialization), this is for network compatibility and such). The thing is, an entity has to know what actions it can actually do, and these actions might change depending on context! For example, a person's default primary action might be to swing their fist, but if they are holding a gun, it needs to override the primary action so they shoot the gun instead of swinging it at someone.
To do this, there is a container type: An action palette. This holds a number of predefined action slots (primary, secondary, tertiary, that sort) that can be stored. These palettes are applied to a species to declare their default actions, then can be applied to items to override certain slots using a priority system. To call back to Risk of Rain 2 again, think of the Heretic's lunar items, and how they replace your skills. Basically the same thing.
How will it work with custom stuff?
The game enforces that actions can be performed with a minimal amount of commonly available data. This means that while certain actions may require some context (of any type, as it is defined by the developer (myself or modders)), at a base level actions require nothing more than the entity performing them.
Currently, the technique to get information (like configuration for a common type of action, so that actions can be shared) is undetermined. I have a way in mind, but it is unsafe and uses unmanaged memory so it's obviously not the best for C#.