|
| 1 | +--- |
| 2 | +name: 生成INI标签 Generate INI tag |
| 3 | +description: "A \"tag\" is an INI key that generally corresponds to a C++ property. Defining a tag requires modifications in four places within the target `ExtData` class: **declaration**, **initialization**, **serialization**, and **INI loading**. If the user does not provide all information explicitly, the AI should infer the missing pieces, present them to the user for confirmation, and only proceed after approval." |
| 4 | +--- |
| 5 | + |
| 6 | +#### 1. Determine the Class |
| 7 | + |
| 8 | +Game entities have **instance classes** (e.g., `BuildingClass`) and **static type classes** (e.g., `BuildingTypeClass`). Tags are almost always defined in the static type class's `ExtData` — when the user says "add a tag for buildings", they mean `BuildingTypeExt::ExtData`. Same pattern applies: |
| 9 | + |
| 10 | +| User says | Corresponding ExtData | |
| 11 | +|-----------|----------------------| |
| 12 | +| Building / BuildingType | `BuildingTypeExt::ExtData` | |
| 13 | +| Vehicle / Unit / UnitType | `UnitTypeExt::ExtData` (or `TechnoTypeExt::ExtData`) | |
| 14 | +| Infantry / InfantryType | `InfantryTypeClass` → `TechnoTypeExt::ExtData` | |
| 15 | +| Aircraft / AircraftType | `AircraftTypeClass` → `TechnoTypeExt::ExtData` | |
| 16 | +| Warhead | `WarheadTypeExt::ExtData` | |
| 17 | +| Weapon | `WeaponTypeExt::ExtData` | |
| 18 | +| Bullet / Projectile | `BulletTypeExt::ExtData` | |
| 19 | +| SuperWeapon / SW | `SWTypeExt::ExtData` | |
| 20 | +| Animation / Anim | `AnimTypeExt::ExtData` | |
| 21 | +| Particle | `ParticleTypeExt::ExtData` | |
| 22 | +| Terrain / TerrainType | `TerrainTypeExt::ExtData` | |
| 23 | +| Overlay / OverlayType | `OverlayTypeExt::ExtData` | |
| 24 | +| Global / Rules | `RulesExt::ExtData` | |
| 25 | + |
| 26 | +Note: `TechnoTypeExt::ExtData` is the **common base class** extension for `BuildingType`, `UnitType`, `InfantryType`, and `AircraftType`. If a tag applies to all Techno types, place it in `TechnoTypeExt`; if it applies only to a specific subtype, place it in the corresponding subclass Ext (e.g., buildings only → `BuildingTypeExt`). |
| 27 | + |
| 28 | +#### 2. Determine the Section |
| 29 | + |
| 30 | +- **Non-global tags**: Read from `pSection` (the INI section matching the instance ID/name) inside `LoadFromINIFile`. Determine whether to use `pSection` or `pArtSection`: |
| 31 | + - `pSection` = `pThis->ID` — reads from the identically-named section in `rulesmd.ini`. The vast majority of tags go here. |
| 32 | + - `pArtSection` = `pThis->ImageFile` — reads from the identically-named section in `artmd.ini`, using `INI_Art` / `exArtINI`. Generally used for visual, graphical, or animation-related tags. Check whether the class's `LoadFromINIFile` defines a `pArtSection` variable and `exArtINI` to see if this is supported. |
| 33 | +- **Global tags**: For `RulesExt::ExtData`, read from fixed global sections such as `GameStrings::General` (`[General]`), `GameStrings::CombatDamage` (`[CombatDamage]`), `GameStrings::Radiation` (`[Radiation]`), `GameStrings::AudioVisual` (`[AudioVisual]`), `GameStrings::AI` (`[AI]`), etc. Infer the appropriate section based on the key name's semantics. |
| 34 | + |
| 35 | +#### 3. Determine the Key Name |
| 36 | + |
| 37 | +The INI key name specified by the user. **Critical conversion rule: dots `.` in the key name become underscores `_` in the C++ property name.** |
| 38 | + |
| 39 | +For example: `"Factory.IsSuper"` → C++ property name `Factory_IsSuper` |
| 40 | + |
| 41 | +#### 4. Determine the Type |
| 42 | + |
| 43 | +Infer the C++ type based on semantics. Common types and their wrappers: |
| 44 | + |
| 45 | +| Semantics | C++ Type | Wrapper | |
| 46 | +|-----------|---------|---------| |
| 47 | +| Boolean on/off switch | `bool` | `Valueable<bool>` | |
| 48 | +| Integer (count, frames, int percentage) | `int` | `Valueable<int>` | |
| 49 | +| Floating point (ratio, multiplier, speed) | `double` | `Valueable<double>` | |
| 50 | +| In-game distance (Lepton) | `Leptons` | `Valueable<Leptons>` | |
| 51 | +| Coordinate | `CoordStruct` / `Point2D` | `Valueable<CoordStruct>` | |
| 52 | +| Color | `ColorStruct` | `Valueable<ColorStruct>` | |
| 53 | +| Nullable (omitting means use default logic) | any | `Nullable<T>` | |
| 54 | +| List (comma-separated values) | `std::vector<T>` | `ValueableVector<T>` | |
| 55 | +| Pointer to another game type | `WeaponTypeClass*` etc. | `Valueable<WeaponTypeClass*>` | |
| 56 | +| Index lookup (sounds etc.) | see `ValueableIdx` | `ValueableIdx<VocClass>` | |
| 57 | +| Enum | game enum | `Valueable<AffectedHouse>` etc. | |
| 58 | + |
| 59 | +**Inference rules:** |
| 60 | +- Key name contains `Is`/`Can`/`Allow`/`Use`/`Has`/`Enable`/`Disable` → likely `Valueable<bool>` |
| 61 | +- Key name contains `Amount`/`Count`/`Max`/`Min`/`Delay`/`Rate`/`Frame` (integer) → likely `Valueable<int>` |
| 62 | +- Key name contains `Factor`/`Mult`/`Percent`/`Speed`/`Ratio`/`Chance` → likely `Valueable<double>` |
| 63 | +- Key name contains `Type` (singular pointer) → `Valueable<SomeTypeClass*>` |
| 64 | +- Key name contains `Types` (plural) → `ValueableVector<SomeTypeClass*>` |
| 65 | +- When unsure about optionality, default to `Valueable<T>` (required); use `Nullable<T>` if omitting is semantically valid. |
| 66 | + |
| 67 | +#### 5. Implementation Steps |
| 68 | + |
| 69 | +Modify the `Body.h` and `Body.cpp` of the target ExtData. Follow these four steps: |
| 70 | + |
| 71 | +**A. Declare the property (Body.h → ExtData public section)** |
| 72 | + |
| 73 | +Follow existing declaration style, e.g.: |
| 74 | +```cpp |
| 75 | +Valueable<bool> Factory_IsSuper; |
| 76 | +``` |
| 77 | + |
| 78 | +**B. Initialize the property (Body.h → ExtData constructor initializer list)** |
| 79 | + |
| 80 | +Add a default value in the constructor, matching the existing format (comma-first, aligned): |
| 81 | +```cpp |
| 82 | +, Factory_IsSuper { false } |
| 83 | +``` |
| 84 | +
|
| 85 | +**C. Register in serialization (Body.cpp → Serialize function)** |
| 86 | +
|
| 87 | +Insert into the `Stm` chain in `Serialize(T& Stm)`, ordered alphabetically or logically: |
| 88 | +```cpp |
| 89 | +.Process(this->Factory_IsSuper) |
| 90 | +``` |
| 91 | + |
| 92 | +**D. INI loading (Body.cpp → LoadFromINIFile function)** |
| 93 | + |
| 94 | +Based on the section determined in step 2, choose `exINI` or `exArtINI`, and `pSection` or `pArtSection`: |
| 95 | +```cpp |
| 96 | +// From rulesmd.ini (most common) |
| 97 | +this->Factory_IsSuper.Read(exINI, pSection, "Factory.IsSuper"); |
| 98 | + |
| 99 | +// From artmd.ini (visual/graphical) |
| 100 | +this->Factory_IsSuper.Read(exArtINI, pArtSection, "Factory.IsSuper"); |
| 101 | + |
| 102 | +// Global tag example (RulesExt) |
| 103 | +this->Factory_IsSuper.Read(exINI, GameStrings::General, "Factory.IsSuper"); |
| 104 | +``` |
| 105 | + |
| 106 | +If the property is a pointer to another game type (e.g., `Valueable<WeaponTypeClass*>`), use `.Read<true>` to enable auto-creation: |
| 107 | +```cpp |
| 108 | +this->SomeWeapon.Read<true>(exINI, pSection, "SomeWeapon"); |
| 109 | +``` |
| 110 | + |
| 111 | +#### 6. Full Example |
| 112 | + |
| 113 | +User says: "add a tag called `Factory.IsSuper` for buildings" |
| 114 | + |
| 115 | +Inference process: |
| 116 | +- Class: `BuildingTypeExt::ExtData` ("buildings" → building type static data) |
| 117 | +- Section: `pSection` (not visual-related) |
| 118 | +- Key: `Factory.IsSuper` → property name `Factory_IsSuper` |
| 119 | +- Type: `Valueable<bool>` (contains `Is`, boolean semantics) |
| 120 | +- Default: `false` (conservative default) |
| 121 | + |
| 122 | +After confirmation, modify: |
| 123 | +- [Body.h](file:///f:/RA2%20Engine%20Extension/MJobos/src/Ext/BuildingType/Body.h): declaration + initialization |
| 124 | +- [Body.cpp](file:///f:/RA2%20Engine%20Extension/MJobos/src/Ext/BuildingType/Body.cpp): Serialize + LoadFromINIFile |
0 commit comments