Particles from a Later-Loading Pack
You want your weapon to show the I_Fire_Blue particle, but the particle system that defines it ships in a separate pack that loads after yours. Done naively, your item asset resolves before the particle exists.
Goal
- Your item displays the
I_Fire_Blueparticle. - The particle system itself lives in a different pack (
Riprod:Hexcode) that loads after your item asset, defined atServer/Particles/.../I_Fire_Blue.particlesystem. - The stock particles already on the item stay intact.
The key fact: particle systems are .particlesystem files and are NOT patchable. Patchly only patches .json. What you patch is the .json item asset that REFERENCES a particle by its SystemId string. The string is resolved against the registered particle systems at merge time.
The Asset
Server/Item/Items/Weapon/Sword/Template_Weapon_Sword.json
{
"TranslationProperties": {
"Name": "server.items.Template_Weapon_Sword.name"
},
"DroppedItemAnimation": "Items/Animations/Dropped/Dropped_Diagonal_Left.blockyanim",
"Model": "Items/Weapons/Sword/Iron.blockymodel",
"Texture": "Items/Weapons/Sword/Iron_Texture.png",
"Icon": "Icons/ItemsGenerated/Weapon_Sword_Iron.png",
"PlayerAnimationsId": "Sword",
"Reticle": "DefaultMelee",
"Quality": "Template",
"ItemLevel": 15,
"Categories": [
"Items.Weapons"
],
"IconProperties": {
"Scale": 0.35,
"Translation": [
-22,
-22
],
"Rotation": [
45,
90,
0
]
},
"Utility": {
"Compatible": true
},
"Interactions": {
"Primary": "Root_Weapon_Sword_Primary",
"Secondary": "Root_Weapon_Sword_Secondary_Guard",
"Ability1": "Root_Weapon_Sword_Signature_Vortexstrike"
},
"Tags": {
"Type": [
"Weapon"
],
"Family": [
"Sword"
]
},
"Weapon": {
"EntityStatsToClear": [
"SignatureEnergy"
],
"StatModifiers": {
"SignatureEnergy": [
{
"Amount": 20,
"CalculationType": "Additive"
}
]
}
},
"ItemAppearanceConditions": {
"SignatureEnergy": [
{
"Condition": [
100,
100
],
"ConditionValueType": "Percent",
"Particles": [ // you want to ADD one particle entry to this array
{
"SystemId": "Sword_Signature_Ready",
"TargetNodeName": "Handle",
"PositionOffset": {
"X": 0.8
},
"TargetEntityPart": "PrimaryItem"
},
{
"SystemId": "Sword_Signature_Status_Spawn",
"TargetNodeName": "Handle",
"PositionOffset": {
"X": 0.5
},
"TargetEntityPart": "PrimaryItem"
},
{
"SystemId": "Sword_Signature_Status",
"TargetNodeName": "Handle",
"PositionOffset": {
"X": 0.55
},
"TargetEntityPart": "PrimaryItem",
"Scale": 1.3
}
],
"FirstPersonParticles": [
{
"SystemId": "Sword_Signature_Ready",
"TargetNodeName": "Handle",
"PositionOffset": {
"X": 0.8
},
"TargetEntityPart": "PrimaryItem"
},
{
"SystemId": "Sword_Signature_Status_Spawn",
"TargetNodeName": "Handle",
"TargetEntityPart": "PrimaryItem",
"PositionOffset": {
"Y": -100
}
},
{
"SystemId": "Sword_Signature_Status",
"TargetNodeName": "Handle",
"PositionOffset": {
"X": 0.5
},
"TargetEntityPart": "PrimaryItem"
}
],
"ModelVFXId": "Sword_Signature_Status"
}
]
},
"ItemSoundSetId": "ISS_Weapons_Blade_Large",
"MaxDurability": 80,
"DurabilityLossOnHit": 0.21
}
SystemId is a string id. A stock system it names lives at Server/Particles/.../Sword_Signature_Ready.particlesystem; the one you want to add, I_Fire_Blue, lives at Server/Particles/.../I_Fire_Blue.particlesystem inside the Riprod:Hexcode pack.
The patch
Goes at the item's path with .json swapped for .patch. Use Particles+ to APPEND your reference into the existing condition's array instead of replacing the stock particles. $Requires keeps the reference out until Riprod:Hexcode is actually present.
{
"$Requires": "Riprod:Hexcode",
"ItemAppearanceConditions": {
"SignatureEnergy": [
{
"Particles+": [
{
"SystemId": "I_Fire_Blue",
"TargetNodeName": "Handle",
"TargetEntityPart": "PrimaryItem"
}
]
}
]
}
}
Adjust the condition key (SignatureEnergy here) and the entry shape to match the real asset you are patching. The point is the + suffix: it appends a reference without wiping what is already there.
After
- The
SignatureEnergycondition'sParticlesarray now holds both the stockSword_Signature_Readyentry AND yourI_Fire_Blueentry. - The stock particle survives because
Particles+appends rather than replaces. - The merged item is written after
Riprod:Hexcoderegisters, so by the time the asset resolves, theI_Fire_Bluesystem already exists and theSystemIdstring resolves.
Why the load order works out: Patchly re-runs its merge on every AssetPackRegisterEvent. When Riprod:Hexcode registers, the merge re-runs and the merged item is (re)written with I_Fire_Blue present. $Requires: "Riprod:Hexcode" means the reference is skipped on any earlier pass when Riprod:Hexcode is not yet loaded, so you never write a dangling SystemId.
Notes
- You CANNOT patch the
.particlesystemfile itself (yet). It is not JSON. If the particle system does not exist in any pack, ship its.particlesystemas a NORMAL full asset file in your pack. Patchly only wires the JSON reference to it. - The same rule applies to models (
.blockymodel), textures (.png), and lang (.lang): patch the JSON that REFERENCES the binary asset, never the binary asset. Ship those as normal full files. - Use
Particles+, notParticles, unless you genuinely intend to drop the stock particles. A bareParticlesarray REPLACES the whole array. See the syntax reference for the append rules and Removing Values for deletion. - Use
$Requireswhenever your patch names an id that only exists once another pack is loaded. It guards against writing references the engine cannot resolve yet. Full meta-key reference is in the syntax reference.
