From 7780f608daae57febc6d429fc5ce553499d96c12 Mon Sep 17 00:00:00 2001 From: false_genesis Date: Sun, 8 Jun 2008 19:49:00 +0000 Subject: [PATCH] * added experimental character movement (jump/strafe not yet done). press POS1/Home key to toggle camera/character WASD movement. camera NOT yet linked to character!! * conf supports now client 2.4.2. no code changes. * packets can now be sent not only from the PseuInstance main thread * added new conf option "softquit" to disable instant terminate (+data loss) on win32 systems if user [X]'ed console window. * misc fixes & code changes (personal note: exams are over, back to coding, yay) --- bin/conf/PseuWoW.conf.default | 12 +- bin/conf/ScriptConfig.conf.default | 3 + bin/data/scp/map.scp | 12 ++ bin/scripts/__core_eventstubs.def | 12 ++ bin/scripts/__core_internal.def | 4 - src/Client/GUI/MCamera.h | 44 +++++- src/Client/GUI/PseuGUI.cpp | 47 +++---- src/Client/GUI/Scene.h | 7 + src/Client/GUI/SceneWorld.cpp | 187 ++++++++++++++++++++++++-- src/Client/PseuWoW.cpp | 11 +- src/Client/PseuWoW.h | 1 + src/Client/World/MapMgr.cpp | 9 +- src/Client/World/MovementMgr.cpp | 206 ++++++++++++++++++++++------- src/Client/World/MovementMgr.h | 22 ++- src/Client/World/Object.h | 1 + src/Client/World/World.cpp | 16 +++ src/Client/World/World.h | 5 + src/Client/World/WorldSession.cpp | 10 +- src/Client/World/WorldSession.h | 1 + src/shared/MapTile.cpp | 33 +++-- src/shared/MapTile.h | 2 + 21 files changed, 519 insertions(+), 126 deletions(-) diff --git a/bin/conf/PseuWoW.conf.default b/bin/conf/PseuWoW.conf.default index de14571..528ced8 100644 --- a/bin/conf/PseuWoW.conf.default +++ b/bin/conf/PseuWoW.conf.default @@ -16,6 +16,12 @@ debug=0 // defines if the program should quit on error/exception or stay opened (for debugging) exitonerror=0 +// shutdown instead of terminating forcefully when user clicks the [X] (close) button. +// If this is disabled, you have to close PseuWoW with Ctrl+C or by typing "exit" into the console to save data! +// The problem is that windows usually gives processes 5 secs time to close after clicking [X], if they don't, they are marked as crashed. +// Default: 1 (enabled) -- [Win32 only] +softquit=1 + // reconnect on failure/disconnect // 0 = dont't reconnect // everything else: delay (in ms) until the next connection attempt. @@ -62,8 +68,8 @@ charname=Pseuwow // Client emulation configuration -ClientVersion=2.4.1 -ClientBuild=8125 +ClientVersion=2.4.2 +ClientBuild=8278 ClientLanguage=enUS // or change to enGB, deDE, ... @@ -127,7 +133,7 @@ SkipAddonChat=1 // Note that packet dumps are valid for 1 session only, the counter gets reset when the WorldSession is destroyed. // This means they get overwritten if not saved! // 0 - no packet dumping -// 1 - dump packets that caused an excpetion or object update error +// 1 - dump packets that caused an exception or object update error // 2 - like [1] + all packets with opcodes not handled by the core // (doesn't matter if they have scripts attached or not, they will be dumped always) DumpPackets=1 diff --git a/bin/conf/ScriptConfig.conf.default b/bin/conf/ScriptConfig.conf.default index c5725e0..f4181ba 100644 --- a/bin/conf/ScriptConfig.conf.default +++ b/bin/conf/ScriptConfig.conf.default @@ -18,6 +18,9 @@ other_cmd_chars=.! // Set to 1 if PseuWoW should exit after the GUI is closed (if there is a GUI) ExitOnGUIClose=0 +// Upon closing PseuWoW will say something you can specify here. Leave blank do disable. +ExitMessage=Terminating Proc... + [#normal] diff --git a/bin/data/scp/map.scp b/bin/data/scp/map.scp index 0a8c600..256941d 100644 --- a/bin/data/scp/map.scp +++ b/bin/data/scp/map.scp @@ -283,6 +283,10 @@ name=Zul'Aman name_general=PVPLordaeron name=Ruins of Lordaeron +[580] +name_general=SunwellPlateau +name=The Sunwell + [582] name_general=Transport176244 name=Transport: Rut'theran to Auberdine @@ -291,6 +295,10 @@ name=Transport: Rut'theran to Auberdine name_general=Transport176231 name=Transport: Menethil to Theramore +[585] +name_general=Sunwell5ManFix +name=Magister's Terrace + [586] name_general=Transport181645 name=Transport: Exodar to Auberdine @@ -319,3 +327,7 @@ name=Transport: Undercity to Orgrimmar name_general=Transport20808 name=Transport: Booty Bay to Ratchet +[598] +name_general=Sunwell5Man +name=Sunwell Fix (Unused) + diff --git a/bin/scripts/__core_eventstubs.def b/bin/scripts/__core_eventstubs.def index 8045c84..0999b9c 100644 --- a/bin/scripts/__core_eventstubs.def +++ b/bin/scripts/__core_eventstubs.def @@ -111,4 +111,16 @@ EMOTE 66 // say NO! //- script content here +#script=_onexit +// called just before PseuWoW exits +// @0: error? (0/1) + +if ${@inworld} + set,m ?{getvar #EXITMESSAGE} + if ?{strlen ${m}} + say ${m} + endif + unset m +endif + diff --git a/bin/scripts/__core_internal.def b/bin/scripts/__core_internal.def index 6d03222..7236804 100644 --- a/bin/scripts/__core_internal.def +++ b/bin/scripts/__core_internal.def @@ -16,10 +16,6 @@ QUIT #script=quit #permission=255 //-------------------------------------------------------- -// quit PseuWoW, say goodbye when logged in -IF ${@inworld} - SAY Terminating proc... -ENDIF SHDN diff --git a/src/Client/GUI/MCamera.h b/src/Client/GUI/MCamera.h index b859641..f4f0523 100644 --- a/src/Client/GUI/MCamera.h +++ b/src/Client/GUI/MCamera.h @@ -33,6 +33,44 @@ public: } ~MCameraFPS(){} + + void update(void) + { + turnLeft(0); + turnUp(0); + moveForward(0); + } + + /* + void setTarget(core::vector3df t) + { + direction = t - getTarget(); + camera->setTarget(t); + rotationX = RADTODEG * asin(DEGTORAD * t.X); + rotationY = RADTODEG * (acos(DEGTORAD * t.Y) + (PI/2.0f)); + if(rotationY>=360)rotationY-=360; + if(rotationY<0)rotationY+=360; + if(rotationX>=360)rotationX-=360; + if(rotationX<0)rotationX+=360; + direction.normalize(); + }*/ + + void setRotationLeft(f32 i) + { + rotationY = i; + if(rotationY>=360)rotationY-=360; + if(rotationY<0)rotationY+=360; + + direction = core::vector3df(0,0,1); + + core::matrix4 matrix; + matrix.setRotationDegrees(core::vector3df (rotationX,rotationY,0)); + matrix.rotateVect(direction); + + camera->setTarget(camera->getPosition() + direction); + camera->updateAbsolutePosition(); + } + void turnRight(f32 i) { @@ -55,13 +93,13 @@ public: rotationY -= i; if(rotationY>=360)rotationY-=360; if(rotationY<0)rotationY+=360; - + direction = core::vector3df(0,0,1); - + core::matrix4 matrix; matrix.setRotationDegrees(core::vector3df (rotationX,rotationY,0)); matrix.rotateVect(direction); - + camera->setTarget(camera->getPosition() + direction); camera->updateAbsolutePosition(); } diff --git a/src/Client/GUI/PseuGUI.cpp b/src/Client/GUI/PseuGUI.cpp index 3647d0f..3956b4a 100644 --- a/src/Client/GUI/PseuGUI.cpp +++ b/src/Client/GUI/PseuGUI.cpp @@ -185,36 +185,29 @@ void PseuGUI::Run(void) _device->sleep(10); // save cpu & gpu power if not focused } - try + _UpdateSceneState(); + + if(!_scene) { - _UpdateSceneState(); - - if(!_scene) - { - _device->sleep(10); - continue; - } - - _scene->OnUpdate(_passtimediff); // custom: process input, set camera, etc - _driver->beginScene(true, true, _scene->GetBackgroundColor()); // irr: call driver to start drawing - _scene->OnDrawBegin(); // custom: draw everything before irrlicht draws everything by itself - _smgr->drawAll(); // irr: draw all scene nodes - _guienv->drawAll(); // irr: draw gui elements - _scene->OnDraw(); // custom: draw everything that has to be draw late (post-processing also belongs here) - _driver->endScene(); // irr: drawing done - if(_driver->getFPS()>100 && _throttle < 10)//Primitive FPS-Limiter - upper cap hardcoded 100 FPS. - _throttle++; //lowercap 60 (if it drops below, limiting is eased). - if(_driver->getFPS()<60 && _throttle>0) //but honestly, a 10 msec delay is not worth this amount of code. - _throttle--; //If the FPS is down, it will never be because of this - if(_throttle>0) //Thus i opt for dropping the charade and using a fixed conf value of max 10. - _device->sleep(_throttle); //sleeps max 10 msec (=_throttle) here. - - } - catch(...) - { - logerror("Unhandled exception in PseuGUI::Run() device=%X smgr=%X objects:%u", _device, _smgr, domgr.StorageSize()); + _device->sleep(10); + continue; } + _scene->OnUpdate(_passtimediff); // custom: process input, set camera, etc + _driver->beginScene(true, true, _scene->GetBackgroundColor()); // irr: call driver to start drawing + _scene->OnDrawBegin(); // custom: draw everything before irrlicht draws everything by itself + _smgr->drawAll(); // irr: draw all scene nodes + _guienv->drawAll(); // irr: draw gui elements + _scene->OnDraw(); // custom: draw everything that has to be draw late (post-processing also belongs here) + _driver->endScene(); // irr: drawing done + if(_driver->getFPS()>100 && _throttle < 10)//Primitive FPS-Limiter - upper cap hardcoded 100 FPS. + _throttle++; //lowercap 60 (if it drops below, limiting is eased). + if(_driver->getFPS()<60 && _throttle>0) //but honestly, a 10 msec delay is not worth this amount of code. + _throttle--; //If the FPS is down, it will never be because of this + if(_throttle>0) //Thus i opt for dropping the charade and using a fixed conf value of max 10. + _device->sleep(_throttle); //sleeps max 10 msec (=_throttle) here. + + fps = _driver->getFPS(); if (lastFPS != fps) diff --git a/src/Client/GUI/Scene.h b/src/Client/GUI/Scene.h index 0a395bc..5f90e95 100644 --- a/src/Client/GUI/Scene.h +++ b/src/Client/GUI/Scene.h @@ -78,6 +78,8 @@ class MCameraOrbit; class MyEventReceiver; class MapMgr; class WorldSession; +class MovementMgr; +class MyCharacter; class SceneWorld : public Scene { @@ -117,6 +119,11 @@ private: scene::ISceneNode *sky; scene::ISceneNode *selectedNode, *oldSelectedNode, *focusedNode, *oldFocusedNode; video::SColor envBasicColor; + MovementMgr *movemgr; + MyCharacter *mychar; + bool _freeCameraMove; + void _CalcXYMoveVect(float o); + core::vector2df xyCharMovement; // stores sin() and cos() values for current MyCharacter orientation, so that they need to be calculated only if the character turns around }; diff --git a/src/Client/GUI/SceneWorld.cpp b/src/Client/GUI/SceneWorld.cpp index 44121b0..fe0d452 100644 --- a/src/Client/GUI/SceneWorld.cpp +++ b/src/Client/GUI/SceneWorld.cpp @@ -12,17 +12,23 @@ #include "WorldSession.h" #include "World.h" #include "CCursorController.h" +#include "MovementMgr.h" SceneWorld::SceneWorld(PseuGUI *g) : Scene(g) { DEBUG(logdebug("SceneWorld: Initializing...")); debugmode = false; + _freeCameraMove = true; // store some pointers right now to prevent repeated ptr dereferencing later (speeds up code) gui = g; wsession = gui->GetInstance()->GetWSession(); world = wsession->GetWorld(); mapmgr = world->GetMapMgr(); + movemgr = world->GetMoveMgr(); + mychar = wsession->GetMyChar(); + ASSERT(mychar); + _CalcXYMoveVect(mychar->GetO()); ILightSceneNode* light = smgr->addLightSceneNode(0, core::vector3df(0,0,0), SColorf(255, 255, 255, 255), 1000.0f); SLight ldata = light->getLightData(); @@ -118,30 +124,176 @@ void SceneWorld::OnUpdate(s32 timediff) selectedNode = focusedNode; }*/ // i'll continue working on this - [FG] + if(eventrecv->key.pressed_once(KEY_KEY_L)) + ((ICameraSceneNode*)camera->getNode())->setTarget(vector3df(0,0,0)); + + // maybe it is better to replace the sin() and cos() with some irr::core::matrix4 calcualtions... not sure what is more efficient if(eventrecv->key.pressed(KEY_KEY_W) || (mouse_pressed_left && mouse_pressed_right)) - camera->moveForward(50 * timediff_f); + { + if(_freeCameraMove) + camera->moveForward(50 * timediff_f); + else + { + f32 speedfactor = timediff_f * mychar->GetSpeed(MOVE_RUN); + movemgr->SetMoveMode(MOVEMODE_MANUAL); + movemgr->MoveStartForward(); + WorldPosition wp = mychar->GetPosition(); + wp.x += (xyCharMovement.X * speedfactor); + wp.y += (xyCharMovement.Y * speedfactor); + wp.z = terrain->getHeight(WPToIrr(wp)); + mychar->SetPosition(wp); + } + } + if(eventrecv->key.pressed(KEY_KEY_S)) - camera->moveBack(50 * timediff_f); - if(eventrecv->key.pressed(KEY_KEY_E)) - camera->moveRight(50 * timediff_f); - if(eventrecv->key.pressed(KEY_KEY_Q)) - camera->moveLeft(50 * timediff_f); + { + if(_freeCameraMove) + camera->moveBack(50 * timediff_f); + else + { + f32 speedfactor = timediff_f * mychar->GetSpeed(MOVE_WALKBACK); + movemgr->SetMoveMode(MOVEMODE_MANUAL); + movemgr->MoveStartBackward(); + WorldPosition wp = mychar->GetPosition(); + wp.x -= (xyCharMovement.X * speedfactor); + wp.y -= (xyCharMovement.Y * speedfactor); + wp.z = terrain->getHeight(WPToIrr(wp)); + mychar->SetPosition(wp); + } + } // if right mouse button pressed, move in axis, if not, turn camera if(eventrecv->key.pressed(KEY_KEY_D)) { if(mouse_pressed_right) - camera->moveRight(50 * timediff_f); + { + if(_freeCameraMove) + camera->moveRight(50 * timediff_f); + else + { + // TODO: strafe case + } + } else - camera->turnRight(timediff_f * M_PI * 25); + { + if(_freeCameraMove) + camera->turnRight(timediff_f * M_PI * 25); + else + { + movemgr->SetMoveMode(MOVEMODE_MANUAL); + movemgr->MoveStartTurnRight(); + WorldPosition wp = mychar->GetPosition(); + wp.z = terrain->getHeight(WPToIrr(wp)); + wp.o -= (timediff_f * mychar->GetSpeed(MOVE_TURN)); + wp.o = RAD_FIX(wp.o); + mychar->SetPosition(wp); + _CalcXYMoveVect(wp.o); + } + } } + if(eventrecv->key.pressed(KEY_KEY_A)) { if(mouse_pressed_right) + { + if(_freeCameraMove) + camera->moveLeft(50 * timediff_f); + else + { + // TODO: strafe case + } + } + else + { + if(_freeCameraMove) + camera->turnLeft(timediff_f * M_PI * 25); + else + { + movemgr->SetMoveMode(MOVEMODE_MANUAL); + movemgr->MoveStartTurnLeft(); + WorldPosition wp = mychar->GetPosition(); + wp.z = terrain->getHeight(WPToIrr(wp)); + wp.o += (timediff_f * mychar->GetSpeed(MOVE_TURN)); + wp.o = RAD_FIX(wp.o); + mychar->SetPosition(wp); + _CalcXYMoveVect(wp.o); + } + } + } + + if(eventrecv->key.pressed(KEY_KEY_E)) + { + if(_freeCameraMove) + camera->moveRight(50 * timediff_f); + else + {/* + f32 speedfactor = timediff_f * mychar->GetSpeed(MOVE_RUN); + movemgr->SetMoveMode(MOVEMODE_MANUAL); + movemgr->MoveStartStrafeRight(); + WorldPosition wp = mychar->GetPosition(); + wp.x -= (xyCharMovement.X * speedfactor); + wp.y -= (xyCharMovement.Y * speedfactor); + wp.z = terrain->getHeight(WPToIrr(wp)); + mychar->SetPosition(wp); + */} + } + + if(eventrecv->key.pressed(KEY_KEY_Q)) + { + if(_freeCameraMove) camera->moveLeft(50 * timediff_f); else - camera->turnLeft(timediff_f * M_PI * 25); + {/* + f32 speedfactor = timediff_f * mychar->GetSpeed(MOVE_RUN); + movemgr->SetMoveMode(MOVEMODE_MANUAL); + movemgr->MoveStartStrafeLeft(); + WorldPosition wp = mychar->GetPosition(); + wp.x -= (xyCharMovement.X * speedfactor); + wp.y -= (xyCharMovement.Y * speedfactor); + wp.z = terrain->getHeight(WPToIrr(wp)); + mychar->SetPosition(wp); + */} + } + + /*if(eventrecv->key.pressed(KEY_SPACE)) + { + movemgr->SetMoveMode(MOVEMODE_MANUAL); + movemgr->MoveJump(); + }*/ + + // listen to *not* pressed keys only if manually moving + if(movemgr->GetMoveMode() == MOVEMODE_MANUAL) + { + if (!eventrecv->key.pressed(KEY_KEY_D) && !eventrecv->key.pressed(KEY_KEY_A)) + { + movemgr->MoveStopTurn(); + } + if (!eventrecv->key.pressed(KEY_KEY_W) && !eventrecv->key.pressed(KEY_KEY_S)) + { + movemgr->MoveStop(); + } + // TODO: add strafe case + } + + // if we moved, relocate MyCharacter + /*if(movemgr->IsMoved()) + { + MyCharacter *my = wsession->GetMyChar(); + if(my) + { + WorldPosition newpos = GetWorldPosition(); + my->SetPosition(newpos); + } + else + { + logerror("SceneWorld: Can't move MyCharacter, not found!"); + } + }*/ + + if(eventrecv->key.pressed_once(KEY_HOME)) + { + _freeCameraMove = !_freeCameraMove; } if(eventrecv->key.pressed_once(KEY_BACK)) @@ -212,7 +364,7 @@ void SceneWorld::OnUpdate(s32 timediff) DEBUG( WorldPosition wp = GetWorldPosition(); - str += L"Camera: pitch:"; + str += L" Camera: pitch:"; str += camera->getPitch(); str += L" c pos:"; str += camera->getPosition().X; @@ -224,7 +376,7 @@ void SceneWorld::OnUpdate(s32 timediff) str += " ## HEAD: "; str += IRR_TO_O(camera->getHeading()); str += L" Pos: "; - str = ((((((str + wp.x) + L" | ") + wp.y) + L" | ") + wp.z) + L" | OR:") + wp.o; + str += ((((((str + wp.x) + L" | ") + wp.y) + L" | ") + wp.z) + L" | OR:") + wp.o; str += L" -- Terrain: Sectors: "; str += (int)terrain->getSectorsRendered(); str += L" / "; @@ -381,9 +533,12 @@ void SceneWorld::UpdateTerrain(void) for(s32 tilex = 0; tilex < 3; tilex++) { MapTile *maptile = mapmgr->GetNearTile(tilex - 1, tiley - 1); + uint32 tile_real_x = mapmgr->GetGridX() + tilex - 1; + uint32 tile_real_y = mapmgr->GetGridY() + tiley - 1; if(maptile) { // apply map height data + logdebug("Applying height data for tile (%u, %u)", tile_real_x, tile_real_y); for(uint32 chy = 0; chy < 16; chy++) { for(uint32 chx = 0; chx < 16; chx++) @@ -402,6 +557,7 @@ void SceneWorld::UpdateTerrain(void) } } // create doodads + logdebug("Loading %u doodads for tile (%u, %u)", maptile->GetDoodadCount(), tile_real_x, tile_real_y); for(uint32 i = 0; i < maptile->GetDoodadCount(); i++) { Doodad *d = maptile->GetDoodad(i); @@ -446,7 +602,7 @@ void SceneWorld::UpdateTerrain(void) } else { - logerror("SceneWorld: MapTile (%u, %u) not loaded, can't apply heightmap!", mapmgr->GetGridX()+tilex, mapmgr->GetGridY()+tiley); + logerror("SceneWorld: MapTile (%u, %u) not loaded!", tile_real_x, tile_real_y); } } } @@ -523,7 +679,7 @@ WorldPosition SceneWorld::GetWorldPosition(void) { // TODO: later do not use CAMERA, but CHARACTER position, as soon as camera is changed from 1st to 3rd person view // and floating around character in the middle - return IrrToWP(camera->getPosition(), IRR_TO_O(DEG_TO_RAD(camera->getHeading()))); + return IrrToWP(camera->getPosition(), DEG_TO_RAD(camera->getHeading())); } video::SColor SceneWorld::GetBackgroundColor(void) @@ -531,5 +687,10 @@ video::SColor SceneWorld::GetBackgroundColor(void) return envBasicColor; } +void SceneWorld::_CalcXYMoveVect(float o) +{ + xyCharMovement.X = cos(o); + xyCharMovement.Y = sin(o); +} diff --git a/src/Client/PseuWoW.cpp b/src/Client/PseuWoW.cpp index 9be86e4..6374382 100644 --- a/src/Client/PseuWoW.cpp +++ b/src/Client/PseuWoW.cpp @@ -250,7 +250,8 @@ void PseuInstance::Run(void) } // fastquit is defined if we clicked [X] (on windows) - if(_fastquit) + // If softquit is set, do not terminate forcefully, but shut it down instead + if(_fastquit && !_conf->softquit) { log("Aborting Instance..."); return; @@ -265,6 +266,13 @@ void PseuInstance::Run(void) //... } + if(GetScripts()->ScriptExists("_onexit")) + { + CmdSet Set; + Set.arg[0] = DefScriptTools::toString(_error); + GetScripts()->RunScript("_onexit",&Set); + } + if(GetConf()->exitonerror == false && _error) { log("Exiting on error is disabled, PseuWoW is now IDLE"); @@ -468,6 +476,7 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v) useMaps=(bool)atoi(v.Get("USEMAPS").c_str()); skipaddonchat=(bool)atoi(v.Get("SKIPADDONCHAT").c_str()); dumpPackets=(uint8)atoi(v.Get("DUMPPACKETS").c_str()); + softquit=(bool)atoi(v.Get("SOFTQUIT").c_str()); // clientversion is a bit more complicated to add { diff --git a/src/Client/PseuWoW.h b/src/Client/PseuWoW.h index 8594008..18cae89 100644 --- a/src/Client/PseuWoW.h +++ b/src/Client/PseuWoW.h @@ -57,6 +57,7 @@ class PseuInstanceConf bool useMaps; bool skipaddonchat; uint8 dumpPackets; + bool softquit; // gui related bool enablegui; diff --git a/src/Client/World/MapMgr.cpp b/src/Client/World/MapMgr.cpp index ebbbc2a..f365841 100644 --- a/src/Client/World/MapMgr.cpp +++ b/src/Client/World/MapMgr.cpp @@ -186,20 +186,15 @@ uint32 MapMgr::GetLoadedMapsCount(void) float MapMgr::GetZ(float x, float y) { - return -99999.0f; // for now return lowest possible number, GetZ() will be implemented correctly later -/* GridCoordPair gcoords = GetTransformGridCoordPair(x,y); + GridCoordPair gcoords = GetTransformGridCoordPair(x,y); MapTile *tile = _tiles->GetTile(gcoords.x,gcoords.y); if(tile) { -#ifdef _DEBUG - tile->DebugDumpToFile(); - logdebug("DEBUG: tile dumped"); -#endif return tile->GetZ(x,y); } logerror("MapMgr::GetZ() called for not loaded MapTile (%u, %u) for (%f, %f)",gcoords.x,gcoords.y,x,y); - return 0;*/ + return INVALID_HEIGHT; } std::string MapMgr::GetLoadedTilesString(void) diff --git a/src/Client/World/MovementMgr.cpp b/src/Client/World/MovementMgr.cpp index f570dc7..1500e39 100644 --- a/src/Client/World/MovementMgr.cpp +++ b/src/Client/World/MovementMgr.cpp @@ -10,6 +10,7 @@ MovementMgr::MovementMgr() _instance = NULL; _optime = 0; _updatetime = 0; + _moved = false; } MovementMgr::~MovementMgr() @@ -21,151 +22,258 @@ void MovementMgr::SetInstance(PseuInstance *inst) _movemode = MOVEMODE_MANUAL; _instance = inst; _mychar = inst->GetWSession()->GetMyChar(); + if(!_mychar) + { + logerror("MovementMgr: MyCharacter doesn't exist!"); + // it will likely crash somewhere after outputting this message, but in case it really appears, + // we can be sure there is something absolutely not ok... + } } void MovementMgr::_BuildPacket(uint16 opcode) { - WorldPacket wp(opcode,4+1+4+12); // it can be larger, if we are juming, on transport or swimming - wp << _moveFlags; - wp << (uint8)0; // unk - wp << getMSTime(); - wp << _mychar->GetPosition(); + WorldPacket *wp = new WorldPacket(opcode,4+1+4+12); // it can be larger, if we are jumping, on transport or swimming + *wp << _moveFlags; + *wp << (uint8)0; // unk + *wp << getMSTime(); + *wp << _mychar->GetPosition(); // TODO: transport not yet handled/done if(_moveFlags & MOVEMENTFLAG_ONTRANSPORT) { - wp << (uint64)0; // transport guid - wp << WorldPosition(); // transport position - wp << getMSTime(); // transport time (??) + *wp << (uint64)0; // transport guid + *wp << WorldPosition(); // transport position + *wp << getMSTime(); // transport time (??) } // TODO: swimming not yet done if(_moveFlags & MOVEMENTFLAG_SWIMMING) { - wp << (float)0; // angle; 1.55=looking up, -1.55=looking down, 0=looking forward + *wp << (float)0; // angle; 1.55=looking up, -1.55=looking down, 0=looking forward } - wp << (uint32)0; // last fall time (also used when jumping) - // TODO: jumping not yet done + *wp << (uint32)0; // last fall time (also used when jumping) + if(_moveFlags & MOVEMENTFLAG_JUMPING) + { + *wp << (float)0; //unk value, or as mangos calls it: j_unk ^^ + *wp << sin(_mychar->GetO()+ (M_PI/2)); + *wp << cos(_mychar->GetO()+ (M_PI/2)); + *wp << _movespeed; + } + // TODO: spline not yet done - + DEBUG(logdebug("Move flags: 0x%X (packet: %u bytes)",_moveFlags,wp->size())); + // send the packet, threadsafe + _instance->GetWSession()->AddSendWorldPacket(wp); + _moved = true; _optime = getMSTime(); } -void MovementMgr::Update(bool calcpos) +void MovementMgr::Update(bool sendDirect) { uint32 curtime = getMSTime(); uint32 timediff = curtime - _updatetime; _updatetime = curtime; - if(_movemode == MOVEMODE_AUTO) + WorldPosition pos = _mychar->GetPosition(); + float turnspeed = _mychar->GetSpeed(MOVE_TURN) / 1000.0f * timediff; + float runspeed = _mychar->GetSpeed(MOVE_RUN) / 1000.0f * timediff; + _movespeed = runspeed; // or use walkspeed, depending on setting. for now use only runspeed + // TODO: calc other speeds as soon as implemented +/* + if(_movemode == MOVEMODE_MANUAL) { - WorldPosition pos = _mychar->GetPosition(); - float turnspeed = _mychar->GetSpeed(MOVE_TURN) / 1000.0f * timediff; - float runspeed = _mychar->GetSpeed(MOVE_RUN) / 1000.0f * timediff; - float movespeed = runspeed; // or use walkspeed, depending on setting. for now use only runspeed - // TODO: calc other speeds as soon as implemented - - /* - if(_moveFlags & MOVEMENTFLAG_FORWARD) + if(_moveFlags & MOVEMENTFLAG_JUMPING) { - pos.x += movespeed * sin(pos.o); - pos.y += movespeed * cos(pos.o); + // approx. jumping formula + _jumptime += timediff / 1000.0f; + if (_jumptime < 0.4f) + pos.z += 2.0f / 1000.0f * timediff; + if (_jumptime >= 0.4f && _jumptime < 0.8f) + { + pos.z -= 2.0f / 1000.0f * timediff; + } + if (_jumptime >= 0.8f) + { + _jumptime = 0.0f; + _moveFlags &= ~MOVEMENTFLAG_JUMPING; + } + } + + if(_movemode == MOVEMODE_AUTO) + { + if(_moveFlags & MOVEMENTFLAG_FORWARD) + { + + WorldPosition oldpos = pos; + pos.x += _movespeed * sin(pos.o + (M_PI/2)); + pos.y -= _movespeed * cos(pos.o + (M_PI/2)); + if (_instance->GetWSession()->GetWorld()->GetPosZ(pos.x,pos.y) > 5.0f + pos.z) + { + pos = oldpos; + } + } + if(_moveFlags & MOVEMENTFLAG_BACKWARD) + { + + WorldPosition oldpos = pos; + pos.x -= _movespeed * sin(pos.o + (M_PI/2)); + pos.y += _movespeed * cos(pos.o + (M_PI/2)); + if (_instance->GetWSession()->GetWorld()->GetPosZ(pos.x,pos.y) > 5.0f + pos.z) + { + pos = oldpos; + } + } } // ... if(_moveFlags & MOVEMENTFLAG_LEFT) { - pos.o -= turnspeed; + pos.o += turnspeed; } if(_moveFlags & MOVEMENTFLAG_RIGHT) { - pos.o += turnspeed; + pos.o -= turnspeed; } if(pos.o < 0) - pos.o += 2 * M_PI; + pos.o += float(2 * M_PI); else if(pos.o > 2 * M_PI) - pos.o -= 2 * M_PI; + pos.o -= float(2 * M_PI); + //pos.z = _instance->GetWSession()->GetWorld()->GetPosZ(pos.x,pos.y); + + if(_movemode == MOVEMODE_AUTO) + { + _mychar->SetPosition(pos); + } + }*/ - pos.z = _instance->GetWSession()->GetWorld()->GetPosZ(pos.x,pos.y); - */ - // ^ It should look like this later on, but its not finished, and formulas are not tested. - // see it as some future plans that need a lot of finetuning ;) - } - - // if we are moving, and 500ms have passed, send an heartbeat packet - if( (_moveFlags & MOVEMENTFLAG_ANY_MOVE) && _optime + MOVE_HEARTBEAT_DELAY < getMSTime()) + // if we are moving, and 500ms have passed, send an heartbeat packet. just in case 500ms have passed but the packet is sent by another function, do not send here + if( !sendDirect && (_moveFlags & MOVEMENTFLAG_ANY_MOVE) && _optime + MOVE_HEARTBEAT_DELAY < getMSTime()) { _BuildPacket(MSG_MOVE_HEARTBEAT); } - // TODO: apply gravity, handle falling, swimming, etc. } +// stops void MovementMgr::MoveStop(void) { - _moveFlags &= ~(MOVEMENTFLAG_ANY_MOVE); - Update(false); + if(!(_moveFlags & (MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD))) + return; + _moveFlags &= ~(MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD | MOVEMENTFLAG_WALK); + Update(true); _BuildPacket(MSG_MOVE_STOP); } void MovementMgr::MoveStartForward(void) { + if(_moveFlags & MOVEMENTFLAG_FORWARD) + return; _moveFlags |= MOVEMENTFLAG_FORWARD; _moveFlags &= ~MOVEMENTFLAG_BACKWARD; - Update(false); + Update(true); _BuildPacket(MSG_MOVE_START_FORWARD); } void MovementMgr::MoveStartBackward(void) { - _moveFlags |= MOVEMENTFLAG_BACKWARD; + if(_moveFlags & MOVEMENTFLAG_BACKWARD) + return; + _moveFlags |= (MOVEMENTFLAG_BACKWARD | MOVEMENTFLAG_WALK); // backward walk is always slow; flag must be set, otherwise causing weird movement in other client _moveFlags &= ~MOVEMENTFLAG_FORWARD; - Update(false); + Update(true); _BuildPacket(MSG_MOVE_START_BACKWARD); } void MovementMgr::MoveStartStrafeLeft(void) { + if(_moveFlags & MOVEMENTFLAG_STRAFE_LEFT) + return; _moveFlags |= MOVEMENTFLAG_STRAFE_LEFT; _moveFlags &= ~MOVEMENTFLAG_STRAFE_RIGHT; - Update(false); + Update(true); _BuildPacket(MSG_MOVE_START_STRAFE_LEFT); } void MovementMgr::MoveStartStrafeRight(void) { + if(_moveFlags & MOVEMENTFLAG_STRAFE_RIGHT) + return; _moveFlags |= MOVEMENTFLAG_STRAFE_RIGHT; _moveFlags &= ~MOVEMENTFLAG_STRAFE_LEFT; - Update(false); + Update(true); _BuildPacket(MSG_MOVE_START_STRAFE_RIGHT); } +void MovementMgr::MoveStopStrafe(void) +{ + if(!(_moveFlags & (MOVEMENTFLAG_STRAFE_RIGHT | MOVEMENTFLAG_STRAFE_LEFT))) + return; + _moveFlags &= ~(MOVEMENTFLAG_STRAFE_RIGHT | MOVEMENTFLAG_STRAFE_LEFT); + Update(true); + _BuildPacket(MSG_MOVE_START_STRAFE_RIGHT); +} + + void MovementMgr::MoveStartTurnLeft(void) { + if(_moveFlags & MOVEMENTFLAG_LEFT) + return; _moveFlags |= MOVEMENTFLAG_LEFT; _moveFlags &= ~MOVEMENTFLAG_RIGHT; - Update(false); + Update(true); _BuildPacket(MSG_MOVE_START_TURN_LEFT); } void MovementMgr::MoveStartTurnRight(void) { + if(_moveFlags & MOVEMENTFLAG_RIGHT) + return; _moveFlags |= MOVEMENTFLAG_RIGHT; _moveFlags &= ~MOVEMENTFLAG_LEFT; - Update(false); + Update(true); _BuildPacket(MSG_MOVE_START_TURN_RIGHT); } void MovementMgr::MoveStopTurn(void) { + if(!(_moveFlags & (MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT))) + return; _moveFlags &= ~(MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT); - Update(false); + Update(true); _BuildPacket(MSG_MOVE_STOP_TURN); } -void MovementMgr::MoveSetFacing(float o) +void MovementMgr::MoveSetFacing(void) { - _mychar->SetPosition(_mychar->GetX(), _mychar->GetY(), _mychar->GetZ(), o); Update(true); _BuildPacket(MSG_MOVE_SET_FACING); } +void MovementMgr::MoveJump(void) +{ + if(!(_moveFlags & (MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING))) + return; + _moveFlags |= MOVEMENTFLAG_JUMPING; + Update(true); + _BuildPacket(MSG_MOVE_JUMP); +} + +bool MovementMgr::IsMoving(void) +{ + return _moveFlags & MOVEMENTFLAG_ANY_MOVE; +} + +bool MovementMgr::IsTurning(void) +{ + return _moveFlags & (MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT); +} + +bool MovementMgr::IsWalking(void) +{ + return _moveFlags & (MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD); +} + +bool MovementMgr::IsStrafing(void) +{ + return _moveFlags & (MOVEMENTFLAG_STRAFE_LEFT | MOVEMENTFLAG_STRAFE_RIGHT); +} + diff --git a/src/Client/World/MovementMgr.h b/src/Client/World/MovementMgr.h index 76632c1..5c8f4d0 100644 --- a/src/Client/World/MovementMgr.h +++ b/src/Client/World/MovementMgr.h @@ -19,8 +19,8 @@ enum MovementFlagsEx enum MoveModes { - MOVEMODE_AUTO, // CPU controlling movement, MyCharacter must be updated - MOVEMODE_MANUAL, // user controlling movement, MyCharacter is updated by the GUI already + MOVEMODE_AUTO, // CPU controlling movement, MyCharacter must be updated by MovementMgr + MOVEMODE_MANUAL, // user controlling movement, MyCharacter must be updated by the GUI }; class PseuInstance; @@ -34,17 +34,30 @@ public: ~MovementMgr(); void SetInstance(PseuInstance*); inline void SetMoveMode(uint8 mode) { _movemode = mode; } + inline uint8 GetMoveMode(void) { return _movemode; } void Update(bool); void MoveStartForward(void); void MoveStartBackward(void); void MoveStop(void); void MoveStartStrafeLeft(void); void MoveStartStrafeRight(void); + void MoveStopStrafe(void); void MoveStartTurnLeft(void); void MoveStartTurnRight(void); void MoveStopTurn(void); void MoveFallLand(void); - void MoveSetFacing(float); + void MoveSetFacing(void); + void MoveJump(void); + //bool IsJumping(void); + inline bool GetMoveFlags(void) { return _moveFlags; } + inline bool HasMoveFlag(uint32 flag) { return _moveFlags & flag; } + bool IsMoved(void) { bool m = _moved; _moved = false; return m; } // true if the character moved since last call + bool IsMoving(void); // any move? + bool IsTurning(void); // spinning around? + bool IsWalking(void); // walking straight forward/backward? + bool IsStrafing(void); // strafing left/right? + + private: void _BuildPacket(uint16); @@ -54,7 +67,10 @@ private: uint32 _updatetime; // timeMS of last update cycle uint32 _optime; // timeMS when last opcode was sent uint8 _movemode; // automatic or manual + float _movespeed; // current xy movement speed + float _jumptime; UnitMoveType _movetype; // index used for speed selection + bool _moved; }; diff --git a/src/Client/World/Object.h b/src/Client/World/Object.h index e4a9ed4..ed6e68f 100644 --- a/src/Client/World/Object.h +++ b/src/Client/World/Object.h @@ -125,6 +125,7 @@ public: inline void SetPosition(WorldPosition& wp) { _wpos = wp; } inline void SetPosition(WorldPosition& wp, uint16 mapid) { SetPosition(wp); _m = mapid; } inline WorldPosition GetPosition(void) {return _wpos; } + inline WorldPosition *GetPositionPtr(void) {return &_wpos; } inline float GetX(void) { return _wpos.x; } inline float GetY(void) { return _wpos.y; } inline float GetZ(void) { return _wpos.z; } diff --git a/src/Client/World/World.cpp b/src/Client/World/World.cpp index 5495e0f..649b842 100644 --- a/src/Client/World/World.cpp +++ b/src/Client/World/World.cpp @@ -2,14 +2,19 @@ #include "MapMgr.h" #include "WorldSession.h" #include "World.h" +#include "MovementMgr.h" World::World(WorldSession *s) { _session = s; _mapId = -1; _mapmgr = NULL; + _movemgr = NULL; if(_session->GetInstance()->GetConf()->useMaps) + { _mapmgr = new MapMgr(); + } + } World::~World() @@ -39,6 +44,10 @@ void World::Update(void) { _mapmgr->Update(_x,_y,_mapId); } + if(_movemgr) + { + _movemgr->Update(false); + } // some debug code for testing... /*if(_mapmgr && _x != _lastx || _y != _lasty) @@ -71,3 +80,10 @@ float World::GetPosZ(float x, float y) logdebug("WORLD: GetPosZ() called, but no MapMgr exists (do you really use maps?)"); return 0; } + +// must be called after MyCharacter is created +void World::CreateMoveMgr(void) +{ + _movemgr = new MovementMgr(); + _movemgr->SetInstance(_session->GetInstance()); +} diff --git a/src/Client/World/World.h b/src/Client/World/World.h index 759416b..e2a39bd 100644 --- a/src/Client/World/World.h +++ b/src/Client/World/World.h @@ -3,6 +3,7 @@ class WorldSession; class MapMgr; +class MovementMgr; struct WorldPosition { @@ -39,6 +40,8 @@ public: void UpdatePos(float,float); float GetPosZ(float x, float y); inline MapMgr *GetMapMgr(void) { return _mapmgr; } + inline MovementMgr *GetMoveMgr(void) { return _movemgr; } + void CreateMoveMgr(void); private: WorldSession *_session; @@ -47,6 +50,8 @@ private: float _x,_y; float _lastx,_lasty; + MovementMgr *_movemgr; + }; #endif diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index 750171a..8263df1 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -362,7 +362,13 @@ void WorldSession::AddSendWorldPacket(WorldPacket *pkt) { sendPktQueue.add(pkt); } - +void WorldSession::AddSendWorldPacket(WorldPacket& pkt) +{ + WorldPacket *wp = new WorldPacket(pkt.GetOpcode(),pkt.size()); + if(pkt.size()) + wp->append(pkt.contents(),pkt.size()); + sendPktQueue.add(wp); +} void WorldSession::SetTarget(uint64 guid) { @@ -1254,7 +1260,7 @@ void WorldSession::_HandleLoginVerifyWorldOpcode(WorldPacket& recvPacket) // update the world as soon as the server confirmed that we are where we are. _world->UpdatePos(x,y,m); _world->Update(); - //_world->CreateMoveMgr(); + _world->CreateMoveMgr(); // temp. solution to test terrain rendering if(PseuGUI *gui = GetInstance()->GetGUI()) diff --git a/src/Client/World/WorldSession.h b/src/Client/World/WorldSession.h index f9a894a..738bd3e 100644 --- a/src/Client/World/WorldSession.h +++ b/src/Client/World/WorldSession.h @@ -61,6 +61,7 @@ public: void SetMustDie(void); void SendWorldPacket(WorldPacket&); void AddSendWorldPacket(WorldPacket *pkt); + void AddSendWorldPacket(WorldPacket& pkt); inline bool InWorld(void) { return _logged; } inline uint32 GetLagMS(void) { return _lag_ms; } diff --git a/src/shared/MapTile.cpp b/src/shared/MapTile.cpp index 56e23d2..dd87cd0 100644 --- a/src/shared/MapTile.cpp +++ b/src/shared/MapTile.cpp @@ -117,12 +117,10 @@ void MapTileStorage::_DebugDump(void) } // get approx Z position for world position (x,y). -// TODO: use inner vertices also -// TODO: interpolate values instead of choosing closest vertex -// formula taken from BoogieBot, thx! -/*float MapTile::GetZ(float x, float y) +float MapTile::GetZ(float x, float y) { float bx,by; + float real_z; bx = _chunks[0].basex; // world base coords of tile by = _chunks[0].basey; uint32 chx = (uint32)fabs((bx - x) / CHUNKSIZE); // get chunk id for given coords @@ -131,22 +129,29 @@ void MapTileStorage::_DebugDump(void) { logerror("MapTile::GetZ() wrong chunk indexes (%d, %d) for (%f, %f)",chx,chy,x,y); logerror(" - These coords are NOT on this tile!"); - return 0; + return INVALID_HEIGHT; } - MapChunk& ch = _chunks[chy*16 + chx]; + MapChunk& ch = _chunks[chx*16 + chy]; uint32 vx,vy; // get vertex position (0,0) ... (8,8); - vx = (uint32)floor((fabs(ch.basex - x) / UNITSIZE) + 0.5f); - vy = (uint32)floor((fabs(ch.basey - y) / UNITSIZE) + 0.5f); - if(vx > 8 || vy > 8) + vy = (uint32)floor((fabs(ch.basey - y) / (CHUNKSIZE/16.0f)) + 0.5f); + if (vy % 2 == 0) { - logerror("MapTile::GetZ() wrong vertex indexes (%d, %d) for chunk (%d, %d) for (%f, %f)",vx,vy,chx,chy,x,y); - return 0; + vx = (uint32)floor((fabs(ch.basex - x) / (CHUNKSIZE/8.0f)) + 0.5f); + real_z = ch.hmap_rough[vx*9 + (vy/2)] + ch.baseheight; + } + else if (vy % 2 != 0) + { + vx = (uint32)floor((fabs(ch.basex - x) / (CHUNKSIZE/7.0f)) ); //edit: removed + 0.5f + real_z = ch.hmap_fine[vx*8 + ((vy-1)/2)] + ch.baseheight; + } + if(vx > 8 || vy > 17) + { + logerror("MapTile::GetZ() wrong vertex indexes (%d, %d) for chunk (%d, %d) for (%f, %f) chunkpos (%f, %f) tile (%f, %f)",vx,vy,chx,chy,x,y,ch.basex,ch.basey,bx,by); + return INVALID_HEIGHT; } - - float real_z = ch.hmap_rough[vy*9 + vx] + ch.baseheight; return real_z; -}*/ +} void MapTile::DebugDumpToFile(void) { diff --git a/src/shared/MapTile.h b/src/shared/MapTile.h index 57ff75e..9fa56b7 100644 --- a/src/shared/MapTile.h +++ b/src/shared/MapTile.h @@ -11,6 +11,8 @@ #define UNITSIZE (CHUNKSIZE / 8.0f) #define ZEROPOINT (32.0f * (TILESIZE)) +#define INVALID_HEIGHT -99999.0f + // individual chunks of a map class MapChunk {