mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2026-04-26 20:11:42 +00:00
Added BungeeCord64
This commit is contained in:
parent
4f9a51ff90
commit
a07102ba11
13 changed files with 1063 additions and 10 deletions
|
|
@ -11176,6 +11176,61 @@ function set_got_file_coin_hi_score(value)
|
|||
-- ...
|
||||
end
|
||||
|
||||
--- @param port integer
|
||||
--- @return boolean
|
||||
--- [BungeeCord64] Switches to a different server on localhost with the specified port. Returns true if switch was initiated successfully. Only works when connected as client, not as server host.
|
||||
function network_switch_to_server(port)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @return integer
|
||||
--- [BungeeCord64] Gets the current server port the client is connected to or hosting on. Returns 0 if not connected.
|
||||
function network_get_current_port()
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @return string
|
||||
--- [BungeeCord64] Gets the current connection IP address as a string. Returns empty string if not connected.
|
||||
function network_get_current_ip()
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @return boolean
|
||||
--- [BungeeCord64] Checks if the player is currently connected to a server as a client.
|
||||
function network_is_client()
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param port integer
|
||||
--- [BungeeCord64] Sets the global fallback port used when the current server dies unexpectedly.
|
||||
function network_set_bungee_fallback_port(port)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @return integer
|
||||
--- [BungeeCord64] Gets the current global fallback port.
|
||||
function network_get_bungee_fallback_port()
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @return boolean
|
||||
--- [BungeeCord64] Checks if a seamless server switch is currently in progress.
|
||||
function network_is_bungee_switching()
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @param port integer
|
||||
--- [BungeeCord64] SERVER ONLY: Sets the fallback port that clients should reconnect to if this server crashes.
|
||||
function network_set_server_fallback_port(port)
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @return integer
|
||||
--- [BungeeCord64] SERVER ONLY: Gets the configured fallback port for this server.
|
||||
function network_get_server_fallback_port()
|
||||
-- ...
|
||||
end
|
||||
|
||||
--- @return boolean
|
||||
--- Checks if the save file has been modified without saving
|
||||
function get_save_file_modified()
|
||||
|
|
|
|||
434
mods/bungeecord64/main.lua
Normal file
434
mods/bungeecord64/main.lua
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
-- name: BungeeCord64
|
||||
-- description:\#ffff33\--- BungeeCord64 v1.2 ---\n\n\#dcdcdc\Seamless multi-server switching for SM64CoopDX.\nLets you hop between local servers with a smooth transition overlay.\n\n\#ffff33\Commands:\n\#ffffff\/bungeecord64\#aaaaaa\ - Show status\n\#ffffff\/switch <port>\#aaaaaa\ - Switch to server on port\n\#ffffff\/leave\#aaaaaa\ - Return to home server\n\#ffffff\/setfallback <port>\#aaaaaa\ - Set default home server\n\#ffffff\/setserverfallback <port>\#aaaaaa\ - (Server) Set fallback for clients\n\n\#00ff00\This mod must be installed on ALL servers!\n\#ff6666\All servers must be in the same local network (localhost)
|
||||
-- incompatible: gamemode
|
||||
-- pausable: false
|
||||
|
||||
-- =====================================================
|
||||
-- BungeeCord64 - Seamless Server Switching System
|
||||
-- =====================================================
|
||||
-- Enables seamless switching between multiple SM64CoopDX servers
|
||||
-- in the local network (localhost). Inspired by Minecraft BungeeCord.
|
||||
--
|
||||
-- Features:
|
||||
-- - /switch <port> : Smooth switch to another local server
|
||||
-- - /leave : Returns to your home server
|
||||
-- - Auto reconnect : Server sends fallback port to clients
|
||||
-- - Overlay display : "Connecting To Server <PORT>..." while you can still play
|
||||
-- =====================================================
|
||||
|
||||
if incompatibleClient then return end
|
||||
|
||||
local MOD_VERSION = "1.2.0"
|
||||
|
||||
-- Home server: where /leave goes to.
|
||||
-- By default this is the first server you connect to as a client,
|
||||
-- but it can be overridden with /setfallback.
|
||||
local homePort = 0
|
||||
|
||||
-- Optional: configured fallback (if you want a fixed main hub)
|
||||
-- Default: 7777, unless changed via /setfallback or saved config.
|
||||
local fallbackPort = 7777
|
||||
|
||||
-- Known servers in the network (Port -> Name) for nicer status output
|
||||
local knownServers = {}
|
||||
|
||||
-- Runtime state
|
||||
local lastWasConnected = false
|
||||
local lastPort = 0
|
||||
|
||||
-- Note: Switch state is now managed C-side via network_is_bungee_switching()
|
||||
-- We only track Lua-side state for UI/chat messages
|
||||
local luaSwitchReason = nil
|
||||
|
||||
-- Server-side: fallback port to send to clients
|
||||
local serverFallbackPort = 0
|
||||
|
||||
-- ===================
|
||||
-- Helper functions
|
||||
-- ===================
|
||||
|
||||
local function chatMsg(msg, color)
|
||||
color = color or "\\#ffffff\\"
|
||||
djui_chat_message_create(color .. msg)
|
||||
end
|
||||
|
||||
local function popup(msg, lines)
|
||||
djui_popup_create(msg, lines or 2)
|
||||
end
|
||||
|
||||
local function isClient()
|
||||
return network_is_client()
|
||||
end
|
||||
|
||||
local function isServer()
|
||||
return network_is_server()
|
||||
end
|
||||
|
||||
local function getCurrentPort()
|
||||
return network_get_current_port() or 0
|
||||
end
|
||||
|
||||
local function getCurrentIp()
|
||||
return network_get_current_ip() or ""
|
||||
end
|
||||
|
||||
local function ensureHomePort()
|
||||
if homePort ~= 0 then return end
|
||||
local port = getCurrentPort()
|
||||
if port ~= 0 then
|
||||
homePort = port
|
||||
end
|
||||
end
|
||||
|
||||
local function getHomePort()
|
||||
if homePort ~= 0 then return homePort end
|
||||
if fallbackPort ~= 0 then return fallbackPort end
|
||||
return 0
|
||||
end
|
||||
|
||||
local function registerServer(port, name)
|
||||
if not port or port <= 0 then return end
|
||||
knownServers[port] = name or ("Server:" .. port)
|
||||
mod_storage_save("server_" .. port, knownServers[port])
|
||||
end
|
||||
|
||||
local function loadSavedConfig()
|
||||
-- Load client fallback
|
||||
local savedFallback = mod_storage_load("fallback_port")
|
||||
if savedFallback and tonumber(savedFallback) then
|
||||
fallbackPort = tonumber(savedFallback)
|
||||
if homePort == 0 then
|
||||
homePort = fallbackPort
|
||||
end
|
||||
end
|
||||
|
||||
-- Push current fallback down into the C-side global so that even if Lua
|
||||
-- dies (e.g. due to a hard disconnect), the client can still auto-reconnect
|
||||
-- to the fallback server.
|
||||
network_set_bungee_fallback_port(fallbackPort)
|
||||
|
||||
-- Load server fallback (if hosting)
|
||||
local savedServerFallback = mod_storage_load("server_fallback_port")
|
||||
if savedServerFallback and tonumber(savedServerFallback) then
|
||||
serverFallbackPort = tonumber(savedServerFallback)
|
||||
end
|
||||
end
|
||||
|
||||
-- Core switching helper. Now uses the C-side seamless BungeeCord switch
|
||||
-- which shows a big overlay while you can still play, then switches.
|
||||
local function performSwitch(targetPort, reason)
|
||||
if isServer() then
|
||||
chatMsg("You cannot use BungeeCord64 while hosting.", "\\#ff6666\\")
|
||||
return false
|
||||
end
|
||||
|
||||
local currentPort = getCurrentPort()
|
||||
|
||||
if not isClient() and currentPort == 0 then
|
||||
chatMsg("You are not connected to any server.", "\\#ff6666\\")
|
||||
return false
|
||||
end
|
||||
|
||||
if targetPort == nil or targetPort <= 0 then
|
||||
chatMsg("Invalid or unknown target port.", "\\#ff6666\\")
|
||||
return false
|
||||
end
|
||||
|
||||
if currentPort ~= 0 and targetPort == currentPort then
|
||||
chatMsg("You are already on port " .. targetPort .. ".", "\\#ffff00\\")
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check if a switch is already in progress (C-side check)
|
||||
if network_is_bungee_switching() then
|
||||
chatMsg("A server switch is already in progress.", "\\#ffff00\\")
|
||||
return false
|
||||
end
|
||||
|
||||
ensureHomePort()
|
||||
|
||||
local reasonText = reason or "switch"
|
||||
chatMsg("BungeeCord64: Initiating switch to port " .. targetPort .. "...", "\\#00ff00\\")
|
||||
|
||||
luaSwitchReason = reasonText
|
||||
lastWasConnected = false
|
||||
|
||||
-- Use the new C-side seamless switch
|
||||
-- This shows the overlay immediately, lets you play for a moment,
|
||||
-- then performs the actual switch
|
||||
local ok = network_switch_to_server(targetPort)
|
||||
if not ok then
|
||||
chatMsg("BungeeCord64: failed to initiate switch to port " .. targetPort .. ".", "\\#ff6666\\")
|
||||
luaSwitchReason = nil
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- ===================
|
||||
-- Chat commands
|
||||
-- ===================
|
||||
|
||||
local function cmdSwitch(msg)
|
||||
if msg == "" or msg == nil then
|
||||
chatMsg("Usage: /switch <port>", "\\#ffff00\\")
|
||||
chatMsg("Example: /switch 7778", "\\#aaaaaa\\")
|
||||
return true
|
||||
end
|
||||
|
||||
local port = tonumber(msg)
|
||||
if not port then
|
||||
chatMsg("Invalid port: " .. msg, "\\#ff6666\\")
|
||||
return true
|
||||
end
|
||||
|
||||
registerServer(port, knownServers[port])
|
||||
performSwitch(port, "manual")
|
||||
return true
|
||||
end
|
||||
|
||||
local function cmdLeave(msg)
|
||||
local target = getHomePort()
|
||||
if target == 0 then
|
||||
chatMsg("No home server known yet. Join a server first or use /setfallback <port>.", "\\#ff6666\\")
|
||||
return true
|
||||
end
|
||||
|
||||
performSwitch(target, "leave")
|
||||
return true
|
||||
end
|
||||
|
||||
local function cmdSetFallback(msg)
|
||||
if msg == "" or msg == nil then
|
||||
chatMsg("Usage: /setfallback <port>", "\\#ffff00\\")
|
||||
local currentHome = getHomePort()
|
||||
if currentHome ~= 0 then
|
||||
chatMsg("Current home server: port " .. currentHome, "\\#aaaaaa\\")
|
||||
else
|
||||
chatMsg("No home server configured.", "\\#aaaaaa\\")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local port = tonumber(msg)
|
||||
if not port or port <= 0 then
|
||||
chatMsg("Invalid port: " .. msg, "\\#ff6666\\")
|
||||
return true
|
||||
end
|
||||
|
||||
fallbackPort = port
|
||||
mod_storage_save("fallback_port", tostring(port))
|
||||
if homePort == 0 then
|
||||
homePort = port
|
||||
end
|
||||
|
||||
-- Update C-side fallback so C can auto-reconnect on hard disconnects.
|
||||
network_set_bungee_fallback_port(fallbackPort)
|
||||
|
||||
chatMsg("Fallback (home) server set to port " .. port .. ".", "\\#00ff00\\")
|
||||
popup("BungeeCord64\nHome server: port " .. port, 2)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Server-only command: set fallback port that gets sent to clients
|
||||
local function cmdSetServerFallback(msg)
|
||||
if not isServer() then
|
||||
chatMsg("This command is only for server hosts.", "\\#ff6666\\")
|
||||
return true
|
||||
end
|
||||
|
||||
if msg == "" or msg == nil then
|
||||
chatMsg("Usage: /setserverfallback <port>", "\\#ffff00\\")
|
||||
local current = network_get_server_fallback_port()
|
||||
if current ~= 0 then
|
||||
chatMsg("Current server fallback: port " .. current, "\\#aaaaaa\\")
|
||||
else
|
||||
chatMsg("No server fallback configured.", "\\#aaaaaa\\")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local port = tonumber(msg)
|
||||
if not port or port <= 0 then
|
||||
chatMsg("Invalid port: " .. msg, "\\#ff6666\\")
|
||||
return true
|
||||
end
|
||||
|
||||
serverFallbackPort = port
|
||||
mod_storage_save("server_fallback_port", tostring(port))
|
||||
|
||||
-- Set C-side server fallback
|
||||
network_set_server_fallback_port(port)
|
||||
|
||||
chatMsg("Server fallback port set to " .. port .. ".", "\\#00ff00\\")
|
||||
chatMsg("Clients will reconnect to this port if this server crashes.", "\\#aaaaaa\\")
|
||||
popup("BungeeCord64\nServer fallback: port " .. port, 2)
|
||||
return true
|
||||
end
|
||||
|
||||
local function cmdAddServer(msg)
|
||||
if msg == "" or msg == nil then
|
||||
chatMsg("Usage: /addserver <port> <name>", "\\#ffff00\\")
|
||||
chatMsg("Example: /addserver 7779 Minigames", "\\#aaaaaa\\")
|
||||
return true
|
||||
end
|
||||
|
||||
local parts = {}
|
||||
for part in msg:gmatch("%S+") do
|
||||
table.insert(parts, part)
|
||||
end
|
||||
|
||||
local port = tonumber(parts[1])
|
||||
if not port or port <= 0 then
|
||||
chatMsg("Invalid port!", "\\#ff6666\\")
|
||||
return true
|
||||
end
|
||||
|
||||
local name = "Server:" .. port
|
||||
if #parts > 1 then
|
||||
table.remove(parts, 1)
|
||||
name = table.concat(parts, " ")
|
||||
end
|
||||
|
||||
registerServer(port, name)
|
||||
chatMsg("Registered server: " .. name .. " (port " .. port .. ")", "\\#00ff00\\")
|
||||
return true
|
||||
end
|
||||
|
||||
local function cmdStatus(msg)
|
||||
local client = isClient()
|
||||
local server = isServer()
|
||||
local port = getCurrentPort()
|
||||
local ip = getCurrentIp()
|
||||
|
||||
chatMsg("============================================", "\\#ffff33\\")
|
||||
chatMsg(" BungeeCord64 v" .. MOD_VERSION, "\\#ffff33\\")
|
||||
chatMsg("============================================", "\\#ffff33\\")
|
||||
|
||||
if server then
|
||||
chatMsg(">> You are HOSTING a server on port " .. port, "\\#00ff00\\")
|
||||
local srvFallback = network_get_server_fallback_port()
|
||||
if srvFallback ~= 0 then
|
||||
chatMsg(" Server fallback port: " .. srvFallback, "\\#00ffff\\")
|
||||
else
|
||||
chatMsg(" Server fallback: (not set)", "\\#aaaaaa\\")
|
||||
chatMsg(" Use /setserverfallback <port> to set one.", "\\#aaaaaa\\")
|
||||
end
|
||||
elseif client and port ~= 0 then
|
||||
chatMsg(">> Connected as CLIENT on port " .. port, "\\#00ff00\\")
|
||||
if ip ~= "" then
|
||||
chatMsg(" Server IP: " .. ip, "\\#aaaaaa\\")
|
||||
end
|
||||
|
||||
-- Show the fallback port the server sent us
|
||||
local receivedFallback = network_get_bungee_fallback_port()
|
||||
if receivedFallback ~= 0 then
|
||||
chatMsg(" Server's fallback port: " .. receivedFallback, "\\#00ffff\\")
|
||||
end
|
||||
else
|
||||
chatMsg(">> Not connected to any server.", "\\#ff6666\\")
|
||||
end
|
||||
|
||||
local home = getHomePort()
|
||||
if home ~= 0 then
|
||||
chatMsg("Home server (target for /leave): port " .. home, "\\#ffff00\\")
|
||||
else
|
||||
chatMsg("Home server (target for /leave): (not set)", "\\#aaaaaa\\")
|
||||
end
|
||||
|
||||
chatMsg("Client fallback port: " .. tostring(fallbackPort), "\\#00ffff\\")
|
||||
|
||||
chatMsg("", "\\#ffffff\\")
|
||||
chatMsg(">> Commands:", "\\#00ffff\\")
|
||||
chatMsg("/switch <port> - Switch to server", "\\#aaaaaa\\")
|
||||
chatMsg("/leave - Return to home server", "\\#aaaaaa\\")
|
||||
chatMsg("/setfallback <port> - Set client home", "\\#aaaaaa\\")
|
||||
if server then
|
||||
chatMsg("/setserverfallback <port> - Set server fallback", "\\#aaaaaa\\")
|
||||
end
|
||||
chatMsg("/addserver <port> <name> - Register server", "\\#aaaaaa\\")
|
||||
chatMsg("============================================", "\\#ffff33\\")
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- ===================
|
||||
-- Server init: set fallback port on startup
|
||||
-- ===================
|
||||
|
||||
local function onServerInit()
|
||||
if not isServer() then return end
|
||||
|
||||
-- Load saved server fallback
|
||||
local savedFallback = mod_storage_load("server_fallback_port")
|
||||
if savedFallback and tonumber(savedFallback) then
|
||||
serverFallbackPort = tonumber(savedFallback)
|
||||
network_set_server_fallback_port(serverFallbackPort)
|
||||
chatMsg("BungeeCord64: Server fallback port loaded: " .. serverFallbackPort, "\\#00ffff\\")
|
||||
end
|
||||
end
|
||||
|
||||
-- ===================
|
||||
-- Update hook (connection tracking)
|
||||
-- ===================
|
||||
|
||||
local function onUpdate()
|
||||
local client = isClient()
|
||||
local server = isServer()
|
||||
local port = getCurrentPort()
|
||||
local switching = network_is_bungee_switching()
|
||||
|
||||
if client and port ~= 0 then
|
||||
-- Update home port the first time we see a valid connection
|
||||
ensureHomePort()
|
||||
|
||||
-- Check if we just completed a switch
|
||||
if luaSwitchReason ~= nil and not switching then
|
||||
chatMsg("BungeeCord64: Connected to port " .. port .. "!", "\\#00ff00\\")
|
||||
luaSwitchReason = nil
|
||||
end
|
||||
|
||||
lastWasConnected = true
|
||||
lastPort = port
|
||||
return
|
||||
end
|
||||
|
||||
-- If we were connected as client and now we are not, and this wasn't
|
||||
-- an intentional switch that is still in progress, the C-side will
|
||||
-- handle auto-reconnect to fallback port.
|
||||
if lastWasConnected and not switching then
|
||||
lastWasConnected = false
|
||||
end
|
||||
|
||||
lastWasConnected = client and port ~= 0
|
||||
end
|
||||
|
||||
-- ===================
|
||||
-- Init & hook registration
|
||||
-- ===================
|
||||
|
||||
local function init()
|
||||
loadSavedConfig()
|
||||
|
||||
chatMsg("============================================", "\\#ffff33\\")
|
||||
chatMsg("BungeeCord64 v" .. MOD_VERSION .. " loaded!", "\\#00ff00\\")
|
||||
chatMsg("Use /bungeecord64 for status and help.", "\\#aaaaaa\\")
|
||||
chatMsg("============================================", "\\#ffff33\\")
|
||||
|
||||
-- If we're a server, set up server fallback
|
||||
if isServer() then
|
||||
onServerInit()
|
||||
end
|
||||
end
|
||||
|
||||
hook_event(HOOK_UPDATE, onUpdate)
|
||||
|
||||
hook_chat_command("bungeecord64", "[BC64] Show status and help", cmdStatus)
|
||||
hook_chat_command("switch", "[BC64] /switch <port> - Switch to server", cmdSwitch)
|
||||
hook_chat_command("leave", "[BC64] /leave - Return to home server", cmdLeave)
|
||||
hook_chat_command("setfallback", "[BC64] /setfallback <port> - Set home server", cmdSetFallback)
|
||||
hook_chat_command("setserverfallback", "[BC64] /setserverfallback <port> - Set server fallback (host only)", cmdSetServerFallback)
|
||||
hook_chat_command("addserver", "[BC64] /addserver <port> <name> - Register server", cmdAddServer)
|
||||
|
||||
init()
|
||||
|
|
@ -33550,6 +33550,149 @@ int smlua_func_set_got_file_coin_hi_score(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// BungeeCord64 Network Functions
|
||||
|
||||
int smlua_func_network_switch_to_server(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 1) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_switch_to_server", 1, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 port = smlua_to_integer(L, 1);
|
||||
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1 for function '%s'", "network_switch_to_server"); return 0; }
|
||||
|
||||
lua_pushboolean(L, network_switch_to_server(port));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_network_get_current_port(UNUSED lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 0) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_get_current_port", 0, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, network_get_current_port());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_network_get_current_ip(UNUSED lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 0) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_get_current_ip", 0, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushstring(L, network_get_current_ip());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_network_is_client(UNUSED lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 0) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_is_client", 0, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushboolean(L, network_is_client());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_network_set_bungee_fallback_port(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 1) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_set_bungee_fallback_port", 1, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 port = smlua_to_integer(L, 1);
|
||||
if (!gSmLuaConvertSuccess) {
|
||||
LOG_LUA("Failed to convert parameter 1 for function '%s'", "network_set_bungee_fallback_port");
|
||||
return 0;
|
||||
}
|
||||
|
||||
network_set_bungee_fallback_port(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smlua_func_network_get_bungee_fallback_port(UNUSED lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 0) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_get_bungee_fallback_port", 0, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, network_get_bungee_fallback_port());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_network_is_bungee_switching(UNUSED lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 0) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_is_bungee_switching", 0, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushboolean(L, network_is_bungee_switching());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_network_set_server_fallback_port(lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 1) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_set_server_fallback_port", 1, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 port = smlua_to_integer(L, 1);
|
||||
if (!gSmLuaConvertSuccess) {
|
||||
LOG_LUA("Failed to convert parameter 1 for function '%s'", "network_set_server_fallback_port");
|
||||
return 0;
|
||||
}
|
||||
|
||||
network_set_server_fallback_port(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smlua_func_network_get_server_fallback_port(UNUSED lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
int top = lua_gettop(L);
|
||||
if (top != 0) {
|
||||
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_get_server_fallback_port", 0, top);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, network_get_server_fallback_port());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int smlua_func_get_save_file_modified(UNUSED lua_State* L) {
|
||||
if (L == NULL) { return 0; }
|
||||
|
||||
|
|
@ -38756,6 +38899,15 @@ void smlua_bind_functions_autogen(void) {
|
|||
smlua_bind_function(L, "set_last_completed_star_num", smlua_func_set_last_completed_star_num);
|
||||
smlua_bind_function(L, "get_got_file_coin_hi_score", smlua_func_get_got_file_coin_hi_score);
|
||||
smlua_bind_function(L, "set_got_file_coin_hi_score", smlua_func_set_got_file_coin_hi_score);
|
||||
smlua_bind_function(L, "network_switch_to_server", smlua_func_network_switch_to_server);
|
||||
smlua_bind_function(L, "network_get_current_port", smlua_func_network_get_current_port);
|
||||
smlua_bind_function(L, "network_get_current_ip", smlua_func_network_get_current_ip);
|
||||
smlua_bind_function(L, "network_is_client", smlua_func_network_is_client);
|
||||
smlua_bind_function(L, "network_set_bungee_fallback_port", smlua_func_network_set_bungee_fallback_port);
|
||||
smlua_bind_function(L, "network_get_bungee_fallback_port", smlua_func_network_get_bungee_fallback_port);
|
||||
smlua_bind_function(L, "network_is_bungee_switching", smlua_func_network_is_bungee_switching);
|
||||
smlua_bind_function(L, "network_set_server_fallback_port", smlua_func_network_set_server_fallback_port);
|
||||
smlua_bind_function(L, "network_get_server_fallback_port", smlua_func_network_get_server_fallback_port);
|
||||
smlua_bind_function(L, "get_save_file_modified", smlua_func_get_save_file_modified);
|
||||
smlua_bind_function(L, "set_save_file_modified", smlua_func_set_save_file_modified);
|
||||
smlua_bind_function(L, "hud_hide", smlua_func_hud_hide);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
#include "pc/mods/mods.h"
|
||||
#include "pc/mods/mods_utils.h"
|
||||
#include "pc/pc_main.h"
|
||||
#include "pc/network/network.h"
|
||||
#include "pc/configfile.h"
|
||||
#include "game/object_list_processor.h"
|
||||
#include "game/rendering_graph_node.h"
|
||||
#include "game/level_update.h"
|
||||
|
|
@ -623,6 +625,60 @@ const char* get_os_name(void) {
|
|||
}
|
||||
|
||||
///
|
||||
// BungeeCord64 Network Switching Functions
|
||||
// Enables switching between multiple SM64CoopDX servers in local network
|
||||
///
|
||||
|
||||
bool network_switch_to_server(u32 port) {
|
||||
// Only allow switching when acting as a client.
|
||||
if (gNetworkType != NT_CLIENT) {
|
||||
LOG_INFO("BungeeCord64: Cannot switch server - not connected as client");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (port == 0) {
|
||||
LOG_INFO("BungeeCord64: Cannot switch server - invalid port 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if already reconnecting
|
||||
if (network_is_reconnecting()) {
|
||||
LOG_INFO("BungeeCord64: Reconnect already in progress");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("BungeeCord64: Switching to server on port %u", port);
|
||||
|
||||
// Use the standard reconnect flow with the normal connect screen
|
||||
network_bungee_switch_begin(port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 network_get_current_port(void) {
|
||||
if (gNetworkType == NT_CLIENT) {
|
||||
return configJoinPort;
|
||||
} else if (gNetworkType == NT_SERVER) {
|
||||
return configHostPort;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* network_get_current_ip(void) {
|
||||
static char currentIp[MAX_CONFIG_STRING] = "";
|
||||
if (gNetworkType == NT_CLIENT) {
|
||||
snprintf(currentIp, MAX_CONFIG_STRING, "%s", configJoinIp);
|
||||
return currentIp;
|
||||
} else if (gNetworkType == NT_SERVER) {
|
||||
snprintf(currentIp, MAX_CONFIG_STRING, "localhost");
|
||||
return currentIp;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool network_is_client(void) {
|
||||
return gNetworkType == NT_CLIENT;
|
||||
}
|
||||
|
||||
struct GraphNodeRoot* geo_get_current_root(void) {
|
||||
return gCurGraphNodeRoot;
|
||||
|
|
|
|||
|
|
@ -248,6 +248,16 @@ void reset_window_title(void);
|
|||
/* |description|Gets the name of the operating system the game is running on|descriptionEnd| */
|
||||
const char* get_os_name(void);
|
||||
|
||||
// BungeeCord64 - Network Switching Functions for local server hopping
|
||||
/* |description|[BungeeCord64] Switches to a different server on localhost with the specified port. Returns true if switch was initiated successfully. Only works when connected as client, not as server host|descriptionEnd| */
|
||||
bool network_switch_to_server(u32 port);
|
||||
/* |description|[BungeeCord64] Gets the current server port the client is connected to or hosting on. Returns 0 if not connected|descriptionEnd| */
|
||||
u32 network_get_current_port(void);
|
||||
/* |description|[BungeeCord64] Gets the current connection IP address as a string. Returns empty string if not connected|descriptionEnd| */
|
||||
const char* network_get_current_ip(void);
|
||||
/* |description|[BungeeCord64] Checks if the player is currently connected to a server as a client|descriptionEnd| */
|
||||
bool network_is_client(void);
|
||||
|
||||
/* |description|Gets the current GraphNodeRoot|descriptionEnd|*/
|
||||
struct GraphNodeRoot* geo_get_current_root(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,16 @@ u32 gNetworkStartupTimer = 0;
|
|||
u32 sNetworkReconnectTimer = 0;
|
||||
u32 sNetworkRehostTimer = 0;
|
||||
enum NetworkSystemType sNetworkReconnectType = NS_SOCKET;
|
||||
static u32 sBungeeFallbackPort = 0;
|
||||
|
||||
// BungeeCord64: Timer for connection timeout during switch
|
||||
// If connection isn't established within this time, try fallback port
|
||||
static u32 sBungeeConnectionTimer = 0;
|
||||
static u32 sBungeeTargetPort = 0;
|
||||
static u32 sBungeePendingSwitchPort = 0; // Port to switch to (delayed execution)
|
||||
static u32 sBungeePreviousFallbackPort = 0; // Fallback port before switch (in case new server doesn't send one)
|
||||
static u32 sBungeeFirstServerPort = 0; // The first server port we connected to (used as ultimate fallback)
|
||||
#define BUNGEE_CONNECTION_TIMEOUT (15 * 30) // 15 seconds
|
||||
|
||||
struct ServerSettings gServerSettings = {
|
||||
.playerInteractions = PLAYER_INTERACTIONS_SOLID,
|
||||
|
|
@ -453,6 +463,30 @@ void network_reset_reconnect_and_rehost(void) {
|
|||
sNetworkReconnectType = NS_SOCKET;
|
||||
}
|
||||
|
||||
u32 network_get_bungee_fallback_port(void) {
|
||||
// Return current fallback port, or previous one if current is not set
|
||||
// Fall back to first server port as ultimate fallback
|
||||
if (sBungeeFallbackPort != 0) {
|
||||
return sBungeeFallbackPort;
|
||||
}
|
||||
if (sBungeePreviousFallbackPort != 0) {
|
||||
return sBungeePreviousFallbackPort;
|
||||
}
|
||||
return sBungeeFirstServerPort;
|
||||
}
|
||||
|
||||
void network_set_bungee_first_server_port(u32 port) {
|
||||
// Only set if not already set (first connection)
|
||||
if (sBungeeFirstServerPort == 0 && port != 0) {
|
||||
sBungeeFirstServerPort = port;
|
||||
LOG_INFO("BungeeCord64: First server port set to %u", port);
|
||||
}
|
||||
}
|
||||
|
||||
void network_set_bungee_fallback_port(u32 port) {
|
||||
sBungeeFallbackPort = port;
|
||||
}
|
||||
|
||||
void network_reconnect_begin(void) {
|
||||
if (sNetworkReconnectTimer > 0) {
|
||||
return;
|
||||
|
|
@ -492,6 +526,136 @@ bool network_is_reconnecting(void) {
|
|||
return sNetworkReconnectTimer > 0;
|
||||
}
|
||||
|
||||
|
||||
// =====================================================
|
||||
// BungeeCord64 Simple Server Switch
|
||||
// =====================================================
|
||||
// Uses the standard reconnect flow with the default connect screen.
|
||||
// If the target server is offline, automatically tries the fallback port.
|
||||
// Switch is delayed by 1 frame to avoid crashes when called from Lua callbacks.
|
||||
|
||||
void network_bungee_switch_begin(u32 targetPort) {
|
||||
if (targetPort == 0) {
|
||||
LOG_ERROR("BungeeCord64: Invalid target port 0");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sNetworkReconnectTimer > 0 || sBungeePendingSwitchPort != 0) {
|
||||
LOG_INFO("BungeeCord64: Switch already in progress");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("BungeeCord64: Scheduling switch to port %u", targetPort);
|
||||
|
||||
// Schedule the switch for next frame (avoids crash when called from Lua callback)
|
||||
sBungeePendingSwitchPort = targetPort;
|
||||
}
|
||||
|
||||
// Actually performs the switch - called from network_update
|
||||
static void network_bungee_execute_pending_switch(void) {
|
||||
if (sBungeePendingSwitchPort == 0) { return; }
|
||||
|
||||
u32 targetPort = sBungeePendingSwitchPort;
|
||||
sBungeePendingSwitchPort = 0;
|
||||
|
||||
LOG_INFO("BungeeCord64: Executing switch to port %u", targetPort);
|
||||
|
||||
// Save current fallback port before switch (in case new server doesn't send one)
|
||||
if (sBungeeFallbackPort != 0) {
|
||||
sBungeePreviousFallbackPort = sBungeeFallbackPort;
|
||||
LOG_INFO("BungeeCord64: Saved previous fallback port %u", sBungeePreviousFallbackPort);
|
||||
}
|
||||
|
||||
// Save current port as first server port if not already set
|
||||
// This ensures we have a fallback to the original server
|
||||
if (sBungeeFirstServerPort == 0) {
|
||||
sBungeeFirstServerPort = configJoinPort;
|
||||
LOG_INFO("BungeeCord64: Saved first server port %u", sBungeeFirstServerPort);
|
||||
}
|
||||
|
||||
// Save target port and start connection timer
|
||||
sBungeeTargetPort = targetPort;
|
||||
sBungeeConnectionTimer = BUNGEE_CONNECTION_TIMEOUT;
|
||||
|
||||
// Update config for new connection (localhost only for BungeeCord)
|
||||
snprintf(configJoinIp, MAX_CONFIG_STRING, "127.0.0.1");
|
||||
configJoinPort = targetPort;
|
||||
|
||||
// Set up reconnect timer
|
||||
sNetworkReconnectTimer = 2 * 30;
|
||||
sNetworkReconnectType = NS_SOCKET;
|
||||
|
||||
// IMPORTANT: Send leave packet so old server knows we're leaving
|
||||
// and use reconnecting=false so mods get properly unloaded
|
||||
network_shutdown(true, false, false, false); // sendLeaving=true, reconnecting=false
|
||||
|
||||
// Open connect menu
|
||||
djui_connect_menu_open();
|
||||
}
|
||||
|
||||
// Called from network_update to check for connection timeout
|
||||
static void network_bungee_connection_timeout_update(void) {
|
||||
if (sBungeeConnectionTimer == 0) { return; }
|
||||
|
||||
// If we're connected, cancel the timer
|
||||
if (gNetworkType == NT_CLIENT && gNetworkSentJoin) {
|
||||
LOG_INFO("BungeeCord64: Connection established, canceling timeout");
|
||||
sBungeeConnectionTimer = 0;
|
||||
sBungeeTargetPort = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Countdown
|
||||
sBungeeConnectionTimer--;
|
||||
|
||||
// If timer expired and we're still not connected, try fallback
|
||||
if (sBungeeConnectionTimer == 0) {
|
||||
u32 fbPort = network_get_bungee_fallback_port();
|
||||
|
||||
// Only try fallback if it's different from what we tried
|
||||
if (fbPort != 0 && fbPort != sBungeeTargetPort) {
|
||||
LOG_INFO("BungeeCord64: Connection to port %u timed out, trying fallback port %u",
|
||||
sBungeeTargetPort, fbPort);
|
||||
|
||||
sBungeeTargetPort = 0;
|
||||
|
||||
// Update config for fallback connection
|
||||
snprintf(configJoinIp, MAX_CONFIG_STRING, "127.0.0.1");
|
||||
configJoinPort = fbPort;
|
||||
|
||||
// Restart reconnect to fallback
|
||||
network_reconnect_begin();
|
||||
} else {
|
||||
LOG_INFO("BungeeCord64: Connection timed out, no fallback available");
|
||||
sBungeeTargetPort = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void network_bungee_switch_complete(void) {
|
||||
// Cancel connection timer on successful connection
|
||||
sBungeeConnectionTimer = 0;
|
||||
sBungeeTargetPort = 0;
|
||||
}
|
||||
|
||||
bool network_is_bungee_switching(void) {
|
||||
// Check if we're reconnecting, waiting for connection, or have a pending switch
|
||||
return sNetworkReconnectTimer > 0 || sBungeeConnectionTimer > 0 || sBungeePendingSwitchPort != 0;
|
||||
}
|
||||
|
||||
u8 network_get_bungee_switch_phase(void) {
|
||||
// Return 0 (no custom phases anymore)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 network_get_bungee_switch_target(void) {
|
||||
// Return the target port we're trying to connect to
|
||||
if (sBungeeTargetPort != 0) {
|
||||
return sBungeeTargetPort;
|
||||
}
|
||||
return configJoinPort;
|
||||
}
|
||||
|
||||
void network_rehost_begin(void) {
|
||||
for (int i = 1; i < MAX_PLAYERS; i++) {
|
||||
struct NetworkPlayer* np = &gNetworkPlayers[i];
|
||||
|
|
@ -562,8 +726,12 @@ void network_update(void) {
|
|||
gNetworkStartupTimer--;
|
||||
}
|
||||
|
||||
// Execute pending BungeeCord switch (delayed to avoid Lua callback crash)
|
||||
network_bungee_execute_pending_switch();
|
||||
|
||||
network_rehost_update();
|
||||
network_reconnect_update();
|
||||
network_bungee_connection_timeout_update();
|
||||
|
||||
#ifdef COOPNET
|
||||
network_update_coopnet();
|
||||
|
|
@ -701,6 +869,21 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup, bool reconnect
|
|||
|
||||
dynos_model_clear_pool(MODEL_POOL_SESSION);
|
||||
|
||||
// When reconnecting, keep Lua and mods alive so that calls originating
|
||||
// from Lua (e.g. BungeeCord64) do not destroy the VM mid-execution.
|
||||
// We still fully reset the graphics/game state below.
|
||||
if (!reconnecting) {
|
||||
camera_reset_overrides();
|
||||
romhack_camera_reset_settings();
|
||||
free_vtx_scroll_targets();
|
||||
dynos_mod_shutdown();
|
||||
mods_clear(&gActiveMods);
|
||||
mods_clear(&gRemoteMods);
|
||||
smlua_shutdown();
|
||||
} else {
|
||||
free_vtx_scroll_targets();
|
||||
}
|
||||
|
||||
// reset other stuff
|
||||
extern u8* gOverrideEeprom;
|
||||
gOverrideEeprom = NULL;
|
||||
|
|
@ -726,13 +909,6 @@ void network_shutdown(bool sendLeaving, bool exiting, bool popup, bool reconnect
|
|||
gRomhackCameraSettings.centering = FALSE;
|
||||
gOverrideAllowToxicGasCamera = FALSE;
|
||||
gRomhackCameraSettings.dpad = FALSE;
|
||||
camera_reset_overrides();
|
||||
romhack_camera_reset_settings();
|
||||
free_vtx_scroll_targets();
|
||||
dynos_mod_shutdown();
|
||||
mods_clear(&gActiveMods);
|
||||
mods_clear(&gRemoteMods);
|
||||
smlua_shutdown();
|
||||
extern s16 gChangeLevel;
|
||||
gChangeLevel = LEVEL_CASTLE_GROUNDS;
|
||||
network_player_init();
|
||||
|
|
|
|||
|
|
@ -130,5 +130,14 @@ bool network_allow_mod_dev_mode(void);
|
|||
void network_mod_dev_mode_reload(void);
|
||||
void network_update(void);
|
||||
void network_shutdown(bool sendLeaving, bool exiting, bool popup, bool reconnecting);
|
||||
u32 network_get_bungee_fallback_port(void);
|
||||
void network_set_bungee_fallback_port(u32 port);
|
||||
void network_set_bungee_first_server_port(u32 port);
|
||||
|
||||
// BungeeCord64 simple server switching (uses standard reconnect)
|
||||
void network_bungee_switch_begin(u32 targetPort);
|
||||
void network_bungee_switch_complete(void);
|
||||
bool network_is_bungee_switching(void);
|
||||
u8 network_get_bungee_switch_phase(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "pc/djui/djui.h"
|
||||
#include "pc/debuglog.h"
|
||||
#include "pc/utils/misc.h"
|
||||
#include "pc/configfile.h"
|
||||
#include "game/area.h"
|
||||
#include "game/level_info.h"
|
||||
#include "game/hardcoded.h"
|
||||
|
|
@ -243,8 +244,22 @@ void network_player_update(void) {
|
|||
#else
|
||||
if (elapsed > NETWORK_PLAYER_TIMEOUT * 1.5f) {
|
||||
#endif
|
||||
LOG_INFO("dropping due to no server connectivity");
|
||||
network_shutdown(false, false, true, false);
|
||||
// Don't trigger disconnect handling if we're in the middle of a BungeeCord switch
|
||||
if (network_is_bungee_switching()) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 fbPort = network_get_bungee_fallback_port();
|
||||
LOG_INFO("BungeeCord64: Server timeout - fallback port: %u, current port: %u", fbPort, configJoinPort);
|
||||
|
||||
if (fbPort != 0 && fbPort != configJoinPort) {
|
||||
LOG_INFO("BungeeCord64: Auto-reconnecting to fallback port %u", fbPort);
|
||||
// Use BungeeCord switch mechanism for proper fallback handling
|
||||
network_bungee_switch_begin(fbPort);
|
||||
} else {
|
||||
LOG_INFO("dropping due to no server connectivity (no fallback configured)");
|
||||
network_shutdown(false, false, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
elapsed = (clock_elapsed() - np->lastSent);
|
||||
|
|
@ -373,7 +388,17 @@ u8 network_player_disconnected(u8 globalIndex) {
|
|||
LOG_ERROR("player disconnected, but it's local.. this shouldn't happen!");
|
||||
return UNKNOWN_GLOBAL_INDEX;
|
||||
} else {
|
||||
network_shutdown(true, false, true, false);
|
||||
// BungeeCord64: Try to fallback to another server instead of just disconnecting
|
||||
u32 fbPort = network_get_bungee_fallback_port();
|
||||
LOG_INFO("BungeeCord64: Server disconnected - fallback port: %u, current port: %u", fbPort, configJoinPort);
|
||||
|
||||
if (fbPort != 0 && fbPort != configJoinPort) {
|
||||
LOG_INFO("BungeeCord64: Auto-reconnecting to fallback port %u", fbPort);
|
||||
network_bungee_switch_begin(fbPort);
|
||||
} else {
|
||||
network_shutdown(true, false, true, false);
|
||||
}
|
||||
return UNKNOWN_GLOBAL_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -139,6 +139,9 @@ void packet_process(struct Packet* p) {
|
|||
case PACKET_LUA_CUSTOM: network_receive_lua_custom(p); break;
|
||||
case PACKET_LUA_CUSTOM_BYTESTRING: network_receive_lua_custom_bytestring(p); break;
|
||||
|
||||
// BungeeCord64
|
||||
case PACKET_BUNGEE_FALLBACK: network_receive_bungee_fallback(p); break;
|
||||
|
||||
// custom
|
||||
case PACKET_CUSTOM: network_receive_custom(p); break;
|
||||
default: LOG_ERROR("received unknown packet: %d", p->buffer[0]);
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ enum PacketType {
|
|||
|
||||
PACKET_COMMAND,
|
||||
PACKET_MODERATOR,
|
||||
|
||||
// BungeeCord64 - Server sends fallback port to client
|
||||
PACKET_BUNGEE_FALLBACK,
|
||||
|
||||
///
|
||||
PACKET_CUSTOM = 255,
|
||||
|
|
@ -384,4 +387,12 @@ void network_receive_lua_custom(struct Packet* p);
|
|||
void network_send_lua_custom_bytestring(bool broadcast);
|
||||
void network_receive_lua_custom_bytestring(struct Packet* p);
|
||||
|
||||
// packet_bungee_fallback.c
|
||||
void network_set_server_fallback_port(u32 port);
|
||||
u32 network_get_server_fallback_port(void);
|
||||
void network_send_bungee_fallback(u8 toLocalIndex, u32 fallbackPort);
|
||||
void network_send_bungee_fallback_request(void);
|
||||
void network_receive_bungee_fallback(struct Packet* p);
|
||||
void network_receive_bungee_fallback_request(struct Packet* p);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
77
src/pc/network/packets/packet_bungee_fallback.c
Normal file
77
src/pc/network/packets/packet_bungee_fallback.c
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// BungeeCord64 - Fallback Port Packet
|
||||
// Server sends its fallback port to clients so they know where to reconnect
|
||||
// if the server crashes unexpectedly.
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../network.h"
|
||||
#include "pc/debuglog.h"
|
||||
#include "pc/configfile.h"
|
||||
|
||||
// Server-side: configured fallback port (where clients should go if this server dies)
|
||||
// This can be set via server config or command
|
||||
static u32 sServerFallbackPort = 0;
|
||||
|
||||
void network_set_server_fallback_port(u32 port) {
|
||||
sServerFallbackPort = port;
|
||||
LOG_INFO("BungeeCord64: Server fallback port set to %u", port);
|
||||
}
|
||||
|
||||
u32 network_get_server_fallback_port(void) {
|
||||
return sServerFallbackPort;
|
||||
}
|
||||
|
||||
// Server sends fallback port to a specific client
|
||||
void network_send_bungee_fallback(u8 toLocalIndex, u32 fallbackPort) {
|
||||
if (gNetworkType != NT_SERVER) { return; }
|
||||
|
||||
struct Packet p = { 0 };
|
||||
packet_init(&p, PACKET_BUNGEE_FALLBACK, true, PLMT_NONE);
|
||||
packet_write(&p, &fallbackPort, sizeof(u32));
|
||||
|
||||
network_send_to(toLocalIndex, &p);
|
||||
LOG_INFO("BungeeCord64: Sent fallback port %u to player %d", fallbackPort, toLocalIndex);
|
||||
}
|
||||
|
||||
// Client requests fallback port from server
|
||||
void network_send_bungee_fallback_request(void) {
|
||||
if (gNetworkType != NT_CLIENT) { return; }
|
||||
|
||||
struct Packet p = { 0 };
|
||||
packet_init(&p, PACKET_BUNGEE_FALLBACK, true, PLMT_NONE);
|
||||
|
||||
// Empty packet = request
|
||||
u32 zero = 0;
|
||||
packet_write(&p, &zero, sizeof(u32));
|
||||
|
||||
network_send_to(PACKET_DESTINATION_SERVER, &p);
|
||||
LOG_INFO("BungeeCord64: Requesting fallback port from server");
|
||||
}
|
||||
|
||||
// Server receives request, Client receives fallback port
|
||||
void network_receive_bungee_fallback(struct Packet* p) {
|
||||
u32 port = 0;
|
||||
packet_read(p, &port, sizeof(u32));
|
||||
|
||||
if (gNetworkType == NT_SERVER) {
|
||||
// This is a request from a client
|
||||
if (sServerFallbackPort != 0) {
|
||||
network_send_bungee_fallback(p->localIndex, sServerFallbackPort);
|
||||
} else {
|
||||
LOG_INFO("BungeeCord64: Client requested fallback port, but none configured on this server");
|
||||
}
|
||||
} else if (gNetworkType == NT_CLIENT) {
|
||||
// This is the server sending us the fallback port
|
||||
if (port != 0) {
|
||||
network_set_bungee_fallback_port(port);
|
||||
LOG_INFO("BungeeCord64: Received fallback port %u from server", port);
|
||||
} else {
|
||||
LOG_INFO("BungeeCord64: Server has no fallback port configured, keeping previous: %u",
|
||||
network_get_bungee_fallback_port());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alias for backwards compatibility
|
||||
void network_receive_bungee_fallback_request(struct Packet* p) {
|
||||
network_receive_bungee_fallback(p);
|
||||
}
|
||||
|
|
@ -200,7 +200,18 @@ void network_receive_join(struct Packet* p) {
|
|||
network_send_network_players_request();
|
||||
network_send_lua_sync_table_request();
|
||||
|
||||
// BungeeCord64: Save the first server port as ultimate fallback
|
||||
// This ensures we always have a fallback even if no server configures one
|
||||
network_set_bungee_first_server_port(configJoinPort);
|
||||
|
||||
// BungeeCord64: Request fallback port from server
|
||||
network_send_bungee_fallback_request();
|
||||
|
||||
gCurrentlyJoining = false;
|
||||
|
||||
// Complete BungeeCord switch if one was in progress
|
||||
network_bungee_switch_complete();
|
||||
|
||||
smlua_call_event_hooks(HOOK_JOINED_GAME);
|
||||
extern s16 gChangeLevel;
|
||||
gChangeLevel = gLevelValues.entryLevel;
|
||||
|
|
|
|||
34
start_bungeecord64_test.bat
Normal file
34
start_bungeecord64_test.bat
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
@echo off
|
||||
REM =====================================================
|
||||
REM BungeeCord64 Test Environment Launcher
|
||||
REM =====================================================
|
||||
REM This script launches 4 instances of SM64CoopDX:
|
||||
REM - Server 1 on port 7777 (Main Server)
|
||||
REM - Server 2 on port 7778
|
||||
REM - Server 3 on port 7779
|
||||
REM - Player/Client instance (starts normally, join via menu)
|
||||
REM =====================================================
|
||||
|
||||
REM Set the path to the executable (adjust if needed)
|
||||
SET GAME_EXE=build\us_pc\sm64coopdx.exe
|
||||
|
||||
REM Check if executable exists
|
||||
if not exist "%GAME_EXE%" (
|
||||
echo ERROR: Game executable not found at %GAME_EXE%
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM Start all servers and player without showing console windows
|
||||
start "" /min "%GAME_EXE%" --server 7777 --skip-intro --configfile config_server_7777.txt
|
||||
timeout /t 2 /nobreak > nul
|
||||
|
||||
start "" /min "%GAME_EXE%" --server 7778 --skip-intro --configfile config_server_7778.txt
|
||||
timeout /t 2 /nobreak > nul
|
||||
|
||||
start "" /min "%GAME_EXE%" --server 7779 --skip-intro --configfile config_server_7779.txt
|
||||
timeout /t 2 /nobreak > nul
|
||||
|
||||
start "" "%GAME_EXE%" --configfile config_player.txt
|
||||
|
||||
exit
|
||||
Loading…
Add table
Reference in a new issue