Jump to content

Recommended Posts

Posted

Hi! I am very new to coding and learning as I try to make a small mod to change the world generation behavior for surface ore bits. This is the relevant part of code in VSSurvivalMod.dll:

if (shouldGenSurfaceDeposit)
    {
      int surfaceY = (int)heremapchunk.RainHeightMap[lz * 32 + lx];
      int depth = surfaceY - posy;
      float chance = this.SurfaceBlockChance * Math.Max(0f, 1.11f - (float)depth / 9f);
      ...

It calculates a chance for surface ore bits to generate, which decreases by 11.1% per block and reaches 0% by the 10th block. This means that if the ore deposit generates deeper than 10 blocks, no surface ore bits would be generated.

I tried creating a simple .dll mod using Visual Studio and Harmony patching. At first I tested it with only changing the "9" in the calculation to a very large number, which works in a test world. But when I modified the code so that both variables are modified (1.11 and 9), the game gets stuck on loading. What am I doing wrong in this code?

using Vintagestory.API.Client;
using Vintagestory.API.Server;
using Vintagestory.API.Config;
using Vintagestory.API.Common;
using HarmonyLib;
using System.Collections.Generic;
using System.Reflection.Emit;
using Vintagestory.ServerMods;

namespace SurfaceBits;

[HarmonyPatch]
public class MyModSystem : ModSystem
{
    public static ICoreAPI api;
    public Harmony harmony;
    public override void Start(ICoreAPI api)
    {
        MyModSystem.api = api;
        // The mod is started once for the server and once for the client.
        // Prevent the patches from being applied by both in the same process.
        if (!Harmony.HasAnyPatches(Mod.Info.ModID))
        {
            harmony = new Harmony(Mod.Info.ModID);
            harmony.PatchAll(); // Applies all harmony patches
        }
    }

    [HarmonyPatch(typeof(DiscDepositGenerator), nameof(DiscDepositGenerator.GenDeposit))]
    public static class SurfaceOrePatch
    {
        static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
        {
            var matcher = new CodeMatcher(instructions)
                .MatchStartForward(new CodeMatch(OpCodes.Ldc_R4, 9.0f))
                .ThrowIfInvalid("Could not match 9.0")
                .SetOperandAndAdvance(10000.0f)
                .MatchStartForward(new CodeMatch(OpCodes.Ldc_R4, 1.11f))
                .ThrowIfInvalid("Could not match 1.11")
                .SetOperandAndAdvance(0.0f);
            return matcher.Instructions();
        }
    }

    public override void Dispose()
    {
        harmony?.UnpatchAll(Mod.Info.ModID);
    }
}

Thank you very much!

Posted

Although this is a test example, I do not recommend doing patches this way. It is better to bind to some clear labels, for example if(shouldGenSurfaceDeposit) and this.SurfaceBlockChance. Searching and patching a constant in this way is very fragile

Posted
20 minutes ago, DArkHekRoMaNT said:

Although this is a test example, I do not recommend doing patches this way. It is better to bind to some clear labels, for example if(shouldGenSurfaceDeposit) and this.SurfaceBlockChance. Searching and patching a constant in this way is very fragile

That makes a lot of sense. I don't know how to use the CodeMatcher to replace the entire function though.

Apparently the reason my code didn't work is because I'm searching for the two variables in the wrong order, since the 1.11 appears before 9, the second search can't find anything..

  • 2 weeks later...
Posted

From what I understand, a good technique when patching is to inject your own method call, so you can then work with a regular method instead of just IL. So perhaps, after this line:

float chance = this.SurfaceBlockChance * Math.Max(0f, 1.11f - (float)depth / 9f);

You can inject a line like this to override the value:

chance = M;

After which you are free to implement whatever computation you like. You can even pass this.SurfaceBlockChance as a parameter to your injected method if it's not easily accessible from your mod (haven't checked).

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.