Ticket #1950: pausing5.patch
File pausing5.patch, 20.0 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/gui/common/functions_global_object.js
139 139 let messages = []; 140 140 let maxTextWidth = 0; 141 141 142 // TODO: Players who paused the game should be added here143 144 142 // Add network warnings 145 143 if (Engine.ConfigDB_GetValue("user", "overlay.netwarnings") == "true") 146 144 { -
binaries/data/mods/public/gui/credits/texts/programming.json
57 57 {"nick": "dumbo"}, 58 58 {"nick": "dvangennip", "name": "Doménique"}, 59 59 {"nick": "Echelon9", "name": "Rhys Kidd"}, 60 {"nick": "echotangoecho"}, 60 61 {"nick": "eihrul", "name": "Lee Salzman"}, 61 62 {"nick": "elexis", "name": "Alexander Heinsius"}, 62 63 {"nick": "EmjeR", "name": "Matthijs de Rijk"}, -
binaries/data/mods/public/gui/session/menu.js
666 666 } 667 667 668 668 /** 669 * Pause the game in single player mode. 669 * Pause or resume the game. 670 * 671 * @param explicit true if the player explicitly wants to pause or resume. 672 * If this argument isn't set, a multiplayer game won't be paused and the pause overlay 673 * won't be shown. 670 674 */ 671 function pauseGame( )675 function pauseGame(pause = true, explicit = false) 672 676 { 677 if (g_IsNetworked && !explicit) 678 return; 679 680 if (explicit) 681 g_Paused = pause; 682 683 Engine.SetPaused(g_Paused || pause, explicit); 684 673 685 if (g_IsNetworked) 686 { 687 setClientPauseState(Engine.GetPlayerGUID(), g_Paused); 674 688 return; 689 } 675 690 676 Engine.GetGUIObjectByName("pauseButtonText").caption = translate("Resume"); 677 Engine.GetGUIObjectByName("pauseOverlay").hidden = false; 678 Engine.SetPaused(true); 691 updatePauseOverlay(); 679 692 } 680 693 681 function resumeGame() 694 /** 695 * Resume the game. 696 * 697 * @param explicit true if the player explicitly wants to resume the game. 698 * If this argument isn't set, a multiplayer game won't be resumed and the pause overlay won't 699 * be closed. 700 */ 701 function resumeGame(explicit = false) 682 702 { 683 Engine.GetGUIObjectByName("pauseButtonText").caption = translate("Pause"); 684 Engine.GetGUIObjectByName("pauseOverlay").hidden = true; 685 Engine.SetPaused(false); 703 pauseGame(false, explicit); 686 704 } 687 705 706 /** 707 * Called when the current player toggles a pause button. 708 */ 688 709 function togglePause() 689 710 { 690 711 if (!Engine.GetGUIObjectByName("pauseButton").enabled) … … 692 713 693 714 closeOpenDialogs(); 694 715 695 let pauseOverlay = Engine.GetGUIObjectByName("pauseOverlay"); 716 pauseGame(!g_Paused, true); 717 } 696 718 697 Engine.SetPaused(pauseOverlay.hidden); 698 Engine.GetGUIObjectByName("pauseButtonText").caption = pauseOverlay.hidden ? translate("Resume") : translate("Pause"); 719 /** 720 * Called when a client pauses or resumes in a multiplayer game. 721 */ 722 function setClientPauseState(guid, paused) 723 { 724 // Update the list of pausing clients. 725 let index = g_PausingClients.indexOf(guid) 726 if (paused && index == -1) 727 g_PausingClients.push(guid); 728 else if (!paused && index != -1) 729 g_PausingClients.splice(index, 1); 699 730 700 pauseOverlay.hidden = !pauseOverlay.hidden; 731 updatePauseOverlay(g_PausingClients.length); 732 733 Engine.SetPaused(!!g_PausingClients.length, false); 701 734 } 702 735 736 /** 737 * Update the pause overlay. 738 */ 739 function updatePauseOverlay() 740 { 741 Engine.GetGUIObjectByName("pauseOverlay").hidden = !(g_Paused || g_PausingClients.length); 742 Engine.GetGUIObjectByName("pauseButtonText").caption = g_Paused ? translate("Resume") : translate("Pause"); 743 Engine.GetGUIObjectByName("resumeMessage").hidden = !g_Paused; 744 Engine.GetGUIObjectByName("pausedByText").hidden = !g_IsNetworked; 745 Engine.GetGUIObjectByName("pausedByText").caption = translate("Paused by") + " " + 746 g_PausingClients.map(guid => colorizePlayernameByGUID(guid)).join(translate(", ")); 747 Engine.GetGUIObjectByName("pauseOverlay").onPress = g_Paused ? togglePause : function() {}; 748 } 749 703 750 function openManual() 704 751 { 705 752 closeOpenDialogs(); -
binaries/data/mods/public/gui/session/messages.js
31 31 "netstatus": msg => handleNetStatusMessage(msg), 32 32 "netwarn": msg => addNetworkWarning(msg), 33 33 "players": msg => handlePlayerAssignmentsMessage(msg), 34 "paused": msg => setClientPauseState(msg.guid, msg.pause), 34 35 "rejoined": msg => addChatMessage({ "type": "rejoined", "guid": msg.guid }), 35 36 "kicked": msg => addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been kicked"), { "username": msg.username }) }), 36 37 "banned": msg => addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been banned"), { "username": msg.username }) }), … … 449 450 450 451 if (message.status == "disconnected") 451 452 { 453 // Hide the pause overlay, and pause animations. 454 Engine.GetGUIObjectByName("pauseOverlay").hidden = true; 455 Engine.SetPaused(true, false); 456 452 457 g_Disconnected = true; 453 458 closeOpenDialogs(); 454 459 } … … 462 467 if (message.hosts[guid]) 463 468 continue; 464 469 470 setClientPauseState(guid, false); 471 465 472 addChatMessage({ "type": "disconnect", "guid": guid }); 466 473 467 474 for (let id in g_Players) -
binaries/data/mods/public/gui/session/session.js
38 38 var g_HasRejoined = false; 39 39 40 40 /** 41 * True if the current player has paused the game explicitly. 42 */ 43 var g_Paused = false; 44 45 /** 46 * The list of GUIDs of players who have currently paused the game, if the game is networked. 47 */ 48 var g_PausingClients = []; 49 50 /** 41 51 * The playerID selected in the change perspective tool. 42 52 */ 43 53 var g_ViewedPlayer = Engine.GetPlayerID(); … … 440 450 global.music.setState(global.music.states.DEFEAT); 441 451 442 452 if (!leaveGameAfterResign) 443 resumeGame( );453 resumeGame(true); 444 454 } 445 455 446 456 /** … … 809 819 // Setup tooltip 810 820 let tooltip = "[font=\"sans-bold-16\"]" + template.name.specific + "[/font]"; 811 821 let healthLabel = "[font=\"sans-bold-13\"]" + translate("Health:") + "[/font]"; 812 tooltip += "\n" + sprintf(translate("%(label)s %(current)s / %(max)s"), { 822 tooltip += "\n" + sprintf(translate("%(label)s %(current)s / %(max)s"), { 813 823 "label": healthLabel, 814 824 "current": Math.ceil(heroState.hitpoints), 815 825 "max": Math.ceil(heroState.maxHitpoints) -
binaries/data/mods/public/gui/session/session.xml
174 174 <!-- ================================ ================================ --> 175 175 <!-- Pause Overlay --> 176 176 <!-- ================================ ================================ --> 177 <object type="button" 178 name="pauseOverlay" 179 size="0 0 100% 100%" 180 tooltip_style="sessionToolTip" 181 hidden="true" 182 z="0" 183 > 177 <object type="button" name="pauseOverlay" size="0 0 100% 100%" tooltip_style="sessionToolTip" hidden="true" z="0"> 184 178 <object size="0 0 100% 100%" type="image" sprite="devCommandsBackground" ghost="true" z="0"/> 185 <object size="50%-128 50%-20 50%+128 50%+20" type="text" style="PauseText" ghost="true" z="0">179 <object name="pauseText" size="50%-128 40%-20 50%+128 40%+20" type="text" style="PauseText" ghost="true" z="0"> 186 180 <translatableAttribute id="caption">Game Paused</translatableAttribute> 187 181 </object> 188 <object size="50%-128 50%+20 50%+128 50%+30" type="text" style="PauseMessageText" ghost="true" z="0">182 <object name="resumeMessage" size="50%-128 40%+20 50%+128 40%+40" type="text" style="ResumeMessageText" ghost="true" z="0"> 189 183 <translatableAttribute id="caption">Click to Resume Game</translatableAttribute> 190 184 </object> 185 <object name="pausedByText" size="30% 40%+40 70% 100%" type="text" style="PausedByText" ghost="true" hidden="true" z="0"/> 191 186 <action on="Press">togglePause();</action> 192 187 </object> 193 188 … … 261 256 <!-- Trade Window --> 262 257 <!-- ================================ ================================ --> 263 258 <include file="gui/session/trade_window.xml"/> 264 259 265 260 <!-- ================================ ================================ --> 266 261 <!-- Top Panel --> 267 262 <!-- ================================ ================================ --> … … 305 300 <!-- ================================ ================================ --> 306 301 <!-- Supplemental Details Panel (Left of Selection Details) --> 307 302 <!-- ================================ ================================ --> 308 <object 303 <object 309 304 size="50%-304 100%-170 50%-110 100%" 310 305 name="supplementalSelectionDetails" 311 306 type="image" -
binaries/data/mods/public/gui/session/styles.xml
12 12 text_valign="center" 13 13 /> 14 14 15 <style name=" PauseMessageText"15 <style name="ResumeMessageText" 16 16 font="sans-bold-12" 17 17 textcolor="white" 18 18 text_align="center" … … 19 19 text_valign="center" 20 20 /> 21 21 22 <style name="PausedByText" 23 font="sans-bold-16" 24 textcolor="white" 25 text_align="center" 26 text_valign="top" 27 /> 28 22 29 <style name="BuildNameText" 23 30 font="sans-stroke-12" 24 31 textcolor="white" … … 116 123 text_valign="center" 117 124 ghost="true" 118 125 /> 119 126 120 127 <style name="StatsTextCentered" 121 128 font="sans-stroke-12" 122 129 textcolor="white" … … 124 131 text_valign="center" 125 132 ghost="true" 126 133 /> 127 134 128 135 <style name="StatsTextRight" 129 136 font="sans-stroke-12" 130 137 textcolor="white" … … 132 139 text_valign="center" 133 140 ghost="true" 134 141 /> 135 142 136 143 <style name="CarryingTextRight" 137 144 font="sans-bold-stroke-13" 138 145 textcolor="white" … … 140 147 text_valign="center" 141 148 ghost="true" 142 149 /> 143 150 144 151 <style name="SpecificNameCentered" 145 152 font="sans-bold-stroke-13" 146 153 textcolor="gold" … … 148 155 text_valign="center" 149 156 ghost="true" 150 157 /> 151 158 152 159 <style name="GenericNameCentered" 153 160 font="sans-stroke-12" 154 161 textcolor="white" … … 156 163 text_valign="center" 157 164 ghost="true" 158 165 /> 159 166 160 167 <style name="SettingsText" 161 168 font="sans-stroke-16" 162 169 textcolor="white" -
source/gui/scripting/ScriptFunctions.cpp
778 778 } 779 779 780 780 // Pause/unpause the game 781 void SetPaused(ScriptInterface::CxPrivate* pCxPrivate, bool pause )781 void SetPaused(ScriptInterface::CxPrivate* pCxPrivate, bool pause, bool sendMessage) 782 782 { 783 783 if (!g_Game) 784 784 { … … 790 790 if (g_SoundManager) 791 791 g_SoundManager->Pause(pause); 792 792 #endif 793 794 if (g_NetClient && sendMessage) 795 g_NetClient->SendPausedMessage(pause); 793 796 } 794 797 795 798 // Return the global frames-per-second value. … … 1093 1096 scriptInterface.RegisterFunction<JS::Value, &GetProfilerState>("GetProfilerState"); 1094 1097 scriptInterface.RegisterFunction<void, &ExitProgram>("Exit"); 1095 1098 scriptInterface.RegisterFunction<bool, &IsPaused>("IsPaused"); 1096 scriptInterface.RegisterFunction<void, bool, &SetPaused>("SetPaused");1099 scriptInterface.RegisterFunction<void, bool, bool, &SetPaused>("SetPaused"); 1097 1100 scriptInterface.RegisterFunction<int, &GetFps>("GetFPS"); 1098 1101 scriptInterface.RegisterFunction<std::wstring, int, &GetBuildTimestamp>("GetBuildTimestamp"); 1099 1102 scriptInterface.RegisterFunction<JS::Value, std::wstring, &ReadJSONFile>("ReadJSONFile"); -
source/network/NetClient.cpp
122 122 AddTransition(NCS_INGAME, (uint)NMT_KICKED, NCS_INGAME, (void*)&OnKicked, context); 123 123 AddTransition(NCS_INGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_INGAME, (void*)&OnClientTimeout, context); 124 124 AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_INGAME, (void*)&OnClientPerformance, context); 125 AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PAUSED, NCS_INGAME, (void*)&OnClientPaused, context); 125 126 AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, (void*)&OnChat, context); 126 127 AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, (void*)&OnGameSetup, context); 127 128 AddTransition(NCS_INGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_INGAME, (void*)&OnPlayerAssignment, context); … … 341 342 SendMessage(&rejoinedMessage); 342 343 } 343 344 345 void CNetClient::SendPausedMessage(bool pause) 346 { 347 CClientPausedMessage pausedMessage; 348 pausedMessage.m_Pause = pause; 349 SendMessage(&pausedMessage); 350 } 351 344 352 bool CNetClient::HandleMessage(CNetMessage* message) 345 353 { 346 354 // Handle non-FSM messages first … … 727 735 return true; 728 736 } 729 737 738 bool CNetClient::OnClientPaused(void *context, CFsmEvent *event) 739 { 740 ENSURE(event->GetType() == (uint)NMT_CLIENT_PAUSED); 741 742 CNetClient* client = (CNetClient*)context; 743 JSContext* cx = client->GetScriptInterface().GetContext(); 744 CClientPausedMessage* message = (CClientPausedMessage*)event->GetParamRef(); 745 746 JS::RootedValue msg(cx); 747 client->GetScriptInterface().Eval("({ 'type':'paused' })", &msg); 748 client->GetScriptInterface().SetProperty(msg, "pause", message->m_Pause != 0); 749 client->GetScriptInterface().SetProperty(msg, "guid", message->m_GUID); 750 client->PushGuiMessage(msg); 751 752 return true; 753 } 754 730 755 bool CNetClient::OnLoadedGame(void* context, CFsmEvent* event) 731 756 { 732 757 ENSURE(event->GetType() == (uint)NMT_LOADED_GAME); -
source/network/NetClient.h
197 197 */ 198 198 void SendRejoinedMessage(); 199 199 200 /** 201 * Call when the client has paused or unpaused the game. 202 */ 203 void SendPausedMessage(bool pause); 204 200 205 private: 201 206 // Net message / FSM transition handlers 202 207 static bool OnConnect(void* context, CFsmEvent* event); … … 215 220 static bool OnKicked(void* context, CFsmEvent* event); 216 221 static bool OnClientTimeout(void* context, CFsmEvent* event); 217 222 static bool OnClientPerformance(void* context, CFsmEvent* event); 223 static bool OnClientPaused(void* context, CFsmEvent* event); 218 224 static bool OnLoadedGame(void* context, CFsmEvent* event); 219 225 220 226 /** -
source/network/NetMessage.cpp
147 147 pNewMessage = new CClientPerformanceMessage; 148 148 break; 149 149 150 case NMT_CLIENT_PAUSED: 151 pNewMessage = new CClientPausedMessage; 152 break; 153 150 154 case NMT_LOADED_GAME: 151 155 pNewMessage = new CLoadedGameMessage; 152 156 break; -
source/network/NetMessages.h
28 28 29 29 #define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?' 30 30 #define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!' 31 #define PS_PROTOCOL_VERSION 0x0101001 2// Arbitrary protocol31 #define PS_PROTOCOL_VERSION 0x01010013 // Arbitrary protocol 32 32 #define PS_DEFAULT_PORT 0x5073 // 'P', 's' 33 33 34 34 // Defines the list of message types. The order of the list must not change. … … 62 62 63 63 NMT_CLIENT_TIMEOUT, 64 64 NMT_CLIENT_PERFORMANCE, 65 NMT_CLIENT_PAUSED, 65 66 66 67 NMT_LOADED_GAME, 67 68 NMT_GAME_START, … … 183 184 NMT_END_ARRAY() 184 185 END_NMT_CLASS() 185 186 187 START_NMT_CLASS_(ClientPaused, NMT_CLIENT_PAUSED) 188 NMT_FIELD(CStr, m_GUID) 189 NMT_FIELD_INT(m_Pause, u8, 1) 190 END_NMT_CLASS() 191 186 192 START_NMT_CLASS_(LoadedGame, NMT_LOADED_GAME) 187 193 NMT_FIELD_INT(m_CurrentTurn, u32, 4) 188 194 END_NMT_CLASS() -
source/network/NetServer.cpp
655 655 session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnJoinSyncingLoadedGame, context); 656 656 657 657 session->AddTransition(NSS_INGAME, (uint)NMT_REJOINED, NSS_INGAME, (void*)&OnRejoined, context); 658 session->AddTransition(NSS_INGAME, (uint)NMT_CLIENT_PAUSED, NSS_INGAME, (void*)&OnClientPaused, context); 658 659 session->AddTransition(NSS_INGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context); 659 660 session->AddTransition(NSS_INGAME, (uint)NMT_CHAT, NSS_INGAME, (void*)&OnChat, context); 660 661 session->AddTransition(NSS_INGAME, (uint)NMT_SIMULATION_COMMAND, NSS_INGAME, (void*)&OnInGame, context); … … 698 699 699 700 void CNetServerWorker::OnUserLeave(CNetServerSession* session) 700 701 { 702 std::vector<CStr>::iterator pausing = std::find(m_PausingPlayers.begin(), m_PausingPlayers.end(), session->GetGUID()); 703 if (pausing != m_PausingPlayers.end()) 704 m_PausingPlayers.erase(pausing); 705 701 706 RemovePlayer(session->GetGUID()); 702 707 703 708 if (m_ServerTurnManager && session->GetCurrState() != NSS_JOIN_SYNCING) … … 1169 1174 loaded.m_CurrentTurn = readyTurn; 1170 1175 session->SendMessage(&loaded); 1171 1176 1177 // Send all pausing players to the client. 1178 for (const CStr& guid : server.m_PausingPlayers) 1179 { 1180 CClientPausedMessage pausedMessage; 1181 pausedMessage.m_GUID = guid; 1182 pausedMessage.m_Pause = true; 1183 session->SendMessage(&pausedMessage); 1184 } 1185 1172 1186 return true; 1173 1187 } 1174 1188 … … 1201 1215 return true; 1202 1216 } 1203 1217 1218 bool CNetServerWorker::OnClientPaused(void *context, CFsmEvent *event) 1219 { 1220 ENSURE(event->GetType() == (uint)NMT_CLIENT_PAUSED); 1221 1222 CNetServerSession* session = (CNetServerSession*)context; 1223 CNetServerWorker& server = session->GetServer(); 1224 1225 CClientPausedMessage* message = (CClientPausedMessage*)event->GetParamRef(); 1226 1227 message->m_GUID = session->GetGUID(); 1228 1229 // Update the list of pausing players. 1230 std::vector<CStr>::iterator player = std::find(server.m_PausingPlayers.begin(), server.m_PausingPlayers.end(), session->GetGUID()); 1231 1232 if (message->m_Pause) 1233 { 1234 if (player != server.m_PausingPlayers.end()) 1235 return true; 1236 1237 server.m_PausingPlayers.push_back(session->GetGUID()); 1238 } 1239 else 1240 { 1241 if (player == server.m_PausingPlayers.end()) 1242 return true; 1243 1244 server.m_PausingPlayers.erase(player); 1245 } 1246 1247 // Send messages to clients that are in game, and are not the client who paused. 1248 for (CNetServerSession* session : server.m_Sessions) 1249 { 1250 if (session->GetCurrState() == NSS_INGAME && message->m_GUID != session->GetGUID()) 1251 session->SendMessage(message); 1252 } 1253 1254 return true; 1255 } 1256 1204 1257 void CNetServerWorker::CheckGameLoadStatus(CNetServerSession* changedSession) 1205 1258 { 1206 1259 for (const CNetServerSession* session : m_Sessions) -
source/network/NetServer.h
274 274 static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event); 275 275 static bool OnRejoined(void* context, CFsmEvent* event); 276 276 static bool OnDisconnect(void* context, CFsmEvent* event); 277 static bool OnClientPaused(void* context, CFsmEvent* event); 277 278 278 279 void CheckGameLoadStatus(CNetServerSession* changedSession); 279 280 … … 316 317 std::vector<u32> m_BannedIPs; 317 318 std::vector<CStrW> m_BannedPlayers; 318 319 320 /** 321 * Holds the GUIDs of all currently paused players. 322 */ 323 std::vector<CStr> m_PausingPlayers; 324 319 325 u32 m_NextHostID; 320 326 321 327 CNetServerTurnManager* m_ServerTurnManager;