Initial commit: Trading Card Mod scaffold for Escape from Duckov
Set up project structure with: - .NET Standard 2.1 project targeting Duckov modding API - ModBehaviour entry point with card set loading system - Harmony patching infrastructure (depends on HarmonyLoadMod) - Pipe-separated card definition format for user-generated content - Example card set and documentation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
commit
9704516dd7
7
.claude/commands/build.md
Normal file
7
.claude/commands/build.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Build Mod
|
||||||
|
|
||||||
|
Build the TradingCardMod and report any errors.
|
||||||
|
|
||||||
|
1. Run `dotnet build` in the project root
|
||||||
|
2. If successful, show the output DLL path
|
||||||
|
3. If errors occur, analyze and suggest fixes
|
||||||
11
.claude/commands/deploy.md
Normal file
11
.claude/commands/deploy.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Deploy to Game
|
||||||
|
|
||||||
|
Build and deploy the mod to the game's Mods folder.
|
||||||
|
|
||||||
|
1. Run `dotnet build -c Release`
|
||||||
|
2. Copy the following to `{DuckovPath}/Duckov_Data/Mods/TradingCardMod/`:
|
||||||
|
- `TradingCardMod.dll`
|
||||||
|
- `info.ini`
|
||||||
|
- `preview.png` (if exists)
|
||||||
|
- `CardSets/` folder
|
||||||
|
3. Report deployment status
|
||||||
10
.claude/settings.json
Normal file
10
.claude/settings.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://claude.ai/code/settings-schema.json",
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(dotnet build*)",
|
||||||
|
"Bash(dotnet clean*)",
|
||||||
|
"Bash(dotnet restore*)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Build outputs
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
*.user
|
||||||
|
*.suo
|
||||||
|
|
||||||
|
# Claude Code private notes
|
||||||
|
.claude/scratchpad/
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# NuGet
|
||||||
|
*.nupkg
|
||||||
|
packages/
|
||||||
|
|
||||||
|
# Debug logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Card set images (user-generated content)
|
||||||
|
# Uncomment if you don't want to track example images
|
||||||
|
# CardSets/*/images/
|
||||||
|
|
||||||
|
# Preview image (generate your own)
|
||||||
|
# preview.png
|
||||||
80
CLAUDE.md
Normal file
80
CLAUDE.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build the mod
|
||||||
|
dotnet build
|
||||||
|
|
||||||
|
# Build release version
|
||||||
|
dotnet build -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.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
## TODO Items in Code
|
||||||
|
|
||||||
|
The following features need implementation (marked with TODO comments):
|
||||||
|
- `RegisterCardWithGame()` - Create Unity prefabs and register with ItemAssetsCollection
|
||||||
|
- Item cleanup in `OnDestroy()` - Remove registered items on mod unload
|
||||||
|
- `TradingCard.ItemPrefab` property - Store Unity prefab reference
|
||||||
20
CardSets/ExampleSet/cards.txt
Normal file
20
CardSets/ExampleSet/cards.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Example Card Set - Trading Card Mod for Escape from Duckov
|
||||||
|
# Format: CardName | SetName | SetNumber | ImageFile | Rarity | Weight | Value
|
||||||
|
#
|
||||||
|
# Fields:
|
||||||
|
# CardName - Display name of the card
|
||||||
|
# SetName - Name of the card collection
|
||||||
|
# SetNumber - Number within the set (for sorting)
|
||||||
|
# ImageFile - Filename of the card image (must be in images/ subfolder)
|
||||||
|
# Rarity - Card rarity (Common, Uncommon, Rare, Ultra Rare)
|
||||||
|
# Weight - Physical weight in game units
|
||||||
|
# Value - In-game currency value
|
||||||
|
#
|
||||||
|
# Add your own cards below! Just follow the format above.
|
||||||
|
# Place corresponding images in the images/ subfolder.
|
||||||
|
|
||||||
|
Duck Hero | Example Set | 001 | duck_hero.png | Rare | 0.01 | 100
|
||||||
|
Golden Quacker | Example Set | 002 | golden_quacker.png | Ultra Rare | 0.01 | 500
|
||||||
|
Pond Guardian | Example Set | 003 | pond_guardian.png | Uncommon | 0.01 | 25
|
||||||
|
Bread Seeker | Example Set | 004 | bread_seeker.png | Common | 0.01 | 10
|
||||||
|
Feathered Fury | Example Set | 005 | feathered_fury.png | Rare | 0.01 | 75
|
||||||
136
README.md
Normal file
136
README.md
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
# Trading Card Mod for Escape from Duckov
|
||||||
|
|
||||||
|
A customizable trading card system that lets you add your own card sets to the game.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
**Required Mod Dependency:**
|
||||||
|
- [HarmonyLib (HarmonyLoadMod)](https://steamcommunity.com/sharedfiles/filedetails/?id=3589088839) - Subscribe on Steam Workshop
|
||||||
|
|
||||||
|
This mod requires the HarmonyLoadMod to be installed. It provides the Harmony library that many mods share to avoid version conflicts.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Subscribe to [HarmonyLib](https://steamcommunity.com/sharedfiles/filedetails/?id=3589088839) on Steam Workshop
|
||||||
|
2. Build the mod (see Development section)
|
||||||
|
3. Copy the `TradingCardMod` folder to your game's `Duckov_Data/Mods` directory
|
||||||
|
4. Launch the game and enable both HarmonyLib and this mod in the Mods menu
|
||||||
|
|
||||||
|
## Adding Card Sets
|
||||||
|
|
||||||
|
### Creating a New Card Set
|
||||||
|
|
||||||
|
1. Create a new folder in `CardSets/` with your set name (e.g., `CardSets/MyCards/`)
|
||||||
|
2. Create a `cards.txt` file in your folder
|
||||||
|
3. Create an `images/` subfolder for card artwork
|
||||||
|
|
||||||
|
### Card Definition Format
|
||||||
|
|
||||||
|
Cards are defined in `cards.txt` using pipe-separated values:
|
||||||
|
|
||||||
|
```
|
||||||
|
CardName | SetName | SetNumber | ImageFile | Rarity | Weight | Value
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
Blue Dragon | Fantasy Set | 001 | blue_dragon.png | Ultra Rare | 0.01 | 500
|
||||||
|
Fire Sprite | Fantasy Set | 002 | fire_sprite.png | Rare | 0.01 | 100
|
||||||
|
```
|
||||||
|
|
||||||
|
### Field Descriptions
|
||||||
|
|
||||||
|
| Field | Description | Example |
|
||||||
|
|-------|-------------|---------|
|
||||||
|
| CardName | Display name of the card | "Blue Dragon" |
|
||||||
|
| SetName | Name of the collection | "Fantasy Set" |
|
||||||
|
| SetNumber | Number for sorting (as integer) | 001 |
|
||||||
|
| ImageFile | Image filename in images/ folder | "blue_dragon.png" |
|
||||||
|
| Rarity | Card rarity tier | Common, Uncommon, Rare, Ultra Rare |
|
||||||
|
| Weight | Physical weight in game units | 0.01 |
|
||||||
|
| Value | In-game currency value | 500 |
|
||||||
|
|
||||||
|
### Image Requirements
|
||||||
|
|
||||||
|
- Place images in your card set's `images/` subfolder
|
||||||
|
- Recommended format: PNG
|
||||||
|
- Recommended size: 256x256 or similar aspect ratio
|
||||||
|
|
||||||
|
### Comments
|
||||||
|
|
||||||
|
Lines starting with `#` are treated as comments and ignored:
|
||||||
|
|
||||||
|
```
|
||||||
|
# This is a comment
|
||||||
|
# CardName | SetName | SetNumber | ImageFile | Rarity | Weight | Value
|
||||||
|
Blue Dragon | Fantasy Set | 001 | blue_dragon.png | Ultra Rare | 0.01 | 500
|
||||||
|
```
|
||||||
|
|
||||||
|
## Folder Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
TradingCardMod/
|
||||||
|
├── TradingCardMod.dll
|
||||||
|
├── info.ini
|
||||||
|
├── preview.png
|
||||||
|
├── CardSets/
|
||||||
|
│ ├── ExampleSet/
|
||||||
|
│ │ ├── cards.txt
|
||||||
|
│ │ └── images/
|
||||||
|
│ │ └── (card images here)
|
||||||
|
│ └── YourCustomSet/
|
||||||
|
│ ├── cards.txt
|
||||||
|
│ └── images/
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- .NET SDK (for .NET Standard 2.1)
|
||||||
|
- Escape from Duckov installed
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
1. Update `DuckovPath` in `TradingCardMod.csproj` to point to your game installation
|
||||||
|
2. Build the project:
|
||||||
|
```bash
|
||||||
|
dotnet build
|
||||||
|
```
|
||||||
|
3. The compiled DLL will be in `bin/Debug/netstandard2.1/`
|
||||||
|
|
||||||
|
### Linux Steam Paths
|
||||||
|
|
||||||
|
Common Steam library locations on Linux:
|
||||||
|
- `~/.steam/steam/steamapps/common/Escape from Duckov`
|
||||||
|
- `~/.local/share/Steam/steamapps/common/Escape from Duckov`
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
1. Copy the build output to `Duckov_Data/Mods/TradingCardMod/`
|
||||||
|
2. Launch the game through Steam
|
||||||
|
3. Enable the mod in the Mods menu
|
||||||
|
4. Check the game's log for `[TradingCardMod]` messages
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "CardSets directory not found"
|
||||||
|
The mod will create this directory automatically. Add your card sets there.
|
||||||
|
|
||||||
|
### Cards not appearing
|
||||||
|
- Check that `cards.txt` follows the exact format (7 pipe-separated fields)
|
||||||
|
- Ensure image files exist in the `images/` subfolder
|
||||||
|
- Check the game log for parsing errors
|
||||||
|
|
||||||
|
### Build errors
|
||||||
|
- Verify `DuckovPath` in the .csproj points to your actual game installation
|
||||||
|
- Ensure you have .NET SDK installed with `dotnet --version`
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This mod is provided as-is for personal use. Do not distribute copyrighted card artwork.
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
Built using the official Duckov modding framework.
|
||||||
40
TradingCardMod.csproj
Normal file
40
TradingCardMod.csproj
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>8.0</LangVersion>
|
||||||
|
<RootNamespace>TradingCardMod</RootNamespace>
|
||||||
|
<AssemblyName>TradingCardMod</AssemblyName>
|
||||||
|
|
||||||
|
<!-- Game installation path -->
|
||||||
|
<DuckovPath>/mnt/NV2/SteamLibrary/steamapps/common/Escape from Duckov</DuckovPath>
|
||||||
|
|
||||||
|
<SubPath>/Duckov_Data/Managed/</SubPath>
|
||||||
|
|
||||||
|
<!-- Steam Workshop path for mod dependencies -->
|
||||||
|
<WorkshopPath>/mnt/NV2/SteamLibrary/steamapps/workshop/content/3167020</WorkshopPath>
|
||||||
|
|
||||||
|
<!-- HarmonyLoadMod Workshop ID -->
|
||||||
|
<HarmonyModId>3589088839</HarmonyModId>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- Game DLL references -->
|
||||||
|
<Reference Include="$(DuckovPath)$(SubPath)TeamSoda.*"/>
|
||||||
|
<Reference Include="$(DuckovPath)$(SubPath)ItemStatsSystem.dll"/>
|
||||||
|
<Reference Include="$(DuckovPath)$(SubPath)Unity*"/>
|
||||||
|
<Reference Include="$(DuckovPath)$(SubPath)Duckov.dll"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- Harmony library from HarmonyLoadMod (required dependency) -->
|
||||||
|
<Reference Include="$(WorkshopPath)/$(HarmonyModId)/0Harmony.dll"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- Exclude non-code files from compilation -->
|
||||||
|
<None Include="CardSets/**/*" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
<None Include="info.ini" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
<None Include="preview.png" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
3
info.ini
Normal file
3
info.ini
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
name=TradingCardMod
|
||||||
|
displayName=Trading Card Mod
|
||||||
|
description=A customizable trading card system with storage solutions. Add your own card sets!
|
||||||
203
src/ModBehaviour.cs
Normal file
203
src/ModBehaviour.cs
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using ItemStatsSystem;
|
||||||
|
using SodaCraft.Localizations;
|
||||||
|
|
||||||
|
namespace TradingCardMod
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Main entry point for the Trading Card Mod.
|
||||||
|
/// Inherits from Duckov.Modding.ModBehaviour as required by the mod system.
|
||||||
|
/// </summary>
|
||||||
|
public class ModBehaviour : Duckov.Modding.ModBehaviour
|
||||||
|
{
|
||||||
|
private static ModBehaviour? _instance;
|
||||||
|
public static ModBehaviour Instance => _instance!;
|
||||||
|
|
||||||
|
private string _modPath = string.Empty;
|
||||||
|
private List<TradingCard> _loadedCards = new List<TradingCard>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the mod is loaded. Initialize the card system here.
|
||||||
|
/// </summary>
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
_instance = this;
|
||||||
|
|
||||||
|
// Get the mod's directory path
|
||||||
|
_modPath = Path.GetDirectoryName(GetType().Assembly.Location) ?? string.Empty;
|
||||||
|
|
||||||
|
Debug.Log("[TradingCardMod] Mod initialized!");
|
||||||
|
Debug.Log($"[TradingCardMod] Mod path: {_modPath}");
|
||||||
|
|
||||||
|
// Apply Harmony patches
|
||||||
|
Patches.ApplyPatches();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LoadCardSets();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[TradingCardMod] Failed to load card sets: {ex.Message}");
|
||||||
|
Debug.LogException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Scans the CardSets directory and loads all card definitions.
|
||||||
|
/// </summary>
|
||||||
|
private void LoadCardSets()
|
||||||
|
{
|
||||||
|
string cardSetsPath = Path.Combine(_modPath, "CardSets");
|
||||||
|
|
||||||
|
if (!Directory.Exists(cardSetsPath))
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[TradingCardMod] CardSets directory not found at: {cardSetsPath}");
|
||||||
|
Directory.CreateDirectory(cardSetsPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] setDirectories = Directory.GetDirectories(cardSetsPath);
|
||||||
|
Debug.Log($"[TradingCardMod] Found {setDirectories.Length} card set directories");
|
||||||
|
|
||||||
|
foreach (string setDir in setDirectories)
|
||||||
|
{
|
||||||
|
LoadCardSet(setDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"[TradingCardMod] Total cards loaded: {_loadedCards.Count}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads a single card set from a directory.
|
||||||
|
/// Expects a cards.txt file with pipe-separated values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="setDirectory">Path to the card set directory</param>
|
||||||
|
private void LoadCardSet(string setDirectory)
|
||||||
|
{
|
||||||
|
string setName = Path.GetFileName(setDirectory);
|
||||||
|
string cardsFile = Path.Combine(setDirectory, "cards.txt");
|
||||||
|
|
||||||
|
if (!File.Exists(cardsFile))
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[TradingCardMod] No cards.txt found in {setName}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"[TradingCardMod] Loading card set: {setName}");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string[] lines = File.ReadAllLines(cardsFile);
|
||||||
|
int cardCount = 0;
|
||||||
|
|
||||||
|
foreach (string line in lines)
|
||||||
|
{
|
||||||
|
// Skip empty lines and comments
|
||||||
|
if (string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith("#"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TradingCard? card = ParseCardLine(line, setDirectory);
|
||||||
|
if (card != null)
|
||||||
|
{
|
||||||
|
_loadedCards.Add(card);
|
||||||
|
cardCount++;
|
||||||
|
// TODO: Register card with game's item system
|
||||||
|
// RegisterCardWithGame(card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"[TradingCardMod] Loaded {cardCount} cards from {setName}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[TradingCardMod] Error loading card set {setName}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a single line from cards.txt into a TradingCard object.
|
||||||
|
/// Format: CardName | SetName | SetNumber | ImageFile | Rarity | Weight | Value
|
||||||
|
/// </summary>
|
||||||
|
private TradingCard? ParseCardLine(string line, string setDirectory)
|
||||||
|
{
|
||||||
|
string[] parts = line.Split('|');
|
||||||
|
|
||||||
|
if (parts.Length < 7)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[TradingCardMod] Invalid card line (expected 7 fields): {line}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new TradingCard
|
||||||
|
{
|
||||||
|
CardName = parts[0].Trim(),
|
||||||
|
SetName = parts[1].Trim(),
|
||||||
|
SetNumber = int.Parse(parts[2].Trim()),
|
||||||
|
ImagePath = Path.Combine(setDirectory, "images", parts[3].Trim()),
|
||||||
|
Rarity = parts[4].Trim(),
|
||||||
|
Weight = float.Parse(parts[5].Trim()),
|
||||||
|
Value = int.Parse(parts[6].Trim())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[TradingCardMod] Failed to parse card line: {line} - {ex.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the mod is unloaded. Clean up registered items.
|
||||||
|
/// </summary>
|
||||||
|
void OnDestroy()
|
||||||
|
{
|
||||||
|
Debug.Log("[TradingCardMod] Mod unloading, cleaning up...");
|
||||||
|
|
||||||
|
// Remove Harmony patches
|
||||||
|
Patches.RemovePatches();
|
||||||
|
|
||||||
|
// TODO: Remove registered items from game
|
||||||
|
// foreach (var card in _loadedCards)
|
||||||
|
// {
|
||||||
|
// ItemAssetsCollection.RemoveDynamicEntry(card.ItemPrefab);
|
||||||
|
// }
|
||||||
|
|
||||||
|
_loadedCards.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a trading card's data loaded from a card set file.
|
||||||
|
/// </summary>
|
||||||
|
public class TradingCard
|
||||||
|
{
|
||||||
|
public string CardName { get; set; } = string.Empty;
|
||||||
|
public string SetName { get; set; } = string.Empty;
|
||||||
|
public int SetNumber { get; set; }
|
||||||
|
public string ImagePath { get; set; } = string.Empty;
|
||||||
|
public string Rarity { get; set; } = string.Empty;
|
||||||
|
public float Weight { get; set; }
|
||||||
|
public int Value { get; set; }
|
||||||
|
|
||||||
|
// TODO: Add Unity prefab reference once we understand the item system better
|
||||||
|
// public Item? ItemPrefab { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a unique TypeID for this card to avoid conflicts.
|
||||||
|
/// Uses hash of set name + card name for uniqueness.
|
||||||
|
/// </summary>
|
||||||
|
public int GenerateTypeID()
|
||||||
|
{
|
||||||
|
// Start from a high number to avoid conflicts with base game items
|
||||||
|
// Use hash to ensure consistency across loads
|
||||||
|
string uniqueKey = $"TradingCard_{SetName}_{CardName}";
|
||||||
|
return 100000 + Math.Abs(uniqueKey.GetHashCode() % 900000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
118
src/Patches.cs
Normal file
118
src/Patches.cs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
using System;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace TradingCardMod
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains all Harmony patches for the Trading Card Mod.
|
||||||
|
/// Patches are applied in ModBehaviour.Start() via Harmony.PatchAll().
|
||||||
|
/// </summary>
|
||||||
|
public static class Patches
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Unique Harmony ID for this mod. Used to identify and unpatch if needed.
|
||||||
|
/// </summary>
|
||||||
|
public const string HarmonyId = "com.manticorum.tradingcardgame.duckov";
|
||||||
|
|
||||||
|
private static Harmony? _harmony;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply all Harmony patches defined in this assembly.
|
||||||
|
/// </summary>
|
||||||
|
public static void ApplyPatches()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_harmony = new Harmony(HarmonyId);
|
||||||
|
_harmony.PatchAll();
|
||||||
|
Debug.Log($"[TradingCardMod] Harmony patches applied successfully");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[TradingCardMod] Failed to apply Harmony patches: {ex.Message}");
|
||||||
|
Debug.LogException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove all Harmony patches applied by this mod.
|
||||||
|
/// Called during mod unload to clean up.
|
||||||
|
/// </summary>
|
||||||
|
public static void RemovePatches()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_harmony?.UnpatchSelf();
|
||||||
|
Debug.Log($"[TradingCardMod] Harmony patches removed");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[TradingCardMod] Failed to remove Harmony patches: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
// Example Harmony Patches
|
||||||
|
// ==========================================================================
|
||||||
|
//
|
||||||
|
// Below are example patches showing common patterns. Uncomment and modify
|
||||||
|
// as needed once you've identified the game methods to patch.
|
||||||
|
//
|
||||||
|
// To find methods to patch, use a decompiler (ILSpy) on the game DLLs in:
|
||||||
|
// Duckov_Data/Managed/
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// <summary>
|
||||||
|
/// Example: Postfix patch that runs after a method completes.
|
||||||
|
/// Use case: Log when items are added to inventory, modify return values.
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(ItemStatsSystem.ItemUtilities), "SendToPlayer")]
|
||||||
|
public static class SendToPlayer_Patch
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void Postfix(ItemStatsSystem.Item item)
|
||||||
|
{
|
||||||
|
// Check if the item is one of our trading cards
|
||||||
|
// This runs after the original method completes
|
||||||
|
Debug.Log($"[TradingCardMod] Item sent to player: {item.name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Example: Prefix patch that runs before a method.
|
||||||
|
/// Use case: Modify parameters, skip original method, validate inputs.
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(SomeClass), "SomeMethod")]
|
||||||
|
public static class SomeMethod_Patch
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool Prefix(ref int someParameter)
|
||||||
|
{
|
||||||
|
// Modify parameter before original method runs
|
||||||
|
someParameter = someParameter * 2;
|
||||||
|
|
||||||
|
// Return true to run original method, false to skip it
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Example: Transpiler patch that modifies IL instructions.
|
||||||
|
/// Use case: Complex modifications, inserting code mid-method.
|
||||||
|
/// Note: Advanced technique - prefer Prefix/Postfix when possible.
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(SomeClass), "SomeMethod")]
|
||||||
|
public static class SomeMethod_Transpiler
|
||||||
|
{
|
||||||
|
[HarmonyTranspiler]
|
||||||
|
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
// Modify and return the IL instructions
|
||||||
|
return instructions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user