refactor: implement binary parsing in L0 DataTable rows
- Add BinaryReaderExtension with Vector2/3/4, Quaternion, Color, Rect types - Implement ParseDataRow(byte[]) in TagRow and RarityTagBudgetRow - Update CLAUDE.md with GameFramework module table and improved architecture docs - Remove unnecessary InternalsVisibleTo and L1 wrapper classes Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
5e7ea48ca8
commit
24c8efe03d
78
CLAUDE.md
78
CLAUDE.md
|
|
@ -10,10 +10,25 @@ This is a Unity project that **cannot build standalone** outside of Unity Editor
|
||||||
|
|
||||||
### Three-Layer Structure (per `docs/LayeredArchitectureDesign.md`)
|
### Three-Layer Structure (per `docs/LayeredArchitectureDesign.md`)
|
||||||
|
|
||||||
- **L0 (Domain)**: Pure C# business logic with no Unity dependencies. Contains enums, constants, data structures, CombatNode domain, PlayerInventory, InventoryGeneration, UI use cases.
|
- **L0 (Domain)**: Pure C# business logic. References `GameFramework.dll` (pure C#, no Unity dependency). Contains enums, constants, data structures, CombatNode domain, PlayerInventory, InventoryGeneration, UI use cases.
|
||||||
- **L1 (Infrastructure)**: Glue layer bridging L0 and Unity. Implements L0 interfaces, holds L0 service instances, manages Unity lifecycle.
|
- **L1 (Infrastructure)**: Glue layer bridging L0 and Unity. Implements GameFramework Unity adapters (Resource/Scene/Entity/UI/Sound), implements L0 interfaces, holds L0 service instances, manages Unity lifecycle.
|
||||||
- **L2 (Presentation)**: Unity MonoBehaviour classes, UGuiForm implementations, Entity Logic (Player, Enemy, Tower).
|
- **L2 (Presentation)**: Unity MonoBehaviour classes, UGuiForm implementations, Entity Logic (Player, Enemy, Tower).
|
||||||
|
|
||||||
|
### GameFramework.dll Modules Usable in L0
|
||||||
|
|
||||||
|
GameFramework.dll is pure C# and provides infrastructure usable directly in L0:
|
||||||
|
|
||||||
|
| Module | L0 Usage |
|
||||||
|
|--------|----------|
|
||||||
|
| Event | `GameFramework.Event.EventManager` - custom args inherit `GameEventArgs` |
|
||||||
|
| ObjectPool | `ObjectPoolManager` - entities inherit `ObjectBase` |
|
||||||
|
| Fsm | `FsmManager` - states inherit `FsmState<T>` |
|
||||||
|
| ReferencePool | `ReferencePool.Acquire<T>() / Release()` |
|
||||||
|
| DataNode | Tree data structure, use directly |
|
||||||
|
| DataTable | DataRow classes implement `IDataRow` in L0 |
|
||||||
|
|
||||||
|
Modules requiring L1 Unity adapters: Resource, Scene, Entity, UI, Sound.
|
||||||
|
|
||||||
### Key Domain Boundaries
|
### Key Domain Boundaries
|
||||||
|
|
||||||
| Domain | Key Files | Responsibility |
|
| Domain | Key Files | Responsibility |
|
||||||
|
|
@ -23,6 +38,7 @@ This is a Unity project that **cannot build standalone** outside of Unity Editor
|
||||||
| **PlayerInventory** | `PlayerInventoryComponent.cs`, `PlayerInventoryTowerAssemblyService.cs` | Backpack, trading, tower assembly |
|
| **PlayerInventory** | `PlayerInventoryComponent.cs`, `PlayerInventoryTowerAssemblyService.cs` | Backpack, trading, tower assembly |
|
||||||
| **InventoryGeneration** | `InventoryGenerationComponent.cs`, `DropPoolRoller.cs`, `ShopGoodsBuilder.cs` | Drops, shop goods, rewards |
|
| **InventoryGeneration** | `InventoryGenerationComponent.cs`, `DropPoolRoller.cs`, `ShopGoodsBuilder.cs` | Drops, shop goods, rewards |
|
||||||
| **MapEntity** | `MapEntity.cs`, `MapTopologyService.cs`, `TowerPlacementService.cs` | Map orchestration, grid/path, tower placement |
|
| **MapEntity** | `MapEntity.cs`, `MapTopologyService.cs`, `TowerPlacementService.cs` | Map orchestration, grid/path, tower placement |
|
||||||
|
| **TagSystem** | `TagGenerationRuleRegistry.cs`, `RarityTagBudgetRuleRegistry.cs`, `TagDefinitionRegistry.cs` | Tag generation rules and definitions |
|
||||||
|
|
||||||
### Combat State Machine Flow
|
### Combat State Machine Flow
|
||||||
|
|
||||||
|
|
@ -30,14 +46,25 @@ This is a Unity project that **cannot build standalone** outside of Unity Editor
|
||||||
|
|
||||||
### Dual-Currency System
|
### Dual-Currency System
|
||||||
|
|
||||||
- **Coin**: Single-combat internal currency (`CombatRunResourceStore.CurrentCoin`)
|
- **Coin**: Single-combat internal currency (`CombatRunResourceStore.CurrentCoin`). Used for build/upgrade/destroy in combat. Reset per combat from `DRLevel.StartCoin`.
|
||||||
- **Gold**: Cross-combat persistent currency (`PlayerInventoryComponent.Gold`)
|
- **Gold**: Cross-combat persistent currency (`PlayerInventoryComponent.Gold`). Used for shop buy/sell. Persists across nodes.
|
||||||
|
|
||||||
### Tag System
|
### Tag System
|
||||||
|
|
||||||
Three-table configuration: `Tag.txt`, `RarityTagBudget.txt`, `TagConfig.txt`. Current shipped 7 tags: Fire, Ice, Crit, Execution, Shatter, Inferno, AbsoluteZero.
|
Three-table configuration: `Tag.txt`, `RarityTagBudget.txt`, `TagConfig.txt`.
|
||||||
|
|
||||||
## Service Naming Conventions
|
**Active Tags (7)**: Fire, Ice, Crit, Execution, Shatter, Inferno, AbsoluteZero.
|
||||||
|
|
||||||
|
**Deferred Tags (5)**: BurnSpread, IgniteBurst, FreezeMask, Pierce, Overpenetrate (metadata only, not combat-active).
|
||||||
|
|
||||||
|
**Tag Runtime Structure**:
|
||||||
|
- Component instances hold `TagType[]`
|
||||||
|
- Tower instances hold `TagRuntimeData[]` (grouped by TagType with Stack count)
|
||||||
|
- `TagGenerationRuleRegistry` and `RarityTagBudgetRuleRegistry` load from `TagRow` / `RarityTagBudgetRow` (IDataRow implementations)
|
||||||
|
|
||||||
|
**Tag Generation Uses `InventoryGenerationRandomContext`** for reproducibility (RunSeed + SourceType + ItemInstanceId + ConfigId).
|
||||||
|
|
||||||
|
### Service Naming Conventions
|
||||||
|
|
||||||
- `Scheduler`: State machine boundary only
|
- `Scheduler`: State machine boundary only
|
||||||
- `Manager`: Facade/aggregate entry for subdomain
|
- `Manager`: Facade/aggregate entry for subdomain
|
||||||
|
|
@ -47,6 +74,8 @@ Three-table configuration: `Tag.txt`, `RarityTagBudget.txt`, `TagConfig.txt`. Cu
|
||||||
- `Bridge`: Framework boundary adapter
|
- `Bridge`: Framework boundary adapter
|
||||||
- `Runtime`: Mutable state carrier
|
- `Runtime`: Mutable state carrier
|
||||||
- `Resolver`: Mapping/lookup/resolution
|
- `Resolver`: Mapping/lookup/resolution
|
||||||
|
- `Tracker`: Tracks running entities or factual truth values
|
||||||
|
- `Port`: Restricted host interface for internal state/use cases
|
||||||
|
|
||||||
## Key Invariants
|
## Key Invariants
|
||||||
|
|
||||||
|
|
@ -56,12 +85,41 @@ Three-table configuration: `Tag.txt`, `RarityTagBudget.txt`, `TagConfig.txt`. Cu
|
||||||
4. `EnemyLifecycleTracker` is sole source for `AliveEnemyCount` and `HasAliveBoss`
|
4. `EnemyLifecycleTracker` is sole source for `AliveEnemyCount` and `HasAliveBoss`
|
||||||
5. `MapEntity` accesses combat context via `MapData` + Events only
|
5. `MapEntity` accesses combat context via `MapData` + Events only
|
||||||
6. Tag generation uses `InventoryGenerationRandomContext` for reproducibility
|
6. Tag generation uses `InventoryGenerationRandomContext` for reproducibility
|
||||||
|
7. `TowerPlacementService` is sole write entry for tower mapping state
|
||||||
|
8. `MapTopologyService` is sole source for Path/Foundation data
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── GeometryTD.Domain/ # L0 - Pure C#, references GameFramework.dll
|
||||||
|
│ ├── Definition/
|
||||||
|
│ │ ├── Enum/ # All enums (TagType, RarityType, etc.)
|
||||||
|
│ │ ├── Constant/ # Constants
|
||||||
|
│ │ ├── DataStruct/ # POCOs (AttackPayload, HitContext, TowerStatsData)
|
||||||
|
│ │ └── Tag/ # Tag definitions, generation rules, combat effects
|
||||||
|
│ ├── Event/ # GameEventArgs subclasses by domain
|
||||||
|
│ ├── UI/ # UI contexts and use case interfaces
|
||||||
|
│ ├── DataTable/ # IDataRow implementations (TagRow, RarityTagBudgetRow)
|
||||||
|
│ └── CustomComponent/ # L0 services (CombatScheduler, EnemyManager, etc.)
|
||||||
|
│
|
||||||
|
├── GeometryTD.Infrastructure/ # L1 - Unity adapter layer
|
||||||
|
│ ├── Entity/ # EntityLogic, EntityData DTOs
|
||||||
|
│ ├── Scene/Map/ # MapTopologyService, TowerPlacementService
|
||||||
|
│ ├── UI/ # UGuiForm base, controllers
|
||||||
|
│ ├── DataTable/ # L1 DataRowBase wrappers over L0 rows
|
||||||
|
│ └── CustomComponent/ # Unity Components holding L0 services
|
||||||
|
│
|
||||||
|
└── GeometryTD.Presentation/ # L2 - Unity MonoBehaviours, Views
|
||||||
|
├── Entity/Logic/ # Player, Enemy, Tower, Bullet entities
|
||||||
|
└── Components/ # MovementComponent, ShooterBullet, etc.
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- `docs/LayeredArchitectureDesign.md` - Three-layer architecture
|
- `docs/LayeredArchitectureDesign.md` - Three-layer architecture, GameFramework integration, migration phases
|
||||||
- `docs/CombatNodeArchitecture.md` - Combat scheduler and state machine
|
- `docs/CombatNodeArchitecture.md` - Combat scheduler, state machine, EnemyManager, resource store
|
||||||
- `docs/MapEntityArchitecture.md` - Map orchestration services
|
- `docs/MapEntityArchitecture.md` - Map orchestration, tower placement, topology services
|
||||||
- `docs/TagSystemDesign.md` - Tag system rules
|
- `docs/TagSystemDesign.md` - Tag system rules, generation, three-table config, combat effects
|
||||||
- `docs/GameDesign.md` - High-level game design
|
- `docs/GameDesign.md` - High-level game design
|
||||||
- `docs/MVP-Scope.md` - Current MVP scope
|
- `docs/MVP-Scope.md` - Current MVP scope
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace GeometryTD.Domain.DataTable
|
||||||
|
{
|
||||||
|
public static class BinaryReaderExtension
|
||||||
|
{
|
||||||
|
public static Vector2 ReadVector2(this BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
return new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 ReadVector3(this BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
return new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector4 ReadVector4(this BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
return new Vector4(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Quaternion ReadQuaternion(this BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
return new Quaternion(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color ReadColor(this BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
return new Color(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color32 ReadColor32(this BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
return new Color32(binaryReader.ReadByte(), binaryReader.ReadByte(), binaryReader.ReadByte(), binaryReader.ReadByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rect ReadRect(this BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
return new Rect(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime ReadDateTime(this BinaryReader binaryReader)
|
||||||
|
{
|
||||||
|
return new DateTime(binaryReader.ReadInt64());
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly struct Color
|
||||||
|
{
|
||||||
|
public float R { get; }
|
||||||
|
public float G { get; }
|
||||||
|
public float B { get; }
|
||||||
|
public float A { get; }
|
||||||
|
|
||||||
|
public Color(float r, float g, float b, float a)
|
||||||
|
{
|
||||||
|
R = r;
|
||||||
|
G = g;
|
||||||
|
B = b;
|
||||||
|
A = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly struct Color32
|
||||||
|
{
|
||||||
|
public byte R { get; }
|
||||||
|
public byte G { get; }
|
||||||
|
public byte B { get; }
|
||||||
|
public byte A { get; }
|
||||||
|
|
||||||
|
public Color32(byte r, byte g, byte b, byte a)
|
||||||
|
{
|
||||||
|
R = r;
|
||||||
|
G = g;
|
||||||
|
B = b;
|
||||||
|
A = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly struct Rect
|
||||||
|
{
|
||||||
|
public float X { get; }
|
||||||
|
public float Y { get; }
|
||||||
|
public float Width { get; }
|
||||||
|
public float Height { get; }
|
||||||
|
|
||||||
|
public Rect(float x, float y, float width, float height)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
using GameFramework.DataTable;
|
using GameFramework.DataTable;
|
||||||
using GeometryTD.Definition;
|
using GeometryTD.Definition;
|
||||||
|
|
||||||
|
|
@ -38,7 +40,18 @@ namespace GeometryTD.Domain.DataTable
|
||||||
|
|
||||||
public bool ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData)
|
public bool ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Binary parsing is not supported.");
|
using (MemoryStream memoryStream = new MemoryStream(dataRowBytes, startIndex, length, false))
|
||||||
|
{
|
||||||
|
using (BinaryReader binaryReader = new BinaryReader(memoryStream, Encoding.UTF8))
|
||||||
|
{
|
||||||
|
Id = binaryReader.Read7BitEncodedInt32();
|
||||||
|
Rarity = (RarityType)binaryReader.Read7BitEncodedInt32();
|
||||||
|
MinCount = binaryReader.Read7BitEncodedInt32();
|
||||||
|
MaxCount = binaryReader.Read7BitEncodedInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
using GameFramework.DataTable;
|
using GameFramework.DataTable;
|
||||||
using GeometryTD.Definition;
|
using GeometryTD.Definition;
|
||||||
|
|
||||||
|
|
@ -53,7 +55,18 @@ namespace GeometryTD.Domain.DataTable
|
||||||
|
|
||||||
public bool ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData)
|
public bool ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Binary parsing is not supported.");
|
using (MemoryStream memoryStream = new MemoryStream(dataRowBytes, startIndex, length, false))
|
||||||
|
{
|
||||||
|
using (BinaryReader binaryReader = new BinaryReader(memoryStream, Encoding.UTF8))
|
||||||
|
{
|
||||||
|
Id = binaryReader.Read7BitEncodedInt32();
|
||||||
|
MinRarity = (RarityType)binaryReader.Read7BitEncodedInt32();
|
||||||
|
Weight = binaryReader.Read7BitEncodedInt32();
|
||||||
|
IsImplemented = binaryReader.ReadBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue