Merge Rules
merge / replace
GP-Next now has two file-level modes for ordinary JSON patching:
mergereplace
If you only remember one sentence:
merge: write only the parts you want to changereplace: you take over the whole JSON for that type
This page is dedicated to the difference between those two modes, how to configure them, and when each one makes sense.
Default Behavior
By default, GP-Next treats ordinary JSON patches like this:
features/objects:mergelevels: effectively whole-file replacementlang: still deep-merged intoMultiLanguage.lyricsworldmap: uses GP-Next's own runtime system, not the rules on this page
So this page mainly focuses on:
jsons/features/*.jsonjsons/objects/*.json
What merge Means
merge is GP-Next's original default approach.
Its goal is to:
- keep as much of the original game JSON as possible
- override only the fields you explicitly write
- keep patches small and more compatible with future game updates
For example, if you only want to change the stats of one plant, merge should usually be your first choice.
{
"objects": [
{
"aliases": ["peashooter"],
"objclass": "PlantProperties",
"objdata": {
"SunCost": 50,
"Cooldown": 2
}
}
]
}This patch does not replace all of PlantProps. It only changes those two fields on peashooter.
What replace Means
replace means:
- GP-Next stops using the normal merge rules for that type
- your patch file directly replaces the whole original JSON of that type
It is useful when:
- you want to fully rebuild the store contents
- you want to clearly remove a large amount of vanilla data
- you do not want any old content from that original type to remain
So replace is not just "stronger override". It means "this whole type is now owned by your file".
How To Configure It
Put the config file here:
jsons/config/patching.jsonMinimal example:
{
"defaultMode": "merge",
"features": {
"StoreCommodityFeatures": { "mode": "replace" }
},
"objects": {
"PlantProps": { "mode": "replace" }
}
}This means:
- types not listed still use
merge StoreCommodityFeaturesuses fullreplacePlantPropsuses fullreplace
Current Scope
Right now this config only affects:
featuresobjects
That means files like:
features/PlantFeatures.jsonfeatures/StoreCommodityFeatures.jsonobjects/PlantProps.jsonobjects/ZombieProps.json
can be switched between merge and replace through patching.json.
These are not controlled by this page's rules:
levelslangworldmap
Config Rules
The current rules are simple:
- write type names under
featuresandobjects - types not listed use
defaultMode - if
defaultModeis omitted, it falls back tomerge - currently only
mergeandreplaceare supported
For example:
{
"features": {
"StoreCommodityFeatures": { "mode": "replace" }
}
}This switches only StoreCommodityFeatures to replace. Everything else keeps the default behavior.
What GP-Next Does in merge
Features
Features files are not merged by array index. They are matched through identifier fields.
Common cases:
- most Features files:
CODENAME MintObtainRoute:FamilyStoreCommodityFeatures.Plants / Upgrade:CommodityName
Objects
Objects files usually locate entries inside the objects array by:
aliases[0]
So if you are editing a plant or zombie, you usually write its first alias.
Arrays Need Extra Care
Even in merge, arrays are not merged item by item by index.
In GP-Next, arrays are still replaced as a whole by default.
That usually applies to things like:
- zombie pools
PLANTSSEEDCHOOSERDEFAULTORDER- certain full store lists
So merge does not mean "everything is automatically appended in a smart way". It mainly means object fields are merged by rule, while arrays still tend to replace.
Special Note on StoreCommodityFeatures
StoreCommodityFeatures is not one single array. It contains several parallel sections:
PlantsUpgradeGemCoinZen
Under normal merge:
Plants/Upgrade: merged byCommodityNameGem/Coin/Zen: usually replaced as whole arrays
If your goal is "the whole store should now follow my own version", replace is often clearer than continuing to mix with vanilla data.
When To Choose merge
merge is usually better when:
- you only want to change a few plant or zombie stats
- you only want to edit a small number of almanac texts or descriptions
- you only want to adjust a few store prices
- you want better compatibility with future game updates and new fields
Short version:
If a local change is enough, prefer merge.
When To Choose replace
replace is usually better when:
- you want to completely rebuild one type
- you clearly want to remove a large amount of vanilla content
- you do not want the original JSON of that type to participate anymore
- you are ready to maintain that entire type file yourself
Short version:
Use replace when you want to take over the whole type.
A Quick Decision Test
Ask yourself:
- Am I only changing a small number of fields?
- Do I want future vanilla fields to stay whenever possible?
- Do I want to avoid maintaining a whole type file?
If most answers are yes, use merge.
On the other hand:
- Am I ready to maintain the full type file myself?
- Do I want old vanilla content to stop mixing in?
- Am I intentionally rebuilding this whole type?
If most answers are yes, use replace.
Recommended Workflow
- Inspect the real structure in the Data page first
- Start with the smallest possible
mergepatch - Switch to
replaceonly if the real need is "take over the whole type" - Reload and confirm the result again in the Data page
