diff --git a/.agents/skills/openshc-attempt-bytecode-matching-dll/SKILL.md b/.agents/skills/openshc-attempt-bytecode-matching-dll/SKILL.md new file mode 100644 index 00000000..57b6518e --- /dev/null +++ b/.agents/skills/openshc-attempt-bytecode-matching-dll/SKILL.md @@ -0,0 +1,104 @@ +# Attempt Bytecode Matching DLL + +Iteratively improve bytecode matching between a reimplementation and the original binary using the workflow: + +**Locate → Setup → Build → Compare → Analyze → Modify → Repeat** + +At each iteration, perform the next phase only if the previous one succeeded. + +## Workflow + +### Locate +- Use the **find-function-implementation** skill to locate the target `.cpp` file. + +### Setup +- Ask whether to enable source compilation for the located function. +- Mention that it is assumed the function is already active if declined. +- If yes, invoke **enable-local-function-dev** for the located function. + +### Build +Run: + +```powershell +.\build --wrap-quiet RelWithDebInfo OpenSHC.dll > $null 2>&1 +``` + +If the build fails: +- Stop the workflow. +- Offer to rerun with verbose output: + +```powershell +.\build RelWithDebInfo OpenSHC.dll +``` + +### Compare +Extract the hexadecimal address from the function comment: + +```cpp +// FUNCTION: STRONGHOLDCRUSADER 0x... +``` + +Run: + +```powershell +$env:PYTHONIOENCODING="utf-8"; reccmp/dll/run --wrap-quiet reccmp-reccmp --target STRONGHOLDCRUSADER --verbose
2>$null +``` + +If the comparison fails or produces no output: +- Stop the workflow. +- Offer to rerun with stderr enabled for diagnosis, noting that the output may be large. + +### Analyze +Compare **structure**, not exact bytes. + +Treat the following as expected differences: +- proxied function calls +- global resolver addresses + +Instead, compare: +- control flow +- call placement +- global access patterns +- local variable ordering +- stack usage +- casts and type conversions + +### Modify +Attempt structural improvements without changing program behavior. + +Typical changes include: +- reordering local variables +- reordering statements +- introducing or removing temporary variables +- moving casts +- expanding or simplifying expressions +- restructuring control flow + +### Repeat +Return to the **Build** phase. + +After each iteration: +- report whether the match improved +- explain likely causes of remaining mismatches +- ask whether another iteration should be attempted + +If 3–4 consecutive iterations show no improvement, recommend stopping. + +### Optional: Enable Struct Implementations +If many diffs appear to be caused by global resolver usage, offer to enable struct implementations. +Note that this will only remove diffs caused by `` <-> `` mismatches if the structure fits. +It will **not** improve structural differences. + +If accepted: +1. Find every included `OpenSHC/Globals/...` header used by the function. +2. In each included header, locate its `MACRO_STRUCT_RESOLVER(...)` definition. +3. Change the second macro argument from `false` to `true`. +4. Return to the **Build** phase. +5. Report whether the match improved. + +## Principles + +- Preserve program behavior at all times. +- Prefer structural changes over logic changes. +- Function calls will always and global accesses will often appear as differences because they are proxied or resolved; compare only their structural placement. +- The user decides whether to continue after every iteration. diff --git a/.agents/skills/openshc-clean-decomp-body/SKILL.md b/.agents/skills/openshc-clean-decomp-body/SKILL.md new file mode 100644 index 00000000..6854914e --- /dev/null +++ b/.agents/skills/openshc-clean-decomp-body/SKILL.md @@ -0,0 +1,179 @@ +# Clean Decomp Body + +Transforms decompiled C++ function implementations into the project's macro/global style while preserving the original logic. + +## Workflow + +### Input + +Request the function implementation file using **Find Function Implementation**. + +Transform the file directly. Do not create a separate replacement snippet unless requested. + +### Abort Conditions + +Do not transform if: +- The body is empty or contains no meaningful code. +- The code already matches cleaned style: + - Uses `MACRO_CALL` / `MACRO_CALL_MEMBER`. + - Uses `::instance` / `::ptr` for global access. + - Uses `_Func` namespaces inside function macros. + - Already uses correct namespaces and imports. + +Report that no transformation is required. + +--- + +## Rules + +Preserve: +- Control flow. +- Local variables. +- Conditions. +- Returns. +- Statement order. +- Switch structure. +- Original logic. + +Do not: +- Refactor. +- Simplify. +- Remove code. +- Reorder code. + +Never invent: +- namespaces +- globals +- singleton names +- imports + +If a required transformation cannot be resolved from the implementation or project context, ask for clarification instead of guessing. +Leave all code not covered by these transformation rules unchanged. + +--- + +## Transformation Process + +Apply transformations in this order: + +### 1. Determine Context + +Identify: +- Current class if member function. +- Existing imports. +- Function and class namespaces. +- Required function/global dependencies. + +Use this information for all following transformations. + +--- + +### 2. Member Field Access + +Member field access might appear through a global in the code, since many are singletons. + +Determine from the function signature whether the implementation is a member function: `::()` + +If so, identify the singleton/global representing the current class. For example: `DAT_` + +Transform to `this` access: + +`DAT_.field` → `this->field` + +If the required global cannot be identified, ask for clarification instead of guessing. + +--- + +### 3. Global Access + +Convert globals for field access: + +`SEC_RNG.currentNumber1` → `SEC_RNG::instance.currentNumber1` + +Only use pointer in cases of function calls or pointer assigns: + +`&DAT_Global` → `DAT_Global::ptr` + +Keep global namespaces. + +--- + +### 4. Function Calls + +Replace direct calls: + +`Namespace::Function(args)` → `MACRO_CALL(Namespace_Func::Function)(args)` + +Replace member calls using: + +- the "this" pointer if the current function is a member function of the same class: +`Namespace::Class::Function(&ClassObject, args)` or `Namespace::Class::Function(ClassObject, args)` → `MACRO_CALL_MEMBER(Namespace::Class_Func::Function, this)(args)` + +- global objects otherwise: +`Namespace::Class::Function(&Global, args)` or `Namespace::Class::Function(Global, args)` → `MACRO_CALL_MEMBER(Namespace::Class_Func::Function, Global::ptr)(args)` + +Rules: +- Keep normal namespaces for classes and functions. +- Only add `_Func` inside macro function references. +- Use the resolved namespace to determine the required `.func.hpp` import. +- Apply transformations recursively, including nested function calls. + +--- + +### 5. Namespace Resolution + +Ensure classes, functions, and types use their correct namespaces after transformation. + +Rules: +- Macro function references use the `_Func` namespace: `SFX::SFXState_Func::PlaySpeechSFX` +- Types and globals keep their normal namespaces. + +Use namespace information to identify required imports. + +--- + +### 6. Imports + +Add only required dependency imports. + +Rules: +- The current file's relative `.func.hpp` import already exists. Do not add or modify it. +- Add `.func.hpp` imports for called functions/classes. +- Add global `.hpp` imports for accessed globals. Not for the transformed class global. +- Global imports always use `OpenSHC/Globals/.hpp`. +- All new imports must use the full project path. +- Do not add unused imports. +- Preserve existing include grouping. +- Do not duplicate existing imports. + +Example: + +```cpp +#include "OpenSHC/Audio/SFX/SFXState.func.hpp" + +#include "OpenSHC/Globals/DAT_SFXState.hpp" +``` + +--- + +## File Structure + +Keep the existing file structure. + +Preserve: +- Existing namespace layout. +- Function address comments: `// FUNCTION: STRONGHOLDCRUSADER 0xXXXXXXXX` + +--- + +## Output + +Apply the transformation directly to the function implementation file. + +The CLI response should only contain a short summary: +- Functions converted to `MACRO_CALL` / `MACRO_CALL_MEMBER`. +- Globals converted to `::instance`, `::ptr`, or `this`. +- Imports added. +- Namespace/type adjustments made. + +Do not output the full transformed file unless explicitly requested. diff --git a/.agents/skills/openshc-enable-local-function-dev/SKILL.md b/.agents/skills/openshc-enable-local-function-dev/SKILL.md new file mode 100644 index 00000000..46d1e21d --- /dev/null +++ b/.agents/skills/openshc-enable-local-function-dev/SKILL.md @@ -0,0 +1,66 @@ +# Enable Local Function Development + +Configure `cmake/openshc-sources.txt.local` with selected `.cpp` implementations. + +## Input + +Request a list of functions. + +Accepted formats: + +- Function: `wipeAICMemory` +- Class/function: `AICState::wipeAICMemory` +- Path: `src/OpenSHC/AI/AICState/wipeAICMemory.cpp` +- Address: `0x004C6D30` + +Mixed formats are allowed. + +--- + +## Resolve Inputs + +Resolve each input using **Find Function Implementation**. + +Rules: + +- Deduplicate resolved paths while preserving input order. +- If any input fails to resolve, abort. +- Do not modify files on failure. +- Report the failing input and reason. + +--- + +## Update Configuration + +Manage: + +`cmake/openshc-sources.txt.local` + +Create it if missing. + +Rewrite the file contents with the resolved paths. Do not append. + +Rules: +- Paths are relative to project root +- Use `/` separators +- Preserve order +- End with newline + +Never modify: + +`cmake/openshc-sources.txt` + +--- + +## Completion + +Output: + +```text +Configured files for local development + +Files: + + +... +``` diff --git a/.agents/skills/openshc-find-function-implementation/SKILL.md b/.agents/skills/openshc-find-function-implementation/SKILL.md new file mode 100644 index 00000000..42e1a6b4 --- /dev/null +++ b/.agents/skills/openshc-find-function-implementation/SKILL.md @@ -0,0 +1,74 @@ +# Find Function Implementation + +Resolve a single function reference to exactly one `.cpp` implementation file. + +## Input + +Accepted formats: + +- Function: `wipeAICMemory` +- Class/function: `AICState::wipeAICMemory` +- Path: `src/OpenSHC/AI/AICState/wipeAICMemory.cpp` +- Address: `0x004C6D30` + +--- + +## Resolution + +### Function + +Search `src/**/*.cpp` for implementation filenames matching the function name. + +### Class/function + +Restrict the search to the class folder. + +Example: + +`AICState::wipeAICMemory` → `src/**/AICState/wipeAICMemory.cpp` + +### Path + +Verify that the `.cpp` file exists. + +### Address + +Requires an available CLI or optimized text-search tool. + +Search all `.cpp` files under `src/` for: + +`FUNCTION: STRONGHOLDCRUSADER ` + +Requirements: + +- Use the search tool only. +- Do not inspect files individually. + +### Match Rules + +For function, class/function, and address resolution: + +- One match → return path. +- Zero matches → fail. +- Multiple matches → fail and report matches. + +--- + +## Failure + +On failure: + +- Do not modify files. +- Stop processing. +- Report: + - Input. + - Reason. + - Matches (if applicable). + +--- + +## Output + +Success: `` + +Example: `src/OpenSHC/AI/AICState/wipeAICMemory.cpp` diff --git a/.agents/skills/setup-function/SKILL.md b/.agents/skills/setup-function/SKILL.md new file mode 100644 index 00000000..79b3ae1f --- /dev/null +++ b/.agents/skills/setup-function/SKILL.md @@ -0,0 +1,126 @@ +# Setup Function for Reimplementation + +Creates a new C++ implementation file for an existing Stronghold Crusader function. + +## Input + +Ask for: + +```text +File: +Function: +``` + +If validation fails, abort without creating or modifying files. Report source `.func.hpp` path, function name, and failure reason. + +--- + +## Workflow + +### 1. Validate `.func.hpp` + +Locate `src/`. + +Find `MACRO_FUNCTION_RESOLVER(..., &Class::Function) Function;`. + +The function identifier after the macro must match the requested function. + +--- + +### 2. Extract Address + +Extract only the hexadecimal value from `Address::SHC_xxxxxxxx_0xXXXXXXXX`. + +Example: + +`Address::SHC_3BB0A8C1_0x004C6D30` → `0x004C6D30` + +Never use the symbolic identifier. + +--- + +### 3. Resolve Paths + +From `src//.func.hpp`, derive: + +- Implementation folder: `src///` +- Declaration file: `src//.hpp` + +Create the implementation folder if missing. Abort if creation fails. + +--- + +### 4. Check Implementation + +Target: `src///.cpp`. + +If it exists, abort. Never overwrite. + +--- + +### 5. Validate Declaration + +Search `.hpp` for the class-qualified function declaration. + +Use the exact header declaration as the implementation signature. + +Abort if: +- Header is missing +- Declaration is missing +- Namespace extraction fails + +--- + +### 6. Generate File + +Create `src///.cpp`. + +Content: + +```cpp +#include "../.func.hpp" + + + +// FUNCTION: STRONGHOLDCRUSADER
+ { +} +``` + +Rules: +- Preserve namespace order and nesting +- Copy only normal `namespace` declarations +- Ignore `using` declarations and namespace aliases +- Do not modify existing files + +Example: +``` +#include "../AICState.func.hpp" + +namespace OpenSHC { +namespace AI { + + // FUNCTION: STRONGHOLDCRUSADER 0x004C6D30 + void AICState::wipeAICMemory() { + } + +} +} +``` + +--- + +## Completion Report + +Output: + +```text +Created: + + +Function: + + +Address: + +```