liyun_1981 发表于 2019-2-2 23:02

Unity引擎类游戏MOD制作通用教程,一个非游戏软件行业的软件系统架构师的经验谈,跟水友们分享经验,2019年春节前的献礼!!!

本帖最后由 liyun_1981 于 2019-2-3 16:08 编辑

前言:


    如题,本人是一个非游戏软件行业的软件开发人员,基于个人对计算机游戏的强烈兴趣,在空闲时间时常会研究下当前各种主流的游戏引擎,以便于使得制作游戏MOD成为可能!在春节前夕,打算整一个Unity引擎类游戏MOD的通用教程,分享给各位水友!:lol


正题:


    本教程计划分为五个部分分别讲述,从第二楼起,每楼阐述一个部分。


第一部分:MOD制作前必备的工具软件;


第二部分:DLL文件的反编译与重编译;


第三部分:IL文件的修改;


第四部分:IL汇编语言相关;


第五部分:对MOD制作的一些展望。


最后,水友们觉得写得不错的都给俺评个分点个赞,谢谢!!!:lol




liyun_1981 发表于 2019-4-12 17:42

午茶心情 发表于 2019-4-12 17:38
大佬请问一下,使用40级上限那个补丁之后,新建角色和角色升级的时候,种族的名字和天赋的名字都不显示了, ...

在“游戏设置”界面把字体调到最小就行,这个是游戏的UI的框框不能自动跟随字体动态调整的问题。

liyun_1981 发表于 2019-4-15 22:35

午茶心情 发表于 2019-4-15 21:40
大佬游戏更新到1.3.2,40级上限那个mod是不是不能用了

是的,游戏每次更新都必须同步更新这个补丁。

liyun_1981 发表于 2019-2-2 23:02

第一部分:MOD制作前必备的工具软件


1、Visual Studio 2017(C++、C#语言类开发IDE);
2、dotPeek(个人认为该软件是最好的.NET框架反编译工具,网址:https://www.jetbrains.com/decompiler/?fromMenu);
3、UtralEdit或者EditPlus(二者选其一即可,个人认为这两个文本编辑软件是最好的)。


对上述工具的作用简要说明下:


    dotPeek主要用来将游戏目录下的XXXX_Data\Managed目录下的游戏业务逻辑类库文件Assembly-CSharp.dll反编译成VS2017的.NET项目;Visual Studio 2017主要用来查看将Assembly-CSharp.dll反编译后得到的源代码,有助于理解游戏的业务逻辑;UtralEdit或者EditPlus主要用来修改将Assembly-CSharp.dll反编译后得到的Assembly-CSharp.il文件。


liyun_1981 发表于 2019-2-2 23:02

本帖最后由 liyun_1981 于 2019-5-31 11:38 编辑

第二部分:DLL文件的反编译与重编译


1、打开dotPeek后,先打开文件Assembly-CSharp.dll再导出VS项目,如下图:

导出成功后即可到导出目录双击*.sln文件打开VS2017查看源代码了;

2、在任意硬盘分区新建3个目录,例如:E:\Decompile,E:\Decompile\DLL,E:\Decompile\DLL-ildasm,将文件Assembly-CSharp.dll复制到E:\Decompile\DLL目录;


3、打开“VS 2017的开发人员命令提示符 ”,输入命令:
cd /d "E:\Decompile\DLL"
ildasm Assembly-CSharp.dll /output:..\DLL-ildasm\Assembly-CSharp.il
此时在E:\Decompile\DLL-ildasm目录会生成Assembly-CSharp.res和Assembly-CSharp.il两个文件,我们只关心文件Assembly-CSharp.il,该文件就是反编译文件Assembly-CSharp.dll后得到的il中间语言文件,后续的MOD制作都是基于该文件的;


4、使用UtralEdit或者EditPlus修改完文件Assembly-CSharp.il后,再输入命令:

cd /d "E:\Decompile\DLL-ildasm"

ilasm /dll /resource:Assembly-CSharp.res Assembly-CSharp.il /output:Assembly-CSharp.dll
此时在E:\Decompile\DLL-ildasm目录会生成文件Assembly-CSharp.dll,该文件就是重编译文件Assembly-CSharp.il后得到的新的类库文件;

5、将步骤4得到的新类库文件Assembly-CSharp.dll复制到游戏目录下的XXXX_Data\Managed目录即完成了MOD制作,此时可以运行游戏查看效果了。







liyun_1981 发表于 2019-2-2 23:02

本帖最后由 liyun_1981 于 2019-2-22 16:39 编辑

第三部分:IL文件的修改


    这部分内容是MOD制作的核心,对观看的水友有一定的要求,需要能读懂C#语言和IL汇编语言;考虑到不懂这两种语言的水友,我尽可能简明的举例说明下怎么修改。


下面我以角色负重值修改(100倍负重)为例具体说明下操作过程:


1、双击*.sln文件打开VS2017,在左侧的解决方案资源管理器窗口定位到C#源文件EncumbranceHelper.cs并双击图标,此时在右侧源代码编辑窗口搜索GetHeavy定位到获得角色负重值上限的方法,记住最后一行return语句表示的代码含义,如下图:



2、使用UtralEdit或者EditPlus打开文件Assembly-CSharp.il,搜索关键字// end of method EncumbranceHelper::GetHeavy定位到GetHeavy方法结尾处,往上回溯查看GetHeavy方法的IL代码,将标签IL_007a到标签IL_007f包含的内容替换为以下5行IL代码:    IL_007a:call       float64 System.Math::Round(float64)
    IL_007b:conv.i4
    IL_007c:ldc.i4.s   100
    IL_007d:mul
    IL_007f:conv.i4

如下图:



3、保存文件Assembly-CSharp.il,并按照第二部分的操作重编译为文件Assembly-CSharp.dll,至此角色负重值修改(100倍负重)已全部完成;


4、使用dotPeek打开重编译后的文件Assembly-CSharp.dll,并双击打开EncumbranceHelper类的源代码文件EncumbranceHelper.cs,搜索GetHeavy定位到方法,可以看到该方法最后的return语句已经变成了return (int) Math.Round(Math.Truncate(100.0 * a / num + 0.5) * num) * 100;,说明方才已经正确的将角色负重上限修改为100倍了,如下图:



下面为方便水友们自己修改,提供我自制的《开拓者:拥王者》40级上限修改补丁的所有修改的相关IL代码片段如下:*开头的行表示需要替换,+开头的行表示需要新增,右边是查询需要被修改的IL代码片段的关键字


角色等级上限及经验值修改
*} // end of method LevelUpController::CanLevelUp
    IL_0034:ldloc.0
    IL_0035:ldc.i4.s   40
    IL_0036:blt      IL_0039
    IL_0037:ldc.i4.0
    IL_0038:ret

    IL_0039:ldloc.0
    IL_003a:ldc.i4.s   20
    IL_003b:bge      IL_004e
    IL_003c:call       class Kingmaker.Game Kingmaker.Game::get_Instance()
    IL_003d:callvirt   instance class Kingmaker.Blueprints.Root.BlueprintRoot Kingmaker.Game::get_BlueprintRoot()
    IL_003e:ldfld      class Kingmaker.Blueprints.Root.ProgressionRoot Kingmaker.Blueprints.Root.BlueprintRoot::Progression
    IL_003f:ldfld      class Kingmaker.Blueprints.Classes.BlueprintStatProgression Kingmaker.Blueprints.Root.ProgressionRoot::XPTable
    IL_0040:ldloc.0
    IL_0041:ldc.i4.1
    IL_0042:add
    IL_0043:callvirt   instance int32 Kingmaker.Blueprints.Classes.BlueprintStatProgression::GetBonus(int32)
    IL_0044:ldc.i4.2
    IL_0045:div
    IL_0046:stloc.1
    IL_0047:ldloc.1
    IL_0048:ldarg.0
    IL_0049:ldfld      class Kingmaker.UnitLogic.UnitProgressionData Kingmaker.UnitLogic.UnitDescriptor::Progression
    IL_004a:callvirt   instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_Experience()
    IL_004b:ble      IL_006e
    IL_004c:ldc.i4.0
    IL_004d:ret

    IL_004e:call       class Kingmaker.Game Kingmaker.Game::get_Instance()
    IL_004f:callvirt   instance class Kingmaker.Blueprints.Root.BlueprintRoot Kingmaker.Game::get_BlueprintRoot()
    IL_0050:ldfld      class Kingmaker.Blueprints.Root.ProgressionRoot Kingmaker.Blueprints.Root.BlueprintRoot::Progression
    IL_0051:ldfld      class Kingmaker.Blueprints.Classes.BlueprintStatProgression Kingmaker.Blueprints.Root.ProgressionRoot::XPTable
    IL_0052:ldc.i4.s   20
    IL_0053:callvirt   instance int32 Kingmaker.Blueprints.Classes.BlueprintStatProgression::GetBonus(int32)
    IL_0054:ldc.i4.2
    IL_0055:div
    IL_0056:ldloc.0
    IL_0057:ldc.i4.s   19
    IL_0058:sub
    IL_0059:ldc.i4   90000
    IL_005a:mul
    IL_005b:add
    IL_005c:stloc.1
    IL_005d:ldloc.1
    IL_005e:ldarg.0
    IL_005f:ldfld      class Kingmaker.UnitLogic.UnitProgressionData Kingmaker.UnitLogic.UnitDescriptor::Progression
    IL_0060:callvirt   instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_Experience()
    IL_0061:ble      IL_006e
    IL_006c:ldc.i4.0

*} // end of method UnitProgressionData::AddClassLevel
    IL_0061:ldloc.0
    IL_0062:ldloc.0
    IL_0063:ldlen
    IL_0064:conv.i4
    IL_0065:ldc.i4.1
    IL_0066:sub
    IL_0067:ldarg.0
    IL_0068:call       instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_CharacterLevel()
    IL_0069:call       int32 System.Math::Min(int32,
                                                          int32)
    IL_006a:ldelem.i4
    IL_006b:ldc.i4.2
    IL_006c:div
    IL_006d:stloc.1
    IL_006e:ldarg.0
    IL_006f:call       instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_CharacterLevel()
    IL_0070:ldc.i4.s   20
    IL_0071:ble      IL_007b
    IL_0072:ldloc.1
    IL_0073:ldarg.0
    IL_0074:call       instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_CharacterLevel()
    IL_0075:ldc.i4.s   20
    IL_0076:sub
    IL_0077:ldc.i4   90000
    IL_0078:mul
    IL_0079:add
    IL_007a:stloc.1
    IL_007b:ldarg.0
    IL_007c:ldarg.0
    IL_007d:call       instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_Experience()
    IL_007e:ldloc.1
    IL_007f:call       int32 System.Math::Max(int32,
                                                          int32)
    IL_0081:call       instance void Kingmaker.UnitLogic.UnitProgressionData::set_Experience(int32)

*} // end of method CharSLevel::FillData
    IL_00bd:br         IL_0100
    IL_00c2:ldarg.0
    IL_00c3:ldfld      class ['Assembly-CSharp-firstpass']TMPro.TextMeshProUGUI Kingmaker.UI.ServiceWindow.CharacterScreen.CharSLevel::Level
    IL_00c8:ldloc.0
    IL_00c9:ldfld      class Kingmaker.Localization.LocalizedString Kingmaker.Blueprints.Root.Strings.UITextCharSheet::LEVEL
    IL_00ce:call       string Kingmaker.Localization.LocalizedString::op_Implicit(class Kingmaker.Localization.LocalizedString)
    IL_00d3:ldstr      " "
    IL_00d8:ldarg.1
    IL_00d9:ldfld      class Kingmaker.UnitLogic.UnitProgressionData Kingmaker.UnitLogic.UnitDescriptor::Progression
    IL_00de:callvirt   instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_CharacterLevel()
    IL_00e3:box      System.Int32
    IL_00e8:call       string System.String::Concat(object,
                                                                object,
                                                                object)
    IL_00ed:callvirt   instance void ['Assembly-CSharp-firstpass']TMPro.TMP_Text::set_text(string)
    IL_00f2:ldarg.0
    IL_00f3:ldfld      class UnityEngine.UI.Image Kingmaker.UI.ServiceWindow.CharacterScreen.CharSLevel::NegativeLevel
    IL_00f8:callvirt   instance class UnityEngine.GameObject UnityEngine.Component::get_gameObject()
    IL_00fd:ldc.i4.0
    IL_00fe:callvirt   instance void UnityEngine.GameObject::SetActive(bool)
    IL_0100:ldarg.1
    IL_0101:ldfld      class Kingmaker.UnitLogic.UnitProgressionData Kingmaker.UnitLogic.UnitDescriptor::Progression
    IL_0102:callvirt   instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_CharacterLevel()
    IL_0103:ldc.i4.s20
    IL_0104:bge      IL_0141
    IL_0105:call       class Kingmaker.Game Kingmaker.Game::get_Instance()
    IL_0106:callvirt   instance class Kingmaker.Blueprints.Root.BlueprintRoot Kingmaker.Game::get_BlueprintRoot()
    IL_0107:ldfld      class Kingmaker.Blueprints.Root.ProgressionRoot Kingmaker.Blueprints.Root.BlueprintRoot::Progression
    IL_0108:ldfld      class Kingmaker.Blueprints.Classes.BlueprintStatProgression Kingmaker.Blueprints.Root.ProgressionRoot::XPTable
    IL_0109:ldfld      int32[] Kingmaker.Blueprints.Classes.BlueprintStatProgression::Bonuses
    IL_010a:ldarg.1
    IL_010b:ldfld      class Kingmaker.UnitLogic.UnitProgressionData Kingmaker.UnitLogic.UnitDescriptor::Progression
    IL_010c:callvirt   instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_CharacterLevel()
    IL_010d:ldc.i4.1
    IL_010e:add
    IL_010f:ldelem.i4
    IL_0110:ldc.i4.2
    IL_0111:div
    IL_011c:stloc.3
    IL_011d:call       class Kingmaker.Game Kingmaker.Game::get_Instance()
    IL_011e:callvirt   instance class Kingmaker.Blueprints.Root.BlueprintRoot Kingmaker.Game::get_BlueprintRoot()
    IL_011f:ldfld      class Kingmaker.Blueprints.Root.ProgressionRoot Kingmaker.Blueprints.Root.BlueprintRoot::Progression
    IL_0120:ldfld      class Kingmaker.Blueprints.Classes.BlueprintStatProgression Kingmaker.Blueprints.Root.ProgressionRoot::XPTable
    IL_0121:ldfld      int32[] Kingmaker.Blueprints.Classes.BlueprintStatProgression::Bonuses
    IL_0122:ldarg.1
    IL_0123:ldfld      class Kingmaker.UnitLogic.UnitProgressionData Kingmaker.UnitLogic.UnitDescriptor::Progression
    IL_0124:callvirt   instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_CharacterLevel()
    IL_0125:ldelem.i4
    IL_0126:ldc.i4.2
    IL_0127:div
    IL_0128:stloc.s    V_4

    IL_0140:br      IL_0174
    IL_0141:call       class Kingmaker.Game Kingmaker.Game::get_Instance()
    IL_0142:callvirt   instance class Kingmaker.Blueprints.Root.BlueprintRoot Kingmaker.Game::get_BlueprintRoot()
    IL_0143:ldfld      class Kingmaker.Blueprints.Root.ProgressionRoot Kingmaker.Blueprints.Root.BlueprintRoot::Progression
    IL_0144:ldfld      class Kingmaker.Blueprints.Classes.BlueprintStatProgression Kingmaker.Blueprints.Root.ProgressionRoot::XPTable
    IL_0145:ldfld      int32[] Kingmaker.Blueprints.Classes.BlueprintStatProgression::Bonuses
    IL_0146:ldc.i4.s20
    IL_0147:ldelem.i4
    IL_0148:ldc.i4.2
    IL_0149:div
    IL_014a:ldarg.1
    IL_014b:ldfld      class Kingmaker.UnitLogic.UnitProgressionData Kingmaker.UnitLogic.UnitDescriptor::Progression
    IL_014c:callvirt   instance int32 Kingmaker.UnitLogic.UnitProgressionData::get_CharacterLevel()
    IL_014d:ldc.i4.s19
    IL_014e:sub
    IL_014f:ldc.i490000
    IL_0150:mul
    IL_0151:add
    IL_0152:stloc.3
    IL_0153:ldloc.3
    IL_0154:ldc.i490000
    IL_0155:sub
    IL_0172:stloc.s    V_4

职业等级上限及升级能力点数修改
*} // end of method BlueprintCharacterClass::MeetsPrerequisites
    IL_001a:ldc.i4.s   40
    IL_001c:blt      IL_0023

    IL_0021:ldc.i4.0
    IL_0022:ret

    IL_0023:ldarg.0
    IL_0024:ldfld      bool Kingmaker.Blueprints.Classes.BlueprintCharacterClass::PrestigeClass
    IL_0029:brfalse    IL_0038

    IL_002e:ldloc.0
    IL_002f:ldc.i4.s   40

*} // end of method ProgressionData::GetLevelEntry
    IL_0000:ldarg.1
    IL_0001:ldc.i4.s   20
    IL_0002:rem
    IL_0003:starg.s   level
    IL_0004:ldarg.1
    IL_0005:brtrue.s   IL_0008
    IL_0006:ldc.i4.s   20
    IL_0007:starg.s   level
    IL_0008:newobj   instance void Kingmaker.UnitLogic.ProgressionData/'<GetLevelEntry>c__AnonStorey0'::.ctor()
    IL_0009:stloc.0
    IL_000a:ldloc.0
    IL_000b:ldarg.1
    IL_000c:stfld      int32 Kingmaker.UnitLogic.ProgressionData/'<GetLevelEntry>c__AnonStorey0'::level
    IL_000d:ldarg.0

角色属性点获得修改(每两级获得1点属性点)
*} // end of method LevelUpState::.ctor
    IL_00c8:ldc.i4.2

角色升级生命值修改(每级获得生命点数为:角色生命骰+2+体质加点)
*// end of method ApplyClassMechanics::ApplyHitPoints
    IL_00d4:ldc.i4.1

角色负重值修改(100倍负重)
*} // end of method EncumbranceHelper::GetHeavy
    IL_007a:call       float64 System.Math::Round(float64)
    IL_007b:conv.i4
    IL_007c:ldc.i4.s   100
    IL_007d:mul
    IL_007f:conv.i4

角色移动速度修改(移动1.5倍速,战斗1.25倍速)
*} // end of method TimeController::Tick
    IL_0063:beq      IL_0068

    IL_0064:call       class Kingmaker.Game Kingmaker.Game::get_Instance()
    IL_0065:callvirt   instance valuetype Kingmaker.GameModes.GameModeType Kingmaker.Game::get_CurrentMode()
    IL_0066:ldc.i4.7
    IL_0067:bne.un   IL_00aa

    IL_0068:call       class Kingmaker.Game Kingmaker.Game::get_Instance()
    IL_0069:callvirt   instance class Kingmaker.Player Kingmaker.Game::get_Player()
    IL_006a:callvirt   instance bool Kingmaker.Player::get_IsInCombat()
    IL_006b:brtrue    IL_0073
    IL_006c:ldarg.0
    IL_006d:ldarg.0
    IL_006e:call       instance float32 Kingmaker.Controllers.TimeController::get_DeltaTime()
    IL_006f:ldc.r4   1.5
    IL_0070:mul
    IL_0071:call       instance void Kingmaker.Controllers.TimeController::set_DeltaTime(float32)
    IL_0072:br    IL_0079
    IL_0073:ldarg.0
    IL_0074:ldarg.0
    IL_0075:call       instance float32 Kingmaker.Controllers.TimeController::get_DeltaTime()
    IL_0076:ldc.r4   1.25
    IL_0077:mul
    IL_0078:call       instance void Kingmaker.Controllers.TimeController::set_DeltaTime(float32)
    IL_0079:ldarg.0
    IL_007a:ldarg.0
    IL_007b:call       instance float32 Kingmaker.Controllers.TimeController::get_DeltaTime()
    IL_007f:call       instance void Kingmaker.Controllers.TimeController::set_GameDeltaTime(float32)

角色大地图移动速度修改(VisualSpeedBase越大移动越快,MechanicsSpeedBase越大游戏时间流逝越慢)
*} // end of method GlobalMapRoot::.ctor
    IL_0000:ldarg.0
    IL_0001:ldc.r4   0.02
    IL_0006:stfld      float32 Kingmaker.Blueprints.Root.GlobalMapRoot::VisualSpeedBase
    IL_000b:ldarg.0
    IL_000c:ldc.r4   12.
    IL_0011:stfld      float32 Kingmaker.Blueprints.Root.GlobalMapRoot::MechanicsSpeedBase

视野缩放范围修改
*} // end of method CameraZoom::TickZoom
    IL_0088:ldc.r4      30
    IL_008f:ldc.r4      5

新增隐藏UI开关快捷键 Ctrl + Alt + H
*} // end of method KeyboardAccess::RegisterBuiltinBindings
    IL_04d1:ldarg.0
    IL_04d2:ldstr      "RapidBugReportWindowOpen"
    IL_04d3:ldc.i4.s   98
    IL_04d4:ldloc.0
    IL_04d5:ldc.i4.1
    IL_04d6:ldc.i4.1
    IL_04d7:ldc.i4.1
    IL_04d8:ldc.i4.0
    IL_04d9:ldc.i4.0
    IL_04da:call       instance void Kingmaker.UI.KeyboardAccess::RegisterBinding(string,
                                                                                    valuetype UnityEngine.KeyCode,
                                                                                    class System.Collections.Generic.IEnumerable`1<valuetype Kingmaker.GameModes.GameModeType>,
                                                                                    bool,
                                                                                    bool,
                                                                                    bool,
                                                                                    bool,
                                                                                    valuetype Kingmaker.UI.KeyboardAccess/ModificationSide)
    IL_04db:ldarg.0
    IL_04dc:ldstr      "HideUI"
    IL_04dd:ldc.i4.s   104
    IL_04de:ldloc.0
    IL_04df:ldc.i4.1
    IL_04e0:ldc.i4.1
    IL_04e1:ldc.i4.0
    IL_04e2:ldc.i4.0
    IL_04e3:ldc.i4.0
    IL_04e4:call       instance void Kingmaker.UI.KeyboardAccess::RegisterBinding(string,
                                                                                    valuetype UnityEngine.KeyCode,
                                                                                    class System.Collections.Generic.IEnumerable`1<valuetype Kingmaker.GameModes.GameModeType>,
                                                                                    bool,
                                                                                    bool,
                                                                                    bool,
                                                                                    bool,
                                                                                    valuetype Kingmaker.UI.KeyboardAccess/ModificationSide)
    IL_04e5:ldarg.0
    IL_04e6:call       void Kingmaker.PubSubSystem.EventBus::Subscribe(object)
    IL_04ea:ret

+.field public class Kingmaker.GameStatistic Statistic
.field public class UnityEngine.GameObject GameObject

+} // end of method Game::.cctor

.method private hidebysig instance void
          '<Initialize>m__13'() cil managed
{
    .custom instance void System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
    // 代码大小       19 (0x13)
    .maxstack8
    IL_0000:ldarg.0
    IL_0001:ldfld      class UnityEngine.GameObject Kingmaker.Game::GameObject
    IL_0002:brtrue   IL_000a
    IL_0003:ldarg.0
    IL_0004:ldarg.0
    IL_0005:ldfld      class Kingmaker.UI.UIAccess Kingmaker.Game::UI
    IL_0006:callvirt   instance class Kingmaker.Assets.UI.MainCanvas Kingmaker.UI.UIAccess::get_MainCanvas()
    IL_0007:callvirt   instance class UnityEngine.CanvasGroup Kingmaker.Assets.UI.MainCanvas::get_CanvasGroup()
    IL_0008:callvirt   instance class UnityEngine.GameObject UnityEngine.Component::get_gameObject()
    IL_0009:stfld      class UnityEngine.GameObject Kingmaker.Game::GameObject
    IL_000a:ldarg.0
    IL_000b:ldfld      class UnityEngine.GameObject Kingmaker.Game::GameObject
    IL_000c:ldarg.0
    IL_000d:ldfld      class UnityEngine.GameObject Kingmaker.Game::GameObject
    IL_000e:callvirt   instance bool UnityEngine.GameObject::get_activeSelf()
    IL_000f:ldc.i4.0
    IL_0010:ceq
    IL_0011:callvirt   instance void UnityEngine.GameObject::SetActive(bool)
    IL_0012:ret
} // end of method Game::'<Initialize>m__13'

*} // end of method Game::Initialize
      IL_0037:ldarg.0
      IL_0038:ldfld      class Kingmaker.UI.KeyboardAccess Kingmaker.Game::Keyboard
      IL_0039:call       void Kingmaker.Utility.Screenshot::Initialize(class Kingmaker.UI.KeyboardAccess)
      IL_003a:ldarg.0
      IL_003b:ldfld      class AuraSupport Kingmaker.Game::AuraSupport
      IL_003c:callvirt   instance void AuraSupport::Initialize()
      IL_003d:ldarg.0
      IL_003e:ldfld      class Kingmaker.UI.KeyboardAccess Kingmaker.Game::Keyboard
      IL_003f:ldstr      "HideUI"
      IL_0040:ldarg.0
      IL_0041:ldftn      instance void Kingmaker.Game::'<Initialize>m__13'()
      IL_0042:newobj   instance void System.Action::.ctor(object,
                                                                        native int)
      IL_0048:callvirt   instance void Kingmaker.UI.KeyboardAccess::Bind(string,
                                                                           class System.Action)

修改施法造成的友军伤害减半
*} // end of method AbilityAcceptBurnOnCast::OnCast
    IL_0019:ldfld      int32 Kingmaker.UnitLogic.Class.Kineticist.AbilityAcceptBurnOnCast::BurnValue
    IL_001a:ldc.i4.2
    IL_001b:div
    IL_001e:ldarg.1

*} // end of method KineticistAbilityBurnCost::GetTotal
    IL_0095:brfalse    IL_009c

    IL_009a:ldc.i4.1
    IL_009b:br         IL_009d

    IL_009c:ldc.i4.0
    IL_009d:mul
    IL_009e:add
    IL_009f:ldc.i4.2
    IL_00a0:div
    IL_00a3:ret


liyun_1981 发表于 2019-2-2 23:02

本帖最后由 liyun_1981 于 2019-2-8 18:08 编辑

第四部分:IL语言相关


IL汇编语言是什么?简单来说,IL是微软.NET平台上衍生出的一门中间语言,.NET平台上的各种高级语言(如C#,VB,F#)的编译器会将各自的代码转化为IL;详细介绍推荐给有C#编程基础的水友看下这两篇文章:https://blog.csdn.net/dodream/article/details/4726421和http://www.cnblogs.com/xiaoxiang ... /08/08/2130768.html。


    本人为了修改IL文件时能方便的查询IL指令,自制了一个IL语言帮助命令,可查询和配置管理IL指令和IL语句的帮助信息;该命令使用说明:
1、解压缩game.7z(有需要的水友请到我这个帖子下载:http://bbs.3dmgame.com/thread-5745545-1-1.html)到任意目录,例如:D:\tools;
2、运行命令提示符,输入cd /d d:\tools\game\bin,再输入 il -h 会显示详细的命令行参数帮助信息:
参数说明:

il [-i|-s]

-i      只显示IL指令的帮助信息。

-s      只显示IL语句的帮助信息。

name    IL指令或语句的名称。

单条命令:

il

il -i

il -s

il -i name

il -s name

示例:

il
显示所有IL指令和IL语句的帮助信息。

il -i
显示所有IL指令的帮助信息。

il -s
显示所有IL语句的帮助信息。

il -i ldc.i4
显示IL指令名称为ldc.i4的帮助信息。

il -s instance
显示IL语句名称为instance的帮助信息。

3、第1次运行il命令后,程序会在game\bin目录生成配置文件il.xml,该文件格式如下:
<IL>
    <Instructions>
      <Helper>
            <name>add</name>
            <desc>将两个值相加并将结果推送到计算堆栈上。</desc>
            <example>
            // V_0 += 1
            IL_0001:ldloc.0
            IL_0002:ldc.i4.1
            IL_0003:add
            IL_0004:stloc.0
            </example>
      </Helper>

    </Instructions>
    <Statements>
      <Helper>
            <name>class</name>
            <desc></desc>
            <example></example>
      </Helper>

    </Statements>
</IL>

其中,Instructions表示IL指令的帮助信息,Statements表示IL语句的帮助信息;每个Helper节点表示一个帮助信息对象,Helper节点包含3个子节点;name表示IL指令或IL语句名称,desc表示IL指令或IL语句的具体描述,example表示IL指令或IL语句的示例代码;直接输入il可以显示所有IL指令和IL语句的帮助信息;该配置文件水友们可以修改或新增内容以丰富IL指令和IL语句的帮助信息。



liyun_1981 发表于 2019-2-2 23:02

本帖最后由 liyun_1981 于 2019-2-22 16:43 编辑

第五部分:对MOD制作的一些展望


    根据本人对Unity引擎和IL语言的研究心得,目前觉得将来实现以下两个工具提高MOD制作效率是有可能的:


1、使用C#整一个Unity引擎类游戏通用的控制台插件dll,可以在任何Unity引擎类游戏中打开控制台,这样就可以正确的调用所有针对具体的游戏实现了的控制台命令;


2、使用Java扩展下file命令,使其能根据指定的IL替换代码片段自动替换文件Assembly-CSharp.il。



最后,提前祝水友们猪年发大财!:lol


2019年2月22日已实现了第二个展望:使用Java扩展下file命令,使其能根据指定的IL替换代码片段自动替换文件Assembly-CSharp.il,感兴趣的水友请见我今天发的帖子:自制IL汇编语言源文件内容自动替换工具,继年前的帖子“Unity引擎类游戏MOD制作通用教程。。。”后新年第一弹!!!

q372856439 发表于 2019-2-8 22:37

强力支持~希望好MOD越来越多。

乱逛 发表于 2019-2-10 21:51

楼主对游戏是真爱

chenghu000 发表于 2019-2-13 12:19

楼主牛逼

lwqhoho 发表于 2019-2-15 17:05

感谢分享!~

bin4633 发表于 2019-3-9 02:12

66666666666666666666666666666

bin4633 发表于 2019-3-9 02:21

66666666666666666666666666666

bin4633 发表于 2019-3-10 01:41

liyun_1981 发表于 2019-2-2 23:02
第二部分:DLL文件的反编译与重编译




第二部分第4条第二个ildasm少了个d

bin4633 发表于 2019-3-13 01:51

liyun_1981 发表于 2019-2-2 23:02
第三部分:IL文件的修改




大神,我很好奇你是怎么得知需要修改的目标代码的查询关键字的?望指点

韩步不乖 发表于 2019-4-9 19:26

bin4633 发表于 2019-3-13 01:51
大神,我很好奇你是怎么得知需要修改的目标代码的查询关键字的?望指点
...

这种时候一般都是根据方法名类名去猜测的,在看看代码的具体逻辑,得出结论并不难,难的是汇编看着太费劲了

韩步不乖 发表于 2019-4-11 23:40

大佬打包成dll时候错了ilasm /dll /resource:Assembly-CSharp.res Assembly-CSharp.il /output:Assembly-CSharp.dll 这一步报错了,fail to write output file, error code=0x80070005:Q

韩步不乖 发表于 2019-4-12 00:44

楼主你不仅把移动速度改成1.5了吧,整个游戏时间被你加快了1.5倍

午茶心情 发表于 2019-4-12 17:38

大佬请问一下,使用40级上限那个补丁之后,新建角色和角色升级的时候,种族的名字和天赋的名字都不显示了,

午茶心情 发表于 2019-4-12 17:48

liyun_1981 发表于 2019-4-12 17:42
在“游戏设置”界面把字体调到最小就行,这个是游戏的UI的框框不能自动跟随字体动态调整的问题。
...

谢大佬,去试一试

午茶心情 发表于 2019-4-15 21:40

大佬游戏更新到1.3.2,40级上限那个mod是不是不能用了

午茶心情 发表于 2019-4-16 17:38

那就等大佬更新mod了{:3_113:}

云海风暴 发表于 2019-5-12 17:01

楼主牛逼!!!!!!!!!!!!

luciferfiend 发表于 2019-6-15 00:24

厉害!!!!!!!!!!!!

aawwss1234 发表于 2019-6-22 07:34

谢大佬。。不过升两级拿属性的代码被改了。。还是那里是要加一行啊

fiyingwing 发表于 2019-6-24 18:03

大佬牛逼啊,必须支持

5256457 发表于 2019-6-28 20:55

liyun_1981 发表于 2019-2-2 23:02
第三部分:IL文件的修改




LZ求问魔战士的法术战斗(SpellCombat)怎么改成神术/双手/双持武器可用?

榨汁姬 发表于 2019-7-18 14:31

借地问一下,40级mod里秘术师10级之后不提升神术施法者等级了啊

hawk813 发表于 2019-8-18 23:29

真干货,感谢楼主分享
页: [1] 2
查看完整版本: Unity引擎类游戏MOD制作通用教程,一个非游戏软件行业的软件系统架构师的经验谈,跟水友们分享经验,2019年春节前的献礼!!!