s25client icon indicating copy to clipboard operation
s25client copied to clipboard

Use text-serialization-format for game data

Open Flamefire opened this issue 10 years ago • 8 comments

Move out all game constants to text files (XML/lua). This should also include texture paths.

  • [ ] Player colors
  • [ ] Building data
  • [ ] Figure data
  • [ ] Ware data

Flamefire avatar Aug 05 '15 12:08 Flamefire

It's not a good idea to move all constants out to XML without dealing with some other things at the same time. The main problem that is given rise is that XML "disconnects" the constants from the game, making it easy to modify values and thereby creating asyncs/bugs nobody can ever resolve. To avoid this, values need to be serialized with the game state, i.e. saved and transfered to other players via network.

As in the future, buildings/figures/wares should be modular, it makes sense to talk about a meaningful XML representation first.

As for textures, I'd opt for a converter that converts the old formats into something new (like png) with transparency support etc., making it a lot easier to create new graphics without using a palette from another file that no modern graphics suite can really work with. That would allow to run an initial conversion to re-create all S2 Gold jobs/buildings/wares and also allow to add new ones.

As we are dealing with strings then, I strongly suggest something like Enum.cpp / Enum.hpp (first draft). This way all constants can be identified using a fixed-size unsigned integer in the game, but a string in save games or XML representations.

The idea is that you have something like Enum buildingTypes; and then get the id for a building using Enum_ID_t warehouseTypeId = buildingTypes.get("Warehouse");.

MarcusSt avatar Aug 05 '15 14:08 MarcusSt

about the enum stuff: thats what protobuf can do - you can even runtime compile data - perhaps thats a possible way to represent the stuff - kind of lua for logic, protobuf for definition?

Flow86 avatar Aug 05 '15 14:08 Flow86

What I don't like about the Enum is that it is too easy to misspell the string. It also adds a map lookup on every access which might be to slow. I'd stick to the current enums and rather map classes to xml by a string. I got some nice ideas for decoupled loading from XML (first drafts implemented in the dynamic_nations branch)

Flamefire avatar Aug 05 '15 15:08 Flamefire

@Flow86 Sounds good.

@Flamefire No, ingame you use an integer, not a string. Strings are just for XML or saved data and looked up once while loading. Therefore there's exactly one point in the code where you really use the string. Another thing is that lua needs to know about buildings, even if they are modular and new ones are added. The main advantage is that you have continuous unsigned integers and can create vectors easily using the number of entries in the Enum. That way you can e.g. keep a list of all buildings per type etc and also have a lookup table to handle events for certain buildings in lua.

The networking layer sends the serialized Enum and then uses ids (same everywhere). That way id 3 means "charburner" in every client. The next game may have that building disabled, so id 3 could become something different.

How else than be string are you going to reference the buildings in XML files?

MarcusSt avatar Aug 05 '15 15:08 MarcusSt

By registering a class with its data. I'd use a static mapping from enum-entry to its value. So id 3 is ALWAYS the same. One can use an additional array or a macro generated enum that is able to return the string from a value (and vice versa) Every class now registers itself with the enum value in the loader. When a node is loaded, the mapping to an enum value exists an all classes that are registred get their properties loaded.

What I wanted to achieve: You have the following mappings: 1 class -> N properties (and 1 property -> N classes) 1 enum value -> 1 class (but 1 class -> N enum values)

It is not possible to have 1 property per building (e.g. WoodcutterProperties, BarracksProperties) as buildings and therefore properties are hierarchical: MilitaryBuilding<-BaseBuilding --> MilitaryProperties<-BaseProperties. One can solve this via inheritance of the properties or composition: BaseBuilding has BaseProperties, Militarybuilding has BaseProperties (inherited since it IS a BaseBuilding) and another member MilitaryProperties. Also one has to be careful because multiple buildings share the same class (e.g. military or "simple production")

So I'd make the mapping enum<->string fixed. We need a fixed mapping of enum->class because otherwise factories are gonne get a lot harder

Flamefire avatar Aug 05 '15 17:08 Flamefire

We should maybe consider JSON as an alternative to XML, see e.g. http://www.json.org/xml.html

MarcusSt avatar Aug 16 '15 06:08 MarcusSt

I wrote my approach in the branch with abstract classes that can be mapped to XML OR JSON as a side effect. Yes XML is pretty verbose. Maybe JSON is better. But converting one to the other is really easy.

Flamefire avatar Aug 16 '15 10:08 Flamefire

@Flow86: Do you have some resources or information on "runtime compile data"? Sounds intresting... @MarcusSt: About the lookup when string->enum mapping: How would you handle e.g. the AI, which needs to check, if there is a "forester" at position (x,y)? Only way I see would be: gwg->GetNO(x,y)->GetType() == BUILDINGS.get("forester")

Flamefire avatar Mar 15 '16 09:03 Flamefire