2 * Whether we are attempting to join or host a game.
4 var g_IsConnecting = false;
12 * Server title shown in the lobby gamelist.
14 var g_ServerName = "";
17 * Cached to pass it to the gamesetup of the controller to report the game to the lobby.
21 var g_IsRejoining = false;
22 var g_GameAttributes; // used when rejoining
23 var g_PlayerAssignments; // used when rejoining
27 * Object containing the IP address and port of the STUN server.
31 function init(attribs)
33 g_UserRating = attribs.rating;
35 switch (attribs.multiplayerGameType)
39 if (Engine.HasXmppClient())
41 if (startJoin(attribs.name, attribs.ip, getValidPort(attribs.port), attribs.useSTUN, attribs.hostJID))
42 switchSetupPage("pageConnecting");
45 switchSetupPage("pageJoin");
50 Engine.GetGUIObjectByName("hostSTUNWrapper").hidden = !Engine.HasXmppClient();
51 if (Engine.HasXmppClient())
53 Engine.GetGUIObjectByName("hostPlayerName").caption = attribs.name;
54 Engine.GetGUIObjectByName("hostServerName").caption =
55 sprintf(translate("%(name)s's game"), { "name": attribs.name });
57 Engine.GetGUIObjectByName("useSTUN").checked = Engine.ConfigDB_GetValue("user", "lobby.stun.enabled") == "true";
60 switchSetupPage("pageHost");
64 error("Unrecognised multiplayer game type: " + attribs.multiplayerGameType);
69 function cancelSetup()
72 Engine.DisconnectNetworkGame();
74 if (Engine.HasXmppClient())
75 Engine.LobbySetPlayerPresence("available");
77 // Keep the page open if an attempt to join/host by ip failed
78 if (!g_IsConnecting || (Engine.HasXmppClient() && g_GameType == "client"))
84 g_IsConnecting = false;
85 Engine.GetGUIObjectByName("hostFeedback").caption = "";
87 if (g_GameType == "client")
88 switchSetupPage("pageJoin");
89 else if (g_GameType == "server")
90 switchSetupPage("pageHost");
92 error("cancelSetup: Unrecognised multiplayer game type: " + g_GameType);
95 function confirmSetup()
97 if (!Engine.GetGUIObjectByName("pageJoin").hidden)
99 let joinPlayerName = Engine.GetGUIObjectByName("joinPlayerName").caption;
100 let joinServer = Engine.GetGUIObjectByName("joinServer").caption;
101 let joinPort = Engine.GetGUIObjectByName("joinPort").caption;
103 if (startJoin(joinPlayerName, joinServer, getValidPort(joinPort), false))
104 switchSetupPage("pageConnecting");
106 else if (!Engine.GetGUIObjectByName("pageHost").hidden)
108 let hostPlayerName = Engine.GetGUIObjectByName("hostPlayerName").caption;
109 let hostServerName = Engine.GetGUIObjectByName("hostServerName").caption;
110 let hostPort = Engine.GetGUIObjectByName("hostPort").caption;
114 Engine.GetGUIObjectByName("hostFeedback").caption = translate("Please enter a valid server name.");
118 if (getValidPort(hostPort) != +hostPort)
120 Engine.GetGUIObjectByName("hostFeedback").caption = sprintf(
121 translate("Server port number must be between %(min)s and %(max)s."), {
122 "min": g_ValidPorts.min,
123 "max": g_ValidPorts.max
128 if (startHost(hostPlayerName, hostServerName, getValidPort(hostPort)))
129 switchSetupPage("pageConnecting");
133 function startConnectionStatus(type)
136 g_IsConnecting = true;
137 g_IsRejoining = false;
138 Engine.GetGUIObjectByName("connectionStatus").caption = translate("Connecting to server...");
146 pollAndHandleNetworkClient();
149 function pollAndHandleNetworkClient()
153 var message = Engine.PollNetworkClient();
157 log(sprintf(translate("Net message: %(message)s"), { "message": uneval(message) }));
159 // If we're rejoining an active game, we don't want to actually display
160 // the game setup screen, so perform similar processing to gamesetup.js
163 switch (message.type)
166 switch (message.status)
170 reportDisconnect(message.reason, false);
174 error("Unrecognised netstatus type: " + message.status);
180 g_GameAttributes = message.data;
184 g_PlayerAssignments = message.newAssignments;
188 // Copy playernames from initial player assignment to the settings
189 for (let guid in g_PlayerAssignments)
191 let player = g_PlayerAssignments[guid];
192 if (player.player > 0) // not observer or GAIA
193 g_GameAttributes.settings.PlayerData[player.player - 1].Name = player.name;
196 Engine.SwitchGuiPage("page_loading.xml", {
197 "attribs": g_GameAttributes,
198 "isRejoining": g_IsRejoining,
199 "playerAssignments": g_PlayerAssignments
210 error("Unrecognised net message type: " + message.type);
213 // Not rejoining - just trying to connect to server
215 switch (message.type)
218 switch (message.status)
221 Engine.GetGUIObjectByName("connectionStatus").caption = translate("Registering with server...");
224 case "authenticated":
225 if (message.rejoining)
227 Engine.GetGUIObjectByName("connectionStatus").caption = translate("Game has already started, rejoining...");
228 g_IsRejoining = true;
229 return; // we'll process the game setup messages in the next tick
231 Engine.SwitchGuiPage("page_gamesetup.xml", {
233 "serverName": g_ServerName,
234 "serverPort": g_ServerPort,
235 "stunEndpoint": g_StunEndpoint
237 return; // don't process any more messages - leave them for the game GUI loop
241 reportDisconnect(message.reason, false);
245 error("Unrecognised netstatus type: " + message.status);
254 error("Unrecognised net message type: " + message.type);
260 function switchSetupPage(newPage)
262 let multiplayerPages = Engine.GetGUIObjectByName("multiplayerPages");
263 for (let page of multiplayerPages.children)
264 if (page.name.startsWith("page"))
267 if (newPage == "pageJoin" || newPage == "pageHost")
269 let pageSize = multiplayerPages.size;
270 let halfHeight = newPage == "pageJoin" ? 130 : Engine.HasXmppClient() ? 125 : 110;
271 pageSize.top = -halfHeight;
272 pageSize.bottom = halfHeight;
273 multiplayerPages.size = pageSize;
276 Engine.GetGUIObjectByName(newPage).hidden = false;
278 Engine.GetGUIObjectByName("hostPlayerNameWrapper").hidden = Engine.HasXmppClient();
279 Engine.GetGUIObjectByName("hostServerNameWrapper").hidden = !Engine.HasXmppClient();
281 Engine.GetGUIObjectByName("continueButton").hidden = newPage == "pageConnecting";
284 function startHost(playername, servername, port)
286 startConnectionStatus("server");
288 saveSettingAndWriteToUserConfig("playername.multiplayer", playername);
290 saveSettingAndWriteToUserConfig("multiplayerhosting.port", port);
292 let hostFeedback = Engine.GetGUIObjectByName("hostFeedback");
294 // Disallow identically named games in the multiplayer lobby
295 if (Engine.HasXmppClient() &&
296 Engine.GetGameList().some(game => game.name == servername))
299 hostFeedback.caption = translate("Game name already in use.");
303 if (Engine.HasXmppClient() && Engine.GetGUIObjectByName("useSTUN").checked)
305 g_StunEndpoint = Engine.FindStunEndpoint(port);
309 hostFeedback.caption = translate("Failed to host via STUN.");
316 Engine.StartNetworkHost(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), port, playername);
323 sprintf(translate("Cannot host game: %(message)s."), { "message": e.message }),
329 g_ServerName = servername;
332 if (Engine.HasXmppClient())
333 Engine.LobbySetPlayerPresence("playing");
339 * Connects via STUN if the hostJID is given.
341 function startJoin(playername, ip, port, useSTUN, hostJID = "")
345 Engine.StartNetworkJoin(playername + (g_UserRating ? " (" + g_UserRating + ")" : ""), ip, port, useSTUN, hostJID);
352 sprintf(translate("Cannot join game: %(message)s."), { "message": e.message }),
358 startConnectionStatus("client");
360 if (Engine.HasXmppClient())
361 Engine.LobbySetPlayerPresence("playing");
364 // Only save the player name and host address if they're valid and we're not in the lobby
365 saveSettingAndWriteToUserConfig("playername.multiplayer", playername);
366 saveSettingAndWriteToUserConfig("multiplayerserver", ip);
367 saveSettingAndWriteToUserConfig("multiplayerjoining.port", port);
372 function getDefaultGameName()
374 return sprintf(translate("%(playername)s's game"), {
375 "playername": multiplayerName()