efd-trading-card-base/CLAUDE.md
Cal Corum 8d23f152eb Add unit testing framework and refactor parsing logic
- Created TradingCardMod.Tests.csproj with xUnit for testable components
- Extracted CardParser.cs with pure parsing logic (no Unity deps)
- Extracted TradingCard.cs data class from ModBehaviour
- Added 37 unit tests covering parsing, validation, rarity mapping
- Updated cards.txt format with optional description field
- Fixed DLL references (explicit HintPath for paths with spaces)
- Fixed Harmony UnpatchAll API usage
- Updated CLAUDE.md with test commands and current project status

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 19:40:43 -06:00

5.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

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

# Build the mod
dotnet build TradingCardMod.csproj

# Build release version
dotnet build TradingCardMod.csproj -c Release

# Output location: bin/Debug/netstandard2.1/TradingCardMod.dll

Important: Before building, update DuckovPath in TradingCardMod.csproj (line 10) to your actual game installation path.

Testing

# 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

Mod Loading System

The game loads mods from Duckov_Data/Mods/. Each mod requires:

  • A DLL with namespace matching info.ini's name field
  • A ModBehaviour class inheriting from Duckov.Modding.ModBehaviour
  • The info.ini and preview.png files

Key Classes

  • 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().

  • Patches (src/Patches.cs): Harmony patch definitions. Uses HarmonyLib for runtime method patching. Patches are applied in Start() and removed in OnDestroy().

  • TradingCard: Data class representing card properties. Contains GenerateTypeID() for creating unique item IDs (100000+ range to avoid game conflicts).

Dependencies

  • HarmonyLoadMod (Workshop ID: 3589088839): Required mod dependency providing Harmony 2.4.1. Referenced at build time but not bundled to avoid version conflicts.

Card Definition Format

Cards are defined in CardSets/{SetName}/cards.txt using pipe-separated values:

CardName | SetName | SetNumber | ImageFile | Rarity | Weight | Value

Images go in CardSets/{SetName}/images/.

Game API Reference

Key namespaces and APIs from the game:

  • ItemStatsSystem.ItemAssetsCollection.AddDynamicEntry(Item prefab) - Register custom items
  • 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: 2 - Core Card Framework Project Plan: .claude/scratchpad/PROJECT_PLAN.md Technical Analysis: .claude/scratchpad/item-system-analysis.md

Implementation Approach: Clone + Reflection

Based on analysis of the AdditionalCollectibles mod, we're using a viable approach:

  1. Clone existing game items as templates (not create from scratch)
  2. Use reflection to set private fields (typeID, weight, value, etc.)
  3. Create custom tags by cloning existing ScriptableObject tags
  4. Load sprites from user files in CardSets/*/images/

Key patterns:

// Clone base item
Item original = ItemAssetsCollection.GetPrefab(135);
GameObject clone = Object.Instantiate(original.gameObject);
Object.DontDestroyOnLoad(clone);

// Set properties via reflection
item.SetPrivateField("typeID", newId);
item.SetPrivateField("value", cardValue);

// Get/create tags
Tag tag = Resources.FindObjectsOfTypeAll<Tag>()
    .FirstOrDefault(t => t.name == "Luxury");

Next Implementation Steps

  1. Create src/ItemExtensions.cs - reflection helper methods
  2. Create src/TagHelper.cs - tag operations
  3. Update src/ModBehaviour.cs - use clone+reflection approach
  4. Test card creation in-game

Files to Create

File Purpose
src/ItemExtensions.cs SetPrivateField(), GetPrivateField() extensions
src/TagHelper.cs GetTargetTag(), CreateOrCloneTag()

Research References

  • Decompiled game code: .claude/scratchpad/decompiled/
  • Item system analysis: .claude/scratchpad/item-system-analysis.md
  • AdditionalCollectibles mod: Workshop ID 3591453758 (reference implementation)