Ticket #1949: rejoined_message_v3.patch
File rejoined_message_v3.patch, 32.6 KB (added by , 9 years ago) |
---|
-
binaries/data/mods/public/gui/gamesetup/gamesetup_mp.js
94 94 return; 95 95 96 96 default: 97 97 error(sprintf("Unrecognised netstatus type %(netType)s", { netType: message.status })); 98 98 break; 99 99 } 100 100 break; 101 101 102 102 case "gamesetup": 103 103 g_GameAttributes = message.data; 104 104 break; 105 105 106 106 case "players": 107 107 g_PlayerAssignments = message.hosts; 108 108 break; 109 109 110 110 case "start": 111 111 Engine.SwitchGuiPage("page_loading.xml", { 112 112 "attribs": g_GameAttributes, 113 113 "isNetworked" : true, 114 "isRejoining" : g_IsRejoining, 114 115 "playerAssignments": g_PlayerAssignments 115 116 }); 116 117 break; 117 118 118 119 case "chat": 119 120 // Ignore, since we have nowhere to display chat messages 120 121 break; 121 122 122 123 default: 123 124 error(sprintf("Unrecognised net message type %(messageType)s", { messageType: message.type })); 124 125 } 125 126 } 126 127 else 127 128 { 128 129 // Not rejoining - just trying to connect to server 129 130 130 131 switch (message.type) 131 132 { 132 133 case "netstatus": 133 134 switch (message.status) -
binaries/data/mods/public/gui/loading/loading.js
96 96 rightSide.size = size; 97 97 } 98 98 } 99 99 100 100 // ==================================================================== 101 101 function reallyStartGame() 102 102 { 103 103 // Stop the music 104 104 // if (global.curr_music) 105 105 // global.curr_music.fade(-1, 0.0, 5.0); // fade to 0 over 5 seconds 106 106 107 107 108 108 // This is a reserved function name that is executed by the engine when it is ready 109 109 // to start the game (i.e. loading progress has reached 100%). 110 110 111 111 // Switch GUI from loading screen to game session. 112 112 Engine.SwitchGuiPage("page_session.xml", g_Data); 113 113 114 114 // Restore default cursor. 115 115 Engine.SetCursor("arrow-default"); 116 117 // Notify the other clients that we have finished the loading screen 118 if (g_Data.isNetworked && g_Data.isRejoining) 119 Engine.SendNetworkRejoined(); 116 120 } -
binaries/data/mods/public/gui/session/messages.js
274 274 } 275 275 } 276 276 277 277 g_PlayerAssignments = message.hosts; 278 278 279 279 if (g_IsController && Engine.HasXmppClient()) 280 280 { 281 281 var players = [ assignment.name for each (assignment in g_PlayerAssignments) ] 282 282 Engine.SendChangeStateGame(Object.keys(g_PlayerAssignments).length, players.join(", ")); 283 283 } 284 284 285 285 break; 286 286 287 287 case "chat": 288 288 addChatMessage({ "type": "message", "guid": message.guid, "text": message.text }); 289 289 break; 290 290 291 291 case "aichat": 292 292 addChatMessage({ "type": "message", "guid": message.guid, "text": message.text, "translate": true }); 293 293 break; 294 294 295 case "rejoined": 296 addChatMessage({ "type": "rejoined", "guid": message.guid}); 297 break; 298 295 299 // To prevent errors, ignore these message types that occur during autostart 296 300 case "gamesetup": 297 301 case "start": 298 302 break; 299 303 300 304 default: 301 305 error("Unrecognised net message type '" + message.type + "'"); 302 306 } 303 307 } 304 308 305 309 function submitChatDirectly(text) 306 310 { 307 311 if (text.length) 308 312 { 309 313 if (g_IsNetworked) 310 314 Engine.SendNetworkChat(text); 311 315 else 312 316 addChatMessage({ "type": "message", "guid": "local", "text": text }); 313 317 } 314 318 } … … 414 418 else if (msg.type == "defeat" && msg.player) 415 419 { 416 420 [username, playerColor] = getUsernameAndColor(msg.player); 417 421 } 418 422 else if (msg.type == "message") 419 423 { 420 424 [username, playerColor] = getUsernameAndColor(msg.player); 421 425 parseChatCommands(msg, playerAssignments); 422 426 } 423 427 else 424 428 { 425 429 playerColor = "255 255 255"; 426 430 username = translate("Unknown player"); 427 431 } 428 432 429 433 var formatted; 430 434 431 435 switch (msg.type) 432 436 { 433 437 case "connect": 434 formatted = sprintf(translate("%(player)s has joined the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" });438 formatted = sprintf(translate("%(player)s is connecting..."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 435 439 break; 436 440 case "disconnect": 437 441 formatted = sprintf(translate("%(player)s has left the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 438 442 break; 443 case "rejoined": 444 formatted = sprintf(translate("%(player)s has rejoined the game."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 445 break; 439 446 case "defeat": 440 447 // In singleplayer, the local player is "You". "You has" is incorrect. 441 448 if (!g_IsNetworked && msg.player == Engine.GetPlayerID()) 442 449 formatted = translate("You have been defeated."); 443 450 else 444 451 formatted = sprintf(translate("%(player)s has been defeated."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 445 452 break; 446 453 case "diplomacy": 447 454 var status = (msg.status == "ally" ? "allied" : (msg.status == "enemy" ? "at war" : "neutral")); 448 455 if (msg.player == Engine.GetPlayerID()) 449 456 { 450 457 [username, playerColor] = getUsernameAndColor(msg.player1); 451 458 if (msg.status == "ally") 452 459 formatted = sprintf(translate("You are now allied with %(player)s."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 453 460 else if (msg.status == "enemy") 454 461 formatted = sprintf(translate("You are now at war with %(player)s."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 455 462 else // (msg.status == "neutral") 456 463 formatted = sprintf(translate("You are now neutral with %(player)s."), { player: "[color=\"" + playerColor + "\"]" + username + "[/color]" }); 457 464 } 458 465 else if (msg.player1 == Engine.GetPlayerID()) -
source/gui/scripting/ScriptFunctions.cpp
371 371 { 372 372 ENSURE(g_NetServer); 373 373 374 374 g_NetServer->SetPlayerReady(guid, ready); 375 375 } 376 376 377 377 void ClearAllPlayerReady (ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) 378 378 { 379 379 ENSURE(g_NetServer); 380 380 381 381 g_NetServer->ClearAllPlayerReady(); 382 382 } 383 383 384 384 void SendNetworkChat(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::wstring message) 385 385 { 386 386 ENSURE(g_NetClient); 387 387 388 388 g_NetClient->SendChatMessage(message); 389 389 } 390 390 391 void SendNetworkRejoined(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) 392 { 393 ENSURE(g_NetClient); 394 395 g_NetClient->SendRejoinedMessage(); 396 } 397 391 398 void SendNetworkReady(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), int message) 392 399 { 393 400 ENSURE(g_NetClient); 394 401 395 402 g_NetClient->SendReadyMessage(message); 396 403 } 397 404 398 405 JS::Value GetAIs(ScriptInterface::CxPrivate* pCxPrivate) 399 406 { 400 407 return ICmpAIManager::GetAIs(*(pCxPrivate->pScriptInterface)); 401 408 } 402 409 403 410 JS::Value GetSavedGames(ScriptInterface::CxPrivate* pCxPrivate) 404 411 { 405 412 return SavedGames::GetSavedGames(*(pCxPrivate->pScriptInterface)); 406 413 } 407 414 408 415 bool DeleteSavedGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), std::wstring name) 409 416 { 410 417 return SavedGames::DeleteSavedGame(name); … … 934 941 scriptInterface.RegisterFunction<entity_id_t, int, int, &PickEntityAtPoint>("PickEntityAtPoint"); 935 942 scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, int, int, &PickFriendlyEntitiesInRect>("PickFriendlyEntitiesInRect"); 936 943 scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, &PickFriendlyEntitiesOnScreen>("PickFriendlyEntitiesOnScreen"); 937 944 scriptInterface.RegisterFunction<std::vector<entity_id_t>, std::string, bool, bool, bool, &PickSimilarFriendlyEntities>("PickSimilarFriendlyEntities"); 938 945 scriptInterface.RegisterFunction<CFixedVector3D, int, int, &GetTerrainAtScreenPoint>("GetTerrainAtScreenPoint"); 939 946 940 947 // Network / game setup functions 941 948 scriptInterface.RegisterFunction<void, &StartNetworkGame>("StartNetworkGame"); 942 949 scriptInterface.RegisterFunction<void, JS::HandleValue, int, &StartGame>("StartGame"); 943 950 scriptInterface.RegisterFunction<void, &Script_EndGame>("EndGame"); 944 951 scriptInterface.RegisterFunction<void, std::wstring, &StartNetworkHost>("StartNetworkHost"); 945 952 scriptInterface.RegisterFunction<void, std::wstring, std::string, &StartNetworkJoin>("StartNetworkJoin"); 946 953 scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame"); 947 954 scriptInterface.RegisterFunction<JS::Value, &PollNetworkClient>("PollNetworkClient"); 948 955 scriptInterface.RegisterFunction<void, JS::HandleValue, &SetNetworkGameAttributes>("SetNetworkGameAttributes"); 949 956 scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer"); 950 957 scriptInterface.RegisterFunction<void, std::string, int, &SetNetworkPlayerStatus>("SetNetworkPlayerStatus"); 951 958 scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady"); 952 959 scriptInterface.RegisterFunction<void, std::wstring, &SendNetworkChat>("SendNetworkChat"); 953 960 scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady"); 961 scriptInterface.RegisterFunction<void, &SendNetworkRejoined>("SendNetworkRejoined"); 954 962 scriptInterface.RegisterFunction<JS::Value, &GetAIs>("GetAIs"); 955 963 scriptInterface.RegisterFunction<JS::Value, &GetEngineInfo>("GetEngineInfo"); 956 964 957 965 // Saved games 958 966 scriptInterface.RegisterFunction<JS::Value, std::wstring, &StartSavedGame>("StartSavedGame"); 959 967 scriptInterface.RegisterFunction<JS::Value, &GetSavedGames>("GetSavedGames"); 960 968 scriptInterface.RegisterFunction<bool, std::wstring, &DeleteSavedGame>("DeleteSavedGame"); 961 969 scriptInterface.RegisterFunction<void, std::wstring, std::wstring, JS::HandleValue, &SaveGame>("SaveGame"); 962 970 scriptInterface.RegisterFunction<void, std::wstring, std::wstring, JS::HandleValue, &SaveGamePrefix>("SaveGamePrefix"); 963 971 scriptInterface.RegisterFunction<void, &QuickSave>("QuickSave"); 964 972 scriptInterface.RegisterFunction<void, &QuickLoad>("QuickLoad"); 965 973 966 974 // Misc functions 967 975 scriptInterface.RegisterFunction<std::wstring, std::wstring, &SetCursor>("SetCursor"); 968 976 scriptInterface.RegisterFunction<int, &GetPlayerID>("GetPlayerID"); 969 977 scriptInterface.RegisterFunction<void, int, &SetPlayerID>("SetPlayerID"); 970 978 scriptInterface.RegisterFunction<void, std::string, &OpenURL>("OpenURL"); 971 979 scriptInterface.RegisterFunction<std::wstring, &GetMatchID>("GetMatchID"); 972 980 scriptInterface.RegisterFunction<void, &RestartInAtlas>("RestartInAtlas"); 973 981 scriptInterface.RegisterFunction<bool, &AtlasIsAvailable>("AtlasIsAvailable"); -
source/network/NetClient.cpp
98 98 99 99 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CHAT, NCS_JOIN_SYNCING, (void*)&OnChat, context); 100 100 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_SETUP, NCS_JOIN_SYNCING, (void*)&OnGameSetup, context); 101 101 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_JOIN_SYNCING, (void*)&OnPlayerAssignment, context); 102 102 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_START, NCS_JOIN_SYNCING, (void*)&OnGameStart, context); 103 103 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_SIMULATION_COMMAND, NCS_JOIN_SYNCING, (void*)&OnInGame, context); 104 104 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_END_COMMAND_BATCH, NCS_JOIN_SYNCING, (void*)&OnJoinSyncEndCommandBatch, context); 105 105 AddTransition(NCS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context); 106 106 107 107 AddTransition(NCS_LOADING, (uint)NMT_CHAT, NCS_LOADING, (void*)&OnChat, context); 108 108 AddTransition(NCS_LOADING, (uint)NMT_GAME_SETUP, NCS_LOADING, (void*)&OnGameSetup, context); 109 109 AddTransition(NCS_LOADING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_LOADING, (void*)&OnPlayerAssignment, context); 110 110 AddTransition(NCS_LOADING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context); 111 111 112 112 AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, (void*)&OnChat, context); 113 113 AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, (void*)&OnGameSetup, context); 114 114 AddTransition(NCS_INGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_INGAME, (void*)&OnPlayerAssignment, context); 115 115 AddTransition(NCS_INGAME, (uint)NMT_SIMULATION_COMMAND, NCS_INGAME, (void*)&OnInGame, context); 116 116 AddTransition(NCS_INGAME, (uint)NMT_SYNC_ERROR, NCS_INGAME, (void*)&OnInGame, context); 117 117 AddTransition(NCS_INGAME, (uint)NMT_END_COMMAND_BATCH, NCS_INGAME, (void*)&OnInGame, context); 118 AddTransition(NCS_INGAME, (uint)NMT_REJOINED, NCS_INGAME, (void*)&OnRejoined, context); 118 119 119 120 // Set first state 120 121 SetFirstState(NCS_UNCONNECTED); 121 122 } 122 123 123 124 CNetClient::~CNetClient() 124 125 { 125 126 DestroyConnection(); 126 127 JS_RemoveExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this); 127 128 } 128 129 129 130 void CNetClient::TraceMember(JSTracer *trc) 130 131 { 131 132 std::deque<JS::Heap<JS::Value> >::iterator itr; 132 133 for (itr=m_GuiMessageQueue.begin(); itr != m_GuiMessageQueue.end(); ++itr) 133 134 JS_CallHeapValueTracer(trc, &*itr, "m_GuiMessageQueue"); 134 135 } 135 136 136 137 void CNetClient::SetUserName(const CStrW& username) 137 138 { … … 269 270 270 271 // Update the state immediately to UNCONNECTED (don't bother with FSM transitions since 271 272 // we'd need one for every single state, and we don't need to use per-state actions) 272 273 SetCurrState(NCS_UNCONNECTED); 273 274 } 274 275 275 276 void CNetClient::SendChatMessage(const std::wstring& text) 276 277 { 277 278 CChatMessage chat; 278 279 chat.m_Message = text; 279 280 SendMessage(&chat); 280 281 } 281 282 282 283 void CNetClient::SendReadyMessage(const int status) 283 284 { 284 285 CReadyMessage readyStatus; 285 286 readyStatus.m_Status = status; 286 287 SendMessage(&readyStatus); 287 288 } 288 289 290 void CNetClient::SendRejoinedMessage() 291 { 292 CRejoinedMessage rejoinedMessage; 293 SendMessage(&rejoinedMessage); 294 } 295 289 296 bool CNetClient::HandleMessage(CNetMessage* message) 290 297 { 291 298 // Handle non-FSM messages first 292 299 293 300 Status status = m_Session->GetFileTransferer().HandleMessageReceive(message); 294 301 if (status == INFO::OK) 295 302 return true; 296 303 if (status != INFO::SKIPPED) 297 304 return false; 298 305 299 306 if (message->GetType() == NMT_FILE_TRANSFER_REQUEST) 300 307 { 301 308 CFileTransferRequestMessage* reqMessage = (CFileTransferRequestMessage*)message; 302 309 303 310 // TODO: we should support different transfer request types, instead of assuming 304 311 // it's always requesting the simulation state 305 312 306 313 std::stringstream stream; 307 314 308 315 LOGMESSAGERENDER("Serializing game at turn %u for rejoining player", m_ClientTurnManager->GetCurrentTurn()); … … 567 574 568 575 return true; 569 576 } 570 577 571 578 bool CNetClient::OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event) 572 579 { 573 580 ENSURE(event->GetType() == (uint)NMT_END_COMMAND_BATCH); 574 581 575 582 CNetClient* client = (CNetClient*)context; 576 583 577 584 CEndCommandBatchMessage* endMessage = (CEndCommandBatchMessage*)event->GetParamRef(); 578 585 579 586 client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn, endMessage->m_TurnLength); 580 587 581 588 // Execute all the received commands for the latest turn 582 589 client->m_ClientTurnManager->UpdateFastForward(); 583 590 584 591 return true; 585 592 } 586 593 594 bool CNetClient::OnRejoined(void *context, CFsmEvent* event) 595 { 596 ENSURE(event->GetType() == (uint)NMT_REJOINED); 597 598 CNetClient* client = (CNetClient*)context; 599 JSContext* cx = client->GetScriptInterface().GetContext(); 600 601 CRejoinedMessage* message = (CRejoinedMessage*)event->GetParamRef(); 602 JS::RootedValue msg(cx); 603 client->GetScriptInterface().Eval("({'type':'rejoined'})", &msg); 604 client->GetScriptInterface().SetProperty(msg, "guid", std::string(message->m_GUID), false); 605 client->PushGuiMessage(msg); 606 607 return true; 608 } 609 587 610 bool CNetClient::OnLoadedGame(void* context, CFsmEvent* event) 588 611 { 589 612 ENSURE(event->GetType() == (uint)NMT_LOADED_GAME); 590 613 591 614 CNetClient* client = (CNetClient*)context; 592 615 JSContext* cx = client->GetScriptInterface().GetContext(); 593 616 JSAutoRequest rq(cx); 594 617 595 618 // All players have loaded the game - start running the turn manager 596 619 // so that the game begins 597 620 client->m_Game->SetTurnManager(client->m_ClientTurnManager); 598 621 599 622 JS::RootedValue msg(cx); 600 623 client->GetScriptInterface().Eval("({'type':'netstatus','status':'active'})", &msg); 601 624 client->PushGuiMessage(msg); 602 625 603 626 return true; 604 627 } 605 628 606 629 bool CNetClient::OnInGame(void *context, CFsmEvent* event) … … 614 637 { 615 638 if (message->GetType() == NMT_SIMULATION_COMMAND) 616 639 { 617 640 CSimulationMessage* simMessage = static_cast<CSimulationMessage*> (message); 618 641 client->m_ClientTurnManager->OnSimulationMessage(simMessage); 619 642 } 620 643 else if (message->GetType() == NMT_SYNC_ERROR) 621 644 { 622 645 CSyncErrorMessage* syncMessage = static_cast<CSyncErrorMessage*> (message); 623 646 client->m_ClientTurnManager->OnSyncError(syncMessage->m_Turn, syncMessage->m_HashExpected); 624 647 } 625 648 else if (message->GetType() == NMT_END_COMMAND_BATCH) 626 649 { 627 650 CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (message); 628 651 client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn, endMessage->m_TurnLength); 629 652 } 630 653 } 631 654 632 655 return true; 633 656 } 657 -
source/network/NetClient.h
163 163 /** 164 164 * Call when the network connection has been lost. 165 165 */ 166 166 void HandleDisconnect(u32 reason); 167 167 168 168 /** 169 169 * Call when a message has been received from the network. 170 170 */ 171 171 bool HandleMessage(CNetMessage* message); 172 172 173 173 /** 174 174 * Call when the game has started and all data files have been loaded, 175 175 * to signal to the server that we are ready to begin the game. 176 176 */ 177 177 void LoadFinished(); 178 178 179 179 void SendChatMessage(const std::wstring& text); 180 180 181 181 void SendReadyMessage(const int status); 182 182 183 /** 184 * Call when the client has rejoined a running match and finished 185 * the loading screen. 186 */ 187 void SendRejoinedMessage(); 188 189 183 190 private: 184 191 // Net message / FSM transition handlers 185 192 static bool OnConnect(void* context, CFsmEvent* event); 186 193 static bool OnHandshake(void* context, CFsmEvent* event); 187 194 static bool OnHandshakeResponse(void* context, CFsmEvent* event); 188 195 static bool OnAuthenticate(void* context, CFsmEvent* event); 189 196 static bool OnChat(void* context, CFsmEvent* event); 190 197 static bool OnReady(void* context, CFsmEvent* event); 191 198 static bool OnGameSetup(void* context, CFsmEvent* event); 192 199 static bool OnPlayerAssignment(void* context, CFsmEvent* event); 193 200 static bool OnInGame(void* context, CFsmEvent* event); 194 201 static bool OnGameStart(void* context, CFsmEvent* event); 195 202 static bool OnJoinSyncStart(void* context, CFsmEvent* event); 196 203 static bool OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event); 197 204 static bool OnLoadedGame(void* context, CFsmEvent* event); 205 static bool OnRejoined(void* context, CFsmEvent* event); 198 206 199 207 /** 200 208 * Take ownership of a session object, and use it for all network communication. 201 209 */ 202 210 void SetAndOwnSession(CNetClientSession* session); 203 211 204 212 /** 205 213 * Push a message onto the GUI queue listing the current player assignments. 206 214 */ 207 215 void PostPlayerAssignmentsToScript(); 208 216 209 217 CGame *m_Game; 210 218 CStrW m_UserName; 211 219 212 220 /// Current network session (or NULL if not connected) 213 221 CNetClientSession* m_Session; 214 222 215 223 /// Turn manager associated with the current game (or NULL if we haven't started the game yet) 216 224 CNetClientTurnManager* m_ClientTurnManager; 217 225 -
source/network/NetMessage.cpp
114 114 case NMT_FILE_TRANSFER_REQUEST: 115 115 pNewMessage = new CFileTransferRequestMessage; 116 116 break; 117 117 118 118 case NMT_FILE_TRANSFER_RESPONSE: 119 119 pNewMessage = new CFileTransferResponseMessage; 120 120 break; 121 121 122 122 case NMT_FILE_TRANSFER_DATA: 123 123 pNewMessage = new CFileTransferDataMessage; 124 124 break; 125 125 126 126 case NMT_FILE_TRANSFER_ACK: 127 127 pNewMessage = new CFileTransferAckMessage; 128 128 break; 129 129 130 130 case NMT_JOIN_SYNC_START: 131 131 pNewMessage = new CJoinSyncStartMessage; 132 132 break; 133 133 134 case NMT_REJOINED: 135 pNewMessage = new CRejoinedMessage; 136 break; 137 134 138 case NMT_LOADED_GAME: 135 139 pNewMessage = new CLoadedGameMessage; 136 140 break; 137 141 138 142 case NMT_SERVER_HANDSHAKE: 139 143 pNewMessage = new CSrvHandshakeMessage; 140 144 break; 141 145 142 146 case NMT_SERVER_HANDSHAKE_RESPONSE: 143 147 pNewMessage = new CSrvHandshakeResponseMessage; 144 148 break; 145 149 146 150 case NMT_CLIENT_HANDSHAKE: 147 151 pNewMessage = new CCliHandshakeMessage; 148 152 break; 149 153 150 154 case NMT_AUTHENTICATE: 151 155 pNewMessage = new CAuthenticateMessage; 152 156 break; 153 157 … … 157 161 158 162 case NMT_GAME_START: 159 163 pNewMessage = new CGameStartMessage; 160 164 break; 161 165 162 166 case NMT_END_COMMAND_BATCH: 163 167 pNewMessage = new CEndCommandBatchMessage; 164 168 break; 165 169 166 170 case NMT_SYNC_CHECK: 167 171 pNewMessage = new CSyncCheckMessage; 168 172 break; 169 173 170 174 case NMT_SYNC_ERROR: 171 175 pNewMessage = new CSyncErrorMessage; 172 176 break; 173 177 174 178 case NMT_CHAT: 175 179 pNewMessage = new CChatMessage; 176 180 break; 177 181 178 182 case NMT_READY: 179 183 pNewMessage = new CReadyMessage; 180 184 break; 181 185 182 186 case NMT_SIMULATION_COMMAND: 183 187 pNewMessage = new CSimulationMessage(scriptInterface); 184 188 break; 185 189 186 190 default: 187 191 LOGERROR("CNetMessageFactory::CreateMessage(): Unknown message type '%d' received", header.GetType()); 188 192 break; 189 193 } 190 194 191 195 if (pNewMessage) 192 196 pNewMessage->Deserialize((const u8*)pData, (const u8*)pData + dataSize); 193 197 194 198 return pNewMessage; 195 199 } -
source/network/NetMessages.h
30 30 #define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!' 31 31 #define PS_PROTOCOL_VERSION 0x01010005 // 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. 35 35 // The message types having a negative value are used internally and not sent 36 36 // over the network. The message types used for network communication have 37 37 // positive values. 38 38 enum NetMessageType 39 39 { 40 40 NMT_CONNECT_COMPLETE = -256, // Connection is complete 41 41 NMT_CONNECTION_LOST, 42 42 NMT_INVALID = 0, // Invalid message 43 43 NMT_SERVER_HANDSHAKE, // Handshake stage 44 44 NMT_CLIENT_HANDSHAKE, 45 45 NMT_SERVER_HANDSHAKE_RESPONSE, 46 46 NMT_AUTHENTICATE, // Authentication stage 47 47 NMT_AUTHENTICATE_RESULT, 48 48 NMT_CHAT, // Common chat message 49 49 NMT_READY, 50 NMT_REJOINED, 50 51 NMT_GAME_SETUP, 51 52 NMT_PLAYER_ASSIGNMENT, 52 53 53 54 NMT_FILE_TRANSFER_REQUEST, 54 55 NMT_FILE_TRANSFER_RESPONSE, 55 56 NMT_FILE_TRANSFER_DATA, 56 57 NMT_FILE_TRANSFER_ACK, 57 58 58 59 NMT_JOIN_SYNC_START, 59 60 60 61 NMT_LOADED_GAME, 61 62 NMT_GAME_START, 62 63 NMT_END_COMMAND_BATCH, 63 64 NMT_SYNC_CHECK, // OOS-detection hash checking 64 65 NMT_SYNC_ERROR, // OOS-detection error 65 66 NMT_SIMULATION_COMMAND, 66 67 NMT_LAST // Last message in the list 67 68 }; 68 69 69 70 // Authentication result codes … … 138 139 END_NMT_CLASS() 139 140 140 141 START_NMT_CLASS_(FileTransferResponse, NMT_FILE_TRANSFER_RESPONSE) 141 142 NMT_FIELD_INT(m_RequestID, u32, 4) 142 143 NMT_FIELD_INT(m_Length, u32, 4) 143 144 END_NMT_CLASS() 144 145 145 146 START_NMT_CLASS_(FileTransferData, NMT_FILE_TRANSFER_DATA) 146 147 NMT_FIELD_INT(m_RequestID, u32, 4) 147 148 NMT_FIELD(CStr8, m_Data) 148 149 END_NMT_CLASS() 149 150 150 151 START_NMT_CLASS_(FileTransferAck, NMT_FILE_TRANSFER_ACK) 151 152 NMT_FIELD_INT(m_RequestID, u32, 4) 152 153 NMT_FIELD_INT(m_NumPackets, u32, 4) 153 154 END_NMT_CLASS() 154 155 155 156 START_NMT_CLASS_(JoinSyncStart, NMT_JOIN_SYNC_START) 156 157 END_NMT_CLASS() 157 158 159 START_NMT_CLASS_(Rejoined, NMT_REJOINED) 160 NMT_FIELD(CStr8, m_GUID) 161 END_NMT_CLASS() 162 158 163 START_NMT_CLASS_(LoadedGame, NMT_LOADED_GAME) 159 164 NMT_FIELD_INT(m_CurrentTurn, u32, 4) 160 165 END_NMT_CLASS() 161 166 162 167 START_NMT_CLASS_(GameStart, NMT_GAME_START) 163 168 END_NMT_CLASS() 164 169 165 170 START_NMT_CLASS_(EndCommandBatch, NMT_END_COMMAND_BATCH) 166 171 NMT_FIELD_INT(m_Turn, u32, 4) 167 172 NMT_FIELD_INT(m_TurnLength, u32, 2) 168 173 END_NMT_CLASS() 169 174 170 175 START_NMT_CLASS_(SyncCheck, NMT_SYNC_CHECK) 171 176 NMT_FIELD_INT(m_Turn, u32, 4) 172 177 NMT_FIELD(CStr, m_Hash) 173 178 END_NMT_CLASS() 174 179 175 180 START_NMT_CLASS_(SyncError, NMT_SYNC_ERROR) 176 181 NMT_FIELD_INT(m_Turn, u32, 4) 177 182 NMT_FIELD(CStr, m_HashExpected) -
source/network/NetServer.cpp
581 581 582 582 session->AddTransition(NSS_HANDSHAKE, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED); 583 583 session->AddTransition(NSS_HANDSHAKE, (uint)NMT_CLIENT_HANDSHAKE, NSS_AUTHENTICATE, (void*)&OnClientHandshake, context); 584 584 585 585 session->AddTransition(NSS_AUTHENTICATE, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED); 586 586 session->AddTransition(NSS_AUTHENTICATE, (uint)NMT_AUTHENTICATE, NSS_PREGAME, (void*)&OnAuthenticate, context); 587 587 588 588 session->AddTransition(NSS_PREGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context); 589 589 session->AddTransition(NSS_PREGAME, (uint)NMT_CHAT, NSS_PREGAME, (void*)&OnChat, context); 590 590 session->AddTransition(NSS_PREGAME, (uint)NMT_READY, NSS_PREGAME, (void*)&OnReady, context); 591 591 session->AddTransition(NSS_PREGAME, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnLoadedGame, context); 592 592 593 593 session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context); 594 594 session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnJoinSyncingLoadedGame, context); 595 595 596 596 session->AddTransition(NSS_INGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context); 597 597 session->AddTransition(NSS_INGAME, (uint)NMT_CHAT, NSS_INGAME, (void*)&OnChat, context); 598 598 session->AddTransition(NSS_INGAME, (uint)NMT_SIMULATION_COMMAND, NSS_INGAME, (void*)&OnInGame, context); 599 599 session->AddTransition(NSS_INGAME, (uint)NMT_SYNC_CHECK, NSS_INGAME, (void*)&OnInGame, context); 600 600 session->AddTransition(NSS_INGAME, (uint)NMT_END_COMMAND_BATCH, NSS_INGAME, (void*)&OnInGame, context); 601 session->AddTransition(NSS_INGAME, (uint)NMT_REJOINED, NSS_INGAME, (void*)&OnRejoined, context); 601 602 602 603 // Set first state 603 604 session->SetFirstState(NSS_HANDSHAKE); 604 605 } 605 606 606 607 bool CNetServerWorker::HandleConnect(CNetServerSession* session) 607 608 { 608 609 CSrvHandshakeMessage handshake; 609 610 handshake.m_Magic = PS_PROTOCOL_MAGIC; 610 611 handshake.m_ProtocolVersion = PS_PROTOCOL_VERSION; 611 612 handshake.m_SoftwareVersion = PS_PROTOCOL_VERSION; 612 613 return session->SendMessage(&handshake); 613 614 } 614 615 615 616 void CNetServerWorker::OnUserJoin(CNetServerSession* session) 616 617 { 617 618 AddPlayer(session->GetGUID(), session->GetUserName()); 618 619 619 620 CGameSetupMessage gameSetupMessage(GetScriptInterface()); 620 621 gameSetupMessage.m_Data = m_GameAttributes.get(); … … 905 906 906 907 return true; 907 908 } 908 909 909 910 bool CNetServerWorker::OnReady(void* context, CFsmEvent* event) 910 911 { 911 912 ENSURE(event->GetType() == (uint)NMT_READY); 912 913 913 914 CNetServerSession* session = (CNetServerSession*)context; 914 915 CNetServerWorker& server = session->GetServer(); 915 916 916 917 CReadyMessage* message = (CReadyMessage*)event->GetParamRef(); 917 918 918 919 message->m_GUID = session->GetGUID(); 919 920 920 921 server.Broadcast(message); 921 922 922 923 return true; 923 924 } 924 925 926 925 927 bool CNetServerWorker::OnLoadedGame(void* context, CFsmEvent* event) 926 928 { 927 929 ENSURE(event->GetType() == (uint)NMT_LOADED_GAME); 928 930 929 931 CNetServerSession* session = (CNetServerSession*)context; 930 932 CNetServerWorker& server = session->GetServer(); 931 933 932 934 // We're in the loading state, so wait until every player has loaded before 933 935 // starting the game 934 936 ENSURE(server.m_State == SERVER_STATE_LOADING); 935 937 server.CheckGameLoadStatus(session); 936 938 937 939 return true; 938 940 } 939 941 940 942 bool CNetServerWorker::OnJoinSyncingLoadedGame(void* context, CFsmEvent* event) 941 943 { 942 944 // A client rejoining an in-progress game has now finished loading the 943 945 // map and deserialized the initial state. 944 946 // The simulation may have progressed since then, so send any subsequent … … 971 973 if (i <= readyTurn) 972 974 { 973 975 CEndCommandBatchMessage endMessage; 974 976 endMessage.m_Turn = i; 975 977 endMessage.m_TurnLength = server.m_ServerTurnManager->GetSavedTurnLength(i); 976 978 session->SendMessage(&endMessage); 977 979 } 978 980 } 979 981 980 982 // Tell the turn manager to expect commands from this new client 981 983 server.m_ServerTurnManager->InitialiseClient(session->GetHostID(), readyTurn); 982 984 983 985 // Tell the client that everything has finished loading and it should start now 984 986 CLoadedGameMessage loaded; 985 987 loaded.m_CurrentTurn = readyTurn; 986 988 session->SendMessage(&loaded); 987 989 988 990 return true; 989 991 } 990 992 993 bool CNetServerWorker::OnRejoined(void* context, CFsmEvent* event) 994 { 995 996 // A client has finished rejoining and his/her loading screen disappeared. 997 998 ENSURE(event->GetType() == (uint)NMT_REJOINED); 999 1000 CNetServerSession* session = (CNetServerSession*)context; 1001 CNetServerWorker& server = session->GetServer(); 1002 1003 CRejoinedMessage* message = (CRejoinedMessage*)event->GetParamRef(); 1004 1005 message->m_GUID = session->GetGUID(); 1006 1007 server.Broadcast(message); 1008 1009 return true; 1010 } 1011 991 1012 bool CNetServerWorker::OnDisconnect(void* context, CFsmEvent* event) 992 1013 { 993 1014 ENSURE(event->GetType() == (uint)NMT_CONNECTION_LOST); 994 1015 995 1016 CNetServerSession* session = (CNetServerSession*)context; 996 1017 CNetServerWorker& server = session->GetServer(); 997 1018 998 1019 server.OnUserLeave(session); 999 1020 1000 1021 return true; 1001 1022 } 1002 1023 1003 1024 void CNetServerWorker::CheckGameLoadStatus(CNetServerSession* changedSession) 1004 1025 { 1005 1026 for (size_t i = 0; i < m_Sessions.size(); ++i) 1006 1027 { 1007 1028 if (m_Sessions[i] != changedSession && m_Sessions[i]->GetCurrState() != NSS_INGAME) 1008 1029 return; 1009 1030 } 1010 1031 -
source/network/NetServer.h
245 245 246 246 void AddPlayer(const CStr& guid, const CStrW& name); 247 247 void RemovePlayer(const CStr& guid); 248 248 void SetPlayerReady(const CStr& guid, const int ready); 249 249 void SendPlayerAssignments(); 250 250 void ClearAllPlayerReady(); 251 251 252 252 void SetupSession(CNetServerSession* session); 253 253 bool HandleConnect(CNetServerSession* session); 254 254 255 255 void OnUserJoin(CNetServerSession* session); 256 256 void OnUserLeave(CNetServerSession* session); 257 257 258 258 static bool OnClientHandshake(void* context, CFsmEvent* event); 259 259 static bool OnAuthenticate(void* context, CFsmEvent* event); 260 260 static bool OnInGame(void* context, CFsmEvent* event); 261 261 static bool OnChat(void* context, CFsmEvent* event); 262 262 static bool OnReady(void* context, CFsmEvent* event); 263 263 static bool OnLoadedGame(void* context, CFsmEvent* event); 264 264 static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event); 265 static bool OnRejoined(void* context, CFsmEvent* event); 265 266 static bool OnDisconnect(void* context, CFsmEvent* event); 266 267 267 268 void CheckGameLoadStatus(CNetServerSession* changedSession); 268 269 269 270 void ConstructPlayerAssignmentMessage(CPlayerAssignmentMessage& message); 270 271 271 272 void HandleMessageReceive(const CNetMessage* message, CNetServerSession* session); 272 273 273 274 274 275 /** 275 276 * Internal script context for (de)serializing script messages, 276 277 * and for storing game attributes. 277 278 * (TODO: we shouldn't bother deserializing (except for debug printing of messages), 278 279 * we should just forward messages blindly and efficiently.) 279 280 */ 280 281 ScriptInterface* m_ScriptInterface; 281 282 282 283 PlayerAssignmentMap m_PlayerAssignments; 283 284 284 285 /** -
source/ps/Game.cpp
218 218 m_Simulation2->PreInitGame(); 219 219 220 220 JS::RootedValue settings(cx); 221 221 JS::RootedValue tmpInitAttributes(cx, m_Simulation2->GetInitAttributes()); 222 222 m_Simulation2->GetScriptInterface().GetProperty(tmpInitAttributes, "settings", &settings); 223 223 m_Simulation2->InitGame(settings); 224 224 } 225 225 226 226 // We need to do an initial Interpolate call to set up all the models etc, 227 227 // because Update might never interpolate (e.g. if the game starts paused) 228 228 // and we could end up rendering before having set up any models (so they'd 229 229 // all be invisible) 230 230 Interpolate(0, 0); 231 231 232 232 m_GameStarted=true; 233 233 234 234 // Render a frame to begin loading assets 235 235 if (CRenderer::IsInitialised()) 236 236 Render(); 237 237 238 if (g_NetClient) 239 g_NetClient->LoadFinished(); 240 238 241 // Call the reallyStartGame GUI function, but only if it exists 239 242 if (g_GUI && g_GUI->HasPages()) 240 243 { 241 244 JS::RootedValue global(cx, g_GUI->GetActiveGUI()->GetGlobalObject()); 242 245 if (g_GUI->GetActiveGUI()->GetScriptInterface()->HasProperty(global, "reallyStartGame")) 243 246 g_GUI->GetActiveGUI()->GetScriptInterface()->CallFunctionVoid(global, "reallyStartGame"); 244 247 } 245 248 246 if (g_NetClient)247 g_NetClient->LoadFinished();248 249 249 debug_printf("GAME STARTED, ALL INIT COMPLETE\n"); 250 250 251 251 // The call tree we've built for pregame probably isn't useful in-game. 252 252 if (CProfileManager::IsInitialised()) 253 253 g_Profiler.StructuralReset(); 254 254 255 255 // Mark terrain as modified so the minimap can repaint (is there a cleaner way of handling this?) 256 256 g_GameRestarted = true; 257 257 258 258 return 0; 259 259 } 260 260 261 261 int CGame::GetPlayerID() 262 262 { 263 263 return m_PlayerID; 264 264 } 265 265 266 266 void CGame::SetPlayerID(int playerID) 267 267 { 268 268 m_PlayerID = playerID;