| 1150 | } |
| 1151 | |
| 1152 | const char *CClient::LoadMap(const char *pName, const char *pFilename, const std::optional<SHA256_DIGEST> &WantedSha256, unsigned WantedCrc) |
| 1153 | { |
| 1154 | static char s_aErrorMsg[128]; |
| 1155 | |
| 1156 | SetState(IClient::STATE_LOADING); |
| 1157 | SetLoadingStateDetail(IClient::LOADING_STATE_DETAIL_LOADING_MAP); |
| 1158 | if((bool)m_LoadingCallback) |
| 1159 | m_LoadingCallback(IClient::LOADING_CALLBACK_DETAIL_MAP); |
| 1160 | |
| 1161 | if(!GameClient()->Map()->Load(pName, Storage(), pFilename, IStorage::TYPE_ALL)) |
| 1162 | { |
| 1163 | str_format(s_aErrorMsg, sizeof(s_aErrorMsg), "map '%s' not found", pFilename); |
| 1164 | return s_aErrorMsg; |
| 1165 | } |
| 1166 | |
| 1167 | if(WantedSha256.has_value() && GameClient()->Map()->Sha256() != WantedSha256.value()) |
| 1168 | { |
| 1169 | char aWanted[SHA256_MAXSTRSIZE]; |
| 1170 | char aGot[SHA256_MAXSTRSIZE]; |
| 1171 | sha256_str(WantedSha256.value(), aWanted, sizeof(aWanted)); |
| 1172 | sha256_str(GameClient()->Map()->Sha256(), aGot, sizeof(aWanted)); |
| 1173 | str_format(s_aErrorMsg, sizeof(s_aErrorMsg), "map differs from the server. %s != %s", aGot, aWanted); |
| 1174 | m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", s_aErrorMsg); |
| 1175 | GameClient()->Map()->Unload(); |
| 1176 | return s_aErrorMsg; |
| 1177 | } |
| 1178 | |
| 1179 | // Only check CRC if we don't have the secure SHA256. |
| 1180 | if(!WantedSha256.has_value() && GameClient()->Map()->Crc() != WantedCrc) |
| 1181 | { |
| 1182 | str_format(s_aErrorMsg, sizeof(s_aErrorMsg), "map differs from the server. %08x != %08x", GameClient()->Map()->Crc(), WantedCrc); |
| 1183 | m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", s_aErrorMsg); |
| 1184 | GameClient()->Map()->Unload(); |
| 1185 | return s_aErrorMsg; |
| 1186 | } |
| 1187 | |
| 1188 | // stop demo recording if we loaded a new map |
| 1189 | for(int Recorder = 0; Recorder < RECORDER_MAX; Recorder++) |
| 1190 | { |
| 1191 | DemoRecorder(Recorder)->Stop(Recorder == RECORDER_REPLAYS ? IDemoRecorder::EStopMode::REMOVE_FILE : IDemoRecorder::EStopMode::KEEP_FILE); |
| 1192 | } |
| 1193 | |
| 1194 | char aBuf[256]; |
| 1195 | str_format(aBuf, sizeof(aBuf), "loaded map '%s'", pFilename); |
| 1196 | m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aBuf); |
| 1197 | |
| 1198 | return nullptr; |
| 1199 | } |
| 1200 | |
| 1201 | static void FormatMapDownloadFilename(const char *pName, const std::optional<SHA256_DIGEST> &Sha256, int Crc, bool Temp, char *pBuffer, int BufferSize) |
| 1202 | { |