翻译:Notealot
近期,《骑马与砍*2:霸主》在版本更新至e1.8.1版本的同时允许玩家自己开设骑砍2联机服务器、创建自定义游戏模式、游戏场景构造等,中文站已将教程翻译成了中文版本并上传至了官方在线文档,请前往骑砍中文站或者官方公众号获取,欢迎modders来这里获取资料。
也可以直接前往中文站论坛进行查看
【中文站汉化组】骑马与砍*2MOD制作教程中文版——官方开发文档及非官方API文档汉化(请前往骑砍中文站或者官方公众号获取)
以下为教程具体内容。
◆前言
本文主要内容为骑友们所能用到的与多人游戏服务器开设有关的知识,内容分为三部分,分别是搭建一个自定义服务器、创建自定义游戏模式以及多人游戏场景的构造。
◆搭建一个自定义服务器
本部分为搭建自定义服务器的教程,从安装到部署整个流程包括在内。同时,文档内还有关于服务器参数的讲解,以及一些注意事项和可能碰到的问题的说明。在文档最后,还有常见问题环节,用来回答开发者们可能会问的一些普遍的问题。
安装
在你的 Steam 库中选到“工具”,你会在列表里看到“Mount & Blade II: Dedicated Server”,下载并安装它。
搭建
服务器不支持匿名搭建,你需要先进入游戏生成一个令牌(Token)。
生成一个令牌(Token)
启动游戏 Mount & Blade II: Bannerlord 多人模式并登录到联机大厅:
通过按键 ALT 波浪号键(~) 打开游戏控制台:
在输入框中输入 customserver.gettoken 并按下 Enter 键:
你的令牌生成了并保存到了 Documents\Mount & Blade II Bannerlord\Tokens 目录下:
如果你计划在安装了《骑砍2》的同一台计算机上搭建独立服务器,那么针对令牌的操作到这一步就可以了。但如果你计划在另外一台不同的计算机上搭建服务器,请复制你的令牌文件到目标电脑上的 Documents\Mount & Blade II Bannerlord\Tokens 目录下。还有一种方法是通过程序启动参数来输入令牌,在下面的“启动参数”一节说明。
注意,这个生成的令牌文件是绑定你的《骑砍2》账户的,如果有任何滥用令牌的行为,我们都可以追溯到创建令牌的用户。我们建议你只自己用,并且不要将它分享给其他人。
另外请记住,为了安全起见,你的令牌会在 3 个月后过期,届时你可以重新生成并更换令牌。
服务器管理你可以在你的服务器控制台(在启动服务器时会显示)里输入命令来管理你的服务器。
通过输入 list 然后按下 enter 键,你可以获取到独立服务器的所有可用命令:
例如,想要简单启动一个服务器,你可以在控制台输入以下命令:
通过执行这些命令,你的自定义服务器将出现在服务器列表,并且所有玩家都可以访问。
通过 ServerName 和 GameType 命令,你可以轻松地设置你的服务器名字和游戏模式。
通过 start_game 命令,你可以启动你搭建的服务器。你的服务器将变为所有玩家可见,任何进入服务器的玩家都会在中场休息状态下等待。
通过 start_mission 命令,你的服务器将会切换到行动模式,并且玩家能够正式开始游玩。
你可以使用简写 start_game_and_mission 来替代上述两个命令。
提示 & 技巧配置文件你可以指定一个配置文件在初始化时加载运行,该文件的内容将被逐行执行,而不是通过服务器控制台一条一条的来输入命令。
你可以在 Native 模组目录下找到示例配置文件(Modules\Native\ds_config_*.txt)。请注意,目前为止,你自己的配置文件也必须位于该目录下,才能被服务器读取到。关于如何指定要运行的配置文件,请参考下文中提到的“启动参数”。
启动参数目前,有几个特别有用的启动参数:
/dedicatedcustomserverconfigfile [配置文件名] - 指定一个要加载的配置文件,如上文“配置文件”一节中所提到的那样。
/dedicatedcustomserverauthtoken [认证令牌内容] - 当令牌通过启动参数传入,包含令牌的本地文件就不需要了。
/DisableErrorReporting - 禁用崩溃报告上传(Crash Uploader)弹出和自动错误上报。
/LogOutputPath [输出目录] - 设置服务器日志文件的输出目录,路径应该用双引号括起来。
日志文件默认情况下,Windows 的自定义服务器的日志文件可以在你的 ProgramData 目录(%programdata%\Mount and Blade II Bannerlord\logs)下找到。
自动换图次数通过在 enable_automated_battle_switching 之前使用命令 set_automated_battle_count 你可以设置在服务器关闭前可以游玩的行动数量。
例如,set_automated_battle_count 10 会让服务器运行 10 个行动后关闭,如果你想设置为无限行动数量,将值设为 -1。
辅助模组我们提供可选模组 DedicatedCustomServerHelper 来辅助搭建服务器,其中有几个子模组可以实现不同的功能。为了使服务端模组可以通过外部网络使用,你需要开放 TCP 端口 7210。
请注意,尽管该模组对于服务器搭建来说是可选的,但如果你加载了此模组,那么玩家也必须加载此模组。否则,模组不匹配的玩家将无法加入服务器。
网页管理面板这个模组启动了一个网页面板,通过一个通用的管理页面和终端页面与你的自定义服务器进行交互:
你的网页面板初始化完成后,你可以在你的服务器控制台看到它的 URL 地址。
该网页面板受服务器所配置的 AdminPassword 选项的密码保护。默认情况下,该选项的值为空,所以一定要设置一个安全的密码。
如果你不希望除本地网络或机器以外的地方能访问网页面板,同时也不需要下面的地图下载功能,那么你只需要拦截外部对 TCP 端口 7210 的访问即可。
游戏内地图下载我们还提供了一种允许玩家通过游戏内面板下载服务器的地图文件的方式。作为服务器主机,你必须要满足一些条件才能让这个功能发挥作用:
为了让玩家能够打开下载面板,他们需要在加载了 DedicatedCustomServerHelper 模组后启动游戏。现在,他们可以鼠标右击自定义服务器列表项,然后会打开一个上下文菜单,其中会有打开该服务器下载面板的选项。地图下载成功后,无需重新启动游戏,他们应该就能直接加入你的服务器。
请注意,这个功能是用于支持这一简单的使用场景。这不是一个模组管理器功能,也无法支持获取给定的模组分布在其他资产(如 ModuleData、Prefabs 等)中的地图。只有 SceneObj 目录下的内容会在服务端和客户端之间传输。
常见问题在服务器搭建时需要 Steam 保持运行吗?不,你只需要用 Steam 保持你的服务器文件为最新就行,你可以随意拷贝服务器文件到其它计算机上搭建。但我们强烈推荐你带一个 Steam 以保证文件是最新的。区别于《战团》,目前而言,任何旧版本的服务器文件都不兼容我们的系统。
你们计划支持其他的游戏平台吗?是的。
如果我不想用任何游戏平台来获取服务器文件,会有其他选择吗?目前,Steam 是下载服务器文件的唯一渠道。我们计划将服务器文件添加到其他游戏平台,同时也在考虑未来使用 Docker 分发服务器文件这样一个方案。
你们会提供 Linux 支持吗?是的。事实上,我们的后端使用的就是 Linux 服务器,但要给公众使用的话,还需要对系统进行进一步开发。
我的服务器所有人都可以访问吗?是的,你的服务器所有人都可以访问,除非说你设置了密码来保护。
我可以搭建多少服务器?你可以同时运行的服务器数量是有限的。目前,你最多可以同时运行 5 个服务器。
我的服务器在列表里显示了,但玩家无法加入。什么问题?默认情况下,独立服务器使用 UDP 端口 7210。你必须在互联网上有一个大家可以访问的(公共)IP 地址,以及上述端口也必须可以访问到。
硬件要求是什么?这需要看是何种游戏模式以及玩家数量。这是我们搭建游戏服务器时,默认的配置:
但举例来说,你总是可以在一台 2 核机器上搭建一个较少玩家的攻城服务器。
你也可以尝试使用单核机器来搭建一台非常小型的服务器,但你可能在游戏中碰到一些使用率突增卡顿的情况。
带宽要求是什么?这取决于玩家数量。默认情况下,我们会给每个玩家发送 60 个数据包,并且每个数据包少于 1.5 kb(千字节)。对于大多数配置,任何专用服务器供应商都应该能够提供足够的网络连接。
游戏支持任何自定义模组吗?是的!
自定义时的反作弊功能是怎样的?对于自定义游戏反作弊是关闭的。请注意,任何修改过游戏的玩家都无法加入官方服务器。
会有游戏内管理面板来帮助更快更方便地管理服务器吗?我们打算做一个。
◆创建自定义游戏模式
本教程会指导你如何从头开始建立一个包含自定义游戏模式的模组,教程内提供的示例模组将会提供一个试用版本下载链接。
前提条件要制作一个多人游戏模式,你首先需要在你游戏安装目录的 Modules 目录下创建你的模组文件夹。在你的模组目录下,你需要创建一个 bin 文件夹来放置 DLL 文件,还要创建一个 SubModule.xml 文件来存放你的模组定义和额外数据。
对于程序开发,你需要有 .NET Framework 开发工具。配置开发环境的话,下载 Visual Studio 2017 社区版并安装 .NET Framework 4.7.2 支持。完成这些步骤后,新建一个 Class Library 项目。对于客户端而言,添加位于你的 Mount & Blade II: Bannerlord 安装目录的 Win64_Shipping_Client 目录下的所有的 DLL 引用。对于服务端而言,添加位于你的 Mount & Blade II: Dedicated Server 安装目录的 Win64_Shipping_Server 目录下的所有的 DLL 引用。
请保证你项目的输出路径是:
一切准备完毕后,你可以开始对你的游戏模式进行编程。请注意,本文档中创建的游戏模式及其完整的源代码和额外的数据文件,都会以 ZIP 压缩包的形式提供给你。
模组定义(Module Definition)文件再开始定义你的游戏模式行为(behaviors)前,你需要先填写模组定义的 SubModule.xml 文件。在该文件中,你要给你的模组一个名字、一个 ID、一个版本,并定义它的依赖和 DLL 文件。
<Module>
<Name value="MP Bounty"/>
<Id value="BountyMP"/>
<Version value="v1.8.0"/>
<ModuleCategory value="Multiplayer"/>
<DependedModules>
<DependedModule Id="Native" DependentVersion="e1.8.0" Optional="false"/>
</DependedModules>
<SubModules>
<SubModule>
<Name value="BountyMP"/>
<DLLName value="BountyMP.dll"/>
<SubModuleClassType value="BountyMP.BountyMPSubModule"/>
</SubModule>
</SubModules>
</Module>
从这个示例定义文件中,我们可以看到一个模组的基本需求。关于多人游戏模组的 ModuleCategory 节点,其值可以是 Multiplayer 或 Server。如果模组是一个 Multiplayer(多人游戏)模组, 这意味着它在客户端和服务端都会被加载。Server(服务器)模组就只在服务器端被加载,并且可以用于管理和分析需要。
SubModules 节点定义了这个模组创建和使用的 DLL 文件。确保你的 DLL 文件的名称和继承 MBSubModuleBase 类的名称与该文件中的名称一致。
SubModule 类要在代码中定义你的游戏模式,你需要创建一个类并继承自 MBSubModuleBase 类。在这个类中,重写 OnSubModuleLoad 方法并添加此行:
Module.CurrentModule.AddMultiplayerGameMode(new MissionMultiplayerBountyMPMode("BountyMP"))
传递给构造函数的字符串是你游戏模式的名字。在该示例中,我们创建了一个名为 BountyMP 的游戏模式。要加载有文本信息的 XML 文件,重写 InitializeGameStarter 方法,调用其 base 方法然后添加此行:
game.GameTextManager.LoadGameTexts(ModuleHelper.GetModuleFullPath("BountyMP") "ModuleData/multiplayer_strings.xml")
同样,模组名和 XML 文件名都取决于你模组中的文件的名字。
在该 XML 文件中,你可以定义如下内容,这样你的游戏模式的名字就会显示在服务器列表中。
<?xml version="1.0" encoding="utf-8"?>
<base xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" type="string">
<strings>
<string id="str_multiplayer_official_game_type_name.BountyMP" text="{=*}Bounty" />
<string id="str_multiplayer_game_type.BountyMP" text="{=*}Bounty" />
</strings>
</base>
确保 ID 与你在代码和模组定义文件中所定义的 ID 一致。
GameMode 类要让服务器用你的游戏模式开始一场行动(mission),你需要新建一个类继承自 MissionBasedMultiplayerGameMode。在该类中,重写 StartMultiplayerGame 方法如下:
public override void StartMultiplayerGame(string scene) {
MissionState.OpenNew("BountyMP", new MissionInitializerRecord(scene),
missionController => {
if (GameNetwork.IsServer) {
return new MissionBehavior[] {
MissionLobbyComponent.CreateBehavior(),
new MissionMultiplayerBountyMP(),
new MissionMultiplayerBountyMPClient(),
new MultiplayerTimerComponent(),
new MultiplayerMissionAgentVisualSpawnComponent(),
new SpawnComponent(new BountyMPSpawnFrameBehavior(), new BountyMPSpawningBehavior()),
new MissionLobbyEquipmentNetworkComponent(),
new MultiplayerTeamSelectComponent(),
new MissionHardBorderPlacer(),
new MissionBoundaryPlacer(),
new MissionBoundaryCrossingHandler(),
new MultiplayerPollComponent(),
new MultiplayerAdminComponent(),
new MultiplayerGameNotificationsComponent(),
new MissionOptionsComponent(),
new MissionScoreboardComponent(new BountyMPScoreboardData()),
new MissionAgentPanicHandler(),
new AgentHumanAILogic(),
new EquipmentControllerLeaveLogic(),
new MultiplayerPreloadHelper(),
};
} else {
return new MissionBehavior[] {
MissionLobbyComponent.CreateBehavior(),
new MissionMultiplayerBountyMPClient(),
new MultiplayerAchievementComponent(),
new MultiplayerTimerComponent(),
new MultiplayerMissionAgentVisualSpawnComponent(),
new MissionLobbyEquipmentNetworkComponent(),
new MultiplayerTeamSelectComponent(),
new MissionHardBorderPlacer(),
new MissionBoundaryPlacer(),
new MissionBoundaryCrossingHandler(),
new MultiplayerPollComponent(),
new MultiplayerGameNotificationsComponent(),
new MissionOptionsComponent(),
new MissionScoreboardComponent(new BountyMPScoreboardData()),
new MissionMatchHistoryComponent(),
new EquipmentControllerLeaveLogic(),
new MissionRecentPlayersComponent(),
new MultiplayerPreloadHelper(),
};
}
}
);
}
通过这段代码,你可以看见 GameNetwork 有一个变量,可以用在你的代码里,用于检查运行的游戏实例是服务端还是客户端。在该方法中,你可以看到它用来分隔客户端行为和服务器行为。这能确保正确的 MissionBehaviors 被加载到正确类型的游戏。其他方法中, GameNetwork.IsClient 和 GameNetwork.IsServer 可用于对不同事件采取不同处理。
该方法也大概展示了一场行动是如何进行的。所有行动行为(mission behaviors)都是一个接一个加载的,它们分别处理游戏的不同方面。根据你的游戏模式,你可能希望在你的模式中使用全部这些行为,又或者是只使用一部分。另外请注意,其中一些行为之间存在依赖关系,这意味着如果一个行为不存在,其他行为可能无法正确工作。在本例中,如果你按照第一部分中提到的步骤创建了一个空项目,那么有两个任务行为是无法实现的。开发者创建这两个行为来添加自己的游戏逻辑,它们是 MissionMultiplayerBountyMP 和 MissionMultiplayerBountyMPClient。前者从服务端管理游戏模式,后者从客户端管理游戏模式,确保所有重要的共享数据都在你的服务器上并正确同步。
行动行为(Mission Behaviors)对于所有原版游戏模式,服务端的游戏模式逻辑类,示例中的 MissionMultiplayerBountyMP,继承自 MissionMultiplayerGameModeBase。该类定义了基本的重生和同步系统。对于所有的原版游戏模式,客户端游戏模式消息处理逻辑类,示例中的 MissionMultiplayerBountyMPClient,继承自 MissionMultiplayerGameModeBaseClient。该类有几种可用的重写,可以确保消息处理程序(message handlers)的注册和注销在正确的时间发生。
行动典型(Mission Representatives)在原版游戏模式中,所有客户端添加了行动典型(Mission Representative)类来处理游戏模式特定的数据和逻辑。通过这一典型类,客户端可以根据条件查询多种关于游戏的事物。服务端也可以使用客户端的行动典型来计算多种事物,包括获得的金钱、旗帜信息等等。该类的内容依赖于游戏模式自身,行动典型的基类只有客户端的金钱和受控的 AI。在示例中,它是 BountyMPMissionRepresentative。行动典型被添加到了服务端游戏模式的先前一节提到的行动行为(Mission Behavior)类中。
搭建使用模组的自定义服务器要搭建一个使用模组的自定义服务器,你可以使用启动命令,如下:
DedicatedCustomServer.Starter.exe _MODULES_*Native*Multiplayer*YOUR_MODULE_NAME_1*YOUR_MODULE_NAME_2*_MODULES_
在星号之间,你可以放入任何你想要的模组的名称。
你提供给 /dedicatedcustomserverconfigfile 参数的文件也可以包含你的自定义游戏模式的名称。
示例模组你可以通过地址(请前往骑砍中文站或者官方公众号获取)找到添加了一个新多人游戏模式的示例模组。请注意,示例模组中可能有一些小 bug,这不是一个完整的打磨过的官方游戏模式。
要编译示例的客户端,你需要安装 Mount & Blade II: Bannerlord。
要编译示例的服务端,你需要安装 Mount & Blade II: Dedicated Server。
◆多人游戏场景的构造
本技术介绍将使你能够为特定的游戏模式创建自定义多人场景,它详细说明了你的多人游戏场景需要满足哪些要求才不会崩溃。这不是设计指南或最佳实践文档。
游戏模式(Gamemode)细节《霸主》中的每个游戏模式都需要一些不同的相关预制件(prefabs)的设置。
(提示:通过包含所有需要的预制件,可以使场景与多种游戏模式兼容。场景不能与使用不同重生(生成)系统的模式兼容,例如团队死斗场景不能与领军战场景兼容,但如果有合适的重生设置的话,领军战场景也可以用于遭遇战。)
游戏对象作为游戏模式在你的场景中运行所需要的预制件的游戏对象(Gameobjects),你可以在“预制件(Prefabs)”窗口中找到这些。
通用mp_camera_start_pos初始相机位置,这是为正在加入的玩家设置的。它基本上定义了加入服务器时选择阵营的背景,它也是人们看到的你的场景的第一个画面。确保你稍微旋转了它(它默认是向下旋转的)。这玩意儿只用放置一个!
border_soft定义场景周围的软边界(soft border)。如果玩家越过,他们将有几十秒时间返回。该边界用于设置场景的边界,确保边界不会穿进你的可游玩区域。你可以通过在地图周围放置边界探测点(border probes)来定义边界(最佳实践是做一个六边形的形状)。探测点总是会与离其最近的 2 个探测点相连。
(提示:你可以通过在可见性(Visibility)窗口中启用“边界(Borders)”来查看形成的边界,有时最好在这一步之前重新加载场景。)
flee_line这些逃离线(flee lines)是 AI(在我们的游戏模式中只有 AI 马匹)用于逃离战场的,他们会尝试使用导航网格(navmesh)来找到这些。所以这些位置需要放置在 AI 可以通过导航网格触及到的地方。当他们到达这些逃离线,他们会在短时间内消失,你可以放置多个这样的实例。
(提示:围城战时,你要确保城堡里也有这样的逃离线,这样城内的马就可以不经过城门跑出去。导航网格和 AI 不能分清楼梯和坡道,你可能需要调整或删除楼梯上的导航网格,以避免无人骑的马挡住他们。)
envmap_prop当你创建一个新场景时应该已经存在了,如果没有,就放置它并在“检查器(Inspector)”窗口中将其设置为“IsGlobal”,还要确保它在一个有效位置。当然可以有多个探测点,但使用 local_envmap_probe 作进一步探测。
旗帜管理(遭遇战、战场、领军战)Flags这些游戏模式都使用 3 个旗帜。不要被它们的命名搞懵,但是所有的游戏模式都使用相同的预制件!
它们的预制件:flag_pole_big_sergeant_A, flag_pole_big_sergeant_B, flag_pole_big_sergeant_C
旗帜管理(Flag Domination)需要三个独立的旗帜,所以不要复制旗帜 A 两次。
围城战Flags使用了跟旗帜管理一样的旗帜,而且显然更多。放置从 A 到 F 的所有旗帜,并且主旗帜是 G。
它们的预制件:flag_pole_big_sergeant_A, flag_pole_big_sergeant_B, flag_pole_big_sergeant_C, flag_pole_big_sergeant_D, flag_pole_big_sergeant_E, flag_pole_big_sergeant_F, flag_pole_big_sergeant_main
Siege Engines从技术上来讲,它们与单人游戏中的围攻的运作方式相同,但仍有一些明显的差别。首先,它们大多为多人游戏使用了不同的预制件,确保你使用的也是这些!
你的场景中所需的围城战器械没有最小(或最大)数量的要求,也没有部署点的要求,因为围城器械是由你的场景决定的,而不是沙盒战役游戏。此外,你不需要为攻城塔、攻城槌和攻城梯做大量的导航工作。所以你可以忽略检查器(Inspector)中的所有导航网格输入。
攻城槌和攻城塔仍然需要一条路径前进。简单创建一条路径,记住它的名称,并且在检查器的脚本中将其设置为“PathEntityName”。
多人游戏特定预制件:siege_tower_5m_spawnerMP, siege_tower_9m_spawnerMP, siege_tower_12m_spawnerMP, batteringram_a_spawnerMP, mangonel_a_spawnerMP, mangonel_a_spawnerFireMP, mangonel_b_spawnerMP, mangonel_b_spawnerFireMP, mangonel_a_spawnerMP, mangonel_a_spawnerFireMP, ballista_a_spawnerMP, ballista_a_spawnerFireMP, ballista_b_spawnerMP, ballista_b_spawnerFireMP
(提示:大门和攻城梯的预制件与单人游戏的相同。)
arrow_barrel你可以将该预制件(箭筒)放置在你场景内的任何位置,玩家可以使用它来补充弹药。
rock_pile放置该预制件允许玩家捡起石头,它们的工作方式与默认的围城器械相同。在 StonePile 脚本中,你可以设置这个预制件中石头的数量。这个预制件还有一个火罐版本:“pot_pile”
该预制件带有子对象“icon_man”,它定义了你可以从何处捡起石头。如果你不希望从任何方向访问你的石堆,你可以删除那些子对象。
Rock_pile 和 pot_pile 预制件可以伴随投石车和抛石机一起使用。如果你想要给玩家选择弹药的权力,你可以直接把石堆放在围城器械旁边。
决斗对于决斗模式你会需要手动创建地标(landmarks)。有两类地标,3 种定义了部队类型,16 种较小的定义了竞技场和它们所属的类型。
Big landmarks你可以随意使用该预制件,它需要有这两个标记(tags):“duel_zone_landmark”和“flag_x”。这个 x 代表兵种类型,所以应该用“infantry”,“cavalry”或“archery”来替换它。
你还需要(再次)使用脚本定义该区域的兵种类型。为此,添加“DuelZoneLandmark”到你的预制件,并将其设置为你打算在这里生成的任何兵种类型。
Arena landmarks这些地标定义了由大地标(big landmarks)分组的竞技场。同样,你可以使用任何预制件作为其基础。它需要设置两个标记(tags),第一个“flag_x”用于将其引用到大地标。所以如果你想让这个竞技场用于骑兵战斗,你应该使用标记“flag_cavalry”。
你的地标还需要一个引用实际竞技场区域的标记(下面会解释),基本上是一个 ID。为此,使用标记“area_flag_x”,x 是你竞技场的 ID。所以如果你有 16 个竞技场,它们都应该有它们自己的标记,范围从“area_flag_1”到“area_flag_16”。
volume_box这个盒子定义了战斗人员在竞技场中决斗的区域,每场决斗结束后所有掉落在这个盒子里的尸体和武器都会被清除。确保它比你在场景编辑器中创建的物理竞技场稍大。你可以使用 volume_box 预制件并缩放到你喜欢的大小。这个盒子需要一个引用你竞技场 ID 的标记:“area_box_x”,x 应该是你竞技场的 ID。
所以如果你竞技场的标记是“area_flag_5”,你应该给你的 volmue_box 打上标记“area_box_5”。
两个决斗参与者的重生点都要放在这个盒子里,下面细说。
重生点在回合开始时或回合中途玩家重生的点位。旗帜管理(Flag Domination)模式(领军战、遭遇战、战场)使用了几乎相同的重生系统,场景之间只需要做一点工作就可以相互兼容。从技术上来说,是兼容的。
大多数重生点需要设置右侧标记(tag)。这些预制件带有默认标记,要么是“attacker”,要么是“defender”。显然,你需要为对立的两队复制并调整这些预制件及其子对象上的标记。有时候如果标记还没有出现在你的场景中,就需要你手动将其添加到列表中,否则它不会显示在下拉菜单中!
通用spawn_visual进行兵种和特长选择时的位置。该预制件有 6 个子对象,一个给玩家,5 个给其队友。对于大多数游戏模式(除了遭遇战和领军战外的所有游戏模式),只使用有标记“sp_visual_0”的子对象,因为我们没有设置队友的数量。
在兵种/特长选择期间,一个镜头会被放在“sp_visual_0”子对象前面。
(提示:你可以忽略子对象上的“attacker”标记。与很多其他的重生位置不同,这个位置不需要复制给防守方队伍。)
旗帜管理(遭遇战、战场、领军战)skirmish_start_spawn该预制件定义了初始重生点。不要被预制件的名字迷惑到,它可以用于所有 3 个游戏模式的旗帜管理。
带有 9 个子重生点,但你可以复制那些来弄出更多可能的重生位置(例如,如果你不想要人们在 50 vs 50 的战场模式中重生时叠在一起)。所有的子对象需要带有“spawnpoint”,还有“attacker”或“defender”标记。主空间(main zone)的标记“starting”和“spawn_zone”不应该被修改。
(提示:确保点位不低于你正在使用的地形和地面资产。也要记住,马的重生需要周围更大的空间,所以不要把你的重生点太靠近其他人和其他预制件。)
skirmish_respawn预制件定义了遭遇战的重生位置,所以玩家会在死后重生在这里。如果你不放置这些点位,玩家将会在重生时出生在最开始的重生点。
每一边你可以放置最多 3 个。就像初始重生点(start spawn)一样,你必须复制两边的“attacker”和“defender”,主空间的标记“spawn_zone”不应被修改。
重生点选择系统检查周围的敌人时依赖于父实体(parent entity)的位置,玩家将在子实体(child entities)中重生。你可以利用这一点来调整重生位置的偏差。
围城战围城战中的重生与其它模式中有本质上的区别。围城战中的重生空间(Spawnzones)是否活跃取决于对局中被移除的旗帜数量。每个重生空间都通过标记 sp_zone_x(x 是从 0 到 6 的数字)连接到游戏模式(gamemode)逻辑。
该标记是在主重生点(main spawn point)预制件中设置的,其中有单个重生点“mp_spawnpoint”作为子对象。标记的“x”定义了进攻方需要占领(和移除)多少面旗帜,这样重生区域才会活跃。所以在围城战开始时,玩家会重生在有标记 sp_zone_0 的空间里,一旦第一面旗帜被移除,他们就会重生在标记 sp_zone_1 的空间里,诸如此类。如果只剩下 G 旗(主旗帜),玩家将会重生在标记 sp_zone_6 的空间里。
你可以在同一个重生空间上放置多个这些标记,所以你可以为前两面旗帜只创建一个重生空间,只需要给它添加 sp_zone_0 和 sp_zone_1 标记即可。
确保重生空间的子对象有“spawnpoint”,还有“attacker”或“defender”标记,就像其它模式一样。
这个 spawnpoint 没有预制件,所以大多数情况下你需要自己设置标记。我建议你使用“skirmish_start_spawn”预制件。为此,你需要从空间中删除“starting”标记并把它替换为“sp_zone_x”标记。
不要忘记放置进攻方(attacker)和防守方(defender)重生点!
(提示:你可以在重生空间的“mp_spawnpoint”子对象上使用特定的标记来调整什么兵种可以重生在这里。这里不言自明的标记是:“exclude_mounted”和“exclude_footmen”。)
团队死斗团队死斗不使用重生空间,重生点放置在场景周围,没有区分攻守的标记。使用“mp_spawnpoint”预制件就行。确保它们不是另一个预制件的子对象,并且只有“spawnpoint”标记。
决斗决斗不使用重生空间,重生点被放置在场景周围(最好是一种大厅区域),没有区分攻守的标记。使用“mp_spawnpoint”预制件就行。确保它们不是另一个预制件的子对象,并且只有“spawnpoint”标记。
请记住在每个竞技场内放两个 mp_spawnpoints,它们需要被标记连接到竞技场地标(arena landmark)。因此,使用“spawnpoint_area_x”,x 为所属竞技场的 ID。还要确保它们被放置在该竞技场的 volume_box 内。
导航网格一般来说,导航网格在多人游戏中不太重要,因为大多数原版游戏模式不使用 AI 士兵。不过,导航网格还可以用来给马匹定位,让它们找到逃离线(flee lines),并且也可以用来烘焙全局光照。
关于如何创建一个正确的网格请参考我们已有的文档。
你可以忽略 AI 脚本的特定 ID。
领军战一般来说,领军战模式和单人游戏战场地形导航网格工作模式是一样的。你将不得不覆盖一个相对较大的场景,并使用非常精确的导航网格。你无须顾及 ID,你可以像在但游戏中一样消耗导航网格,来阻止 AI 使用某些导航网格的面。
(请记住:比单人游戏更重要的是,那些玩家可以到达但没有导航网格的区域,给了玩家巨大的利用空间。尽量避免出现这样的地方。)
围城战城堡的大门需要在脚本中设置适当的导航网格,就像在单人游戏中一样(参考上面之前链接的文档)。如果你不创建一个适当的导航网格,马匹会感到困惑并卡在你的门里。此外,我们忽略了用于全局光照生成的城堡大门,这将阻止光照透进你的门楼主体。
还要确保马匹在城堡内外都可以够到逃离线。请记住,马匹总是会选择最近的“flee_line”进行逃离,如果“flee_line”恰好在城外,它们会试图找到一条出路,如果你没有正确设置大门和梯子,它们就会被卡住。
其他氛围(Atmosphere)与单人游戏不同,多人游戏场景只使用一种氛围。在进行编辑时不要忘记保存它。
标签(Label)在“SceneOptions”窗口中,你可以为你的场景设置一个标签(Label)。如果你扫描你的场景以查找问题(顶部图标栏中倒数第二个按钮),这会很有帮助。如果你把这个标签设为“mp”,它会过滤掉所有与单人游戏相关的问题。
避免动画点(animation point)预制件使用某些用于单人游戏的预制件会导致你的场景崩溃。请注意不要放置任何有关动画点的资产,这对椅子和类似的东西很重要,但对任何可能附带有动画的 shop_prop 预制件也很重要。
通常,所有这些预制件都有一个非动画点版本。除此之外,你总是可以使用这些资产,只需要删除其动画点子对象,并从预制件上移除所有的标记和脚本。
避免在围城战外使用可破坏对象可破坏对象只与我们的围城战游戏模式正确同步。在其它模式下,放置路障或围城器械这样的可破坏物体可能会使你的游戏崩溃,或造成其他问题。
城墙上的城齿和可破坏的屋顶也是如此。
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved