[Gameplay] Reduce loom cost
[0ad.git] / source / network / NetClientTurnManager.cpp
blob8919c1c3fed1a076edcef435aab7f2397471005f
1 /* Copyright (C) 2021 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #include "precompiled.h"
20 #include "NetClientTurnManager.h"
21 #include "NetClient.h"
23 #include "ps/CLogger.h"
24 #include "ps/Pyrogenesis.h"
25 #include "ps/Replay.h"
26 #include "ps/Profile.h"
27 #include "ps/Util.h"
28 #include "simulation2/Simulation2.h"
30 #include <fstream>
32 #if 0
33 #define NETCLIENTTURN_LOG(...) debug_printf(__VA_ARGS__)
34 #else
35 #define NETCLIENTTURN_LOG(...)
36 #endif
38 extern CStrW g_UniqueLogPostfix;
40 CNetClientTurnManager::CNetClientTurnManager(CSimulation2& simulation, CNetClient& client, int clientId, IReplayLogger& replay)
41 : CTurnManager(simulation, DEFAULT_TURN_LENGTH, COMMAND_DELAY_MP, clientId, replay), m_NetClient(client)
45 void CNetClientTurnManager::PostCommand(JS::HandleValue data)
47 NETCLIENTTURN_LOG("PostCommand()\n");
49 // Transmit command to server
50 CSimulationMessage msg(m_Simulation2.GetScriptInterface(), m_ClientId, m_PlayerId, m_CurrentTurn + m_CommandDelay, data);
51 m_NetClient.SendMessage(&msg);
53 // Add to our local queue
54 //AddCommand(m_ClientId, m_PlayerId, data, m_CurrentTurn + m_CommandDelay);
55 // TODO: we should do this when the server stops sending our commands back to us
58 void CNetClientTurnManager::NotifyFinishedOwnCommands(u32 turn)
60 NETCLIENTTURN_LOG("NotifyFinishedOwnCommands(%d)\n", turn);
62 CEndCommandBatchMessage msg;
64 msg.m_Turn = turn;
66 // The turn-length field of the CEndCommandBatchMessage is currently only relevant
67 // when sending it from the server to the clients.
68 // It could be used to verify that the client simulated the correct turn length.
69 msg.m_TurnLength = 0;
71 m_NetClient.SendMessage(&msg);
74 void CNetClientTurnManager::NotifyFinishedUpdate(u32 turn)
76 bool quick = !TurnNeedsFullHash(turn);
77 std::string hash;
79 PROFILE3("state hash check");
80 ENSURE(m_Simulation2.ComputeStateHash(hash, quick));
83 NETCLIENTTURN_LOG("NotifyFinishedUpdate(%d, %hs)\n", turn, Hexify(hash).c_str());
85 m_Replay.Hash(hash, quick);
87 // Send message to the server
88 CSyncCheckMessage msg;
89 msg.m_Turn = turn;
90 msg.m_Hash = hash;
91 m_NetClient.SendMessage(&msg);
94 void CNetClientTurnManager::OnDestroyConnection()
96 // Attempt to flush messages before leaving.
97 // Notice the sending is not reliable and rarely makes it to the Server.
98 if (m_NetClient.GetCurrState() == NCS_INGAME)
99 NotifyFinishedOwnCommands(m_CurrentTurn + m_CommandDelay);
102 void CNetClientTurnManager::OnSimulationMessage(CSimulationMessage* msg)
104 // Command received from the server - store it for later execution
105 AddCommand(msg->m_Client, msg->m_Player, msg->m_Data, msg->m_Turn);
108 void CNetClientTurnManager::OnSyncError(u32 turn, const CStr& expectedHash, const std::vector<CSyncErrorMessage::S_m_PlayerNames>& playerNames)
110 CStr expectedHashHex(Hexify(expectedHash));
111 NETCLIENTTURN_LOG("OnSyncError(%d, %hs)\n", turn, expectedHashHex.c_str());
113 std::string hash;
114 ENSURE(m_Simulation2.ComputeStateHash(hash, !TurnNeedsFullHash(turn)));
116 OsPath oosdumpPath(psLogDir() / (L"oos_dump" + g_UniqueLogPostfix + L".txt"));
117 std::ofstream file (OsString(oosdumpPath).c_str(), std::ofstream::out | std::ofstream::trunc);
118 file << "oos turn: " << turn << std::endl;
119 file << "net client turn: " << m_CurrentTurn << std::endl;
120 m_Simulation2.DumpDebugState(file);
121 file.close();
123 std::ofstream binfile (OsString(oosdumpPath.ChangeExtension(L".dat")).c_str(), std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
124 m_Simulation2.SerializeState(binfile);
125 binfile.close();
127 std::stringstream playerNamesString;
128 std::vector<CStr> playerNamesStrings;
129 playerNamesStrings.reserve(playerNames.size());
130 for (size_t i = 0; i < playerNames.size(); ++i)
132 CStr name = utf8_from_wstring(playerNames[i].m_Name);
133 playerNamesString << (i == 0 ? "" : ", ") << name;
134 playerNamesStrings.push_back(name);
137 LOGERROR("Out-Of-Sync on turn %d\nPlayers: %s\nDumping state to %s", turn, playerNamesString.str().c_str(), oosdumpPath.string8());
139 m_NetClient.PushGuiMessage(
140 "type", "out-of-sync",
141 "turn", turn,
142 "players", playerNamesStrings,
143 "expectedHash", expectedHashHex,
144 "hash", Hexify(hash),
145 "path_oos_dump", wstring_from_utf8(oosdumpPath.string8()),
146 "path_replay", wstring_from_utf8(m_Replay.GetDirectory().string8()));