Ticket #2447: readyv2.patch
File readyv2.patch, 27.4 KB (added by , 10 years ago) |
---|
-
binaries/data/mods/public/gui/common/modern/sprites.xml
296 296 size="0 0 22 22" 297 297 /> 298 298 </sprite> 299 <sprite name="ModernCheckOn"> 300 <image texture="global/modern/checkbox-on.png" 301 real_texture_placement="0 0 32 32" 302 /> 303 </sprite> 304 <sprite name="ModernCheckOff"> 305 <image texture="global/modern/checkbox-off.png" 306 real_texture_placement="0 0 32 32" 307 /> 308 </sprite> 299 309 </sprites> -
binaries/data/mods/public/gui/gamesetup/gamesetup.js
31 31 // (and therefore shouldn't send further messages to the network) 32 32 var g_IsInGuiUpdate; 33 33 34 // Is this user ready 35 var g_IsReady; 36 37 // Ready data just for the controller 38 var g_ReadyData = []; 39 34 40 var g_PlayerAssignments = {}; 35 41 36 42 // Default game setup attributes … … 97 103 { 98 104 cancelButton.tooltip = "Return to the lobby." 99 105 } 100 106 if (!g_IsNetworked) 107 Engine.GetGUIObjectByName("toggleReady").hidden = true; 101 108 } 102 109 103 110 // Called after the map data is loaded and cached … … 384 391 // Find and report all joinings/leavings 385 392 for (var host in message.hosts) 386 393 if (! g_PlayerAssignments[host]) 394 { 387 395 addChatMessage({ "type": "connect", "username": message.hosts[host].name }); 396 g_ReadyData[host] = false; 397 } 388 398 389 399 for (var host in g_PlayerAssignments) 390 400 if (! message.hosts[host]) 401 { 391 402 addChatMessage({ "type": "disconnect", "guid": host }); 403 delete g_ReadyData[host]; 404 } 392 405 393 406 // Update the player list 394 407 g_PlayerAssignments = message.hosts; … … 416 429 addChatMessage({ "type": "message", "guid": message.guid, "text": message.text }); 417 430 break; 418 431 432 // Singular client to host message 433 case "ready": 434 if (!g_IsController) 435 break; 436 g_ReadyData[message.guid] = (message.text == 1); 437 Engine.SetNetworkReadyData(g_ReadyData); 438 updateReadyUI(); 439 break; 440 441 // Complete data sent by host to everyone. 442 case "readydata": 443 if (g_IsController) 444 break; 445 g_ReadyData = message.data; 446 updateReadyUI(); 447 break; 448 419 449 default: 420 450 error("Unrecognised net message type "+message.type); 421 451 } … … 811 841 812 842 function launchGame() 813 843 { 844 if (g_IsNetworked && !g_IsReady) 845 { 846 for (var guid in g_PlayerAssignments) 847 { 848 if (g_PlayerAssignments[guid].name.split(" (")[0] == Engine.ConfigDB_GetValue("user", "playername") && g_PlayerAssignments[guid].player == -1) 849 break; // Observers don't need to be ready. 850 else 851 return; // Host may have changed their own code. 852 } 853 } 814 854 if (g_IsNetworked && !g_IsController) 815 855 { 816 856 error("Only host can start game"); … … 1126 1166 if (i >= numPlayers) 1127 1167 continue; 1128 1168 1129 var pName = Engine.GetGUIObjectByName("playerName["+i+"]");1130 1169 var pCiv = Engine.GetGUIObjectByName("playerCiv["+i+"]"); 1131 1170 var pCivText = Engine.GetGUIObjectByName("playerCivText["+i+"]"); 1132 1171 var pTeam = Engine.GetGUIObjectByName("playerTeam["+i+"]"); … … 1140 1179 // Common to all game types 1141 1180 var color = iColorToString(getSetting(pData, pDefs, "Colour")); 1142 1181 pColor.sprite = "colour:"+color+" 100"; 1143 pName.caption = getSetting(pData, pDefs, "Name");1144 1182 1145 1183 var team = getSetting(pData, pDefs, "Team"); 1146 1184 var civ = getSetting(pData, pDefs, "Civ"); … … 1177 1215 1178 1216 // Game attributes include AI settings, so update the player list 1179 1217 updatePlayerList(); 1218 1219 // We should have everyone confirm that the new settings are acceptable. 1220 resetReadyData(); 1180 1221 } 1181 1222 1182 1223 function updateGameAttributes() … … 1476 1517 Engine.GetGUIObjectByName("moreOptions").hidden = !Engine.GetGUIObjectByName("moreOptions").hidden; 1477 1518 } 1478 1519 1520 function toggleReady() 1521 { 1522 g_IsReady = !g_IsReady; 1523 if (g_IsController) 1524 Engine.SetNetworkReadyData(g_ReadyData); 1525 if (g_IsReady) 1526 Engine.SendNetworkReady(1); 1527 else 1528 Engine.SendNetworkReady(0); 1529 } 1530 1531 function updateReadyUI() 1532 { 1533 var allReady = true; 1534 for (var guid in g_PlayerAssignments) 1535 { 1536 // We don't really care whether observers are ready. 1537 if (g_PlayerAssignments[guid].player == -1) 1538 return; 1539 if (g_ReadyData[guid]) 1540 Engine.GetGUIObjectByName("playerReadySprite[" + String(g_PlayerAssignments[guid].player - 1) + "]").sprite = "ModernCheckOn"; 1541 else if (!g_IsNetworked) 1542 Engine.GetGUIObjectByName("playerReadySprite[" + String(g_PlayerAssignments[guid].player - 1) + "]").sprite = "ModernCheckOn"; 1543 else 1544 { 1545 Engine.GetGUIObjectByName("playerReadySprite[" + String(g_PlayerAssignments[guid].player - 1) + "]").sprite = "ModernCheckOff"; 1546 allReady = false; 1547 } 1548 } 1549 // AIs are always ready. 1550 for (var playerid = 0; playerid < MAX_PLAYERS; playerid++) 1551 { 1552 if (g_GameAttributes.settings.PlayerData[playerid]) 1553 { 1554 if (g_GameAttributes.settings.PlayerData[playerid].AI != "" || g_GameAttributes.settings.PlayerData[playerid].Name == "Unassigned") 1555 Engine.GetGUIObjectByName("playerReadySprite[" + String(playerid) + "]").sprite = "ModernCheckOn"; 1556 } 1557 } 1558 1559 // The host is not allowed to start until everyone is ready. 1560 if (g_IsNetworked && g_IsController) 1561 Engine.GetGUIObjectByName("startGame").enabled = allReady; 1562 } 1563 1564 function resetReadyData() 1565 { 1566 g_IsReady = false; 1567 for (var guid in g_PlayerAssignments) 1568 { 1569 if (g_ReadyData[guid]) 1570 { 1571 if (!g_IsNetworked) 1572 g_ReadyData[guid] = true; 1573 g_ReadyData[guid] = false; 1574 } 1575 } 1576 updateReadyUI(); 1577 } 1479 1578 //////////////////////////////////////////////////////////////////////////////////////////////// 1480 1579 // Basic map filters API 1481 1580 -
binaries/data/mods/public/gui/gamesetup/gamesetup.xml
14 14 <object style="TitleText" type="text" size="50%-128 4 50%+128 36"> 15 15 Match Setup 16 16 </object> 17 17 18 18 <object type="image" style="ModernDialog" size="50%-190 50%-80 50%+190 50%+80" name="loadingWindow"> 19 19 20 20 <object type="text" style="TitleText" size="50%-128 0%-16 50%+128 16"> … … 32 32 <action on="Tick"> 33 33 onTick(); 34 34 </action> 35 35 36 36 <!-- Number of Players--> 37 37 <object size="24 26 224 54"> 38 38 … … 40 40 <object size="0 0 150 28"> 41 41 <object size="0 0 100% 100%" type="text" style="ModernRightLabelText">Number of players:</object> 42 42 </object> 43 43 44 44 <!-- Number of Players--> 45 45 <object size="150 0 200 28"> 46 46 <object name="numPlayersText" size="0 0 100% 100%" type="text" style="ModernLeftLabelText"/> … … 53 53 <action on="SelectionChange">selectNumPlayers(this.list_data[this.selected]);</action> 54 54 </object> 55 55 </object> 56 </object> 56 57 57 </object>58 59 58 <!-- Player assignments --> 60 59 <object size="24 59 100%-440 358" type="image" sprite="ModernDarkBoxGold" name="playerAssignmentsPannel"> 61 60 <object size="0 6 100% 30"> 62 <object name="playerNameHeading" type="text" style="ModernLabelText" size="0 0 20% 100%">Player Name</object> 63 <object name="playerPlacementHeading" type="text" style="ModernLabelText" size="20%+5 0 50% 100%">Player Placement</object> 64 <object name="playerCivHeading" type="text" style="ModernLabelText" size="50%+65 0 85% 100%">Civilization</object> 61 <object name="playerPlacementHeading" type="text" style="ModernLabelText" size="5 0 40% 100%">Player Name</object> 62 <object name="playerCivHeading" type="text" style="ModernLabelText" size="40%+65 0 75%-26 100%">Civilization</object> 65 63 <object name="civInfoButton" 66 64 type="button" 67 65 sprite="iconInfoGold" 68 66 sprite_over="iconInfoWhite" 69 size=" 82%-8 0 82%+816"67 size="57.5%+68 0 57.5%+84 16" 70 68 tooltip_style="onscreenToolTip" 71 69 tooltip="View civilization info" 72 70 > … … 74 72 Engine.PushGuiPage("page_civinfo.xml"); 75 73 ]]></action> 76 74 </object> 77 <object name="playerTeamHeading" type="text" style="ModernLabelText" size="85%+5 0 100%-5 100%">Team</object> 75 <object name="playerTeamHeading" type="text" style="ModernLabelText" size="75%+5 0 90%-5 100%">Team</object> 76 <object name="playerReadyHeading" type="text" style="ModernLabelText" size="90%+5 0 100%-5 100%">Ready</object> 78 77 </object> 79 78 <object size="1 36 100%-1 100%"> 80 79 <repeat count="8"> 81 80 <object name="playerBox[n]" size="0 0 100% 32" hidden="true"> 82 81 <object name="playerColour[n]" type="image" size="0 0 100% 100%"/> 83 <object name="playerName[n]" type="text" style="ModernLabelText" size="0 2 20% 30"/> 84 <object name="playerAssignment[n]" type="dropdown" style="ModernDropDown" size="20%+5 2 50% 30" tooltip_style="onscreenToolTip" tooltip="Select player."/> 85 <object name="playerConfig[n]" type="button" style="StoneButton" size="50%+5 6 50%+60 26" 82 <object name="playerAssignment[n]" type="dropdown" style="ModernDropDown" size="5 2 40% 30" tooltip_style="onscreenToolTip" tooltip="Select player."/> 83 <object name="playerConfig[n]" type="button" style="StoneButton" size="40%+5 6 40%+60 26" 86 84 tooltip_style="onscreenToolTip" 87 85 tooltip="Configure AI settings." 88 86 font="serif-bold-stroke-12" 89 87 >Settings</object> 90 <object name="playerCiv[n]" type="dropdown" style="ModernDropDown" size="50%+65 2 85% 30" tooltip_style="onscreenToolTip" tooltip="Select player's civilization."/> 91 <object name="playerCivText[n]" type="text" style="ModernLabelText" size="50%+65 0 85% 30"/> 92 <object name="playerTeam[n]" type="dropdown" style="ModernDropDown" size="85%+5 2 100%-5 30" tooltip_style="onscreenToolTip" tooltip="Select player's team."/> 93 <object name="playerTeamText[n]" type="text" style="ModernLabelText" size="85%+5 0 100%-5 100%"/> 88 <object name="playerCiv[n]" type="dropdown" style="ModernDropDown" size="40%+65 2 75% 30" tooltip_style="onscreenToolTip" tooltip="Select player's civilization."/> 89 <object name="playerCivText[n]" type="text" style="ModernLabelText" size="40%+65 0 75% 30"/> 90 <object name="playerTeam[n]" type="dropdown" style="ModernDropDown" size="75%+5 2 90%-5 30" tooltip_style="onscreenToolTip" tooltip="Select player's team."/> 91 <object name="playerTeamText[n]" type="text" style="ModernLabelText" size="75%+5 0 90%-5 100%"/> 92 <object name="playerReadySprite[n]" type="image" sprite="ModernCheckOff" size="95%-16 0 95%+16 32"/> 94 93 </object> 95 94 </repeat> 96 95 </object> 97 96 </object> 98 <object size="24 64 100%-460 358" type="image" sprite="CoverFillDark" name="playerAssignmentsPan nelCover" hidden="true"/>97 <object size="24 64 100%-460 358" type="image" sprite="CoverFillDark" name="playerAssignmentsPanelCover" hidden="true"/> 99 98 <!-- Map selection --> 100 99 101 100 … … 112 111 <object name="mapSelectionText" type="text" style="ModernLeftLabelText" size="0 64 100% 94" hidden="true"/> 113 112 <object name="mapSizeText" type="text" style="ModernLeftLabelText" size="0 96 100% 126" hidden="true"/> 114 113 </object> 115 114 116 115 <object name="mapTypeSelection" 117 116 type="dropdown" 118 117 style="ModernDropDown" … … 159 158 </object> 160 159 161 160 <!-- Chat window --> 162 <object name="chatPanel" size="24 370 100%-440 100%- 60" type="image" sprite="ModernDarkBoxGold">161 <object name="chatPanel" size="24 370 100%-440 100%-58" type="image" sprite="ModernDarkBoxGold"> 163 162 <object name="chatText" size="2 2 100%-2 100%-26" type="text" style="ChatPanel"/> 164 163 165 164 <object name="chatInput" size="4 100%-24 100%-76 100%-4" type="input" style="ModernInput"> … … 179 178 textcolor="white" 180 179 sprite="BackgroundTranslucent" 181 180 hidden="true" 182 size=" 100%-700 100%-56 100%-312100%-24"181 size="25 100%-56 100%-445 100%-24" 183 182 >[Tooltip text]</object> 184 183 184 <!-- Ready Button --> 185 <object 186 name="toggleReady" 187 type="button" 188 style="StoneButton" 189 hidden="false" 190 size="100%-425 100%-52 100%-305 100%-24" 191 tooltip_style="onscreenToolTip" 192 tooltip="Accept the current settings and state you are ready to play!" 193 enabled="true" 194 > 195 Set/Unset Ready 196 <action on="Press">toggleReady();</action> 197 </object> 198 185 199 <!-- Start Button --> 186 200 <object 187 201 name="startGame" 188 202 type="button" 189 203 style="StoneButton" 190 size="100%- 308 100%-52 100%-168100%-24"204 size="100%-285 100%-52 100%-165 100%-24" 191 205 tooltip_style="onscreenToolTip" 192 206 tooltip="Start a new game with the current settings." 193 207 enabled="false" … … 202 216 caption="Back" 203 217 type="button" 204 218 style="StoneButton" 205 size="100%-1 64 100%-52 100%-24100%-24"219 size="100%-145 100%-52 100%-25 100%-24" 206 220 tooltip_style="onscreenToolTip" 207 221 > 208 222 <action on="Press"> … … 215 229 ]]> 216 230 </action> 217 231 </object> 218 232 219 233 <!-- Options --> 220 234 <object name="gameOptionsBox" size="100%-425 497 100%-25 525"> 221 235 <!-- More Options Button --> -
source/gui/scripting/ScriptFunctions.cpp
272 272 273 273 g_NetServer->UpdateGameAttributes(attribs, *(pCxPrivate->pScriptInterface)); 274 274 } 275 void SetNetworkReadyData(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal attribs) 276 { 277 ENSURE(g_NetServer); 275 278 279 g_NetServer->UpdateReadyData(attribs, *(pCxPrivate->pScriptInterface)); 280 } 281 276 282 void StartNetworkHost(ScriptInterface::CxPrivate* pCxPrivate, std::wstring playerName) 277 283 { 278 284 ENSURE(!g_NetClient); … … 350 356 g_NetClient->SendChatMessage(message); 351 357 } 352 358 359 void SendNetworkReady(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int message) 360 { 361 ENSURE(g_NetClient); 362 363 g_NetClient->SendReadyMessage(message); 364 } 365 353 366 std::vector<CScriptValRooted> GetAIs(ScriptInterface::CxPrivate* pCxPrivate) 354 367 { 355 368 return ICmpAIManager::GetAIs(*(pCxPrivate->pScriptInterface)); … … 837 850 scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame"); 838 851 scriptInterface.RegisterFunction<CScriptVal, &PollNetworkClient>("PollNetworkClient"); 839 852 scriptInterface.RegisterFunction<void, CScriptVal, &SetNetworkGameAttributes>("SetNetworkGameAttributes"); 853 scriptInterface.RegisterFunction<void, CScriptVal, &SetNetworkReadyData>("SetNetworkReadyData"); 840 854 scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer"); 841 855 scriptInterface.RegisterFunction<void, std::wstring, &SendNetworkChat>("SendNetworkChat"); 856 scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady"); 842 857 scriptInterface.RegisterFunction<std::vector<CScriptValRooted>, &GetAIs>("GetAIs"); 843 858 scriptInterface.RegisterFunction<CScriptValRooted, &GetEngineInfo>("GetEngineInfo"); 844 859 -
source/network/NetClient.cpp
87 87 AddTransition(NCS_INITIAL_GAMESETUP, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context); 88 88 89 89 AddTransition(NCS_PREGAME, (uint)NMT_CHAT, NCS_PREGAME, (void*)&OnChat, context); 90 AddTransition(NCS_PREGAME, (uint)NMT_READY, NCS_PREGAME, (void*)&OnReady, context); 91 AddTransition(NCS_PREGAME, (uint)NMT_READY_DATA, NCS_PREGAME, (void*)&OnReadyData, context); 90 92 AddTransition(NCS_PREGAME, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context); 91 93 AddTransition(NCS_PREGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_PREGAME, (void*)&OnPlayerAssignment, context); 92 94 AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, (void*)&OnGameStart, context); … … 254 256 SendMessage(&chat); 255 257 } 256 258 259 void CNetClient::SendReadyMessage(const int status) 260 { 261 CReadyMessage readyStatus; 262 readyStatus.m_Status = status; 263 SendMessage(&readyStatus); 264 } 265 257 266 bool CNetClient::HandleMessage(CNetMessage* message) 258 267 { 259 268 // Handle non-FSM messages first … … 419 428 return true; 420 429 } 421 430 431 bool CNetClient::OnReady(void* context, CFsmEvent* event) 432 { 433 ENSURE(event->GetType() == (uint)NMT_READY); 434 435 CNetClient* client = (CNetClient*)context; 436 437 CReadyMessage* message = (CReadyMessage*)event->GetParamRef(); 438 439 CScriptValRooted msg; 440 client->GetScriptInterface().Eval("({'type':'ready'})", msg); 441 client->GetScriptInterface().SetProperty(msg.get(), "guid", std::string(message->m_GUID), false); 442 client->GetScriptInterface().SetProperty(msg.get(), "text", int (message->m_Status), false); 443 client->PushGuiMessage(msg); 444 445 return true; 446 } 447 422 448 bool CNetClient::OnGameSetup(void* context, CFsmEvent* event) 423 449 { 424 450 ENSURE(event->GetType() == (uint)NMT_GAME_SETUP); … … 437 463 return true; 438 464 } 439 465 466 bool CNetClient::OnReadyData(void* context, CFsmEvent* event) 467 { 468 ENSURE(event->GetType() == (uint)NMT_READY_DATA); 469 470 CNetClient* client = (CNetClient*)context; 471 472 CReadyDataMessage* message = (CReadyDataMessage*)event->GetParamRef(); 473 474 client->m_ReadyData = message->m_Data; 475 476 CScriptValRooted msg; 477 client->GetScriptInterface().Eval("({'type':'readydata'})", msg); 478 client->GetScriptInterface().SetProperty(msg.get(), "data", message->m_Data, false); 479 client->PushGuiMessage(msg); 480 481 return true; 482 } 483 440 484 bool CNetClient::OnPlayerAssignment(void* context, CFsmEvent* event) 441 485 { 442 486 ENSURE(event->GetType() == (uint)NMT_PLAYER_ASSIGNMENT); -
source/network/NetClient.h
164 164 void LoadFinished(); 165 165 166 166 void SendChatMessage(const std::wstring& text); 167 168 void SendReadyMessage(const int status); 167 169 168 170 private: 169 171 // Net message / FSM transition handlers … … 172 174 static bool OnHandshakeResponse(void* context, CFsmEvent* event); 173 175 static bool OnAuthenticate(void* context, CFsmEvent* event); 174 176 static bool OnChat(void* context, CFsmEvent* event); 177 static bool OnReady(void* context, CFsmEvent* event); 178 static bool OnReadyData(void* context, CFsmEvent* event); 175 179 static bool OnGameSetup(void* context, CFsmEvent* event); 176 180 static bool OnPlayerAssignment(void* context, CFsmEvent* event); 177 181 static bool OnInGame(void* context, CFsmEvent* event); … … 204 208 205 209 /// Latest copy of game setup attributes heard from the server 206 210 CScriptValRooted m_GameAttributes; 211 212 /// Latest copy of ready data heard from the server 213 CScriptValRooted m_ReadyData; 207 214 208 215 /// Latest copy of player assignments heard from the server 209 216 PlayerAssignmentMap m_PlayerAssignments; -
source/network/NetMessage.cpp
174 174 case NMT_CHAT: 175 175 pNewMessage = new CChatMessage; 176 176 break; 177 178 case NMT_READY: 179 pNewMessage = new CReadyMessage; 180 break; 177 181 182 case NMT_READY_DATA: 183 pNewMessage = new CReadyDataMessage(scriptInterface); 184 break; 185 178 186 case NMT_SIMULATION_COMMAND: 179 187 pNewMessage = new CSimulationMessage(scriptInterface); 180 188 break; -
source/network/NetMessage.h
147 147 ScriptInterface& m_ScriptInterface; 148 148 }; 149 149 150 /** 151 * Special message type for updated ready data. 152 */ 153 class CReadyDataMessage : public CNetMessage 154 { 155 NONCOPYABLE(CReadyDataMessage); 156 public: 157 CReadyDataMessage(ScriptInterface& scriptInterface); 158 CReadyDataMessage(ScriptInterface& scriptInterface, jsval data); 159 virtual u8* Serialize(u8* pBuffer) const; 160 virtual const u8* Deserialize(const u8* pStart, const u8* pEnd); 161 virtual size_t GetSerializedLength() const; 162 virtual CStr ToString() const; 163 164 CScriptValRooted m_Data; 165 private: 166 ScriptInterface& m_ScriptInterface; 167 }; 150 168 // This time, the classes are created 151 169 #include "NetMessages.h" 152 170 -
source/network/NetMessageSim.cpp
219 219 stream << "CGameSetupMessage { m_Data: " << source << " }"; 220 220 return CStr(stream.str()); 221 221 } 222 223 CReadyDataMessage::CReadyDataMessage(ScriptInterface& scriptInterface) : 224 CNetMessage(NMT_READY_DATA), m_ScriptInterface(scriptInterface) 225 { 226 } 227 228 CReadyDataMessage::CReadyDataMessage(ScriptInterface& scriptInterface, jsval data) : 229 CNetMessage(NMT_READY_DATA), m_ScriptInterface(scriptInterface), 230 m_Data(scriptInterface.GetContext(), data) 231 { 232 } 233 234 u8* CReadyDataMessage::Serialize(u8* pBuffer) const 235 { 236 // TODO: ought to handle serialization exceptions 237 238 u8* pos = CNetMessage::Serialize(pBuffer); 239 CBufferBinarySerializer serializer(m_ScriptInterface, pos); 240 serializer.ScriptVal("command", m_Data); 241 return serializer.GetBuffer(); 242 } 243 244 const u8* CReadyDataMessage::Deserialize(const u8* pStart, const u8* pEnd) 245 { 246 // TODO: ought to handle serialization exceptions 247 248 const u8* pos = CNetMessage::Deserialize(pStart, pEnd); 249 std::istringstream stream(std::string(pos, pEnd)); 250 CStdDeserializer deserializer(m_ScriptInterface, stream); 251 deserializer.ScriptVal("command", m_Data); 252 return pEnd; 253 } 254 255 size_t CReadyDataMessage::GetSerializedLength() const 256 { 257 CLengthBinarySerializer serializer(m_ScriptInterface); 258 serializer.ScriptVal("command", m_Data); 259 return CNetMessage::GetSerializedLength() + serializer.GetLength(); 260 } 261 262 CStr CReadyDataMessage::ToString() const 263 { 264 std::string source = utf8_from_wstring(m_ScriptInterface.ToString(m_Data.get())); 265 266 std::stringstream stream; 267 stream << "CReadyDataMessage { m_Data: " << source << " }"; 268 return CStr(stream.str()); 269 } 270 -
source/network/NetMessages.h
46 46 NMT_AUTHENTICATE, // Authentication stage 47 47 NMT_AUTHENTICATE_RESULT, 48 48 NMT_CHAT, // Common chat message 49 NMT_READY, 50 NMT_READY_DATA, 49 51 NMT_GAME_SETUP, 50 52 NMT_PLAYER_ASSIGNMENT, 51 53 … … 118 120 NMT_FIELD(CStrW, m_Message) 119 121 END_NMT_CLASS() 120 122 123 START_NMT_CLASS_(Ready, NMT_READY) 124 NMT_FIELD(CStr8, m_GUID) 125 NMT_FIELD_INT(m_Status, u8, 1) 126 END_NMT_CLASS() 127 121 128 START_NMT_CLASS_(PlayerAssignment, NMT_PLAYER_ASSIGNMENT) 122 129 NMT_START_ARRAY(m_Hosts) 123 130 NMT_FIELD(CStr8, m_GUID) -
source/network/NetServer.cpp
548 548 549 549 session->AddTransition(NSS_PREGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context); 550 550 session->AddTransition(NSS_PREGAME, (uint)NMT_CHAT, NSS_PREGAME, (void*)&OnChat, context); 551 session->AddTransition(NSS_PREGAME, (uint)NMT_READY, NSS_PREGAME, (void*)&OnReady, context); 551 552 session->AddTransition(NSS_PREGAME, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnLoadedGame, context); 552 553 553 554 session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnJoinSyncingLoadedGame, context); … … 578 579 CGameSetupMessage gameSetupMessage(GetScriptInterface()); 579 580 gameSetupMessage.m_Data = m_GameAttributes; 580 581 session->SendMessage(&gameSetupMessage); 582 583 CReadyDataMessage readyDataMessage(GetScriptInterface()); 584 readyDataMessage.m_Data = m_ReadyData; 585 session->SendMessage(&readyDataMessage); 581 586 582 587 CPlayerAssignmentMessage assignMessage; 583 588 ConstructPlayerAssignmentMessage(assignMessage); … … 860 865 return true; 861 866 } 862 867 868 bool CNetServerWorker::OnReady(void* context, CFsmEvent* event) 869 { 870 ENSURE(event->GetType() == (uint)NMT_READY); 871 872 CNetServerSession* session = (CNetServerSession*)context; 873 CNetServerWorker& server = session->GetServer(); 874 875 CReadyMessage* message = (CReadyMessage*)event->GetParamRef(); 876 877 message->m_GUID = session->GetGUID(); 878 879 server.Broadcast(message); 880 881 return true; 882 } 883 863 884 bool CNetServerWorker::OnLoadedGame(void* context, CFsmEvent* event) 864 885 { 865 886 ENSURE(event->GetType() == (uint)NMT_LOADED_GAME); … … 982 1003 Broadcast(&gameSetupMessage); 983 1004 } 984 1005 1006 void CNetServerWorker::UpdateReadyData(const CScriptValRooted& attrs) 1007 { 1008 m_ReadyData = attrs; 1009 1010 if (!m_Host) 1011 return; 1012 1013 CReadyDataMessage readyMessage(GetScriptInterface()); 1014 readyMessage.m_Data = m_ReadyData; 1015 Broadcast(&readyMessage); 1016 } 1017 985 1018 CStrW CNetServerWorker::SanitisePlayerName(const CStrW& original) 986 1019 { 987 1020 const size_t MAX_LENGTH = 32; … … 1069 1102 m_Worker->m_GameAttributesQueue.push_back(attrsJSON); 1070 1103 } 1071 1104 1105 void CNetServer::UpdateReadyData(const CScriptVal& attrs, ScriptInterface& scriptInterface) 1106 { 1107 // Pass the attributes as JSON, since that's the easiest safe 1108 // cross-thread way of passing script data 1109 std::string attrsJSON = scriptInterface.StringifyJSON(attrs.get(), false); 1110 1111 CScopeLock lock(m_Worker->m_WorkerMutex); 1112 m_Worker->m_ReadyDataQueue.push_back(attrsJSON); 1113 } 1114 1072 1115 void CNetServer::SetTurnLength(u32 msecs) 1073 1116 { 1074 1117 CScopeLock lock(m_Worker->m_WorkerMutex); -
source/network/NetServer.h
137 137 void UpdateGameAttributes(const CScriptVal& attrs, ScriptInterface& scriptInterface); 138 138 139 139 /** 140 * Call from the GUI to update the readiness of players. 141 * This must be called at least once before starting the game. 142 * The changes will be asynchronously propagated to all clients. 143 * @param attrs ready data, in the script context of scriptInterface 144 */ 145 void UpdateReadyData(const CScriptVal& attrs, ScriptInterface& scriptInterface); 146 147 /** 140 148 * Set the turn length to a fixed value. 141 149 * TODO: we should replace this with some adapative lag-dependent computation. 142 150 */ … … 211 219 void UpdateGameAttributes(const CScriptValRooted& attrs); 212 220 213 221 /** 222 * Call from the GUI to update the readiness of players. 223 * This must be called at least once before starting the game. 224 * The changes will be propagated to all clients. 225 * @param attrs ready data, in the script context of GetScriptInterface() 226 */ 227 void UpdateReadyData(const CScriptValRooted& attrs); 228 229 /** 214 230 * Make a player name 'nicer' by limiting the length and removing forbidden characters etc. 215 231 */ 216 232 static CStrW SanitisePlayerName(const CStrW& original); … … 245 261 static bool OnAuthenticate(void* context, CFsmEvent* event); 246 262 static bool OnInGame(void* context, CFsmEvent* event); 247 263 static bool OnChat(void* context, CFsmEvent* event); 264 static bool OnReady(void* context, CFsmEvent* event); 248 265 static bool OnLoadedGame(void* context, CFsmEvent* event); 249 266 static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event); 250 267 static bool OnDisconnect(void* context, CFsmEvent* event); … … 267 284 PlayerAssignmentMap m_PlayerAssignments; 268 285 269 286 CScriptValRooted m_GameAttributes; 287 CScriptValRooted m_ReadyData; 270 288 271 289 int m_AutostartPlayers; 272 290 … … 321 339 std::vector<std::pair<int, CStr> > m_AssignPlayerQueue; // protected by m_WorkerMutex 322 340 std::vector<bool> m_StartGameQueue; // protected by m_WorkerMutex 323 341 std::vector<std::string> m_GameAttributesQueue; // protected by m_WorkerMutex 342 std::vector<std::string> m_ReadyDataQueue; // protected by m_WorkerMutex 324 343 std::vector<u32> m_TurnLengthQueue; // protected by m_WorkerMutex 325 344 }; 326 345