Rimworld Mod制作教程6 使用Harmony对C#代码Patch
0.简介如果你看了前几篇文章,应该对XML PatchOperations有印象,它使用xpath的语法对xml文件进行patch操作。而Harmony的作用与之相似,是对C#代码进行patch操作。Harmony是一个运行库,专门为解决mod冲突之类的问题,不仅用于rimworld,还有很多著名的社区都以Harmony为基础创造了很多mod。Harmony的原理是利用反射获取对应类中的方法...
废话
如果你看了前几篇文章,应该对XML PatchOperations有印象,它使用xpath的语法对xml文件进行patch操作。而Harmony的作用与之相似,是对C#代码进行patch操作。
Harmony是一个运行库,专门为解决mod冲突之类的问题,不仅用于rimworld,还有很多著名的社区都以Harmony为基础创造了很多mod。
Harmony的原理是利用反射获取对应类中的方法,然后加上特性标签进行逻辑控制,达到不破坏原有代码进行更新的效果。
核心内容
1.使用Harmony对C#代码Patch
1.1 环境建立
很多人还在使用旧方法,每个人都复制了一份Harmony库到自己的代码里,这样无形增加了储存空间和加载速度。我只讲目前最新的Harmony使用姿势。
按照教程1的步骤建一个C#运行库。然后下载最新的Harmony库文件。可以在创意工坊搜索到,然后引用0Harmony.dll。顺带一提,最新的0Harmony.dll是以framework4.7.2为基础的工程,如果framework版本不够还需要更新一下版本。
1.2 创建管理器实例
using Verse;
using HarmonyLib;
using System.Reflection;
namespace SR.NDQ.Patch
{
[StaticConstructorOnStartup]
public class PatchMain
{
public static Harmony instance;
static PatchMain()
{
instance = new Harmony("SR.NoDecreeQuest");
instance.PatchAll(Assembly.GetExecutingAssembly());//对所有特性标签的方法进行patch
}
}
}
1.3 编写对应Patch方法
[HarmonyPatch]
标签需要填写改写的类和方法名字以及参数类型,至于type参数类型可以不填,只有一种情况不填会报错,就是这个方法有其他重载方法,不填type无法确定是哪个同名方法。
[HarmonyPrefix]
标签表示下面的方法在原函数之前执行,这里的bool返回不是原函数的返回值。
true表示原函数继续执行,false表示原函数被替代,不会继续执行
[HarmonyPatch(typeof(QuestUtility), "SendLetterQuestAvailable", new Type[] { typeof(Quest) })]
class QuestUtility_Patch2
{
[HarmonyPrefix]
static bool Prefix(Quest quest)
{
NDQMain.instance.SRLog("SendLetterQuestAvailable");
if (!NDQMain.instance.modSetting.isOpenMod)
{
return true;
}
return quest != null;
}
}
[HarmonyPatch]标签可以拆分写,像下面注释的那种写法。
如果原函数不是void返回值,那么ref XXX __result表示的就是原来的返回值,而bool就是是否取代原方法。
//[HarmonyPatch(typeof(QuestUtility))]
//[HarmonyPatch("GenerateQuestAndMakeAvailable")]
//[HarmonyPatch(new Type[] {typeof(QuestScriptDef),typeof(Slate)})]
[HarmonyPatch(typeof(QuestUtility), "GenerateQuestAndMakeAvailable", new Type[] { typeof(QuestScriptDef), typeof(Slate) })]
class QuestUtility_Patch1
{
[HarmonyPrefix]
static bool Prefix(ref Quest __result, QuestScriptDef root, Slate vars)
{
NDQMain.instance.SRLog("GenerateQuestAndMakeAvailable");
if (!NDQMain.instance.modSetting.isOpenMod)
{
return true;
}
bool isDecreeQuest = false;
if (root.decreeTags != null)
{
foreach (var s in root.decreeTags)
{
if (s.Equals("All"))
{
isDecreeQuest = true;
}
}
}
if (!isDecreeQuest)
{
Quest quest = QuestGen.Generate(root, vars);
Find.QuestManager.Add(quest);
__result = quest;
}
else
{
__result = null;
NDQMain.instance.SRLog("法令任务已拦截");
}
return false;//false将不执行原方法
}
}
1.4 示例
这份代码的内容是拦截原版法令任务生成。可以参考一下工程结构。源码
https://github.com/pardeike/Harmony/wiki上有更详细的使用方法,本篇只介绍了简单通用的部分。
如果这篇文章对你有帮助,点赞收藏支持一下呗!
更多推荐
所有评论(0)