5

Minetest 如何实现游戏内转账

 1 year ago
source link: https://www.shuizilong.com/house/archives/minetest-in-game-transfer/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
June 5, 2022

客户端修改

之前发现 Minetest 的引擎代码是和 easyrpg 一样是 cpp,那么也就意味着它也同样有机会可以使用 emscripten 编译到浏览器中运行。
网上搜了一圈,发现还真有人已经做了这件事。。。
https://blog.minetest.net/2022/03/27/March/

那么现在转账命令就非常容易实现了,可以先写在 js 里,然后直接调用对应的 js 方法即可。
不考虑安全问题。。我们先做一个简易且泛用的实作。。用邪恶的 Dr.Eval 大法,执行任何脚本。。。

void escape_EM_ASM(const std::wstring &message) {
std::wstring m = translate_string(message);
std::string s(m.length(), 0);
std::transform(m.begin(), m.end(), s.begin(), [] (wchar_t c) {
return (char)c;
});
MAIN_THREAD_ASYNC_EM_ASM(console.log("Msg: " + UTF8ToString($0)), s.c_str());
std::string c;
c = ".EM_ASM ";
if (s.find(c) != std::string::npos) {
s = s.substr(s.find(c) + c.size());
MAIN_THREAD_ASYNC_EM_ASM(eval(UTF8ToString($0)), s.c_str());
return;
}
}

注意这里我踩了一个坑。。。https://github.com/paradust7/minetest-wasm/issues/3
简单来说就是最好用这个命令。。MAIN_THREAD_ASYNC_EM_ASM。。。
上面的代码如果换成 EM_ASM,那么发消息的时候用这个还是能 trigger 里面的 js 代码,
但是如果经过一次服务器收到消息的时候进行解析就无效了,而模组里的 minetest.chat_send_player(name, text) API 是会经过一次服务器的。

模组第一个要求就是我们需要有一个动作能够 trigger 右击玩家这个事件。。。on_rightclick 什么的。。
搜了一圈发现没有现成的 API。。。

但是有一个现成的 mod 里有这个功能。。。所以我们从那个模组开始入手。。。
首先添加 right_click 的事件,我们创建一个菜单。。。

https://rubenwardy.com/minetest_modding_book/en/players/formspecs.html

minetest.register_on_rightclickplayer(function(player, clicker)
local s = clicker:get_player_name()
local t = player:get_player_name()
local controls = clicker:get_player_control()
if not(check_distance(clicker, player)) then
minetest.chat_send_player(s, S("Target too far."))
return
end
local context = get_context(s)
context.target = t 
local formspec = {
"formspec_version[4]",
"size[4.5,5.25]",
"label[0.375,0.5;", minetest.formspec_escape("This is " .. t .. "."), "]",
"button_exit[0.5,1;3.5,0.8;profile;Profile]",
"button_exit[0.5,2;3.5,0.8;transfer;Transfer]",
"button_exit[0.5,3;3.5,0.8;follow;Follow]",
"button_exit[0.5,4;3.5,0.8;cancel;Cancel]"
}
minetest.show_formspec(s, "player:interact", table.concat(formspec, ""))
end)

上面的代码里我们开了一个状态 context.target 用来记录当前交互的对象。。

FUcd02daAAAcnnY.jpg

然后再处理菜单的回执即可。。。

minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "player:interact" then
local s = player:get_player_name()
local t = get_context(s).target    
if fields.profile then         
minetest.chat_send_player(s, ".EM_ASM window.open(\"https://" .. t .. ".test.w3itch.io/zh-CN\", \"new\")")                         
end
if fields.transfer then        
minetest.chat_send_player(s, ".EM_ASM alert(feature not implement yet...)")                        
end
if fields.follow then          
minetest.chat_send_player(s, ".EM_ASM alert(feature not implement yet...)")                        
end
return true
end
end)

Posted by xiaodao
Category: 日常


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK