帝国霸业银河生存吧 关注:3,359贴子:28,299
  • 14回复贴,共1

【半水】关于度娘不让我直接放链接我只好开贴水字数那档子事

只看楼主收藏回复

之前在某个帖子里说尝试复刻部分服务器的虚拟机库功能并共享,上周末其实就已经基本完工,可是换了各种姿势发链接度娘都表示无法满意,所以顺便开一贴水一下帝霸MOD API的那档子破事,分享一下开发思路,最后再放链接


IP属地:山东1楼2023-02-23 16:41回复
    虽然蒸汽的创意工房里没有MOD分享,但是帝霸确实是有文档相对完善的MOD接口的(虽然有一些错误的部分),可以在一定程度上借助于API(应用程序编程接口)对游戏世界做出各种各样的影响,而服务器端的虚拟机库就在此列。
    目前开发商提供了两种风格的API,API1使用请求消息和一个固定的回调函数来实现开发者与游戏世界的交互,而API2则是依赖于一部分Unity引擎的开发包,之前社区反应API2制作的MOD基本无法用于影响游戏世界,只能做一些弹窗、日志和聊天之类的操作,故大多数服务器MOD都是借助于API1制作的,本贴要分享的虚拟机库也是几乎完全基于API1开发。


    IP属地:山东2楼2023-02-23 16:49
    回复
      2025-12-31 06:06:05
      广告
      不感兴趣
      开通SVIP免广告
      首先,需要确定虚拟机库的功能和执行逻辑,我们需要在保证这个功能不被滥用的前提下,让玩家可以从世界中导出自己的载具,并且将载具重新导入到游戏世界中。
      这里面的执行逻辑是
      1.首先确保玩家使用功能时不会滥用并且导致大量消耗服务器算力。
      这里要确保玩家保存的母舰必须是属于自己的,且不能用于和其他玩家的母舰撞模型等滥用场景,所以在玩家要求保存或者放出母舰时,需要检查目标周围是否存在其他实体并检查玩家是否距离目标足够近(防止超远程收放滥用),这里我们通过向位于API2的事件对象ChatMessageSentEventHandler注册一个回调函数(这个函数在官方的示例文件中已经完成)即可响应用户的命令并获取用户所在的区域和ID等数据,将之保存到全局变量以在后续的命令链中方便地调用,由于API1的命令处理是异步的,建议在这里使用互斥锁保证全局变量是线程安全的。
      2.定位玩家的位置,这里通过API1向游戏发送Request_Player_Info并在回调函数中等待Event_Player_Info即可,注意使用序列号seqNr区分事件是否是你所提出申请的返回,简单地说,Event_Player_Info消息中的序列号必须和发送Request_Player_Info所使用的序列号一致,data对象中才是你所请求的数据。


      IP属地:山东3楼2023-02-23 17:10
      回复
        3-a. 这里先描述收纳母舰的情况,放出母舰的情况请查看后面的3-b,在处理Event_Player_Info的最后,继续向游戏请求实体列表,这里有两种方法可以实现,第一种是发送Request_GlobalStructure_List,这个命令将使服务器进程反回Event_GlobalStructure_List事件并附加一个两层结构的包含服务器中全部实体信息的map<string,list>对象,最外层的map中,Key值为区域名,Value值为区域内全部实体的列表,通过步骤1中确定的用户所在区域名,即可找到该区域中的全部实体信息,再逐个确认哪个实体是目标母舰以及是否有距离目标母舰过近的实体即可。
        也可以通过发送Request_Playfield_Entity_List并附加区域名称来直接获取到包含该区域全部实体信息的list对象,当然这种方法你需要处理的是Event_Playfield_Entity_List消息。


        IP属地:山东4楼2023-02-23 17:20
        收起回复
          专业!


          IP属地:北京来自Android客户端5楼2023-02-23 17:23
          回复
            4-a. 完成检查后,我们就可以导出母舰了,这里我们需要知道帝霸的服务端是如何保存一艘母舰的,母舰的全部信息被保存在 /服务端根目录/Saves/Games/游戏存档名称/母舰ID/中,游戏存档名称即服务端运行时配置文件中的GameName选项,默认情况下为Dedigame。
            该文件夹下有两个或者三个文件,
            0.area 文件保存了母舰当前几乎全部状态,方块生命值,货舱内容物等等,甚至母舰周围一定范围内的物品可能也在此文件中(因为未对该文件展开逆向且官方并未提供说明,故只有猜测),也是一般情况下三个文件中最大的文件。
            backup.epb 文件,大概不用说大家也会意识到这就是蓝图文件的格式,这个文件对应了维修模板,如果玩家未保存维修模板,这个文件就不会生成,顺便,该文件对于正确地将保存的母舰重新部署是必要的,如果未能检测到该文件,建议拒绝掉导出母舰地请求并要求玩家保存维修模板。
            ents.dat 文件往往是最小的,这里面保存了母舰的燃料、护盾、氧气等状态信息。
            虽然看起来直接备份并删除0.area就可以实现导出母舰的效果,但是这有可能出现一些不可预料的BUG甚至产生滥用,举例来说,如果要被导出的母舰距离某个建筑过近,删掉该文件可能直接导致另一个建筑一起消失!
            因此这里推荐使用API1的请求Request_Entity_Export来导出对象并通过复制0.area来保留货舱内容(如果你不想保留货舱内容,可以直接无视掉这个文件)。向服务器传递Request_Entity_Export请求需要附带一个正确设置的EntityExportInfo参数包,该参数包的四个参数分别对应了导出实体所在的区域名称,导出实体的对象ID,导出数据的文件路径和是否强制卸载对象,这里只需要将强制卸载对象设置为true,服务器就会在收到请求后直接导出并移除对应的母舰,不需要手动删除文件。但是该文件仅会导出ents.dat的信息内容,为了能将母舰复原,我们还需要手动备份backup.epb和0.area。


            IP属地:山东6楼2023-02-23 17:50
            回复
              3-b. 重新部署母舰的情况要简单一些,首先根据2中获取的玩家信息,计算母舰重新部署的位置,当然你也可以让玩家手动输入坐标,但是考虑到便捷性和避免滥用,我个人更建议直接在玩家的Y方向上一定距离(也就是头顶)的某个点作为重新部署的坐标,反正这游戏又不会被掉下来的母舰砸死
              确定坐标后,你需要向游戏重新申请一个可用的ID来作为母舰的ID,是的,出于避免未知BUG的考虑,这里一般不推荐使用原本的ID直接部署。这里用到的请求是Request_NewEntityId,新的id会以Id类的格式作为消息Event_NewEntityId附加返回值交给回调函数。


              IP属地:山东7楼2023-02-23 18:01
              回复
                4-b. 获取到坐标和新的可用ID之后,你就可以开始配置部署实体的请求参数包了,这个参数包的名字是EntitySpawnInfo,在当前场景的应用下,我推荐如下配置这个参数包:
                forceEntityId 配置为3-b中申请的新的可用ID
                exportedEntityDat 配置为4-a中请求导出的dat文件
                factionId 配置为玩家ID
                entityTypeName 配置为null,用不到的,防止影响
                factionGroup 配置为1,以私人母舰的形式进行部署
                name 配置为null,程序将从dat文件中读取原本的名称进行部署
                prefabName prefabDir 配置为backup.epb文件的文件名和所在目录,注意这里的文件名不包括后缀的.epb
                rot pos 分别配置为PVector(0,0,0)和3-b中计算得到的坐标,这样母舰就会在指定位置平平整整地出现了。
                playfield 配置为2中获取的玩家所在的区域名称
                type 配置为0,这里很重要,0代表未定义类型,程序将从dat文件中获取到正确的类型进行部署,这里是考虑到玩家可能也会想要把飞机和坦克塞进虚拟机库,如果你准备只允许玩家塞入母舰,这里可以配置为3,并在3-a中额外检查类型防止玩家将导出的SV和HV强制转换为CV。(2基地 3母舰 4飞机 5坦克)
                完成这一步之后,如果你不想恢复玩家所导出的飞船的货舱,直接向游戏发出Request_Entity_Spawn请求并附加刚刚配置的参数包即可。


                IP属地:山东8楼2023-02-23 18:18
                回复
                  2025-12-31 06:00:05
                  广告
                  不感兴趣
                  开通SVIP免广告
                  5-b. 如果你想要恢复玩家的库存,就需要将0.area文件覆盖到新的实体目录中,但是在游戏成功执行Request_Entity_Spawn请求后,游戏就会生成一个新的0.area文件并让这个文件维持占用状态导致无法覆盖,所以我们需要在执行Request_Entity_Spawn请求之前,手动创建目录并提前将0.area文件复制进去占住坑,这样一来游戏在执行Request_Entity_Spawn请求时就会发现这个文件从而不生成新的0.area文件,我们的货舱即可得到保留。
                  警告:官方并不建议在地区服务器仍然正常运行的前提下覆盖和移动0.area文件,因此虽然我们在测试中这么做可以保留飞船的货物仓,但是有可能导致未知的不稳定性。


                  IP属地:山东9楼2023-02-23 18:23
                  回复
                    水了这么多了,我再偷偷放个链应该没事了吧,这是做好的版本,在global和system频道输入help就会在私聊频道反回命令列表,群友们提了一点优化意见但是因为我懒还没做,周末再说,记得看readme。


                    IP属地:山东12楼2023-02-23 18:28
                    收起回复