Artemis Entity Tracker - inspecting your game state through network
Let me introduce you Artemis Entity Tracker - a tool to be used for game development in conjuction with artemis-odb (which covers architecture called Entity Component Systems).
Artemis? ECS?
artemis-odb is a high performance and well developed fork of original Artemis Framework developed by Arni Arent.
To read more about ECS, follow this article → Why Entity Component Systems matter?
What is this tool for?
Let’s inspect what’s inside entity (game object) in a developed game. **Then, let’s **update some bits of it’s components, manually. Easy?
Yeah, but include network connection between the inspected data and user interface. Then there’s a challenge. Reflection won’t solve everything, not anymore.
Network connection is a system seller here. Imagine debugging your enemies in an Android game. Now, you could modify their positions, velocity vectors, states etc. using a software on your development PC. This is what we’ll use Artemis Entity Tracker for.
Requirements a.k.a. Challenges under the hood
User interface for Entity Tracker is adjusted to the ECS architecture. However, I need inspection of any Java object:
- download whole object state
- on request, update small parts of it: class fields or elements of simple-typed arrays
- watch over a specific object or field
- handle cyclic references, because it’s not just POJO
- binary. I mean no JSON / YAML / XML / any other text
- frequent updates - object watchers could run 60 times per second
- GUI code is not included in the game. Android wouldn’t like it.
Ideally, the GUI is launched whole the time and not relaunched ever. It automatically connects to just launched game on PC or Android phone. That’s another reason for having GUI code outside of serializer put into game.
Why is this a challenge?
The game is a Server, the Entity Tracker is a Client. Game has all data about structure - types can be inspected through Reflection. Client (GUI) doesn’t have that. Entity Tracker is a separate software that’s independent of any game so it can’t be compiled together with games.
More to it, Entity Tracker System (installed into the Artemis world in a game) connects to a GUI representing the data taken from inspected game. To fetch the data correctly without having reflected types (classes) I have to serialize data structure in the game and send it to Entity Tracker GUI through the network.
Serialize data structure?
Basically, remember how the structure looks like. But there’s a catch. I can’t serialize data structure completely separately from data serialization. Let’s have an example to explain that:
public class GameState {
public GameObject[] objects;
}
public class GameObject {
public Vector3 pos = new Vector3(1, 2, 3);
public Vector2 size = new Vector2(10, 5);
}
public class Vector3 {
public float x, y, z;
}
public class Vector2 {
public float x, y;
}
The catch is - GameState contains array field objects . About GameState class algorithm can remember only the fact it contains exactly one field and it’s type is array of unknown objects.
Why unknown? There is no guarantee that every single object in this array will be an instantiation of GameObject class. User might want to put something like this in there:
public class DerivedGameObject extends GameObject {
public Vector3 speed = new Vector3();
}
That’s why after inspecting only GameState class I know I have one field and that field is an array. During serialization I check if that field is not null and then serialize it. When array of unknown objects is being serialized then the inspection is being made for each array’s element. In this example I could avoid inspection for each element only if GameObject was a final class. I could take advantage of it in Kotlin since there every class is final by default.
Any other ways? No, performance, performance, perf…
Having my requirements, I couldn’t find a better way. Probably, I could use a trick.
Creating a dynamic server that would share and upload .class files from the game. Sending bytecode taken directly from JVM. The client would then fetch the bytecode to have a reflection data to inspect. Then, I could use any kind of serialization, for instance Kryo library that would cache class structure in it’s own way. However, pushing all the bytecode could be not efficient enough, especially on Android where Reflection is known of to be slow.
Moreover, I don’t want to always serialize whole objects due to performance reason - very frequent updates.
There’s even more, I want to update specific fields. This enables me to implement watchers over some fields which could be impossible during serialization of whole object. That’s important for frequently changed objects which is usually a characteristic of action games.
Additionally, there are cyclic references to be detected (efficiency and stuff, it’s gamedev, folks!).
References
- Artemis Entity Tracker @ GitHub
- artemis-odb - the ECS library, Java
- Introduction to Entity Systems - on Wiki of artemis-odb
- Understanding Entity-Component-Systems - other source with more examples
- StackOverflow: What is Reflection and why is it useful?
- Kryo - Java serialization and cloning: fast, efficient, automatic
- How Slow is Reflection in Android?