void GameClient::ExecuteNWF() { // Geschickte Network Commands der Spieler ausführen und ggf. im Replay aufzeichnen AsyncChecksum checksum(RANDOM.GetCurrentRandomValue()); for(unsigned char i = 0; i < players.getCount(); ++i) { if(players[i].isUsed()) { GameMessage_GameCommand& msg = players[i].gc_queue.front(); // Command im Replay aufzeichnen (wenn nicht gerade eins schon läuft xD) // Nur Commands reinschreiben, KEINE PLATZHALTER (nc_count = 0) if(!msg.gcs.empty() && !replay_mode) { // Aktuelle Checksumme reinschreiben msg.checksum = checksum; Serializer ser; msg.Serialize(ser); replayinfo.replay.AddGameCommand(framesinfo.gf_nr, ser.GetLength(), ser.GetData()); } // Das ganze Zeug soll die andere Funktion ausführen ExecuteAllGCs(msg); // Nachricht abwerfen :) players[i].gc_queue.pop(); } } // Send GC message for this NWF send_queue.push(new GameMessage_GameCommand(playerId_, checksum, gameCommands_)); LOG.write("CLIENT >>> GC %u\n", playerId_); // alles gesendet --> Liste löschen gameCommands_.clear(); }
void GameClient::ExecuteNWF() { // Geschickte Network Commands der Spieler ausführen und ggf. im Replay aufzeichnen AsyncChecksum checksum = AsyncChecksum::create(*game); const unsigned curGF = GetGFNumber(); for(const NWFPlayerInfo& player : nwfInfo->getPlayerInfos()) { const PlayerGameCommands& currentGCs = player.commands.front(); // Command im Replay aufzeichnen (wenn nicht gerade eins schon läuft xD) // Nur Commands reinschreiben, KEINE PLATZHALTER (nc_count = 0) if(!currentGCs.gcs.empty() && replayinfo && replayinfo->replay.IsRecording()) { // Set the current checksum as the GF checksum. The checksum from the command is from the last NWF! PlayerGameCommands replayCmds(checksum, currentGCs.gcs); replayinfo->replay.AddGameCommand(curGF, player.id, replayCmds); } // Das ganze Zeug soll die andere Funktion ausführen ExecuteAllGCs(player.id, currentGCs); } // Send GC message for this NWF // First for all potential AIs as we need to combine the AI cmds of the local player with our own ones for(AIPlayer& ai : game->aiPlayers_) { const std::vector<gc::GameCommandPtr> aiGCs = ai.FetchGameCommands(); /// Cmds from own AI get added to our gcs if(ai.GetPlayerId() == GetPlayerId()) gameCommands_.insert(gameCommands_.end(), aiGCs.begin(), aiGCs.end()); else mainPlayer.sendMsgAsync(new GameMessage_GameCommand(ai.GetPlayerId(), checksum, aiGCs)); } mainPlayer.sendMsgAsync(new GameMessage_GameCommand(0xFF, checksum, gameCommands_)); gameCommands_.clear(); }
void GameClient::ExecuteGameFrame_Replay() { randcheckinfo.rand = RANDOM.GetCurrentRandomValue(); AsyncChecksum checksum(randcheckinfo.rand); RTTR_Assert(replayinfo.next_gf >= framesinfo.gf_nr || framesinfo.gf_nr > replayinfo.replay.lastGF_); // Commands alle aus der Datei lesen while(replayinfo.next_gf == framesinfo.gf_nr) // Schon an der Zeit? { // RC-Type auslesen Replay::ReplayCommand rc = replayinfo.replay.ReadRCType(); // Chat Command? if(rc == Replay::RC_CHAT) { unsigned char player, dest; std::string message; replayinfo.replay.ReadChatCommand(&player, &dest, message); // Nächsten Zeitpunkt lesen replayinfo.replay.ReadGF(&replayinfo.next_gf); if(ci) ci->CI_Chat(player, ChatDestination(dest), message); } // Game Command? else if(rc == Replay::RC_GAME) { std::vector<unsigned char> gcData = replayinfo.replay.ReadGameCommand(); Serializer ser(&gcData.front(), gcData.size()); GameMessage_GameCommand msg; msg.Deserialize(ser); // Nächsten Zeitpunkt lesen replayinfo.replay.ReadGF(&replayinfo.next_gf); // NCs ausführen (4 Bytes Checksumme und 1 Byte Player-ID überspringen) ExecuteAllGCs(msg); // Replay ist NSYNC äh ASYNC! if(msg.checksum.randState != 0 && msg.checksum != checksum) { if(replayinfo.async == 0) { // Meldung mit GF erzeugen char text[256]; sprintf(text, _("Warning: The played replay is not in sync with the original match. (GF: %u)"), framesinfo.gf_nr); // Messenger im Game (prints to console too) if(ci) ci->CI_ReplayAsync(text); LOG.lprintf("Async at GF %u: Checksum %i:%i ObjCt %u:%u ObjIdCt %u:%u\n", framesinfo.gf_nr, msg.checksum.randState, checksum.randState, msg.checksum.objCt, checksum.objCt, msg.checksum.objIdCt, checksum.objIdCt); // pausieren framesinfo.isPaused = true; } replayinfo.async++; } // resync random generator, so replay "can't" be async. // (of course it can, since we resynchronize only after each command, the command itself could be use multiple rand values) //RANDOM.ReplaySet(msg.checksum); } } // Frame ausführen NextGF(); // Replay zu Ende? if(framesinfo.gf_nr == replayinfo.replay.lastGF_) { // Replay zu Ende // Meldung erzeugen char text[256]; sprintf(text, _("Notice: The played replay has ended. (GF: %u, %dh %dmin %ds, TF: %u, AVG_FPS: %u)"), framesinfo.gf_nr, GAMEMANAGER.GetRuntime() / 3600, ((GAMEMANAGER.GetRuntime()) % 3600) / 60, (GameManager::inst().GetRuntime()) % 3600 % 60, GameManager::inst().GetFrameCount(), GameManager::inst().GetAverageFPS()); // Messenger im Game if(ci) ci->CI_ReplayEndReached(text); if(replayinfo.async != 0) { char text[256]; sprintf(text, _("Notice: Overall asynchronous frame count: %u"), replayinfo.async); // Messenger im Game if(ci) ci->CI_ReplayEndReached(text); } replayinfo.end = true; // pausieren framesinfo.isPaused = true; } }
void GameClient::ExecuteGameFrame_Replay() { randcheckinfo.rand = RANDOM.GetCurrentRandomValue(); AsyncChecksum checksum(randcheckinfo.rand); const unsigned curGF = GetGFNumber(); RTTR_Assert(replayinfo.next_gf >= curGF || curGF > replayinfo.replay.lastGF_); // Execute all commands from the replay for the current GF while(replayinfo.next_gf == curGF) { // What type of command follows? Replay::ReplayCommand rc = replayinfo.replay.ReadRCType(); if(rc == Replay::RC_CHAT) { unsigned char player, dest; std::string message; replayinfo.replay.ReadChatCommand(&player, &dest, message); if(ci) ci->CI_Chat(player, ChatDestination(dest), message); } else if(rc == Replay::RC_GAME) { std::vector<unsigned char> gcData = replayinfo.replay.ReadGameCommand(); Serializer ser(&gcData.front(), gcData.size()); GameMessage_GameCommand msg; msg.Deserialize(ser); // Execute them ExecuteAllGCs(msg); // Check for async if checksum data is valid if(msg.checksum.randState != 0 && msg.checksum != checksum) { // Show message if this is the first async GF if(replayinfo.async == 0) { char text[256]; sprintf(text, _("Warning: The played replay is not in sync with the original match. (GF: %u)"), curGF); if(ci) ci->CI_ReplayAsync(text); LOG.write("Async at GF %u: Checksum %i:%i ObjCt %u:%u ObjIdCt %u:%u\n") % curGF % msg.checksum.randState % checksum.randState % msg.checksum.objCt % checksum.objCt % msg.checksum.objIdCt % checksum.objIdCt; // and pause the game for further investigation framesinfo.isPaused = true; } replayinfo.async++; } } // Read GF of next command replayinfo.replay.ReadGF(&replayinfo.next_gf); } // Run game simulation NextGF(); // Check for game end if(curGF == replayinfo.replay.lastGF_) { char text[256]; sprintf(text, _("Notice: The played replay has ended. (GF: %u, %dh %dmin %ds, TF: %u, AVG_FPS: %u)"), curGF, GAMEMANAGER.GetRuntime() / 3600, ((GAMEMANAGER.GetRuntime()) % 3600) / 60, (GameManager::inst().GetRuntime()) % 3600 % 60, GameManager::inst().GetFrameCount(), GameManager::inst().GetAverageFPS()); if(ci) ci->CI_ReplayEndReached(text); if(replayinfo.async != 0) { char text[256]; sprintf(text, _("Notice: Overall asynchronous frame count: %u"), replayinfo.async); // Messenger im Game if(ci) ci->CI_ReplayEndReached(text); } replayinfo.end = true; framesinfo.isPaused = true; } }