本帖最后由 JKstring 于 2019-3-10 20:21 编辑
老年人了,所以字体调大一点,希望各位不要介意,这篇文章简单的讲一下游戏的代码修改以及怎么去查找自己想要功能的代码位置,理论上通用所有unity3D的游戏(因为c#的代码反编译太简单了),帖子内容如果自己学过编程语言最好,,没有的话会百度一般都能理解(不过像我这么啰嗦的,应该稍微机灵点的都能学会...)
本文仅以修改幽淬成功率为例子教学,大部分功能都能用下面的方法去定位修改
本帖不会提供任何修改后的文件,不会提供游戏反编译后的代码,不会提供mod,不提供使用到的工具下载,只教方法,本意在激励更多人喜欢编程,写游戏相关mod,也请有更好办法定位修改的大佬不吝赐教!
好了话不多说我们正式开始
首先需要的工具有两个:
1.dnspy (C#反编译工具)
2.sublime text3 或者 visual studio 2017 (后者更好,但是太大了,如果你对编程感兴趣可以下第二个)
本文以sublime text3示例,vs相同且使用更方便
1.怎么定位关键代码
首先我们打开dnspy,左上角标签栏选择 文件->打开->选中自己游戏根目录下/Amazing Cultivation Simulator_Data/Managed/Assembly-CSharp.dll,先不要点确定,选中后先ctrl+c,ctrl+v复制粘帖一下来备份,然后直接确定,不要把DLL文件拖走到别的路径修改,否则可能无法保存模块,因为引用模块的路径就错了,也不要粘帖后选成备份的那个dll!
现在我们就有一份反编译后的代码了,但是这还没完,因为反编译后,不方便定位,毕竟dnspy只是一个反编译工具,这个时候,我们就要把代码导出来,以方便我们搜索关键代码
现在我们选中左侧列表中的Assembly-CSharp,再点击标签栏 文件->导出到工程->随便一个自己找的到的文件夹,其他选项都默认,直接点导出,导出到什么位置随意
现在我们有了一份导出的反编译源码了,接下来就是如何定位代码了,我们打开sublime,点击左上角标签栏 文件->打开文件夹(是文件夹不是文件)->选中你导出的游戏反编译工程文件夹选择打开
在下面这张图里左侧,右键Assembly-CSharp文件夹,选择在文件夹中查找,就会弹出搜索栏,在find一行中,搜索关键词就可以定位到关键代码了,至此怎么搜索关键代码的方式就完了,接下来就是实例了
2.怎么分析定位代码
在第一章里面,我们说明了怎么搜索关键代码,但是光找到了怎么应用呢,这回我们就来个示例讲一下,就拿教程最多的怎么修改灵淬成功率来讲吧,我们用第一章里最后一步的搜索栏搜索幽淬(别打成幽粹)
已经很明显了吧,这几处就算不是关键代码,肯定也跟关键代码有关,那我们就去这里看看,先去那个最显眼的幽淬成功率那里,双击
D:\test\Assembly-CSharp\XiaWorld\UILogicMode_IndividualCommand.cs:下面的行号,比如成功率的行号1298,可以直接跳转到那个文件的那一行,我们双击1298,
我们先来分析一下代码,这里代码,哪怕是没有接触过编程语言的人,大概也能从英文里知道一些信息,我这里普及一下代码知识
图例中1的位置,有一个{0},这个代表什么意思呢,这在C#语言中代表占位符,意思就是这个位置我已经占了,内容我还没想好是啥,等想好的时候替换,那去哪里思考呢?,就是图例中2的位置,GameUlt.GetRateString(rate))这一句,就是把rate转成字符串,显示到{0}的位置上,那么rate又是什么意思呢,从百度翻译我们就知道,rate是率的意思,那么成功率,其实就是rate了? 对了一半,因为游戏的显示和实际成功率是不同的,也就是说,显示成功率9成,未必就真的是九成,要根据代码分许,先说这里,我们看看他的成功率是怎么计算的
<
pow是取密计算,比如 pow(2,4),那就是2的四次方,也就是2*2*2*2,结果16
在这里成功率是多少呢,翻译成中文就是,0.8的 物品品阶+幽淬次数 次方
如物品是2阶凡物,还没有进行过幽淬,那么他的成功率就是0.8的 2(品阶)+0(幽淬次数) 次方 = 0.8*0.8 = 0.64, 64% (注:0.8f的意思就是0.8是个有小数的数字,让编译器认的)
好啦,既然如此,我们知道了计算方法了,那么怎么改才能显示十成概率呢,其实简单粗暴....直接把Mathf.Pow(0.8f, (float)(itemThing.Rate + itemThing.YouPower))删掉,把整条语句改成
<
这样的话,幽淬显示的成功几率永远都是1,也就是100%了,是不是简单,不过这里我想进阶一下,游戏中,成功率的显示并不是64%这么简单明了的,而是XX成,我想给他改成原样输出的64%,这么明确的数字,怎么办呢,答案就是搜索GetRateString,当然还有更方便的,鼠标指向GetRateString,然后sublime会自动帮我们找出这个代码在什么位置,直接点击就好了,这样我们就定位到了这里
非常简短的一个方法,翻译成中文,这条代码的意思就是,如果几率小于0.1(10%),那么就显示微乎其微,不然就显示,最低的十位数+"成"字
{0}的作用上面已经给大家介绍过了,那么后面这句是什么意思呢,有兴趣的自己百度一下这个语句的意思吧,我只说功能,他的功能是把0.64这种数字,乘以10 (6.4),再抹去小数,变成6,再通过Num2Chinese =Num to Chinese = 数字转中文,变成了六,也就是说,哪怕是69%的成功率,显示上,也会显示成六成,那么我们只要把代码换成
<
就解决问题了,这样改后成功率会直接显示类似64%这样的字符,这是拓展知识
好了,拓展知识就到这里了,前文我们说了,我们只是改了显示的成功率,为什么得出这个结论呢,因为我们去游戏里看了?不,因为我们没有看到任何幽淬过程的代码,幽淬成功了,他至少要给幽淬的次数+1吧?可是并没有,那我们就继续找,我们需要返回之前的搜索列表去看其他的吗,不着急!既然这里显示了成功率,那么应该也跟幽淬相关,我们翻上去看看他的代码,明显看到了一个游戏机制的判断
被红线框起来的地方,是判断了品阶是否超过12了,如果我们想要改超过12阶的,可能需要改这里了,虽然这里只是显示,不过,这个地方所有的代码,都包含在case g_emIndividualCommandType.SoulCrystalYouPowerUp:这句下面的,那么这个命令,很可能就是幽淬的关键点了,而名字,我们自己猜测翻译一下,You,幽淬的开头拼音,power up,能力增强,那么关键点可能就是他了,我们用前文提到的文件夹搜索SoulCrystalYouPowerUp
ps:实际上也可以用鼠标指上去,让sublime自动定位到位置,不过上文我们已经用过这个方法了,这次用全文搜索
我们看到一个跟其行长相不同的代码,public bool SoulCrystalYouPowerUp(
在C#语言中,public或者private开头的,就是定义,而名字后面加了"("不管括号后面什么内容,他就是实现某个功能的模块,看来我们直接就知道了这个方法位置,从名字上看这个方法是没跑了,
这个函数关键点很多,从关键点得到这就是真实幽淬代码没跑了,我们来逐条分析一下代码,看看他都做了什么
图例1 明显,判断品阶超过12就直接return (ps return的意思就是下面的不执行了,直接退出这里)
图例2 真正的幽淬成功率就是这里,也就是真实成功率是用a来表示的,根据分析实际上成功率是0.9+失败加成(add是加成,前面加b可能是bad的简写不确定,不过推论上是减益的,也就是负小数),然后是品阶+幽淬次数 次方,差别不大
图例3 irate>0f,那么a直接是irate,这个irate代表了只要制作组想要这个成功率临时改成100,随时可以用irate强制顶掉前面的计算结果,那么就好办了,我们只要在if(irate > 0f)的上一行新增一行,写上irate=1f; ,不管之前irate是多少,判断之前他是1就行了,这样幽淬就100%成功了
图例4 这里就是判断是否成功的语句,那么我们在图例3没改的话,改这里也能达到效果,比如改if (World.RandomRate(a))为if (World.RandomRate(1f)),这就是100%,直接用1f顶掉了a,再或者更简单,if (World.RandomRate(a))直接改成if (true),有简单编程基础的有一万种改法都行,只要让他走if(World.RandomRate(a))下面的语句就可以,哪怕是把判断删掉
图例5 这里有两条,这里的作用是什么呢,count代表总数,那么这条语句翻译成中文就是,如果物品总数是1的话,直接幽淬这个物品,如果不是的(多余1个物品),就用this.Split(1, true);分出来一个物品幽淬(split英文就是分割的意思) 那么简单了,如果我想批量幽淬的话,把判断改成true就好了,if (base.Count == 1)改为if (base.Count >= 1),只要多余或者等于1个,都会进行整体幽淬 如果有兴趣也可以尝试改成一次幽淬3,5张符怎么写,算是拓展知识啦
图例6 这里是幽淬提升量了,rate可以翻译成率,但是这里是代表成功率吗?那为什么要+?,you power,根据脑补就是幽淬的力量(次数),跟youpower同时增长一样的数是什么呢?那就是品阶,如果我们想把品阶和幽淬次数直接到最大该怎么做呢?如下面
<
我们计算出现在的品阶距离12阶差多少,然后得出差值放在tempv里面,然后让幽淬次数和品阶都加上差值,直接就到12了,很简单~
ps:幽淬后不直接增加属性,就是因为他的品阶就真的只是记一下品阶,没有更新道具属性,所以如果有人要开发一个mod,加了幽淬之后直接提升道具属性,可以从这里把道具属性直接更新,就做到了幽淬后直接动态提高物品属性的效果
ps2:我们当然可以直接把youpower和rate都直接改成12,但是幽淬12次才到圣物那最开始不就是垃圾(0)吗....为了看起来方便,才计算差值去补的
图例7 这里就算不会代码,只是玩过游戏,看到这个ding的拼音...也能联想到幽淬成功后那一声脆响吧!
到此分析代码也就结束了,下一篇会教怎么修改代码,之前我们分析了一大堆,实际上并没有改动代码,而且你从sublime这里改动的代码也是无效的,因为你没有生成dll文件~诶嘿嘿
3.如何修改代码并且实际应用到游戏里
在之前的教程里我们只是学会了寻找和分析代码,那么我们怎么才能真实的改动代码呢,实际上,dnspy提供直接修改反编译后的代码,然后重新编译,具体怎么做呢!继续看吧!
首先之前我们已经打开了dnspy,并且从dnspy里打开了游戏的dll.而在如何分析代码那里找出了幽淬的真实位置,我们从dnspy打开标签栏 编辑->搜索程序集(快捷键ctrl+shift+k),在弹出来的搜索栏里搜索SoulCrystalYouPowerUp,双击结果第一个打开(ps:部分修改可能你搜索后结果并不是第一个,可以通过大小写匹配,全字匹配,以及看后面的文件名跟你sublime里面打开的名字是不是一样的来确认)
鼠标左键,把光标聚在上面方法里面,右键,选择编辑方法或者编辑类,这俩有什么区别呢,编辑方法是限定在你选中的方法里的,本文中就是SoulCrystalYouPowerUp,而编辑类是吧当前打开的这个文档全文都编译,虽然很方便多处改动,但是不建议这么做!除非你有编程的基础!
选择编辑方法后会提示反编译中,然后会变成跟之前差不多的窗口,在这里,就可以把我们之前分析代码篇中要改动的代码改动啦
改动完毕后点击右下角的编译就能看到修改后的代码了,注意如果修改代码后发现代码变化很大,不用着急,这是因为dnspy有优化代码的功能,他会把你的冗余代码给优化掉,比如我们之前说的,成功率100%,既然直接改成了if (World.RandomRate(1f))了,那么变量a实际上根本没有啥用了,留着还占用内存占用执行速度,于是dnspy就直接给你删掉了,同时dnspy也会给你检查代码,不用担心自己输错了,如果输错了他不会让你进行更改的~(更何况我们还备份了最原始没有修改的游戏dll)
到这里就可以进游戏了吗?不不不等一下,还没有进行保存,我们点击左上角标签栏 文件->保存模块(没快捷键,别以为按了ctrl+s就行了) 进行保存模块,所有选项默认不改动,直接点确定,修改后的dll就出路了,可以直接去游戏实验效果了!
ps:刚才的改动适用于已经开了的存档直接看效果,无需重新开档,并且大部分只影响游戏数值和显示的修改都不需要重新开档
ps2:只要不点保存模块,其他的操作可以再打开游戏的过程边玩边找,保存模块要退出游戏
看完本文,最关键的是要学会怎么查找关键的代码,你可能有个想要改的思路,但是不会去改哪里,导致你改动实际会优化游戏体验的想法没法实现,本文的目标就是让你改你觉得不合想法的地方,变成自己的修仙模拟器(如果你有好的改动想法我也希望你能共享出来,藏私可不好哟~)
在第四章我会讲一下其他的我改的地方改动思路,但是关键的知识我已经放在上面了,其他的常用改动都是类似上文所说,比如快速画符,画符的品质,网上都有教程,用上文的方法也很方便定位修改,就不多说了,下面都是一些我的一些怪癖改动,不算太影响平衡,但是大多数人不会去改,网上应该也没修改教程,比如我这种只收女弟子的,收上来的年龄有大有小,于是我就改成了年龄固定14岁,再比如我第一次玩这个游戏直接开档真仙,因为第一次玩还真不知道突破成功率,心里没底,于是改成真仙也显示成功率,显示风水提示,再比如我不喜欢一个弟子内门后第二个弟子就成二代了,所以把代数一直固定成一代(其实可以改成每收徒一次提升一代,但是懒的改....),至于根据修为确定符咒的品阶其实也就是把网上的教程稍微改动一下没啥好说的,再比如大凶房有几率死人,改成不死,就可以安全的出产幽珀不会弟子莫名死掉啦
然后就是第四章啦~(还是隐藏一下吧)
好了内容就这么多了,主要是学会修改的思路与怎么定位要改的地方,学会这两个任何功能都能改成自己的想法啦,我不常写教程贴,排版可能很乱,可能部分思路跟打出来的字不同,不过大体意思知道了就好啦
溜了溜了溜了.....
==========================2019/3/10====================
今天查了一下放置物品的代码,对流程有了一点了解,想改成置物台批量放置的,放置物品和查找物体的代码游戏本身就有,只要加一层循环调用就好了,不过那段代码似乎用了动态编译?导致没法直接保存模块,如果直接新加一个按钮调用自定义方法,或者用UnityModManager写一个mod的话实现起来应该不难,不过我并不会unitymodmanager的语法和使用方法,直接反编译的状态下新加按钮流程以我的水平太浪费时间了(我顺代码的时候看到一个新东西,会不自觉的再去顺看到的新东西,浪费大量时间...)
其实吃药传功,给剑阵扔废品都在一个地方,感兴趣的大佬可以考虑做个mod进行批量操作吧....
放置物品的代码是UILogicMode_IndividualCommand中的711行
<
ItemShelf就是放置物品的命令,ItemShelfFabao就是往剑阵扔废品的命令,可以看到他俩实际上都是调用的一个方法
this.BindThing.Bag.AddBegItem(<Apply2Thing>c__AnonStorey.t as ItemThing, 1, "PutCarry");
this.BindTing是要放东西的那个置物台或者剑阵对象,Bag是背包,AddBegItem就是往里面扔东西了,他的参数1是要放置的物品,参数2是放几个?第三个就是命令字符串原样扔就行了
寻找附近的置物台可以用 World.Instance.map.Things.FindBuildingsNearly(int r, int okey, Func<BuildingThing, bool> con = null, string thingname = null)//参数1距离,参数2原点?应该直接用建筑对象中的key属性就行了,参数3过滤条件,参数四也是过滤条件
这段代码在小人救火的时候有用过,应该照着那段代码抄就好了....
查找物品用World.Instance.map.Things.FindItem(null, 9999, "Item_SoulCrystalLing", 0, false, null, 0, 9999, null, false);//参数1原点对象?应该是为了获取原点位置,反正可以是null,参数2搜索范围,参数3物品代码,参数4后都是可选参数不填就行
UILogicMode_Select.Instance.CurSelectThing 应该可以获取目前选中的物品,不过需要判断是不是物品,他也可能是npc之类的...
再次溜了溜了溜了.......
|