Modding:Asset Patching in Code

From Vintage Story Wiki
Revision as of 12:26, 25 October 2024 by Craluminum (talk | contribs) (added example for adding block entity behavior to blocks)

Patching through code is considered more reliable and flexible than JSON_Patching if written correctly. It is more suitable if you want to patch hundreds or thousands of objects at once. Note that most of these examples work only when world is not fully loaded yet.

Attributes

Collectible attributes (not to confuse with itemstack attributes) can be modified using examples below:

Primitive

In this example we add new boolean attribute:

using Newtonsoft.Json.Linq;
using Vintagestory.API.Common;
using Vintagestory.API.Datastructures;

public class WikiExamples : ModSystem
{
    public override void AssetsFinalize(ICoreAPI api)
    {
        foreach (CollectibleObject obj in api.World.Collectibles)
        {
            // Make sure collectible or its code is not null
            if (obj == null || obj.Code == null)
            {
                continue;
            }

            // Make sure attributes are not null
            obj.Attributes ??= new JsonObject(new JObject());
            
            // Make collectible storable on shelf
            obj.Attributes.Token["shelvable"] = JToken.FromObject(true);
        }
    }
}

Complex

In this example we retrieve integer list, modify it, then put it back:

using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using Vintagestory.API.Common;

public class WikiExamples : ModSystem
{
    public override void AssetsFinalize(ICoreAPI api)
    {
        foreach (CollectibleObject obj in api.World.Collectibles)
        {
            // Make sure collectible or its code is not null
            if (obj == null || obj.Code == null)
            {
                continue;
            }

            // Make sure attribute exists
            if (obj.Attributes != null && obj.Attributes.KeyExists("somelist"))
            {
                // Retrieve list
                List<int> list = obj.Attributes["somelist"].AsObject<List<int>>();
                
                // Add new value
                list.Add(1);

                // Put it back
                obj.Attributes.Token["somelist"] = JToken.FromObject(list);
            }
        }
    }
}

Behaviors

Behaviors of collectibles and entities can be modified too. Note that blocks can have both CollectibleBehavior's and BlockBehavior's, while items can only have CollectibleBehavior's.

Adding behavior to collectible

Example of adding behaviors to items and blocks:

using Vintagestory.API.Common;
using Vintagestory.API.Util;
using Vintagestory.GameContent;

public class WikiExamples : ModSystem
{
    public override void AssetsFinalize(ICoreAPI api)
    {
        foreach (Item item in api.World.Items)
        {
            // Make sure item or its code is not null
            if (item == null || item.Code == null)
            {
                continue;
            }

            // Create collectible behavior
            CollectibleBehaviorGroundStorable behavior = new CollectibleBehaviorGroundStorable(item);
            
            // Add behavior to collectible
            item.CollectibleBehaviors = item.CollectibleBehaviors.Append(behavior);
        }

        foreach (Block block in api.World.Blocks)
        {
            // Make sure block or its code is not null
            if (block == null || block.Code == null)
            {
                continue;
            }

            // Create block block behavior
            BlockBehaviorCanIgnite blockBehavior = new BlockBehaviorCanIgnite(block);

            // Add block behavior to block
            block.CollectibleBehaviors = block.CollectibleBehaviors.Append(blockBehavior);
            block.BlockBehaviors = block.BlockBehaviors.Append(blockBehavior);

        }
    }
}

Adding behavior with properties to collectible

Example of adding behavior with properties to collectible:

using Newtonsoft.Json.Linq;
using Vintagestory.API.Common;
using Vintagestory.API.Datastructures;
using Vintagestory.API.Util;
using Vintagestory.GameContent;

public class WikiExamples : ModSystem
{
    public override void AssetsFinalize(ICoreAPI api)
    {
        foreach (CollectibleObject obj in api.World.Collectibles)
        {
            // Make sure collectible or its code is not null
            if (obj == null || obj.Code == null)
            {
                continue;
            }

            // Create collectible behavior
            CollectibleBehaviorGroundStorable behavior = new CollectibleBehaviorGroundStorable(obj);

            // Create empty properties
            JsonObject properties = new JsonObject(new JObject());

            // Fill properties
            properties.Token["layout"] = JToken.FromObject("Quadrants");

            // Initialize behavior with new properties
            behavior.Initialize(properties);

            // Add behavior to collectible
            obj.CollectibleBehaviors = obj.CollectibleBehaviors.Append(behavior);
        }
    }
}

Adding block entity behavior with properties to block

Block entity behaviors can be added to block entities using blocks. Block entity is automatically added to block if it doesn't have any. Example of adding block entity behavior with properties to blocks:

using Newtonsoft.Json.Linq;
using Vintagestory.API.Common;
using Vintagestory.API.Datastructures;
using Vintagestory.API.Util;

public class WikiExamples : ModSystem
{
    public override void AssetsFinalize(ICoreAPI api)
    {
        foreach (Block block in api.World.Blocks)
        {
            // Make sure collectible or its code is not null
            if (block == null || block.Code == null)
            {
                continue;
            }

            // Create block entity behavior
            BlockEntityBehaviorType behavior = new BlockEntityBehaviorType()
            {
                Name = "RainCollector"
            };

            // Create empty properties
            behavior.properties = new JsonObject(new JObject());

            // Fill properties
            behavior.properties.Token["litersPerTick"] = JToken.FromObject(0.1f);

            // Add block entity behavior to block
            block.BlockEntityBehaviors = block.BlockEntityBehaviors.Append(behavior);
        }
    }
}