00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "object-sync.h"
00035
00036
00037 #include "common/wave_ex.h"
00038 #include "map-manager/map-manager.h"
00039 #include "perf/perf.h"
00040 #include "util/circular.h"
00041
00042 namespace aesop {
00043
00044
00046
00049
00050 ObjectSync::~ObjectSync(void) throw() { }
00051
00052
00053
00054 static const float s_largeDifference = 1.5;
00055 static const float s_maxLocalMove = 1.0;
00056
00057 static const int s_clientSendHistory = 16;
00058
00059
00061
00062
00063
00065
00066 class ObjectExistsRequest : public netrq::Request {
00067 public:
00068 ~ObjectExistsRequest(void) throw() { }
00069
00070
00071 const char * getId(void) const throw() { return m_requestId; }
00072 int getMaxBytes(void) const throw() { return 6; }
00073 void write(IO xdrbuf::Output * output) {
00074 ASSERT(output, "null");
00075
00076
00077 output->addInt32Packlet('e',
00078 (int32_t *) &m_objectId, 1);
00079 }
00080
00081
00082 static smart_ptr<netrq::Request> create(IN const char * requestId,
00083 IN dword_t objectId) {
00084 ASSERT(requestId, "null");
00085 ASSERT(objectId, "null");
00086
00087 smart_ptr<ObjectExistsRequest> local =
00088 new ObjectExistsRequest;
00089 ASSERT(local, "out of memory");
00090
00091 strcpy(local->m_requestId, requestId);
00092 local->m_objectId = objectId;
00093
00094 return local;
00095 }
00096
00097 private:
00098
00099 ObjectExistsRequest(void) throw() { }
00100
00101
00102 char m_requestId[64];
00103 dword_t m_objectId;
00104 };
00105
00106
00107
00109
00110
00111
00113
00114 class SyncImpl : public ObjectSync {
00115 public:
00116
00117 ~SyncImpl(void) throw() { }
00118
00119
00120 void initialize(IN smart_ptr<MapManager> mapMgr) throw() {
00121 ASSERT(mapMgr, "null");
00122 m_mapMgr = mapMgr;
00123 }
00124
00125
00126 void serverUpdate(IN dword_t id,
00127 IN dword_t lastClientClock,
00128 IN const state_update_t& state);
00129 void clientUpdate(IN dword_t clientClock);
00130 bool clientMoveRequest(IN dword_t id,
00131 IN const point3d_t& delta,
00132 IN float dt,
00133 OUT point3d_t& newPosition);
00134 bool getState(IN dword_t id,
00135 OUT object_state_t& state);
00136 bool setTypeId(IN dword_t id,
00137 IN const char * typeId);
00138 bool setMapId(IN dword_t id,
00139 IN const char * mapId);
00140 void addRequests(IN netrq::Queue * queue,
00141 IN dword_t clock);
00142 void removeObject(IN dword_t id);
00143
00144 private:
00145
00146 struct client_send_t {
00147 dword_t localClock;
00148 state_update_t update;
00149 };
00150
00151 typedef circular_buffer_t<client_send_t> send_records_t;
00152
00153 struct state_record_t {
00154
00155 state_record_t(void) throw() : sends(s_clientSendHistory) {
00156 lupsu = 0;
00157 correctCount = 0;
00158 dyn = NULL;
00159 }
00160
00161
00162 state_update_t bestGuess;
00163 point3d_t lastKnownGood;
00164 send_records_t sends;
00165 int lupsu;
00166 point3d_t correction;
00167 int correctCount;
00168 AESOPIdBuffer typeId;
00169 AESOPIdBuffer mapId;
00170 smart_ptr<MapDynamics> dyn;
00171 smart_ptr<PhysicsObject> physicsObj;
00172 };
00173
00174 typedef std::map<dword_t, smart_ptr<state_record_t> > obj_map_t;
00175
00176
00177 state_record_t * getRecord(IN dword_t id, IN bool create = false);
00178
00179
00180 obj_map_t m_map;
00181 smart_ptr<MapManager> m_mapMgr;
00182 };
00183
00184
00185
00186 void
00187 SyncImpl::serverUpdate
00188 (
00189 IN dword_t id,
00190 IN dword_t lastClientClock,
00191 IN const state_update_t& update
00192 )
00193 {
00194 ASSERT(id, "null");
00195 ASSERT(lastClientClock, "null");
00196
00197
00198
00199 state_record_t * psr = this->getRecord(id, true);
00200 ASSERT(psr, "null");
00201 PhysicsObject * obj = psr->physicsObj;
00202 if (!obj) {
00203
00204 psr->bestGuess = update;
00205 return;
00206 }
00207
00208
00209
00210 int N = psr->sends.size();
00211 for (int i = N - 1; i >= 0; --i) {
00212 const client_send_t& cs = psr->sends.getSample(i);
00213 if (cs.localClock == lastClientClock) {
00214
00215
00216
00217
00218
00219
00220
00221 point3d_t delta = update.position - cs.update.position;
00222
00223
00224 for (i = i + 1; i < N; ++i) {
00225 client_send_t& csLater =
00226 psr->sends.getSample(i);
00227 csLater.update.position =
00228 csLater.update.position + delta;
00229 }
00230
00231
00232 if (!(lastClientClock % 250)) {
00233 DPRINTF("Comparing local + server view of position at clock %lu",
00234 (long) lastClientClock);
00235 cs.update.position.dump(" local");
00236 update.position.dump( " server");
00237 delta.dump( " delta");
00238 }
00239
00240
00241 int count = psr->lupsu;
00242 if (count < 1) {
00243 count = 1;
00244 }
00245 count = 5;
00246 psr->correction = 0.5 * delta;
00247 psr->correctCount = count;
00248 break;
00249 }
00250 }
00251
00252
00253 obj->setOrientation(update.orientation);
00254 obj->setLinearVelocity(update.linear);
00255 obj->setAngularVelocity(update.angular);
00256
00257 point3d_t diff = psr->bestGuess.position - update.position;
00258 float r2 = dotProduct(diff, diff);
00259
00260 if (r2 > s_largeDifference) {
00261 DPRINTF("Large difference!");
00262 update.position.dump( " server");
00263 psr->bestGuess.position.dump(" local");
00264 psr->bestGuess = update;
00265 obj->setPosition(update.position);
00266 psr->correctCount = 0;
00267 }
00268
00269
00270 psr->lastKnownGood = update.position;
00271 psr->lupsu = 0;
00272 }
00273
00274
00275
00276 void
00277 SyncImpl::clientUpdate
00278 (
00279 IN dword_t clientClock
00280 )
00281 {
00282 ASSERT(clientClock, "null");
00283
00284
00285 for (obj_map_t::iterator i = m_map.begin(); i != m_map.end(); ++i) {
00286 state_record_t * psr = i->second;
00287 ASSERT(psr, "null state record in map?");
00288
00289
00290 PhysicsObject * obj = psr->physicsObj;
00291 if (obj) {
00292 psr->bestGuess.position = obj->getPosition();
00293 } else {
00294
00295
00296 if (!psr->typeId.isEmpty() &&
00297 !psr->mapId.isEmpty()) {
00298
00299 smart_ptr<MapDynamics> dyn = m_mapMgr->getMap(
00300 psr->mapId);
00301 if (dyn) {
00302
00303 smart_ptr<Instance> instance =
00304 Instance::create(NULL, psr->typeId);
00305 placement_t& p = instance->getPlacement();
00306 p.position = psr->bestGuess.position;
00307
00308 psr->physicsObj =
00309 dyn->addInstance(instance);
00310
00311
00312 psr->dyn = dyn;
00313 }
00314 }
00315 }
00316
00317 client_send_t cs;
00318 cs.localClock = clientClock;
00319 cs.update = psr->bestGuess;
00320 psr->sends.addSample(cs);
00321 }
00322 }
00323
00324
00325
00326 bool
00327 SyncImpl::clientMoveRequest
00328 (
00329 IN dword_t id,
00330 IN const point3d_t& delta,
00331 IN float dt,
00332 OUT point3d_t& newPosition
00333 )
00334 {
00335 ASSERT(id, "null");
00336 newPosition.clear();
00337
00338
00339 if (dt <= 0.0)
00340 return true;
00341
00342
00343
00344 state_record_t * psr = this->getRecord(id);
00345 if (!psr) {
00346 DPRINTF("Client requesting update to non-existent object");
00347 return false;
00348 }
00349 PhysicsObject * obj = psr->physicsObj;
00350 if (!obj) {
00351 return true;
00352 }
00353
00354
00355 psr->lupsu++;
00356
00357
00358 point3d_t newPos = psr->bestGuess.position + delta;
00359 point3d_t diff = psr->lastKnownGood - newPos;
00360 float r2 = dotProduct(diff, diff);
00361
00362
00363
00364
00365 point3d_t motion;
00366 if (r2 > s_maxLocalMove) {
00367
00368
00369 DPRINTF(" No move!");
00370 motion.clear();
00371 } else {
00372
00373 motion = delta;
00374 }
00375
00376
00377 if (psr->correctCount > 0) {
00378 --psr->correctCount;
00379 motion += psr->correction;
00380 psr->correction = 0.5 * psr->correction;
00381 }
00382
00383
00384
00385 obj->requestMove(motion, 0.8 * dt);
00386
00387
00388 newPosition = psr->bestGuess.position;
00389 return true;
00390 }
00391
00392
00393
00394 bool
00395 SyncImpl::getState
00396 (
00397 IN dword_t id,
00398 OUT object_state_t& state
00399 )
00400 {
00401 ASSERT(id, "null");
00402 state.clear();
00403
00404 state_record_t * psr = this->getRecord(id);
00405 if (!psr) {
00406 DPRINTF("Requesting state for non-existent object");
00407 return false;
00408 }
00409
00410
00411 state_update_t * update = (state_update_t *) &state;
00412 *update = psr->bestGuess;
00413
00414
00415 state.physicsObject = psr->physicsObj;
00416 state.typeId = psr->typeId;
00417 state.dyn = psr->dyn;
00418
00419 return true;
00420 }
00421
00422
00423
00424 bool
00425 SyncImpl::setTypeId
00426 (
00427 IN dword_t id,
00428 IN const char * typeId
00429 )
00430 {
00431 ASSERT(id, "null");
00432 ASSERT(typeId, "null");
00433
00434 state_record_t * psr = this->getRecord(id);
00435 if (!psr) {
00436 return false;
00437 }
00438
00439
00440 psr->typeId.set(typeId);
00441 return true;
00442 }
00443
00444
00445
00446 bool
00447 SyncImpl::setMapId
00448 (
00449 IN dword_t id,
00450 IN const char * mapId
00451 )
00452 {
00453 ASSERT(id, "null");
00454 ASSERT(mapId, "null");
00455
00456 state_record_t * psr = this->getRecord(id);
00457 if (!psr) {
00458 return false;
00459 }
00460
00461
00462 psr->mapId.set(mapId);
00463
00464
00465
00466
00467 m_mapMgr->requestLoad(mapId);
00468
00469
00470 return true;
00471 }
00472
00473
00474
00475 void
00476 SyncImpl::addRequests
00477 (
00478 IN netrq::Queue * queue,
00479 IN dword_t clock
00480 )
00481 {
00482 ASSERT(queue, "null");
00483
00484
00485 for (obj_map_t::iterator i = m_map.begin(); i != m_map.end(); ++i) {
00486 long id = i->first;
00487
00488 char buffer[64];
00489 sprintf(buffer, "oe-%ld", id);
00490 if (queue->containsRequest(buffer))
00491 continue;
00492
00493 smart_ptr<netrq::Request> request =
00494 ObjectExistsRequest::create(buffer, id);
00495 ASSERT(request, "null");
00496
00497 queue->addRequest(clock + 5 + (rand() % 32), request);
00498 }
00499 }
00500
00501
00502
00503 void
00504 SyncImpl::removeObject
00505 (
00506 IN dword_t id
00507 )
00508 {
00509 ASSERT(id, "bad object id");
00510
00511 obj_map_t::iterator i = m_map.find(id);
00512 if (m_map.end() == i) {
00513 DPRINTF("Object not found to remove: %lu", (long) id);
00514 return;
00515 }
00516
00517 state_record_t * psr = i->second;
00518 if (psr->physicsObj && psr->dyn) {
00519
00520 psr->dyn->removeObject(psr->physicsObj);
00521 } else {
00522 DPRINTF("Removing partially constructed object! %lu",
00523 (long) id);
00524 }
00525
00526
00527 m_map.erase(i);
00528 }
00529
00530
00531
00533
00534
00535
00537
00538 SyncImpl::state_record_t *
00539 SyncImpl::getRecord
00540 (
00541 IN dword_t id,
00542 IN bool create
00543 )
00544 {
00545 ASSERT(id, "null");
00546
00547 obj_map_t::iterator i = m_map.find(id);
00548 if (m_map.end() != i) {
00549
00550 state_record_t * psr = i->second;
00551 ASSERT(psr, "null record in map");
00552 return psr;
00553 }
00554
00555
00556 if (!create)
00557 return NULL;
00558
00559
00560 smart_ptr<state_record_t> psr = new state_record_t;
00561 ASSERT(psr, "null");
00562 m_map[id] = psr;
00563 return psr;
00564 }
00565
00566
00567
00569
00570
00571
00573
00574 smart_ptr<ObjectSync>
00575 ObjectSync::create
00576 (
00577 IN smart_ptr<MapManager> mapMgr
00578 )
00579 {
00580 ASSERT(mapMgr, "null");
00581
00582 smart_ptr<SyncImpl> local = new SyncImpl;
00583 ASSERT(local, "out of memory");
00584
00585 local->initialize(mapMgr);
00586
00587 return local;
00588 }
00589
00590
00591
00592 };
00593