最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

【真正的和平模式】二、任務(wù)系統(tǒng)的實現(xiàn)

2023-07-20 11:32 作者:VUMO北極鵝  | 我要投稿

我像迷途小鹿 得不到救贖

才會在此后的路 忽視了所有景物

我眼里的天空變得荒蕪

連詩里的飛鳥也迷了路

我像迷途小鹿 得不到救贖

才會將所有心跡 毫無保留呈現(xiàn)出

你縱身躍進(jìn)了滿天大霧

我找不到你也忘了歸途

——《迷途小鹿》(歌手:葛雨晴,作詞:巒無眠)

偶然間聽到的歌曲,主題稍微契合就寫進(jìn)來了(逃

本文首發(fā)于知乎,筆者是作者本人,第二轉(zhuǎn)載到bilibili平臺。原文鏈接:https://zhuanlan.zhihu.com/p/644603030

背景

正如前文所述,我們的模組要實現(xiàn)一個任務(wù)系統(tǒng),記錄著每個玩家完成任務(wù)的進(jìn)度,以及觸發(fā)任務(wù)條件等等。

為了方便數(shù)據(jù)包作者和其它模組作者的擴(kuò)展,我決定使用數(shù)據(jù)包形式,單向鏈表結(jié)構(gòu)來添加任務(wù)。第一步就是確定數(shù)據(jù)格式——在這里我選擇使用如下格式:

沒錯,任務(wù)強制只在開始和結(jié)束時才觸發(fā)對話,而對話的目標(biāo)最多只有一位NPC(當(dāng)然也可以是玩家獨白)。這是這個簡易系統(tǒng)唯一的局限性。

至于觸發(fā),后面再講。這里提前簡要說一下,對于任務(wù)開始和結(jié)束,原生模組提供了兩種任務(wù)觸發(fā)方式:其一是summon_block,數(shù)據(jù)包作者們可以直接使用;其二是api.MissionHelper#triggerMissionForPlayers和api.MissionHelper#triggerMissionForPlayer,只有衍生和聯(lián)動模組開發(fā)者們可以使用。

接下來就要想如何實現(xiàn)了。之前做獨立游戲的時候?qū)崿F(xiàn)過任務(wù)系統(tǒng),不過跟Minecraft的情況相去較遠(yuǎn),至少沒辦法直接搬。所以我直接重新造一個輪子。

不過做模組,很重要的一點就是,想想原版有什么類似的功能,那么只需要輕松照抄,稍加修改即可。

我最先想到的則是原版的進(jìn)度系統(tǒng)——數(shù)據(jù)包作者們可以在data/<modid>/advancements中自由添加進(jìn)度。那就容易很多了,說干就干!

ServerAdvancementManager詳解

打開net.minecraft.server.ServerAdvancementManager文件,我們可以看到原版進(jìn)度系統(tǒng)的實現(xiàn):

不太重要的部分已經(jīng)略去,對于這部分我們逐一解讀。

1. MissionManager的實現(xiàn)

首先它繼承了SimpleJsonResourceReloadListener類,這個類原版有兩種Manager繼承了它,其一是進(jìn)度系統(tǒng),其二是合成系統(tǒng);而Forge也定義了LootModifierManager,用以實現(xiàn)戰(zhàn)利品表的更改。這個父類的功能很簡單,可以實現(xiàn)json格式的數(shù)據(jù)讀取和自動加載,只需重寫apply函數(shù)即可。

也許有寫過低版本模組的同仁們就要問了,戰(zhàn)利品表系統(tǒng)不也繼承了它嗎?不錯,曾經(jīng)是,不過1.20這部分被大幅修改了,如今LootDataManager僅僅是實現(xiàn)了SimpleJsonResourceReloadListener的爺爺接口PreparableReloadListener。

回歸正題,apply函數(shù)傳了三個參數(shù),分別是所有JSON文件內(nèi)容(按id索引在map中)、Resource Manager和Profiler Filler。事實上我們實現(xiàn)自己的需求也無需后兩個參數(shù),只要寫好讀取json文件的處理邏輯即可。

其次,構(gòu)造函數(shù)傳遞了兩個參數(shù),一個是編碼JSON文件的方法,一個是掃描文件目錄。對于進(jìn)度系統(tǒng)則是"advancements",如果我希望任務(wù)系統(tǒng)的掃描目錄是data/<modid>/rpm/missions,則傳入"rpm/missions"即可。

于是我們便可以實現(xiàn)任務(wù)系統(tǒng):

然后,如何將這個監(jiān)聽器真正監(jiān)聽在資源加載階段呢?當(dāng)然你可以mixin,但Forge是有這個API的,所以我優(yōu)先去調(diào)用這個API:

并在主類中,通過Forge bus中注冊它。

接著,我們有了總領(lǐng)的任務(wù)系統(tǒng),進(jìn)一步的,如何去維護(hù)每個人的任務(wù)的進(jìn)度?于是我們發(fā)現(xiàn)了PlayerAdvancements類。

2. PlayerMissions的實現(xiàn)

首先,我們可以看到在PlayerList中有一個維護(hù)每個人進(jìn)度完成情況的成員:

而在ServerPlayer中也有自身獨立的PlayerAdvancements:

當(dāng)然,這個advancements只是PlayerList中對應(yīng)的那個PlayerAdvancements的一個影子。

參考這個類,我們可以實現(xiàn)自己的PlayerMissions。它需要包含玩家完成過的任務(wù)、玩家正在進(jìn)行的任務(wù)(其余都是還未接收的任務(wù)):

為了安全性,在這里做了檢查,允許玩家接收的任務(wù),玩家必須已經(jīng)完成過所有前置任務(wù)。

那么,如何將它加進(jìn)PlayerList里呢?其實未必要加進(jìn)PlayerList中,你也可以自己寫一個SavedData來實現(xiàn),不過這次的mixin沒有副作用,而且更符合直覺架構(gòu),因此我選擇了mixin:

這里抽象了一個IPlayerListWithMissions接口,作用是,由于Mixin類無法被實例化或強制轉(zhuǎn)化,所以要想調(diào)用getPlayerMissions函數(shù),必須通過一個接口來訪問。比如:

沒辦法,都mixin了,還在意啥代碼美觀。

那么如何將它進(jìn)行序列化呢?我們又要mixin進(jìn)ServerPlayer類,注入讀寫nbt和restoreFrom方法:

這里的IMonsterHero接口也是同樣,方便其它部分調(diào)用,判斷玩家是否已經(jīng)實現(xiàn)了某個怪物的全部委托。

一定不要忘記restoreFrom函數(shù)!否則玩家不論是從末地返回主世界,還是死亡后重生,這些信息都會消失!

那么任務(wù)系統(tǒng)算是成功實現(xiàn)了,不過還需要客戶端的UI,顯示任務(wù)對話,如題圖所示。該怎么實現(xiàn)呢?

Menu+Screen的兩層架構(gòu)

首先介紹一下Minecraft的UI架構(gòu)。一般的功能性UI都是兩層結(jié)構(gòu):第一層是Menu,位于服務(wù)端(客戶端會同步它),便于與世界交互,如玩家放入熔爐一根烈焰棒(真有人這么富嗎?);第二層是Screen,位于客戶端,執(zhí)行顯示界面,處理玩家請求的功能,如顯示熔爐UI,顯示燃料剩余量、燒煉的進(jìn)度等等。有些UI由于無需與服務(wù)端部分交互,便只有Screen沒有Menu,比如玩家進(jìn)度、統(tǒng)計界面等,只需一次發(fā)包后便可顯示。

而我們的需求是,首先,任務(wù)界面打開過程中,怪物不能攻擊玩家——這就限制了我們的實現(xiàn),Menu部分必須要存在;其次,玩家客戶端要顯示對話,這部分是由服務(wù)端的MissionManager.Mission發(fā)包過來的;最后,對話結(jié)束后要提示玩家接收到了新的任務(wù)或完成了任務(wù),這又是服務(wù)端向客戶端發(fā)送的。

那么我們可以做如下設(shè)計:

  1. Menu部分維護(hù)了該任務(wù)的所有對話。

  2. Screen顯示了對話內(nèi)容和講話的生物,玩家可以按下按鈕來向前/向后閱讀。

Menu的實現(xiàn)

于是我們可以實現(xiàn)如下Menu:

第一個構(gòu)造函數(shù)用于RPMMenuTypes中的注冊:

第二個構(gòu)造函數(shù)則是用于在接收/完成任務(wù)時玩家openMenu的傳參。

由于無需物品欄和槽位的操作,quickMoveStack可直接返回空;stillValid也可以隨便寫寫了,這里是根據(jù)與NPC的距離判斷的。

mission的getter和setter則是用于服務(wù)端向客戶端的發(fā)包:

這一步將服務(wù)端的任務(wù)內(nèi)容傳給了客戶端,并進(jìn)行了驗證。

注冊發(fā)包則是在主類中完成:

Screen的實現(xiàn)

既然Menu實現(xiàn)好了,那Screen不就簡單了嗎?

注意高版本的PoseStack被UI系統(tǒng)棄用了,改用GuiGraphics做渲染,個人感覺更加方便了。

renderBg函數(shù)實現(xiàn)了背景渲染,以及界面右下方對話實體的顯示。renderButtons顯示了向前向后兩個按鈕的渲染,而處理玩家請求則是在mouseClicked(按下按鈕,改變按鈕顏色)和mouseReleased(釋放按鈕,執(zhí)行按鈕功能)中實現(xiàn)。而對話文本的分行是在loadCachedText函數(shù)中實現(xiàn)。

具體blit的數(shù)值取決于GUI資源圖片的排版,由于我將按鈕元素排版在下方,所以便從下方截取圖像并貼在對應(yīng)位置(詳見倉庫中GUI資源文件)。

實現(xiàn)了核心功能,也許玩家會想查看自己的任務(wù)完成情況和任務(wù)描述。接下來介紹顯示客戶端玩家任務(wù)這部分的實現(xiàn)方法。

顯示玩家任務(wù)完成情況

首先我添加了綁定按鍵(默認(rèn)M鍵),按下按鍵后可顯示任務(wù)屏幕GUI。

客戶端也要監(jiān)聽玩家按鍵的事件,處理打開窗口的請求:

這里這里通過客戶端和服務(wù)端之間互相發(fā)包的方式,來獲取玩家任務(wù)列表(包括已完成和進(jìn)行中):

發(fā)包注冊方式和前文相似:

顯示任務(wù)列表的Screen無需與世界交互,所以只實現(xiàn)一個Screen即可,無需Menu:

這里UI右上方有一個按鈕,用來決定客戶端玩家是否查看自己已完成的任務(wù)。這是唯一需要額外接收請求的部分。對于已完成與否的任務(wù),要顯示不同的提示,由于比較簡單,不做額外講解了。

總結(jié)

這樣,我們成功地把整個任務(wù)與對話系統(tǒng)搬到了Minecraft中,而且支持?jǐn)?shù)據(jù)包作者和拓展模組開發(fā)者們添加任務(wù),可以說實現(xiàn)地非常完美了。下一部分打算講輕松點的,主要是模組世界生成中添加結(jié)構(gòu)的方法。

【真正的和平模式】二、任務(wù)系統(tǒng)的實現(xiàn)的評論 (共 條)

分享到微博請遵守國家法律
阿勒泰市| 轮台县| 麻阳| 阜新| 应用必备| 岑巩县| 新巴尔虎左旗| 双柏县| 南充市| 海口市| 融水| 太白县| 山东省| 饶阳县| 闻喜县| 安福县| 开封县| 龙口市| 吉木萨尔县| 屏东市| 固原市| 麻城市| 澄城县| 巴彦淖尔市| 沙田区| 兴业县| 三河市| 廊坊市| 龙门县| 扶沟县| 惠州市| 衢州市| 永清县| 龙井市| 桂阳县| 利辛县| 满洲里市| 通城县| 云南省| 禄丰县| 冕宁县|