local nk = require("nakama") local utils = {} utils.ADMIN_ROLES = { ["admin"] = true, ["moderator"] = true, ["owner"] = true } utils.SYSTEM_USER_ID = "00000000-0000-0000-0000-000000000000" function utils.is_admin(context) if not context.user_id then return false end local status, account = pcall(nk.account_get_id, context.user_id) if not status or not account then return false end local metadata = {} if type(account.user.metadata) == "string" then status, metadata = pcall(nk.json_decode, account.user.metadata) if not status then metadata = {} end else metadata = account.user.metadata or {} end local role = metadata.role or "" return utils.ADMIN_ROLES[role] == true end function utils.is_match_host(context, match_id) if not context.user_id or not match_id then return false end local status, match = pcall(nk.match_get, match_id) if not status or not match then return false end -- Needs to decode match.state if you're using authoritative matches -- Simplified for lua translation: local state = {} if match.state then status, state = pcall(nk.json_decode, match.state) if not status then state = {} end end return state.hostUserId == context.user_id end function utils.require_admin(context) if not utils.is_admin(context) then error("Admin privileges required") end end function utils.require_admin_or_host(context, match_id) if not utils.is_admin(context) and not utils.is_match_host(context, match_id) then error("Admin or host privileges required") end end -- Channel type constants for nk.channel_id_build (Nakama Lua runtime). -- NOTE: these differ from the Godot client's NakamaSocket.ChannelType enum. utils.CHANNEL_TYPE_ROOM = 1 utils.CHANNEL_TYPE_DIRECT = 2 utils.CHANNEL_TYPE_GROUP = 3 -- Resolve a chat channel identifier for admin chat RPCs. -- -- The client may send either an already-hashed Nakama channel ID, or a friendly -- room name (e.g. "social_global"). A raw room name is NOT a valid channel ID for -- nk.channel_messages_list, so we build the canonical hashed ID via the -- authoritative nk.channel_id_build API (system user as sender → global room). -- Returns the resolved channel ID, or the original value if it already looks -- hashed / can't be built. function utils.resolve_channel_id(channel_id) if not channel_id or channel_id == "" then return "" end -- A hashed Nakama channel ID contains a '.' separator; a plain room name does -- not. Only treat dot-free values as room names needing resolution. if string.find(channel_id, "%.") then return channel_id end local status, built = pcall(nk.channel_id_build, "", channel_id, utils.CHANNEL_TYPE_ROOM) if status and built and built ~= "" then return built end return channel_id end return utils