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
00035 #include "srv-game-logic.h"
00036
00037 #include "datahash/datahash_util.h"
00038 #include "map-dynamics/map-dynamics.h"
00039 #include "aesop-srv/srv-object.h"
00040 #include "threadsafe/smart_mutex.h"
00041 #include "timer/timer.h"
00042
00043
00044 namespace aesop {
00045
00046
00048
00049
00050
00052
00053 static float
00054 getRandomX
00055 (
00056 void
00057 )
00058 throw()
00059 {
00060 static const float s_maxX = 0.25;
00061 float x = (1.0 * rand()) / RAND_MAX;
00062 x -= 0.5;
00063 x *= 2 * s_maxX;
00064
00065 return x;
00066 }
00067
00068
00069
00070 static const char *
00071 getIntBuffer
00072 (
00073 IN dword_t dw
00074 )
00075 {
00076 static char s_buffer[64];
00077 sprintf(s_buffer, "%lu", (long) dw);
00078 return s_buffer;
00079 }
00080
00081
00082
00083 static bool
00084 isPortal
00085 (
00086 IN smart_ptr<Instance>& i
00087 )
00088 {
00089 ASSERT(i, "null");
00090
00091 smart_ptr<Datahash> data = i->getInstanceData("game");
00092 if (!data)
00093 return false;
00094
00095 return !strcmp("portal", getOptionalString(data, "type", ""));
00096 }
00097
00098
00099 class DestroyObjectTimer : public timer::Timer {
00100 public:
00101 ~DestroyObjectTimer(void) throw() { }
00102
00103
00104 void notifyTimer(void) {
00105 DPRINTF("removing object %ld", m_objectId);
00106
00107 smart_ptr<PhysicsObject> obj =
00108 getPhysicsObjectById(m_objectId);
00109 if (!obj) {
00110 DPRINTF("Object does not exist: %ld",
00111 m_objectId);
00112 DPRINTF(" Ignoring remove request");
00113 return;
00114 }
00115
00116 MapDynamics * dyn =
00117 getMapDynamicsFromPhysicsObject(obj);
00118 if (!dyn) {
00119 DPRINTF("ERROR: cannot get map from object?");
00120 return;
00121 }
00122 dyn->removeObject(obj);
00123 }
00124
00125
00126 static smart_ptr<timer::Timer> create(IN long objectId) {
00127 smart_ptr<DestroyObjectTimer> local =
00128 new DestroyObjectTimer;
00129 ASSERT(local, "out of memory");
00130
00131 local->m_objectId = objectId;
00132
00133 return local;
00134 }
00135
00136 private:
00137 DestroyObjectTimer(void) throw() { }
00138
00139
00140 long m_objectId;
00141 };
00142
00143
00144
00158 class RefGameLogic : public ServerGameLogic {
00159 public:
00160
00161 ~RefGameLogic(void) throw() { }
00162
00163
00164 void initialize(void);
00165
00166
00167 void setPlayerManager(IN smart_ptr<PlayerManager>& playerMgr);
00168 void setMapManager(IN smart_ptr<MapManager>& mapMgr);
00169 bool requestPlayerStartTS(IO player_rec_t& pr);
00170 void tick(IN float dt);
00171 void parseGameData(IN conn_id_t conn_id, IN xdrbuf::Input * input);
00172
00173 private:
00174
00175 void handleCollision(IN PhysicsWorld * world,
00176 IN smart_ptr<PhysicsObject> obj1,
00177 IN smart_ptr<PhysicsObject> obj2);
00178 void handlePortal(IN PhysicsWorld * world,
00179 IN smart_ptr<Instance>& player,
00180 IN smart_ptr<Instance>& portal);
00181
00182
00183 smart_mutex m_mutex;
00184 smart_ptr<PlayerManager> m_playerMgr;
00185 smart_ptr<MapManager> m_mapMgr;
00186 smart_ptr<timer::Queue> m_timerQueue;
00187 std::string m_mostRecentMapId;
00188 qword_t m_currentTime;
00189 };
00190
00191
00193
00194
00195
00197
00198 void
00199 RefGameLogic::initialize
00200 (
00201 void
00202 )
00203 {
00204 m_timerQueue = timer::Queue::create();
00205 ASSERT(m_timerQueue, "null");
00206 }
00207
00208
00209
00211
00212
00213
00215
00216 void
00217 RefGameLogic::setPlayerManager
00218 (
00219 IN smart_ptr<PlayerManager>& playerMgr
00220 )
00221 {
00222 ASSERT(playerMgr, "null");
00223
00224
00225 m_playerMgr = playerMgr;
00226 }
00227
00228
00229
00230 void
00231 RefGameLogic::setMapManager
00232 (
00233 IN smart_ptr<MapManager>& mapMgr
00234 )
00235 {
00236 ASSERT(mapMgr, "null");
00237
00238
00239 m_mapMgr = mapMgr;
00240 }
00241
00242
00243
00244 bool
00245 RefGameLogic::requestPlayerStartTS
00246 (
00247 IO player_rec_t& pr
00248 )
00249 {
00250 ASSERT(pr.udpConnId, "null");
00251 ASSERT(pr.playerId > 0, "bad player id: %d", pr.playerId);
00252 ASSERT(m_mapMgr, "null");
00253
00254 DPRINTF("Requesting start for player %d, user %s",
00255 pr.playerId, (const char *) pr.username);
00256
00257
00258 if (!pr.isAuthenticated()) {
00259 DPRINTF("Shouldn't be told about unauthenticated players!");
00260 return false;
00261 }
00262
00263
00264 if (pr.obj) {
00265 DPRINTF("Player is already in world");
00266 return false;
00267 }
00268
00269
00270 if ("" == m_mostRecentMapId) {
00271 DPRINTF("No recent map!");
00272 return false;
00273 }
00274
00275 smart_ptr<MapDynamics> dyn = m_mapMgr->getMap(m_mostRecentMapId.c_str());
00276 if (!dyn) {
00277 DPRINTF("Most recently loaded map is no longer relevant");
00278 m_mostRecentMapId = "";
00279 return false;
00280 }
00281
00282
00283 if (!pr.mapId) {
00284
00285 pr.mapId.set(m_mostRecentMapId.c_str());
00286 }
00287
00288
00289 dyn = m_mapMgr->getMap(pr.mapId);
00290 if (!dyn)
00291 return true;
00292 Map * map = dyn->getMap();
00293 ASSERT(map, "null");
00294
00295
00296 if (!pr.startId) {
00297 pr.startId.set(map->getDefaultStartingPointId());
00298 }
00299
00300
00301 destination_t dest;
00302 map->getStartingPoint(pr.startId, dest);
00303
00304
00305 point3d_t mid;
00306 mid.x = 0.5 * (dest.rect.x0 + dest.rect.x1);
00307 mid.y = 0.5 * (dest.rect.y0 + dest.rect.y1);
00308 mid.z = 0.5 * (dest.rect.z0 + dest.rect.z1);
00309
00310
00311
00312 smart_ptr<Datahash> data = Datahash::create();
00313 data->insert("type", "player");
00314 data->insert("udpConnId", getIntBuffer(pr.udpConnId));
00315 data->insert("playerId", getIntBuffer(pr.playerId));
00316
00317
00318 smart_ptr<Instance> instance = Instance::create(pr.playerTag, "player");
00319 placement_t& p = instance->getPlacement();
00320 p.position = mid;
00321 instance->setInstanceData("game", data);
00322 instance->dump("Just added player here");
00323
00324
00325 pr.obj = dyn->addInstance(instance);
00326 if (!pr.obj) {
00327 DPRINTF("Nothing added?");
00328 }
00329
00330
00331 return true;
00332 }
00333
00334
00335
00336 void
00337 RefGameLogic::tick
00338 (
00339 IN float dt
00340 )
00341 {
00342 ASSERT(dt > 0.0, "bad time delta: %f", dt);
00343 ASSERT(m_timerQueue, "null");
00344
00345
00346 m_currentTime += (qword_t) (1.0e6 * dt + 0.5);
00347
00348
00349 m_timerQueue->checkTimers(m_currentTime);
00350
00351
00352 if (!m_mapMgr)
00353 return;
00354
00355
00356 MapManager::iterator_t iter;
00357 m_mapMgr->getIterator(iter);
00358 smart_ptr<MapDynamics> dyn;
00359 while (m_mapMgr->getNextMap(iter, dyn)) {
00360 ASSERT(dyn, "null dynamics");
00361
00362
00363 if ("" == m_mostRecentMapId) {
00364 Map * map = dyn->getMap();
00365 ASSERT(map, "null");
00366 m_mostRecentMapId = map->getId();
00367 }
00368
00369
00370 PhysicsWorld * world = dyn->getPhysics();
00371 ASSERT(world, "null");
00372 PhysicsWorld::collision_iterator_t ci;
00373 world->getCollisionIterator(ci);
00374 PhysicsWorld::collision_record_t cr;
00375 while (world->getNextCollision(ci, cr)) {
00376 this->handleCollision(world, cr.obj1, cr.obj2);
00377 }
00378 }
00379 }
00380
00381
00382
00383 void
00384 RefGameLogic::parseGameData
00385 (
00386 IN conn_id_t conn_id,
00387 IN xdrbuf::Input * input
00388 )
00389 {
00390
00391 ASSERT(input, "null");
00392
00393
00394
00395
00396
00397
00398
00399 while (true) {
00400 xdrbuf::PackletHeader ph = input->getNextPackletHeader();
00401 xdrbuf::ePackletType type = ph.getType();
00402 if (xdrbuf::ePacklet_ParentEnd == type)
00403 break;
00404
00405 char name = ph.getName();
00406 switch (name) {
00407
00408 case 'a':
00409 {
00410
00411
00412 ph = input->getNextPackletHeader();
00413 int32_t l;
00414 input->readInt32s(&l, 1);
00415 int playerId = (int) l;
00416
00417
00418 ph = input->getNextPackletHeader();
00419 const int bufsize = 128;
00420 char buffer[bufsize];
00421 int nChars = ph.getDataCount();
00422 ASSERT_THROW(nChars < bufsize,
00423 "reading animation string of size " <<
00424 nChars);
00425 input->readString(buffer, nChars);
00426 buffer[nChars] = 0;
00427 DPRINTF("Just read animation state: '%s'",
00428 buffer);
00429
00430
00431 ph = input->getNextPackletHeader();
00432 if (xdrbuf::ePacklet_ParentEnd != ph.getType()) {
00433 WAVE_EX(wex);
00434 wex << "Animation packlet not closed";
00435 }
00436
00437 player_rec_t pr;
00438 if (!m_playerMgr->getPlayerByHostAndPlayerId(conn_id,
00439 playerId, pr)) {
00440 DPRINTF("No such player for animation");
00441 } else {
00442 if (!pr.obj) {
00443 DPRINTF("No object for player?");
00444 } else {
00445 smart_ptr<Instance> inst =
00446 getInstanceFromPhysicsObject(pr.obj);
00447 if (!inst) {
00448 DPRINTF("No instance?");
00449 } else {
00450 smart_ptr<ServerObject> so =
00451 getServerObject(inst);
00452 ASSERT_THROW(so, "null");
00453 so->setAnimationState(conn_id, buffer);
00454 }
00455 }
00456 }
00457
00458 }
00459 break;
00460
00461 case 's':
00462 {
00463
00464
00465
00466 ph = input->getNextPackletHeader();
00467 int32_t l;
00468 input->readInt32s(&l, 1);
00469 int playerId = (int) l;
00470 DPRINTF("Shot request from player: %d", playerId);
00471 if (playerId < 1) {
00472 WAVE_EX(wex);
00473 wex << "Bad player id: " << playerId;
00474 }
00475
00476
00477 ph = input->getNextPackletHeader();
00478 float f[7];
00479 input->readFloats(f, 7);
00480
00481 point3d_t pos;
00482 pos.x = f[0];
00483 pos.y = f[1];
00484 pos.z = f[2];
00485
00486 quaternion_t rot;
00487 rot.x = f[3];
00488 rot.y = f[4];
00489 rot.z = f[5];
00490 rot.w = f[6];
00491
00492 DPRINTF("Got shot request");
00493 pos.dump(" position");
00494 rot.dump(" rotation");
00495
00496
00497 ph = input->getNextPackletHeader();
00498 if (xdrbuf::ePacklet_ParentEnd != ph.getType()) {
00499 WAVE_EX(wex);
00500 wex << "Shot packlet not closed";
00501 }
00502
00503
00504 player_rec_t pr;
00505 if (conn_id &&
00506 m_playerMgr->getPlayerByHostAndPlayerId(conn_id, playerId, pr)) {
00507 DPRINTF("Found player!");
00508 DPRINTF(" In map: %s", (const char *) pr.mapId);
00509
00510 smart_ptr<MapDynamics> dyn = m_mapMgr->getMap(pr.mapId);
00511 if (dyn) {
00512 DPRINTF(" have map dynamics!");
00513
00514
00515 point3d_t dir;
00516 getVectorFromQuaternion(rot, dir);
00517
00518
00519 smart_ptr<Instance> inst =
00520 Instance::create(NULL, "25cm-cube");
00521 placement_t& p = inst->getPlacement();
00522 p.position = pos + dir;
00523 p.rotation = rot;
00524
00525 smart_ptr<PhysicsObject> obj = dyn->addInstance(inst);
00526 if (obj) {
00527 DPRINTF(" Added object!");
00528 }
00529
00530
00531 obj->setLinearVelocity(7.5 * dir);
00532
00533
00534 point3d_t angular;
00535 angular.x = getRandomX();
00536 angular.y = getRandomX();
00537 angular.z = getRandomX();
00538 obj->setAngularVelocity(angular);
00539
00540
00541 long objectId = obj->getId();
00542 smart_ptr<timer::Timer> timer =
00543 DestroyObjectTimer::create(objectId);
00544 ASSERT(timer, "null");
00545
00546 qword_t delay = 15 * 1000 * 1000;
00547 m_timerQueue->addTimer(delay, timer);
00548 }
00549 }
00550
00551
00552
00553 }
00554 break;
00555
00556 default:
00557 {
00558 WAVE_EX(wex);
00559 wex << "Unknown packlet type: " << name;
00560 }
00561 }
00562 }
00563 }
00564
00565
00566
00568
00569
00570
00572
00573 void
00574 RefGameLogic::handleCollision
00575 (
00576 IN PhysicsWorld * world,
00577 IN smart_ptr<PhysicsObject> obj1,
00578 IN smart_ptr<PhysicsObject> obj2
00579 )
00580 {
00581 ASSERT(world, "null");
00582 ASSERT(obj1, "null");
00583 ASSERT(obj2, "null");
00584
00585 smart_ptr<Instance> i1 = getInstanceFromPhysicsObject(obj1);
00586 smart_ptr<Instance> i2 = getInstanceFromPhysicsObject(obj2);
00587
00588 DPRINTF("instance %s (type %s) hit instance %s (type %s)",
00589 i1->getInstanceId(), i1->getTypeId(),
00590 i2->getInstanceId(), i2->getTypeId());
00591
00592 bool player1 = !strcmp("player", i1->getTypeId());
00593 bool player2 = !strcmp("player", i2->getTypeId());
00594
00595 bool portal1 = isPortal(i1);
00596 bool portal2 = isPortal(i2);
00597
00598 if (player1 && portal2) {
00599 this->handlePortal(world, i1, i2);
00600 } else if (player2 && portal1) {
00601 this->handlePortal(world, i2, i1);
00602 }
00603 }
00604
00605
00606
00607 void
00608 RefGameLogic::handlePortal
00609 (
00610 IN PhysicsWorld * world,
00611 IN smart_ptr<Instance>& player,
00612 IN smart_ptr<Instance>& portal
00613 )
00614 {
00615 ASSERT(world, "null");
00616 ASSERT(player, "null");
00617 ASSERT(portal, "null");
00618 ASSERT(m_playerMgr, "null");
00619 ASSERT(m_mapMgr, "null");
00620
00621
00622 const Datahash * pdata = player->getInstanceData("game");
00623 if (!pdata) {
00624 DPRINTF("Player instance has no game logic data?");
00625 return;
00626 }
00627 if (strcmp("player", getOptionalString(pdata, "type", ""))) {
00628 DPRINTF("type != player?");
00629 return;
00630 }
00631 conn_id_t udpConnId = (conn_id_t) getLong(pdata, "udpConnId");
00632 int playerId = (int) getLong(pdata, "playerId");
00633
00634 DPRINTF("Player hit portal: from host 0x%08lx, player id %d",
00635 (long) udpConnId, playerId);
00636
00637 player_rec_t pr;
00638 if (!m_playerMgr->getPlayerByHostAndPlayerId(udpConnId, playerId, pr)) {
00639 DPRINTF("Could not find player?");
00640 return;
00641 }
00642 DPRINTF(" username = %s", (const char *) pr.username);
00643
00644
00645 const Datahash * odata = portal->getInstanceData("game");
00646 if (!odata) {
00647 DPRINTF("Portal instance has no game logic data?");
00648 return;
00649 }
00650 if (strcmp("portal", getOptionalString(odata, "type", ""))) {
00651 DPRINTF("type != portal?");
00652 return;
00653 }
00654 const char * mapId = getString(odata, "mapId");
00655 const char * startId = getString(odata, "startId");
00656 DPRINTF("requesting map '%s', start '%s'", mapId, startId);
00657
00658
00659 if (pr.obj) {
00660 world->removeObject(pr.obj);
00661 pr.obj = NULL;
00662 }
00663 pr.mapId.set(mapId);
00664 pr.startId.set(startId);
00665 m_playerMgr->updatePlayer(pr);
00666
00667
00668 m_mostRecentMapId = mapId;
00669
00670
00671 m_mapMgr->requestLoad(mapId);
00672 }
00673
00674
00675
00677
00678
00679
00681
00682 smart_ptr<ServerGameLogic>
00683 createServerGameLogic
00684 (
00685 void
00686 )
00687 {
00688 smart_ptr<RefGameLogic> rp = new RefGameLogic;
00689 ASSERT(rp, "out of memory");
00690
00691 rp->initialize();
00692
00693 return rp;
00694 }
00695
00696
00697 };
00698