使用Reflexil修改Unity3D游戏逻辑

曾经有个游戏叫做《新剑侠传奇》,曾经停留在一个尴尬的版本1.0.7。作为一名抠脚大汉,自然要坐在在电脑前为广大玩家发福利!

故事背景

游戏发售之后出现了一些Bug,官方在更新至1.0.7版本后决定回炉。然而这一版本依然有一些玩家比较需要的Feature没有实现。在长达两周多的回炉阶段,我的补丁横空出现啦!

技术背景

MSIL可以较为轻易地反编译回C#/VB代码,如果不做代码混淆的话,可读性非常高。目前很多国产单机游戏都选择Unity 3D做为引擎:scream: ,并使用C#作为主要逻辑的实现语言。这为我们修改游戏逻辑创造了相当好的条件。

实现功能

  • 打击感增强
    通过在命中目标后停顿画面0.1秒实现。
  • 新增操作模式
    《新》是一个具备跟随视角的3D游戏,鼠标旋转视角,鼠标点击怪物为普攻,感觉略坑爹。新增操作模式采用类似龙之谷的方式:默认隐藏鼠标,鼠标移动旋转视角,鼠标点击为普攻,ctrl键呼出鼠标。
  • 摄像机位置记忆
    每次剧情之后摄像机都会回到初始位置,不会记忆上次用户调整的摄像机与人物的距离。
  • 暂停游戏
    进入战斗或者开始剧情之后,终于可以随意去上厕所了……
  • 跳过开始动画
    打开游戏时无需强制观看片头。
  • 画面改善:对比度增强、Bloom、HDR
    使用Unity内置Shader实现。

工具准备

  1. .NET Reflector
    我们用 .NET Reflector 来对 .NET Managed DLL 进行反编译工作。对于没有进行混淆或加密操作的程序,可以得到可读性很高的代码。
    0<em>1448775094110</em>1.png
  2. Reflexil
    Reflexil 可以在已经编译好的Managed DLL中插入MSIL代码。它提供了.NET Relfector的插件,安装好后即可直接插入IL代码。
  3. XamarinStudio (MonoStudio)
    其实这个有无皆可。但是如果不想所有代码全部使用IL手写的话,还是搞一个比较好。

代码修改

拿打击感增强作为一个例子,我们来看一下如何修改。Unity 3D游戏的主体逻辑都在/xxxx_Data/Managed/Assembly-CSharp.dll中。这个游戏的逻辑由几百个类/枚举构成,如果游戏大量使用了Unity插件(比如可视化编程:see<em>no</em>evil: ),可能还会更多。

增强打击感的方法是在玩家命中敌人后画面停顿0.1秒。所以我们需要在命中时记录当前时间、停顿画面,然后在0.1秒后取消停顿。

经过浏览代码,发现负责进行攻击的逻辑集中在Fighter类中。我们需要修改的有两个函数:一个是CalcHurt,发生在玩家已经命中怪物之 后,用于计算伤害;另一个是Update,每次迭代更新逻辑时都会调用这个函数。我们还需要一个Field用于记录停顿时间,可以直接在类上右击通过 Reflexil添加。

打开CalcHurt方法,在Reflexil中添加IL代码。IL代码非常简单易懂,而且我们并不需要掌握所有的IL指令。简介可以参考Introduction to IL Assembly Language,或者在Common Language Infrastructure (CLI) | ECMA-335中有所有指令的列表。

在修改完IL代码后,.NET Reflector会重新加载并反编译代码。如果指令有错误,.NET Reflector会无法反汇编成功。

停顿功能使用了Unity提供的Time.settimeScale函数,获取时间使用Time.getrealtimeSinceStartup。这些函数可以参考Unity 3D Manual

举例来说,

Time.set_timeScale(0.001f); InjectedField = Time.get_realtimeSinceStartup + 0.1;  

的IL代码如下:

ldc.r4 0.0001 call Time.set_timeScale call Time.get_realtimeSinceStartup ldc.rc 0.1 add stsfld InjectedField #InjectedFiled为静态成员  

就是这么简单啦。

使用XamarinStudio

如果不想所有代码全部手写,可以使用XamarinStudio新写一个Class,将所有新的逻辑放在这里。然后再修改原来的Assembly-CSharp.dll时,所有位置都变成函数调用就行了。

在编写新Class时,需要把游戏的Managed目录中的相关DLL作为引用添加进我们的工程里。对于这个游戏来说,我们主要用到了 UnityEngine、Assembly-CSharp、Assembly-CSharp-firstpass、Assembly- UnityScript-firstpass。

写好Class后,可以使用Reflexil将改Class添加进Assemby-CSharp的引用中。
0<em>1448778641887</em>3.png

请原谅时间久远电脑上已经没有XamarinStudio了:joy:

替换原始文件

没什么问题之后,就可以去论坛或者贴吧收获一番经验了~

关于Intel超线程技术

原回答自知乎:奔腾四和SNB之后的超线程技术一样吗?

1.Pentium 4 HT(NetBurst)和Core i7(Nehalem)中的超线程技术一样吗?

Intel的超线程技术在2002年2月发布的志强处理器中首次出现,并在同年12月发布的Pentium 4 HT中同样加入了这一技术[1]。关于此时的Intel的超线程技术的论文比较多,比如(Deborah T. Marr et al, 2002)[2]。论文中提到,architecture state在各个逻辑线程中是独立存在的,而其余几乎所有资源都是共享的。Architecture state主要包括的是各种寄存器,例如通用寄存器、控制寄存器CR以及APIC寄存器等;而共享的包括缓存、执行部件、分支预测、控制逻辑以及总线。

而后来在Nehalem核心(Core i7)中重新回归的超线程技术,我没有找到官方详细的论文。不过找到了一个德克萨斯A&M大学博士生的论文,关于Nahalem核心的[3]。文中同样提到:对于同一个物理核上的逻辑核心,它们之间

  • 独立:寄存器状态、返回栈缓冲(用于预测函数返回指令)、指令TLB(用于加速虚拟地址与物理地址的转换)
  • 分隔(静态划分):各种缓冲
  • 竞争共享:分为SMT-sensitive 和SMT-insensitive。保留栈(用于实现乱序执行)、数据TLB、二级TLB等属于SMT-sensitive,所有执行单元均为SMT-insensitive。

以及共享Cache。

所以结构上看,基本一致。

两篇论文中都有提到CPU的Pipeline(流水线结构)。当Nehalem开启超线程时,将从两个线程中取指令,之后送入后端乱序执行引擎执 行。而[1]中提到得Pentium 4在开启超线程后的做法则更为详细:两套指针分别记录两个线程的PC,解码后存入Execution Trace Cache(其为一级指令缓存的主要部分)。两个线程再按照时钟周期依次访问这个Cache。如果有一个线程stall住了,则另一个随意用。

大致来看,主要步骤基本相同。不过细节不太清楚。

2.什么是超线程?

超线程(即Simultaneous multithreading[4])属于线程级并行方法。在说超线程技术(多线程技术)之前,我们先来看一下超标量技术。

超标量技术是一种指令级并行技术,具备超标量特性的CPU具有同时发射多条指令的能力,这样CPU就可以充分利用各种执行部件。举例来说,如果单发 射一条加法指令,那么在执行过程中只有加法部件(或算数计算部件)被利用起来;如果我有两条指令:add R1, R2; shr R3, 3(加法和右移),如果两条指令同时执行,那么加法部件和移位部件就同时利用起来了。

然而能够同时执行的前提是:两条指令之间不能有相关性。例如第一条指令需要写R1,第二条指令需要读R1,那么这两条指令无法同时执行。由此即诞生出了乱序执行(Out of Order)技术:如果第三条指令与前两条指令没有相关性,则可以先执行第三条指令。

超线程技术则可以更加充分地利用执行部件:同时执行两条线程,进一步降低了指令之间的相关性。同时,如果一个线程需要访存(意味着大量的时钟周期可能被浪费)、或是分支预测失败(意味着需要清空流水线),超线程的优势就更明显了。

然而对于超线程技术的优劣则有激烈的讨论,主要集中在性能的提升的同时芯片面积与功耗等也在增加,这样的trade-off是否合适。

3.关于超线程技术消失又重现

Pentium Pro、Pentium 2、Pentium 3所使用的架构均为P6架构,Pentium 4使用Netburst架构,后续的Core 2使用的是Core架构,从Core i系列开始进入Nehalem/Sandy Bridge架构等[5]。

然而,NetBurst是相对独立的一个架构,让人记忆深刻的就是超长的流水线和相当高的频率。而Core架构是基于P6的变种Pentium M的架构改进而来的。在Intel的一个Slides中也可以得知,NetBurst和P6的Pipeline差异较大,Nehalem的基础需要在二者 中做出选择。而最后做出让多线程回归的决定,也是一种“抉择”[6]。

Reference

  1. Hyper-threading
  2. Marr D, Binns F, Hill D L, et al. Hyper-Threading Technology Architecture and Microarchitecture[J]. Intel Technology Journal, 2002, 6(1):1.
    http://www.cs.sfu.ca/~fedorova/Teaching/CMPT886/Spring2007/papers/hyper-threading.pdf
  3. Thomadakis M E. The Architecture of the Nehalem Processor and Nehalem-EP SMP Platforms[J]. Jfe Technical Report, 2011.
    http://sc.tamu.edu/systems/eos/nehalem.pdf
  4. Simultaneous multithreading
  5. Nehalem (microarchitecture) P6 (microarchitecture) Intel Core (microarchitecture)
  6. http://web.stanford.edu/class/ee380/Abstracts/100217-slides.pdf