Skip to content

Technical notes

Antti Halme edited this page Jun 14, 2026 · 1 revision

Miscellaneous technical notes relating to OpenCiv3 implementation.

Save File Structure

The save file structure is currently being formalized, as it was realized in 2022 that simply trusting .NET to do its thing would not work, in no small part because of loops in the save file structure. We need to think about how we want to serialize our data for saving, whether we want to or not.

Background

pcen opened the first save PR on April 14, 2022 (https://github.com/C7-Game/Prototype/pull/235). In its comments, he called out the problem of serialization, and noted that there were some issues with AI data. maxpetul noted some issues with null pointers, and Quintillus noted some issues with duplicated nested data.

Unfortunately, activity on the challenge was slow at the time.

On November 4, 2022, Quintillus proposed a set of save format principles (https://github.com/C7-Game/Prototype/discussions/377). The three keys were:

  • Items are not duplicated
  • The format is easy for humans to read
  • Polymorphism is supported

The first one was particularly important from a functionality standpoint, especially as some loops had been introduced in the format by that point (class A references class B, which references class A, or perhaps class B references class C which in turn references class A). But it also would improve human editability.

Polymorphism would allow object-oriented development to continue, but is not natively supported in .NET 6.0. It will be in .NET 7.0, but we don't know how long we will be waiting for Godot to support it. Newtonsoft JSON, the de facto standard in the C# world before Microsoft added their own (Newtonsoft-inspired) implementation, does support polymorphism. Thus it is proposed to move forward with Newtonsoft. Save support is too important of a feature to wait indefinitely for .NET 7.0.

The next step is likely formalizing the identifiers for the various classes. A goal is to have these be human-understandable, and thus GUIDs are not preferred, at least for anything that someone may want to understand at a glance from reading a reference elsewhere in the save file. Keep an eye on this page for updates!

UML Diagram

On February 5, 2023, Quintillus decided to create a UML diagram showing the relationships between the classes in C7DataFormat, to help reason through the question of how the format should be serialized. The UML diagram only shows object references, not primitive types (int, string, double, etc.), thus focusing on the more complex parts of the problem.

The UML diagram lives https://github.com/C7-Game/Prototype/blob/Newtonsoft-Serialization/C7GameData/UML%20Diagram.graphml (you may need to switch to the Development branch in the future), and the PNG equivalent is reproduced below. Blue represents classes storing AI-related data. Right-click and open in a new tab for the full-resolution version.

UML Diagram

As you can see, there are a few loops in the diagram. The good news is that by storing references using item IDs, we can load the data despite the loops, and then use the IDs to link to the actual objects as a secondary step.

Still, care has to be taken with the loops and bidirectional references. Consider the case of Tile's personWorkingTile, which is a CityResident, and CityResident's tileWorked, which is a Tile. If one of these were modified in a text editor, but the other was not, we would have an inconsistent state. To achieve Quintillus's principle of e pluribus unum, and avoid this inconsistency, we must only store this once in the save file. That is why some of the properties are listed as generated.

 

Scene hierarchy (draft)

Just brainstorming, far from definitive.

Key

Scenes replicating Civ3 UI should be in one folder/namespace and named C3ModexxxxxScene

[Brackets] indicate a scene that would be toggled on/off or swapped in from among siblings

Asterisks* indicate a scene that would be dynamically added any number of times

Some of these leaf scenes may actually be configurable nodes ie custom widgets, but the intention is to identify any reusable and/or structurally complex elements

Scene Tree

GameMainScreenScene

  • TopLeftUIScene
  • TopRightUIScene (multiplayer)
  • BottomLeftUIScene
    • MiniMapScene
  • BottomRightUIScene
    • BulkActionsScene
    • GameInfoScene
  • WorldMapScene
    • [TileInfoScene]
    • WorldTileScene* (if multiple nodes are needed to render all layers/effects)
    • WorldUnitScene* (sprite + UI)
    • WorldCityScene (sprite + UI)
  • [AdvisorPopupScene]
  • [AdvisorPromptScene]
  • [DiplomacyScene]
    • AdvisorMessageScene
  • [CityScreenScene]
    • CityResourcesScene
    • CityDataScene
    • CityCultureScene
    • CityLaborScene (tiles worked + citizens)
    • CityBuildingsScene
    • CityLuxuriesScene
    • CityProductionScene
    • CityFoodScene
    • CityCommerceScene
    • CityPollutionScene
    • CityGarrisonScene
    • CityGrowthScene
    • CityBuildScene
    • [CityBuildMenuScene]
    • CityActionScene
    • [CityGovernorScene]
  • [AdvisorScreenScene]
    • AdvisorMessageScene
    • [DomesticAdvisorScene]
      • DomesticBudgetScene
      • DomesticSpendingScene
        • DomesticSpendSliderScene*
      • DomesticCityInfoScene*
    • [TradeAdvisorScene]
    • [MilitaryAdvisorScene]
      • MiniMapScene
      • MilitaryUnitCountScene
      • MilitaryUnitEnumerationScene*
      • MilitaryCapturedLostUnitsScene
    • [ForeignAdvisorScene]
    • [CultureAdvisorScene]
    • [ScienceAdvisorScene]
      • EraTechTreeScene*
  • [CivilopediaScene]
    • PediaUIScene
    • [PediaMenuScene]
    • [PediaContentScene]
      • [PediaDataScene]
        • [PediaCostScene]
        • [PediaStatsScene]
        • [PediaRequiresScene]
        • [PediaTechRequiresAllowsScene]
        • [PediaAllowsScene]
        • [PediaBonusScene]

 

Godot 3.5 to Godot 4 migration notes

  • Textures no longer rendered with nearest filtering by default, causing lots of textures to render incorrectly in Godot 4. Fixed by selecting project -> project settings -> (rendering / textures / canvas textures / default texture filter) -> nearest
  • CanvasItem.Update is now CanvasItem.QueueRedraw: godot forum link
  • SetInputHandled is now a method of ViewPort: reddit link
  • QuadMesh was merged into the PlaneMesh class (pr), and PlaneMesh.Orientation must be set to PlaneMesh.OrientationEnum.Z to face the Z axis, otherwise it will not display (C7 map lies on the XY plane)

Clone this wiki locally