百家號(hào)和網(wǎng)站同步做凡科建站客服電話(huà)
玩過(guò)《哈迪斯》(英文名:Hades)嗎?最近在研究怎么給這款游戲做MOD,想把它的振動(dòng)體驗(yàn)升級(jí)到更高品質(zhì)的RichTap。N站下載了一些別人做的MOD,發(fā)現(xiàn)很多都基于相同的格式,均是對(duì)游戲.sjon文件或.lua文件的修改。我們也可以在游戲的安裝目錄 {installation_path}\Content下看到,Game子目錄里有很多.sjon文件,Scripts子目錄里有很多.lua文件。很顯然,這款游戲支持Lua腳本。如果我要給游戲擴(kuò)展功能,勢(shì)必也要寫(xiě)Lua腳本代碼。Lua有很多歷史版本,需要考慮新寫(xiě)代碼的兼容性。那么,《哈迪斯》自帶的Lua解釋器到底是哪個(gè)版本呢?這便是本文標(biāo)題的由來(lái)。
于是,我到Lua.org官網(wǎng)查看了它的版本歷史,發(fā)現(xiàn)Lua 最近幾個(gè)版本的發(fā)布時(shí)間分別是:
- Lua 5.4:2020年6月。最新版5.4.6發(fā)布于2023年5月。
- Lua 5.3:2015年1月。
- Lua 5.2:2011年12月。
- Lua 5.1:2006年2月。
- Lua 5.0:2003年4月。
而《哈迪斯》最早是在2018年12月發(fā)布的。猜測(cè)它用的Lua不是5.3就是5.2吧。我需要再去驗(yàn)證一下。
我在N站下載了一個(gè)叫“Multiplier Config”的MOD,它能在戰(zhàn)斗場(chǎng)景下動(dòng)態(tài)調(diào)整給主角或敵人帶來(lái)的傷害數(shù)值。按照網(wǎng)站上的指示安裝好MOD。然后,我需要修改其中的MultiplierConfig.lua。我本想加一行print(_VERSION)來(lái)打印Lua的版本號(hào)。問(wèn)題是,我到哪里能看到這個(gè)打印信息呢?
我有個(gè)想法。因?yàn)镽ichTap Windows SDK是以DLL的形式提供的,我在Lua代碼里識(shí)別游戲場(chǎng)景后是需要調(diào)用這個(gè)DLL來(lái)觸發(fā)高品質(zhì)振動(dòng)的。我何不在這個(gè)DLL里實(shí)現(xiàn)一個(gè)ShowMsg函數(shù),讓它把收到的內(nèi)容以Windows MessageBox的方式彈出來(lái)呢。經(jīng)過(guò)一番研究,發(fā)現(xiàn)能被Lua代碼調(diào)用的DLL是需要特殊定制的,那我就重新開(kāi)發(fā)一個(gè)最簡(jiǎn)單的“轉(zhuǎn)發(fā)器”DLL吧,這篇文章介紹了關(guān)鍵點(diǎn),美中不足的是作者沒(méi)有提供拿來(lái)即用的源代碼工程。于是我在GitHub找了一個(gè),是一個(gè)叫swerg的俄羅斯哥們開(kāi)發(fā)的。swerg維護(hù)了QUIK工具包,他的simple-lua-c-dll工程也依賴(lài)那個(gè)工具環(huán)境,具體來(lái)說(shuō)是他自己編譯的Lua解釋器qlua.dll。通過(guò)Dependency Walker也能確認(rèn)這一點(diǎn):
我想盡可能減少依賴(lài)!看來(lái)我還不得不自己編譯Lua源代碼呀!感謝faybull的這篇文章:“Windows下lua的編譯與環(huán)境搭建”,寫(xiě)得很清晰,看完一遍就懂了!不過(guò)我下載的是Lua 5.2.4的源代碼,代碼工程上傳到GitHub了,我編譯出了自己的lua.exe、lua52.dll和lua52.lib!然后我從swerg的simple-lua-c-dll fork了一個(gè)版本出來(lái),再把我編出來(lái)的庫(kù)文件以及相應(yīng)的頭文件用到我fork出來(lái)的simple-lua-c-dll工程,稍作修改后便順利編譯通過(guò)了。寫(xiě)了最簡(jiǎn)單的測(cè)試腳本test1.lua:
print(_VERSION)
print("Hello World")
然后在控制臺(tái)運(yùn)行:lua.exe {path}\test1.lua,順利通過(guò)!
接下來(lái),我就要給simple-lua-c-dll實(shí)現(xiàn)ShowMsg函數(shù)了:
static int forLua_ShowMsg(lua_State* L) {const int n = lua_gettop(L);if (n > 0) {int type = lua_type(L, 1); // 只處理第一個(gè)輸入?yún)?shù)if (type == LUA_TNUMBER) {char strMsg[100] = { 0 };sprintf(strMsg, "The number is %.2f", lua_tonumber(L, 1));MessageBox(NULL, strMsg, _T("QM"), MB_OK);}else if (type == LUA_TSTRING) {const char* pStr = lua_tostring(L, 1);if (pStr) {MessageBox(NULL, pStr, _T("QM"), MB_OK);}}}return(1);
}
將編譯出來(lái)的luacdll.dll拷貝到游戲安裝目錄的{installation_path}\x86下,也即把它跟主程序Hades.exe放在一起。修改MOD的MultiplierConfig.lua腳本如下:
ModUtil.WrapBaseFunction("Damage",function(baseFunc, victim, triggerArgs)local multiplier = MultiplierConfig.Config.Multiplier-- My codes beginluacdll = require("luacdll")if luacdll ~= nil thenluacdll.ShowMsg(_VERSION)end-- My codes endif victim ~= nil thenif victim == CurrentRun.Hero thentriggerArgs.DamageAmount = triggerArgs.DamageAmount * multiplier.DamageTakenelsetriggerArgs.DamageAmount = triggerArgs.DamageAmount * multiplier.Damageendendreturn baseFunc(victim, triggerArgs)end
)
見(jiàn)證奇跡的時(shí)刻到了!運(yùn)行游戲。在進(jìn)入戰(zhàn)斗場(chǎng)景后,很快就會(huì)看到彈出這樣的消息框:
完美!!!然后……然后……我在游戲主程序所在的目錄下看到了lua52.dll😂 好吧,這不重要了。我在整個(gè)過(guò)程中學(xué)到了很多。而且,我所做的工作在未來(lái)是可復(fù)用的?