tome4吧 关注:8,490贴子:80,075

【MOD入门】职业MOD的入门讲解

只看楼主收藏回复

【前言】
我不懂lua,我也第一次做MOD,所以有些玩意儿的具体原理也不怎么清楚
首先我会大概的介绍一下结构,之后介绍一些常用的东西
边想边说,开始施工,就酱


IP属地:湖北1楼2019-10-23 14:23回复
    addon都是不压缩的压缩文件,后缀改成“.teaa”就直接可以拿来用了
    打开压缩文件,里面的内容基本就是下图所示

    【这里就要重点说明一下,有些固有格式是必须严格遵守的】
    一旦格式错误,载入都可能失败,你根本不知道错在哪儿的
    当然要提前说说这个报错机制,正常载入了也会在运行时触发错误内容而报错
    但是,能够报错准确的内容没有想象中多,很多报错也不知道为什么,甚至程序死亡
    所以必须重点提醒:一定要注重格式正确!
    (可以说我大部分时间都在跟格式出错勾心斗角)
    【init】
    在介绍这个文件之前,提前说说文件名这个东西
    你的MOD总归是要有个名字的对吧,那么init里面有个short_name参数,记录的就是文件名
    MOD上传的时候,也是要求固定的格式:“tome-文件名”的文件夹,放在addon里面
    例如:(此处summonerplus就是我的文件名)

    不需要压缩,这个文件夹就会被游戏默认载入addon中,测试的时候会很方便
    (顺便一提我并不知道,最后上传才知道的,全程被坑。。)
    此外,文件名还会用在少数几个文件中,之后再说
    下面是我的init的内容:

    所以基本上,就是short_name这一项必须严格遵守,最好不要有特殊符号
    (我估计空格、下划线、横杠就差不多了,我用过+号,官网上传出问题了)


    IP属地:湖北2楼2019-10-23 14:51
    收起回复

      四个文件夹,分别有不同的固定作用
      date:代码层面,就是你主要工作的地方
      overload:里面的资源会覆盖原始游戏,其中的新内容自然就是添加进原始游戏,我就只是添加了几个图片,以及几个设置文件,我还不清楚覆盖原始游戏会有啥讲究,大概同路径+同名就覆盖?
      superload:也是覆盖,我不清楚和前者的具体区别,但似乎总被用于高级一点的地方,通常改高级文件比较容易发生MOD冲突,新加内容可能还行,重写内容可能就比较严重,我没用过,看过一点点别的MOD,只知道这么多
      【hooks文件夹里面的load.lua】
      这里就要重点说一下它了
      说白了就是个载入管理,它负责了你的文件载入,不载入没法用
      我琢磨着,应该是因为文件格式本身没有那么固定,所以有些人的文件名太过于自由
      所以就必须用这个文件手动载入
      例如我的:

      很简洁,头顶的一系列local就是载入某些功能,懂点编程的就知道是作用域的问题
      下面的诸如Birther:loadDefinition(略)就是使用这些功能载入文件
      乍看之下,好像有点繁琐,不过对于不懂编程的人也能够理解的信息是:
      程序知道了你的这个文件是被哪个功能载入的,自然就知道了这个文件是干嘛用的了
      从这个角度来说,你的文件名毫无意义,但是我还是建议你们最好有强迫症
      乱起名字,写的时候一路爽,查找内容火葬场
      【简单介绍下这几个功能结构】
      lua的格式似乎有好多种,至少TOME4里面是这么用的
      冒号":"代表了调用函数
      那么冒号左边是大类,是容器,是功能的集合体
      而冒号的右边就是这个容器里面的众多功能之一
      可以看到此处的右边亲一色是“loadDefinition”它们隶属于不同的容器,作用性质上相同,实质肯定不同,不会编程的只要记住这是固定格式,而冒号左边的才是关键
      ActorTalents:负责管理技能,从local可以看到它的具体路径,对应的就是一个lua文件,这个lua文件里面一定可以搜索到loadDefinition,如果你想要研究某些功能的结构,这种逆推理的理解是很基本的
      Birther:负责管理职业、种族的选择界面,里面指定了啥职业拥有哪些技能树,等等
      ActorTemporaryEffects:负责管理临时效果,就是BUFF、DEBUFF啦,我载入了3个这类文件,实际上,这三个文件的内容全部写在一个文件里面也没有任何问题,这纯粹就是手动分类而已。。文件名可以乱取,真正决定这些状态是精神还是物理还是魔法,是文件里面的代码决定的
      我就用了这么点功能,所以只用了这么几个载入代码,实际上还可以载入很多其它的功能,取决于你的MOD涉及到更多的功能,比如说,你想要新增“伤害类型”,那么你就要调用并载入伤害类型的文件
      游戏中很多内容可以改,这里不是详细介绍,大体感觉如此,就说说另一层面的功能:

      这同样是写在load里面的内容,是我在别的addon里面看到的,我自己没用过
      从代码内容来看,我猜测是直接将这部分代码,加入到某些容器里面的函数末尾
      代码的具体生效流程我不清楚,也没有试过,这里只是提及确实有这种功能
      那么再补充说下为啥要这么干,其实很简单,有些功能你只能这么实现
      追根究底是作者自己安排不到位,整个游戏的架构问题,有些功能只能改底层代码
      别想太多,了解就好,这种问题,适合懂的人开贴详细说明了,不是一两句的问题
      所以回过头来看我用到的功能,你小改一下,真用不到多少功能:

      对于不懂编程的:
      至于local后面的class啊,Birther啊,都是随便起名,用来代替等号右边,此处推荐同名,别乱起名
      格式直接抄过去用,只改一改关键的地方,比如说文件名
      你们看看summonerplus,它居然接在data-的后面,根本不像是个目录
      你也别想太多,这个游戏引擎就是这么写的,data-后面就是要接你的MOD文件名
      也就是init.lua里面的short_name,也就是addon文件夹的tome-文件名
      它们都是同一个文件名,这是固定格式
      虽然你会发现,addon文件夹里面的名字其实可以乱取,游戏同样载入没问题,不过如果你要上传addon就必须按照格式来


      IP属地:湖北3楼2019-10-23 15:46
      收起回复
        这是我的data文件进入后,没几个文件夹

        这些文件的名字是自由的,hooks的load.lua里面的载入路径的填写就有它们的名字
        必须一一对应,所以不要乱起名字,里面放着啥最好清楚明白
        尤其对于抄代码的新手,最好和原始游戏的文件名一样,抄起来少犯点迷糊
        birth里面放着职业&种族文件夹,里面再分别放着各种职业&种族的lua文件
        timed_effects里面放着BUFF、DEBUFF的lua文件,之前所说,不同lua只是人为分个类,具体BUFF性质是代码决定的
        talents放着技能文件夹,一般是个大系,比如战士类的,法师类的,时空类的这样。而这每个文件夹里面放着的每一个lua文件都是一个技能树,一般呢,是这么安排的,实际情况,也是每个技能的代码决定的,你就是把盾战的盾击的4个技能分别写在4个文件里面,也成,但是请不要这么**


        IP属地:湖北5楼2019-10-23 16:27
        回复


          IP属地:湖北8楼2019-10-23 16:31
          回复
            看看这个gifts.lua最后面的内容吧:

            从这些内容看,就是这一个lua作为总技能lua,帮助把其它的技能lua全部都载入了
            那么Hooks的load.lua要载入技能lua时,就只需要载入这一个总lua了
            如果你有多个总lua,就在load.lua里面载入其它总lua
            格式略有不同,路径的格式和load里面是一样的,外面倒是只需要个load()了,按照格式来就对了
            【那么从头到尾整理一下这个载入链】
            hooks里面的load.lua分别载入了
            1.管理职业选择的lua
            2.临时状态的lua
            3.技能的总lua
            而技能的总lua载入了其它的技能树lua
            至此,我的data文件夹里面的内容都被载入了,那么

            这两个文件夹呢,自然就是不需要载入,只要文件位置与原版游戏是同名路径,自动就会载入
            而其中路径与原版不同的文件呢?那就只能等着被调用了。
            比方说我在乱七八糟的地方存了一张图,而一个BUFF要我提供图片路径,路径是由你写的,写准确就行了
            不如说,里面很多文件都只是放在那里,等着被调用
            我反而觉得奇怪的是,居然有不需要调用就生效的文件
            例如:
            技能的图标,它是直接调用与技能的short_name同名的png图片
            这就导致,如果你有两个技能想用同一个图,你得搞两种名字不同,但其实一模一样的图
            别问,问就是游戏架构的问题


            IP属地:湖北9楼2019-10-23 16:32
            收起回复
              【载入链的介绍到此为止】
              实际上,MOD内容越多,设计的功能越复杂,载入的lua文件就会越多
              只要这个概念清楚就可以了
              一般,这种地方载入出错,大概连选择界面都很难进入
              当然,报错机制本身不完善,代码的错漏同样会在进入选择画面的时候就报错
              但一般来说,连进都进不了的,多半先查看init.lua以及load.lua
              MOD文件名的统一,lua文件的载入没有遗漏写错,事情就算开了个头了


              IP属地:湖北10楼2019-10-23 16:41
              回复
                我来这里讲解一下superload,superload的作用是对已有的文件进行修改,在后面追加新的内容。
                这个游戏的框架里面很多的东西,都是以模块module的方式的形式进行实现的。
                这些module就是你通过require"xxxxxx"读进来的东西
                我们拿恶魔DLC里面Hardened Core这个增加护甲值的技能为例。
                在游戏中,计算护甲值的函数是mod.class.interface.Combat:combatArmor()
                因此,在对应的位置,恶魔DLC里面就有一个文件superload/mod/class/interface/Combat.lua
                在这里面有几个步骤
                首先使用local _M = loadPrevious(...) 其目的是加载原来的这个文件中的模块,将其加载为_M这个变量。
                然后,用local combatArmor = _M.combatArmor 这一句,备份原来的combatArmor函数
                接下来,定义一个新的_M:combatArmor()函数,里面的内容是:
                首先local v = combatArmor(self)用原来的函数计算护甲。
                然后,判断是否有这个技能,如果有的话,则给护甲增加一个乘数。
                if self:isTalentActive(self.T_HARDENED_CORE) then
                local t = self:getTalentFromId(self.T_HARDENED_CORE)
                v = t.armor(self, t, v)
                end
                return v
                在全部修改完之后,需要使用return _M返回新的模块,这样才可以完成对原模块中的函数进行修改。千万不能忘记这一句代码不然会出错。
                这样比起直接用overload的话,有两个好处。
                首先,如果只需要修改一个函数的话,不会影响同一个文件的其他函数,可以减少兼容性问题。
                其次,可以多个模组对一个函数进行修改。例如如果有另外一个addon也修改了那个函数的话,那么就可以 新的addon->恶魔DLC->原游戏的函数。这里面不仅可以覆盖,也可以通过调用原函数的方式,所以也是兼容的。
                hook则是另一种情形。
                hook是一个在一个游戏的特定阶段(比如:伤害结算前,使用法杖掌控的时候,等等,有很多种hook),会触发的一个函数。
                在源代码中,经常会用triggerHook()函数触发一类hook。这个触发不一定发生在函数的结束的时候,也有可能触发在函数的开始,或者结算的中间,都是有可能的。
                这个时候会逐一对于各个addon,调用它们的hook函数。addon里面的hook函数可以在这个机会做一些修改。
                hook的兼容性是最好的,但是第一,游戏里面hook的数量毕竟不能覆盖到你所有想修改的函数。第二,限制性会比较大。


                IP属地:广东11楼2019-10-23 16:44
                回复
                  不太清楚楼主用不用qq,在不在那个tome4的qq大群…不过那个大群基本上平常没啥人聊tome
                  …我个人觉得这个东西用即时聊天工具讨论的话比较方便,这样有问题的话也可以得到更及时的回答
                  汉化组群的话倒是经常有人,如果有兴趣可以加一下,或者开一个专门的mod开发交流群?


                  IP属地:广东12楼2019-10-23 16:50
                  收起回复
                    @√血色蒼穹√
                    @清蒸猫锅
                    因为担心直接发群号在贴吧的话会有打广告的人进来,我私聊你们发一下汉化组群的群号吧,记得打开接收所有人的私信。


                    IP属地:广东14楼2019-10-23 19:30
                    收起回复


                      IP属地:湖北16楼2019-10-23 19:34
                      收起回复









                        IP属地:湖北18楼2019-10-23 19:40
                        收起回复


                          IP属地:湖北22楼2019-10-23 20:18
                          收起回复
                            这是一个职业文件夹,和原版路径一样,原版这里塞满了野性系的职业
                            不过我就拿自己写的举例,只塞了几个召唤的树,文件名似乎是随便的,不过最好还是区分一下
                            拿原版的习惯来说,就是所有的野性职业技能的lua载入,全都塞到了gifts.lua这一个文件里面了

                            那么遵守这个习惯未尝不可,虽然职业多了就显得文件很多,但是有些公共的东西还是这样方便
                            gifts作为一个总职业lua,里面塞了一些公共的功能,而其它lua就只是单纯的写技能
                            话虽如此,总职业lua里面塞的东西也不复杂,基本就是以下形式

                            1.是用来载入技能lua文件的,但实际上是通过技能的名字来进行分类,给这个类型设置一些属性
                            包括是否允许怪物随机学习,是什么力量的,type就是载入那个技能字符串名字
                            name是加点技能树显示的名字,描述就是查看技能树的描述吧
                            2.是多个{ },用来给技能设置参数,就是玩的时候,技能的等级限制
                            一般都是统一的几个,应对0级开始还是10级开始,抄就完事了,顶多改改{ }前面的名字
                            3.是函数,不细说,可有可无的东西,根据需要来
                            4.就是总技能树必须干的事情,载入其它的技能文件,系统会自动的读取所有的技能文件
                            从这些技能文件的技能代码中获取技能的字符串名字,做一个调用&宏观的管理


                            IP属地:湖北23楼2019-10-25 13:20
                            回复
                              如果你查看专门写技能树的lua文件
                              里面清一色的
                              newTalent{
                              吧啦吧啦
                              }
                              这一个大括号里面就是一个小技能,至于这个小技能是不是技能树的技能,是由你决定的
                              比如召唤大树,大树有个冰风暴,那么你肯定要额外写个冰风暴技能,给大树
                              而区分技能是否属于技能,就是由一个参数决定的:
                              type = {"wild-gift/other", 1},
                              type = {"wild-gift/summon-advanced-p", 1},
                              之类的,名字随便你们写,反正被"给包围了",那么里面就是比较随意的字符串
                              不要用奇怪的特殊符号就好,怕万一认不出来,取名字老实点
                              一般习惯上,弄个斜杠"/"前面人为分工为职业技能大类型,右边就是具体的名字
                              这个字符串,就会被调用给newTalentType{ }里面的type
                              多个技能树,功用一个type,一般是写4个,如你们游戏所见,一个技能树有4个技能
                              但是其实估计写多少个都可以,type同名的,都会被放进同一个技能树
                              而other这个类型名字,习惯上被用于不需要登陆技能树的小技能
                              这种小技能不必载入技能树,也不必进行任何载入措施,它们自然而然的就会被系统识别
                              所以这个newTalentType就是专门用来写技能树的代码
                              同样是总技能lua里面的那个{ },在技能里面有个对应的参数
                              require = gifts_req1, --这个东西可要可不要,如果你不写这个参数,技能学习就没有限制
                              从名字上看,和总技能里面的一模一样,所以无脑抄就对了
                              这个功能,自然还可以个性化一些,你不仅仅可以限制属性、限制等级,可以限制得非常花哨
                              只要你在定义gifts_req1的代码里会写函数,就完全自由
                              至于,除了等级&属性之外,还有哪些参数可以用来限制,我不清楚
                              【总结】
                              总技能lua里面的常用功能,就是:
                              1.编写技能树
                              2.编写技能的学习限制
                              3.载入技能lua
                              4.公共函数(这个之后再说,对于不懂编程的人来说,几句话不够,懂编程已经懂了)


                              IP属地:湖北24楼2019-10-25 13:39
                              收起回复