I have an abstract GameObject class that I extend for each object type I have in the game. It has an abstract method “setupPersistenComponents()” that is called only once when a game object entity is created and there I set persistent components on the entity.
Now let’s say I want to update a persistent component in the GameObject class definition (inside the setupPersistenComponents method). This change will only be applied to the new instances that are created after this change and the existing instances of the object that are in the database on a player computer will still use the old component.
What is your suggestion to make this change be applied to all existing instances that are persisted in the database? I am using Zay-ES and its persistent layer to save entities.
One answer might be to set persistent components on the GameObject.initialize() method so it will be reset every time the server starts but is this a good choice? Could it cause performance issues due to mass SQL query updates for all game object instances at once when the server startup? Also, this might spam all the game systems with a redundant update notice.
You might suggest making them non-persistent components because anyway they will be reset every time inside the initialize() method, but there might be cases an entity is not a GameObject (has no object type) and still uses a persistent component that is set just once when the entity is created. I do not have a use case for this atm though.
There are lots of ways to handle the simple case of just changing a value. It presumes you know the old version and new version which might be a better assumption to make in a one-time conversion rather than “on the fly”. But on-the-fly is certainly an option if you have some way to detect the old value is bad other than version.
For adding fields, zay-es SQL stuff will definitely complain. It might complain for removing fields, too… I don’t remember for sure. You pretty much have to use SQL to fix things in these cases.
And given that, even for the “need to change value x from 1 to 2” cases, I’d be tempted to use an SQL script for that, too. Once you have added code to “run these SQL scripts on update”, it would be there for any future use, removing/adding fields, etc…
Not sure if I am understanding it correctly, so am I required to add versioning to GameObjects?
So going to implementation details I would need to add an ObjectVersion component and an ObjectVersionSystem that detects if a game object should be updated:
and calls GameObject.updateVersion(newVersion). Right?
Yeah, I still need to think about how to implement this in code. I also need a way to mark a script as “Applied” so I do not re-apply it next time. I guess I would probably need to save the script status in ES.
No. You started the thread. I assumed presumed that maybe you might know when you would want to change an object.
Maybe you must always do it all at once. We haven’t talked about what kinds of changes so I have to guess a million different things.
There are dozens of ways to skin this particular cat, that is certainly one of them. A file on disk works, too… but storing some game constants in an entity has the advantage of being co-resident with the information you want to update.
For example, let’s say I want to update the “Mass” component. Well, there are two cases when I want to change it. When developing while playing a trial-and-error game to find a value that fits. Another case is when I want to publish a new release for players to download.
I wanted to implement a mechanism that can cover both cases at the same time but maybe I was wrong and better to make them separate things. Maybe for the first case (development), it would be better to just open a groovy console and run a script that finds and update all instances at once.
And use the “SQL update script” for the second case (when giving a new release).
For local development, with hsqldb it’s really easy to open up a UI to edit the tables. It’s built right into the jar. Just have to know some SQL.
…but for local dev, I also spend a lot of time wiping out my database and writing the code in such a way that it recreates missing things if I have a game world with no entities in it. Sometimes the nuclear option is best.