Repository navigation
Creating a cook mod
PATCH_COOK mods apply runtime tweaks while the game is open. You write a small text file of instructions, and the loader applies them during play. Use them for small offline adjustments, string swaps, value tests, or controlled practice-mode experiments.
Runtime mods are less stable than normal file mods. They can cause crashes, failed loads, or unexpected behavior. Use them only in offline or practice modes. Do not use them in online matches, ranked play, or public sessions.
Each mod is a folder under the game's Data\Addons\PATCH_COOK\ directory:
Data\Addons\PATCH_COOK\
my_mod\
info.json (required, marks a valid mod)
my_mod.cook (your instructions, any *.cook or *.cooked name works)
Rules:
- The folder must contain
info.json, or it is ignored. - It must contain at least one
.cookor.cookedfile. You can have several, and each is parsed and applied. - Add an empty file named
.disabledin the folder to skip the whole mod.
{
"visible": true,
"name": "my_mod",
"type": "cook",
"version": "1.0",
"description": "What this mod does.",
"author": "you"
}type must be cook.
Also accepted:
patch_cook
bm
-
.cook: plain text. Easy to author and edit. -
.cooked: protected format used for distribution when you do not want the instructions to be directly readable.
Both can live in the same folder.
The game reloads its scripts at the start of every match. PATCH_COOK currently supports two stages:
- Stage 1 runs when the game first loads.
- Stage 2 runs after you have entered a game once.
Maximum stage is currently 2.
Put this line at the top of your file:
cook_stage 1
If omitted, the stage defaults to 1.
Some targets are not available immediately when the game opens. If something only appears after entering a match, use:
cook_stage 2
When a rule reports not found, the target may not be loaded yet. Try a later stage or check your pattern.
Before any mod runs, the loader performs a one-time access self-test. If that fails, it logs:
access test failed
When this happens, no cook mod runs for that session.
This section is not updated yet.
Use one directive per line.
Blank lines are ignored.
Lines starting with either of these are comments:
#
--
PATCH_COOK supports these directive groups:
find
write
freeze
Use these only for offline testing and practice-mode experiments.
Wherever a pattern or value is expected, use one of these forms:
| Form | Example | Meaning |
|---|---|---|
| String | "TEST_A" |
ASCII text |
| Hex bytes |
90 90 90 or 0xDEADBEEF
|
Raw bytes |
| Integer |
i8 5, i16 100, i32 1000, i64 5
|
Little-endian signed integer |
| Float |
f32 1.5, f64 2.0
|
Little-endian float |
Numbers accept decimal or 0x hex.
find searches for a pattern and applies a replacement when a matching target is found.
find <pattern> [near <pattern> [within N]] [offset X] [all] [zend] -> <value>
All modifiers are optional.
Only accepts matches that have the anchor pattern nearby.
N defaults to:
256
Use this to avoid changing the wrong copy of a common string.
Applies the replacement at match + X instead of directly at the match.
Use this when you find a stable anchor and need to adjust a nearby value.
Applies the rule to every qualifying match.
Without all, only the first qualifying match is changed.
Requires a null byte after the match.
Use this when one name is a prefix of another.
Example:
NAME
NAME_X
Using zend helps match only the complete string.
For string replacements, the available slot is based on the length of the matched pattern.
A shorter replacement is padded cleanly.
A longer replacement can overflow past the original slot and may break nearby data. The parser logs a warning when this happens.
Prefer replacements that are equal length or shorter.
# simple swap
find "TEST_A" -> "TEST_B"
# only the TEST_A that sits near TEST_B, within 128 bytes
find "TEST_A" near "TEST_B" within 128 -> "TEST_B"
# whole-string swap, every occurrence, confirmed by a nearby anchor
find "STRINGTEST" near "OTHERSTRING" zend all -> "STRINGWOW"
# find an anchor, then adjust a nearby float
find "SPEED" offset 0x8 all -> f32 2.5
write applies a value at a specific target address.
write <addr> = <value>
Examples:
write 0x00ABCDEF = "HELLO"
write 0x00ABCDEF = 90 90 90
write 0x00ABCDEF = i32 100
Fixed addresses can change between runs. Prefer pattern-based rules for anything that is not stable.
freeze keeps a value steady through a resolved pointer chain.
freeze ["module"] [+] <baseOffset> chain <off> <off> ... as <type> (hold | = <value>)
This is intended for offline testing where a value changes during play and you want to keep it stable for controlled experiments.
Optional module name.
Example:
"GameApp.dll"
If omitted, the main executable is used.
Offset added to the module base.
Pointer offsets applied in order.
Value type.
Supported types:
i8
i16
i32
i64
f32
f64
Captures the first value read and keeps restoring that value.
Forces a specific value instead of capturing the first one.
cook_stage 2
freeze "GameApp.dll" + 0x000000 chain 0000 0000 0000 as f32 hold
Before every write, the loop checks that the resolved target is valid and writable. If a pointer resolves incorrectly during a scene change, it is skipped instead of being written.
Freezes stop automatically when the game closes.
Use this feature sparingly. Repeated runtime writes can cause instability or detection.
The loader streams the game's loader log silently.
Common messages:
-
CookLoader: access test passed: access OK, mods proceed. -
CookLoader: access test failed (...): access blocked, so nothing runs. -
CookLoader: my_mod applied 3/4: 3 of 4 directives applied successfully. -
1 not found: a directive matched nothing. -
CookLoader: my_mod L8 error: ...: a rule failed, and line 8 is the problem. -
CookLoader: my_mod N freeze active: N freeze rules are running. -
CookScript[my_mod] L5: ...: a parse problem happened on line 5, and that line is skipped. -
CookScript[my_mod] L8: replacement longer than match, will overflow ...: the replacement is longer than the matched slot.
| Symptom | Likely cause or fix |
|---|---|
not found |
Target is not available at this stage. Try cook_stage 2. |
not found on a near rule |
Anchor is too far away. Raise within, or choose a closer anchor. |
| Changes a string it should not | Add zend, or use a tighter near rule. |
| Overflow warning | Replacement is too long. Use an equal-length or shorter value. |
access test failed |
Access was blocked. Mods cannot run this session. |
| Game crashes after a freeze | The target changed, the chain is wrong, or repeated writes caused instability. Remove the freeze to confirm. |
| Wrong value frozen | The chain captured at the wrong moment. Check the offsets and stage. |
Use PATCH_COOK only for offline or practice-mode testing.
Keep edits small and easy to reverse.
Prefer equal-length or shorter string replacements.
Use near and zend when matching common strings.
Avoid broad all rules unless you are sure every match should change.
Avoid fixed addresses when possible because they can change between runs.
Test one directive at a time when debugging.
Keep a backup of every mod folder.
Use .disabled to quickly turn off a mod without deleting it.
Folder:
Data\Addons\PATCH_COOK\
test_swap\
info.json
test_swap.cook
info.json:
{
"visible": true,
"name": "test_swap",
"type": "cook",
"version": "1.0",
"description": "Simple offline test swap.",
"author": "you"
}test_swap.cook:
cook_stage 1
find "TEST_A" -> "TEST_B"