大家好,我是幽白银。时隔1年07个月,我们又见面了其实我一点都不想更新,今天我们来康康新玩具——On
。其实不新了只是我懒得更新
关于On
On是基于Mono的一种技术,可以理解为Hook——钩子,用于修改和控制原函数的流程,甚至阻断。
而tml选择给我们 (modder) 提供 On
,则是考虑到mod开发的自由性的问题。有了On
,我们可以修改原版的公有域的函数。看来私有域还得看我反射
具体的用处是啥呢?比如我想要在添加Buff的时候在左下角提醒一下我挂上了啥Buff
比如我想让所有的伤害都变成真伤(不经过伤害计算),又或者我想在创建角色的页面绘制UI
或者用On干掉原版机制自己重写
本章教学-使用On重写原版的伤害计算
你是不是很久以前就想修改Tr的伤害计算方式了?其实我也是!
在本章我们将使用realDamage = origDamage * const / (defense + const)
公式重写原版的伤害计算。
我们首先在Mod
主类的Load()
函数用On
给原版的伤害计算函数挂上一个钩子
public override void Load() { On.Terraria.Main.CalculateDamage += Main_CalculateDamage; base.Load(); }
这里需要注意的是,On.Terraria.Main.CalculateDamage
语句代表着用On
在Terraria.Main
类的 CalculateDamage
函数挂上名为Main_CalculateDamage
的钩子。一般来说,钩子只需要挂一次,所以我选择在Load
函数挂钩子,也就是在加载Mod
的那一刻给原版的伤害计算函数挂上钩子。
而Main_CalculateDamage
实际上是一个委托,其参数是Main_CalculateDamage(On.Terraria.Main.orig_CalculateDamage orig, int Damage, int Defense)
。我先解释一下这些参数是个啥。第一个参数(orig
)你可以把它当成原版伤害计算的函数,直接orig(Damage, Defense);
就能调用原来的伤害计算函数(注:Damage
和Defense
是传入原版伤害计算函数的参数,只要你想可以随便填);第二个参数(Damage
)是在其他地方使用伤害计算函数时输入的初始伤害;第三个参数(Defense
)是在其他地方使用伤害计算函数时输入的目标防御值。
首先观察我们的公式。 origDamage
是初始伤害值; const
是一个常数,根据这个常数来调整防御机制; defense
则是目标的防御力。假设我们输入的 const
是400,那么根据公式转化为代码,是这样的
double realDamage = Damage * 400 / (Defense + 400);
而如果在委托里返回的话,我们只需要这样写
private double Main_CalculateDamage(On.Terraria.Main.orig_CalculateDamage orig, int Damage, int Defense) { return Damage * 400 / (Defense + 400); }
游戏里的伤害计算机制就被修改了!是不是很简单?我们进游戏里逝逝
经过公式计算,我们造成的伤害是720*400/(400+50)
,加上伤害浮动,这个伤害算是正常范围。
最后,别忘了在Unload
函数里卸载钩子!卸载Mod后恢复原版的样子,是Mod的原则之一。
public override void Unload() { On.Terraria.Main.CalculateDamage -= Main_CalculateDamage; base.Unload(); }
至此,原版伤害机制修改完成。
其实还有个东西叫IL,其能精确修改某个函数的IL代码,其自由度比On更高,在某些地方比On要好用。但是本章我们不讨论这个,感兴趣的pong友可以去官方文档查看。
课后作业
今天就不布置作业了,大家玩得开心。
Pingback: 通过 HookEndpointManager 动态挂钩子 - 裙中世界