00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <coms/ComsSyncCheckMessage.h>
00022 #include <common/Logger.h>
00023 #include <common/OptionsTransient.h>
00024 #include <engine/ActionController.h>
00025 #ifndef S3D_SERVER
00026 #include <client/ScorchedClient.h>
00027 #endif
00028 #include <server/ScorchedServer.h>
00029 #include <target/TargetContainer.h>
00030 #include <target/TargetState.h>
00031 #include <target/TargetLife.h>
00032 #include <tank/TankState.h>
00033 #include <tank/TankScore.h>
00034 #include <tank/Tank.h>
00035 #include <landscapemap/LandscapeMaps.h>
00036 #include <set>
00037
00038 ComsSyncCheckMessage::ComsSyncCheckMessage() :
00039 ComsMessage("ComsSyncCheckMessage")
00040 {
00041
00042 }
00043
00044 ComsSyncCheckMessage::~ComsSyncCheckMessage()
00045 {
00046
00047 }
00048
00049 bool ComsSyncCheckMessage::writeMessage(NetBuffer &buffer)
00050 {
00051
00052 std::vector<std::string>::iterator syncItor;
00053 std::vector<std::string> &syncs =
00054 ScorchedServer::instance()->getActionController().getSyncCheck();
00055 buffer.addToBuffer((int) syncs.size());
00056 for (syncItor = syncs.begin();
00057 syncItor != syncs.end();
00058 syncItor++)
00059 {
00060 buffer.addToBuffer(syncItor->c_str());
00061 }
00062
00063
00064 HeightMap &map = ScorchedServer::instance()->getLandscapeMaps().
00065 getGroundMaps().getHeightMap();
00066 for (int y=0; y<map.getMapHeight(); y++)
00067 {
00068 for (int x=0; x<map.getMapWidth(); x++)
00069 {
00070 fixed height = map.getHeight(x, y);
00071 buffer.addToBuffer(height);
00072 FixedVector &normal = map.getNormal(x, y);
00073 buffer.addToBuffer(normal);
00074 }
00075 }
00076
00077
00078 std::map<unsigned int, Target *> &possibletargets =
00079 ScorchedServer::instance()->getTargetContainer().getTargets();
00080 std::map<unsigned int, Target *>::iterator itor;
00081 buffer.addToBuffer((int) possibletargets.size());
00082 for (itor = possibletargets.begin();
00083 itor != possibletargets.end();
00084 itor++)
00085 {
00086 Target *target = (*itor).second;
00087 buffer.addToBuffer(target->getPlayerId());
00088
00089 if (target->isTarget())
00090 {
00091 if (!target->writeMessage(buffer)) return false;
00092 }
00093 else
00094 {
00095 if (!((Tank*)target)->writeMessage(buffer, true)) return false;
00096 }
00097 }
00098
00099 return true;
00100 }
00101
00102 #ifndef S3D_SERVER
00103
00104 #include <common/FileLogger.h>
00105 #include <image/ImageFactory.h>
00106 #include <landscape/Landscape.h>
00107
00108 static FileLogger *syncCheckFileLogger = 0;
00109
00110 static int syncCount = 0;
00111
00112 static void syncCheckLog(const std::string &message)
00113 {
00114 if (!syncCheckFileLogger)
00115 {
00116 char buffer[256];
00117 snprintf(buffer, 256, "SyncCheckLog-%u-", time(0));
00118 syncCheckFileLogger = new FileLogger(buffer);
00119 }
00120
00121 LoggerInfo info(message.c_str());
00122 info.setTime();
00123 syncCheckFileLogger->logMessage(info);
00124 }
00125
00126 bool ComsSyncCheckMessage::readMessage(NetBufferReader &reader)
00127 {
00128 syncCount++;
00129
00130 std::vector<std::string> &clientsyncs =
00131 ScorchedClient::instance()->getActionController().getSyncCheck();
00132 int serverSyncNo = 0, clientSyncNo = (int) clientsyncs.size();
00133 if (!reader.getFromBuffer(serverSyncNo)) return false;
00134
00135 bool printOutput = false;
00136 std::string output = S3D::formatStringBuffer(
00137 "SyncCheck %i - Action Diffs",
00138 syncCount);
00139 for (int s=0; s<MAX(serverSyncNo, clientSyncNo); s++)
00140 {
00141 std::string clientsync, serversync;
00142 if (s < serverSyncNo)
00143 {
00144 if (!reader.getFromBuffer(serversync)) return false;
00145 }
00146 if (s < clientSyncNo)
00147 {
00148 clientsync = clientsyncs[s];
00149 }
00150
00151 bool diff = (serversync != clientsync);
00152 if (diff) printOutput = true;
00153
00154 output.append(S3D::formatStringBuffer("%i: %s \n %s\n %s\n",
00155 syncCount,
00156 (diff?"***":""),
00157 serversync.c_str(),
00158 clientsync.c_str()));
00159 }
00160 if (printOutput)
00161 {
00162 syncCheckLog(output.c_str());
00163 }
00164
00165
00166 HeightMap &map = ScorchedClient::instance()->getLandscapeMaps().
00167 getGroundMaps().getHeightMap();
00168 int heightDiffs = 0, normalDiffs = 0;
00169 bool *heightDiff = new bool[map.getMapHeight() * map.getMapWidth()];
00170 for (int y=0; y<map.getMapHeight(); y++)
00171 {
00172 for (int x=0; x<map.getMapWidth(); x++)
00173 {
00174 fixed actualheight = map.getHeight(x, y);
00175 FixedVector actualnormal = map.getNormal(x, y);
00176 fixed sentheight;
00177 FixedVector sentnormal;
00178 if (!reader.getFromBuffer(sentheight)) return false;
00179 if (!reader.getFromBuffer(sentnormal)) return false;
00180
00181 if (actualheight != sentheight)
00182 {
00183 syncCheckLog(S3D::formatStringBuffer("*** %i %i",
00184 actualheight.getInternal(), sentheight.getInternal()));
00185 heightDiffs++;
00186 }
00187 if (actualnormal != sentnormal) normalDiffs++;
00188
00189 heightDiff[x + y * map.getMapWidth()] = (actualheight != sentheight);
00190 }
00191 }
00192 if (heightDiffs > 0 || normalDiffs > 0)
00193 {
00194 syncCheckLog(S3D::formatStringBuffer(
00195 "SyncCheck %i - Height diffs %i, Normal diffs %i",
00196 syncCount,
00197 heightDiffs, normalDiffs));
00198
00199 ImageHandle newMap = ImageFactory::createBlank(
00200 Landscape::instance()->getMainMap().getWidth(),
00201 Landscape::instance()->getMainMap().getHeight());
00202
00203 GLubyte *dest = newMap.getBits();
00204 GLubyte *src = Landscape::instance()->getMainMap().getBits();
00205 for (int y=0; y<newMap.getHeight(); y++)
00206 {
00207 for (int x=0; x<newMap.getWidth(); x++)
00208 {
00209 GLubyte r = src[0];
00210 GLubyte g = src[1];
00211 GLubyte b = src[2];
00212
00213 int x2 = (x * map.getMapWidth()) / newMap.getWidth();
00214 int y2 = (y * map.getMapHeight()) / newMap.getHeight();
00215 if (heightDiff[x2 + y2 * map.getMapWidth()])
00216 {
00217 r = g = b = 255;
00218 }
00219
00220 dest[0] = r;
00221 dest[1] = g;
00222 dest[2] = b;
00223
00224 dest+=3;
00225 src+=3;
00226 }
00227 }
00228 Landscape::instance()->getMainTexture().replace(newMap, false);
00229 Landscape::instance()->setTextureType(Landscape::eOther);
00230 }
00231
00232
00233 std::set<unsigned int> readTargets;
00234 int numberTargetsSend = 0;
00235 NetBuffer tmpBuffer;
00236
00237
00238 static Target *tmpTarget = new Target(0, LangString(),
00239 ScorchedClient::instance()->getContext());
00240 tmpTarget->getLife().setLife(0);
00241 static Tank *tmpTank = new Tank(
00242 ScorchedClient::instance()->getContext(),
00243 0,
00244 0,
00245 LangString(),
00246 Vector::getNullVector(),
00247 "",
00248 "");
00249 tmpTank->getState().setState(TankState::sDead);
00250
00251 if (!reader.getFromBuffer(numberTargetsSend)) return false;
00252 for (int i=0; i<numberTargetsSend; i++)
00253 {
00254 unsigned int playerId = 0;
00255 if (!reader.getFromBuffer(playerId)) return false;
00256 readTargets.insert(playerId);
00257
00258 Target *target = ScorchedClient::instance()->getTargetContainer().getTargetById(playerId);
00259 if (!target)
00260 {
00261 syncCheckLog(S3D::formatStringBuffer(
00262 "SyncCheck %i - Failed to find a client target : %u", syncCount, playerId));
00263 return true;
00264 }
00265
00266 tmpBuffer.reset();
00267 if (target->isTarget())
00268 {
00269 target->writeMessage(tmpBuffer);
00270 }
00271 else
00272 {
00273 ((Tank*)target)->writeMessage(tmpBuffer, true);
00274 }
00275
00276 bool different = false;
00277 if (!target->getTargetState().getMovement())
00278 {
00279 for (unsigned int i=0; i<tmpBuffer.getBufferUsed(); i++)
00280 {
00281 if (reader.getReadSize() + i >= reader.getBufferSize())
00282 {
00283 syncCheckLog(S3D::formatStringBuffer(
00284 "SyncCheck %i - Targets premature end of buffer : %u:%s, position %i",
00285 syncCount, playerId,
00286 target->getCStrName().c_str(), i));
00287
00288 different = true;
00289 break;
00290 }
00291 else if(tmpBuffer.getBuffer()[i] != reader.getBuffer()[reader.getReadSize() + i])
00292 {
00293 syncCheckLog(S3D::formatStringBuffer(
00294 "SyncCheck %i - Targets values differ : %u:%s, position %i",
00295 syncCount, playerId,
00296 target->getCStrName().c_str(), i));
00297
00298 different = true;
00299 Logger::addLogger(syncCheckFileLogger);
00300
00301
00302
00303 tmpBuffer.setBufferUsed(i);
00304 NetBufferReader tmpReader(tmpBuffer);
00305 if (target->isTarget())
00306 {
00307 tmpTarget->readMessage(tmpReader);
00308 tmpTarget->getLife().setLife(0);
00309 }
00310 else
00311 {
00312 tmpTank->readMessage(tmpReader);
00313 tmpTank->getState().setState(TankState::sDead);
00314 }
00315
00316 Logger::remLogger(syncCheckFileLogger);
00317 break;
00318 }
00319 }
00320 }
00321
00322 if (target->isTarget())
00323 {
00324 if (!tmpTarget->readMessage(reader)) return false;
00325 tmpTarget->getLife().setLife(0);
00326 }
00327 else
00328 {
00329 if (!tmpTank->readMessage(reader)) return false;
00330
00331 if (different)
00332 {
00333 syncCheckLog(S3D::formatStringBuffer("Server : %s:%s",
00334 tmpTank->getState().getStateString(),
00335 tmpTank->getScore().getScoreString()));
00336 syncCheckLog(S3D::formatStringBuffer("Client : %s:%s",
00337 ((Tank*)target)->getState().getStateString(),
00338 ((Tank*)target)->getScore().getScoreString()));
00339 }
00340
00341 tmpTank->getState().setState(TankState::sDead);
00342 }
00343 }
00344 if (reader.getBufferSize() != reader.getReadSize())
00345 {
00346 syncCheckLog(S3D::formatStringBuffer("SyncCheck not all bytes read : %i %i,%i",
00347 syncCount, reader.getBufferSize(), reader.getReadSize()));
00348 }
00349
00350 if (syncCheckFileLogger)
00351 {
00352 syncCheckLog(S3D::formatStringBuffer("SyncCheck : %i,%i",
00353 syncCount,
00354 ScorchedClient::instance()->getOptionsTransient().getCurrentGameNo()));
00355 }
00356
00357 if (syncCheckFileLogger)
00358 {
00359 syncCheckLog(S3D::formatStringBuffer("SyncCheck %i checked. (%i syncs)", syncCount, serverSyncNo));
00360 }
00361 else
00362 {
00363 Logger::log(S3D::formatStringBuffer("SyncCheck %i checked. (%i syncs)", syncCount, serverSyncNo));
00364 }
00365
00366 return true;
00367 }
00368
00369 #else // #ifndef S3D_SERVER
00370
00371 bool ComsSyncCheckMessage::readMessage(NetBufferReader &reader)
00372 {
00373 return true;
00374 }
00375
00376 #endif // #ifndef S3D_SERVER