Compare commits

...

1 Commits

Author SHA1 Message Date
Cal Corum
44fd044541 Optimize CLAUDE.md from 240 to 63 lines
Remove detailed reflection patterns (belong in code comments), project status
tracking, completed features list, and implementation approach docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 08:31:10 -06:00

251
CLAUDE.md
View File

@ -1,239 +1,62 @@
# CLAUDE.md # EfD Trading Card Mod
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. Unity mod for Escape from Duckov adding a customizable trading card system with storage.
## Project Overview ## Commands
A Unity mod for Escape from Duckov that adds a customizable trading card system with storage solutions. The framework supports user-generated content through simple pipe-separated text files, allowing non-programmers to add their own card sets.
## Build Commands
```bash ```bash
# Build the mod dotnet build TradingCardMod.csproj # Build (debug)
dotnet build TradingCardMod.csproj dotnet build TradingCardMod.csproj -c Release # Build (release)
dotnet test TradingCardMod.Tests.csproj # Run tests
# Build release version ./deploy.sh # Build + deploy to game
dotnet build TradingCardMod.csproj -c Release ./deploy.sh --release # Deploy release build
./remove.sh # Remove mod from game
# Output location: bin/Debug/netstandard2.1/TradingCardMod.dll
``` ```
**Important**: Before building, update `DuckovPath` in `TradingCardMod.csproj` (line 10) to your actual game installation path. **Before building**: Update `DuckovPath` in `TradingCardMod.csproj` (line 10) to your game path.
## Deployment
```bash
# Deploy to game (builds and copies all files)
./deploy.sh
# Deploy release build
./deploy.sh --release
# Remove mod from game
./remove.sh
# Remove with backup
./remove.sh --backup
```
## Project Skills ## Project Skills
Two workflow skills are available in this project: - `/build` — Build and deploy locally for testing
- `/deploy` — Build Release and stage for Steam Workshop upload
- `/build` - Build and deploy locally for testing (runs `dotnet build` + `./deploy.sh`)
- `/deploy` - Build Release and stage for Steam Workshop upload (uses `workshop-upload.sh`)
Skills are defined in `.claude/skills/`.
## Testing
```bash
# Run all unit tests
dotnet test TradingCardMod.Tests.csproj
# Run tests with verbose output
dotnet test TradingCardMod.Tests.csproj --verbosity normal
# Run specific test class
dotnet test TradingCardMod.Tests.csproj --filter "FullyQualifiedName~CardParserTests"
# Run single test
dotnet test TradingCardMod.Tests.csproj --filter "ParseLine_ValidLineWithoutDescription_ReturnsCard"
```
**Test Coverage:** Parsing logic, validation, rarity mapping, TypeID generation, and description auto-generation are all tested. Unity-dependent code (item creation, tags) cannot be unit tested.
## Architecture ## Architecture
### Mod Loading System - **Clone + Reflection**: Clone game items as templates (base ID 135), set private fields via reflection
- **Custom tags**: Clone existing ScriptableObject tags. Parent tag pattern for slot filtering (Unity requireTags uses AND logic)
The game loads mods from `Duckov_Data/Mods/`. Each mod requires: - **TypeIDs**: 100000+ range to avoid game/mod conflicts
- A DLL with namespace matching `info.ini`'s `name` field - **Cost struct reflection**: Cost is a value type — must box before reflection, then unbox (see `DisassemblyHelper.cs`)
- A `ModBehaviour` class inheriting from `Duckov.Modding.ModBehaviour`
- The `info.ini` and `preview.png` files
### Key Classes ### Key Classes
| Class | Role |
- **`ModBehaviour`** (`src/ModBehaviour.cs`): Main entry point. Inherits from `Duckov.Modding.ModBehaviour` (which extends `MonoBehaviour`). Handles card set loading in `Start()` and cleanup in `OnDestroy()`. |-------|------|
| `ModBehaviour` | Entry point, card set loading/cleanup |
- **`Patches`** (`src/Patches.cs`): Harmony patch definitions. Uses `HarmonyLib` for runtime method patching. Patches are applied in `Start()` and removed in `OnDestroy()`. | `Patches` | Harmony runtime method patches |
| `CardParser` | Pipe-separated card file parser (pure C#, fully tested) |
- **`TradingCard`** (`src/TradingCard.cs`): Data class representing card properties. Contains `GenerateTypeID()` for creating unique item IDs (100000+ range to avoid game conflicts). | `PackUsageBehavior` | Card pack opening with gacha-style rarity weights |
| `StorageHelper` | Multi-tag slot filtering for hierarchical storage |
- **`CardParser`** (`src/CardParser.cs`): Parses card definition files. Pure C# with no Unity dependencies, fully unit tested. | `DisassemblyHelper` | Runtime disassembly formulas via reflection |
- **`ItemExtensions`** (`src/ItemExtensions.cs`): Reflection helpers for setting private fields on game objects.
- **`TagHelper`** (`src/TagHelper.cs`): Utilities for working with game tags, including creating custom tags.
- **`PackUsageBehavior`** (`src/PackUsageBehavior.cs`): Handles card pack opening mechanics. Implements gacha-style random card distribution based on rarity weights.
- **`ModConfigApi`** (`src/ModConfigApi.cs`): Optional integration with ModConfig mod. Adds card set information (set name, card number, rarity) to item descriptions in inventory. Also displays mod statistics including disabled card sets count.
- **`StorageHelper`** (`src/StorageHelper.cs`): Helper class for creating storage items with multi-tag slot filtering, enabling hierarchical storage systems.
- **`DisassemblyHelper`** (`src/DisassemblyHelper.cs`): Helper class for adding disassembly (deconstruction) formulas to custom items at runtime.
### Disassembly System Pattern
The game's disassembly system uses `DecomposeDatabase` (singleton in `Duckov.Economy` namespace) to store formulas. Key implementation details:
**Types:**
- `DecomposeFormula`: Contains `item` (TypeID), `valid` (bool), and `result` (Cost)
- `Cost`: A **struct** with `money` (long) and `items` (ItemEntry[])
- `Cost+ItemEntry`: **Nested struct** inside Cost with `id` (int) and `amount` (long)
**Critical Reflection Pattern (Cost is a struct):**
```csharp
// Cost is a VALUE TYPE - must box before reflection, then unbox
Cost result = new Cost { money = 0L };
object boxedResult = result; // Box the struct
itemsField.SetValue(boxedResult, itemEntries); // Modify boxed copy
result = (Cost)boxedResult; // Unbox back
formula.result = result;
```
**Adding a Formula:**
1. Get `DecomposeDatabase.Instance`
2. Access private `entries` field via reflection
3. Create `DecomposeFormula` with item TypeID and `valid = true`
4. Create `Cost` with money and/or items array
5. For items: Create `Cost+ItemEntry[]` via reflection (type found from `Cost.items` field type)
6. Add formula to list, write back via reflection
7. Call private `RebuildDictionary()` method
**Known Material TypeIDs:**
- Polyethylene Sheet: `764`
**Cleanup:** Track added item IDs and remove formulas in `OnDestroy()`.
See `DisassemblyHelper.cs` for complete implementation.
### Dependencies ### Dependencies
- **HarmonyLoadMod** (Workshop 3589088839): Required — provides Harmony 2.4.1
- **ModConfig** (Workshop 3592433938): Optional — enhances card descriptions in inventory
- **HarmonyLoadMod** (Workshop ID: 3589088839): Required mod dependency providing Harmony 2.4.1. Referenced at build time but not bundled to avoid version conflicts. ## Card Sets
- **ModConfig** (Workshop ID: 3592433938): Optional mod dependency. When installed, enhances card descriptions with set information in the inventory UI. Cards defined in `CardSets/{SetName}/cards.txt`:
### Card Definition Format
Cards are defined in `CardSets/{SetName}/cards.txt` using pipe-separated values:
``` ```
CardName | SetName | SetNumber | ImageFile | Rarity | Weight | Value | Description (optional) CardName | SetName | SetNumber | ImageFile | Rarity | Weight | Value | Description (optional)
``` ```
Images in `CardSets/{SetName}/images/`. Prefix folder with `_` to disable loading.
The Description field is optional. If provided, it will be displayed in the item's in-game description/tooltip. ## Storage System
Images go in `CardSets/{SetName}/images/`. - **Binder Sheet** (9 slots): Holds trading cards only
- **Card Binder** (12 slots): Holds cards OR binder sheets (nested storage)
**Disabling Card Sets:** Prefix a card set folder name with `_` (underscore) to exclude it from loading. For example, `_TestSet/` will be skipped. This is useful for work-in-progress sets or seasonal content. The count of disabled sets is displayed in ModConfig. ## Dev Notes
## Game API Reference - Target: .NET Standard 2.1, C# 8.0
- Logging: `Debug.Log()` with `[TradingCardMod]` prefix
Key namespaces and APIs from the game: - Log file: `/mnt/NV2/SteamLibrary/steamapps/compatdata/3167020/pfx/drive_c/users/steamuser/AppData/LocalLow/TeamSoda/Duckov/Player.log`
- `ItemStatsSystem.ItemAssetsCollection.AddDynamicEntry(Item prefab)` - Register custom items - Research: `.claude/scratchpad/decompiled/`, `.claude/scratchpad/item-system-analysis.md`
- `ItemStatsSystem.ItemAssetsCollection.RemoveDynamicEntry(Item prefab)` - Remove on unload
- `SodaCraft.Localizations.LocalizationManager.SetOverrideText(string key, string value)` - Localization
- `ItemStatsSystem.ItemUtilities.SendToPlayer(Item item)` - Give items to player
## Development Notes
- Target framework: .NET Standard 2.1
- C# language version: 8.0
- All logging uses `Debug.Log()` with `[TradingCardMod]` prefix
- Custom items need unique TypeIDs to avoid conflicts with base game and other mods
## Testing
1. Copy build output to `{GamePath}/Duckov_Data/Mods/TradingCardMod/`
2. Include: `TradingCardMod.dll`, `info.ini`, `preview.png`, `CardSets/` folder
3. Launch game and enable mod in Mods menu
4. Check game logs for `[TradingCardMod]` messages
## Current Project Status
**Phase:** 3 - Storage System ✅
**Status:** Ready for first release
**Project Plan:** `.claude/scratchpad/PROJECT_PLAN.md`
**Technical Analysis:** `.claude/scratchpad/item-system-analysis.md`
### Completed Features
- Cards load from `CardSets/*/cards.txt` files with optional descriptions
- Custom PNG images display as item icons
- Cards register as game items with proper TypeIDs
- Custom tags for slot filtering:
- "TradingCard": Identifies trading cards
- "BinderSheet": Identifies binder sheet items
- "CardBinderContent": Parent tag for both cards and binder sheets (enables hierarchical storage)
- Hierarchical storage system:
- **Binder Sheet** (9 slots, weight 0.1): Holds trading cards only
- **Card Binder** (12 slots, weight 1.5): Holds trading cards OR binder sheets
- Nested storage: Cards → Binder Sheets → Card Binders
- Card set exclusion: Prefix folders with `_` to disable loading
- ModConfig integration:
- Enhanced card info display (set name, number, rarity)
- Mod statistics display (total cards, disabled sets)
- Debug spawn window with F10 key (for testing):
- Spawn storage items (Card Binder, Binder Sheet)
- Spawn random cards by rarity
- Draggable OnGUI window interface
- Disassembly support for storage items:
- Binder Sheet → 2x Polyethylene Sheet
- Card Binder → 4x Polyethylene Sheet
- Cards intentionally have no disassembly (collectibles)
- Deploy/remove scripts for quick iteration
- Unit tests for parsing logic
### Implementation Approach: Clone + Reflection
Based on analysis of the AdditionalCollectibles mod:
1. **Clone existing game items** as templates (base item ID 135)
2. **Use reflection** to set private fields (typeID, weight, value, etc.)
3. **Create custom tags** by cloning existing ScriptableObject tags
4. **Parent tag pattern** for slot filtering (Unity's requireTags uses AND logic, so parent tags enable OR-like behavior)
5. **Load sprites** from user files in `CardSets/*/images/`
6. **Attach custom behaviors** for pack opening mechanics
### Upcoming Features
- **Card packs** with gacha-style mechanics (weighted random distribution) - disabled pending fix
- Additional storage variants or customization options (e.g., larger binders, themed storage boxes)
### Future Considerations
- Investigate new ItemBuilder API (added in recent game update) as potential replacement for reflection-based approach
### Log File Location
Unity logs (for debugging):
```
/mnt/NV2/SteamLibrary/steamapps/compatdata/3167020/pfx/drive_c/users/steamuser/AppData/LocalLow/TeamSoda/Duckov/Player.log
```
## Research References
- **Decompiled game code:** `.claude/scratchpad/decompiled/`
- **Item system analysis:** `.claude/scratchpad/item-system-analysis.md`
- **AdditionalCollectibles mod:** Workshop ID 3591453758 (reference implementation)