CSimulationImpl.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2004 Werewolf
00008  *
00009  * This file is part of Werewolf.
00010  * Werewolf is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * Werewolf is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with Werewolf; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 //
00027 // Standard Includes
00028 //
00029 #include "stdpch.h"
00030 
00031 //
00032 // System Includes
00033 //
00034 
00035 //
00036 // NeL Includes
00037 //
00038 #include <nel/misc/types_nl.h>
00039 #include <nel/net/message.h>
00040 
00041 //
00042 // Werewolf Includes
00043 //
00044 #include "wwcommon/ISimulationObj.h"
00045 #include "wwcommon/CPerformer.h"
00046 #include "CActorProxy.h"
00047 
00048 #include <wwcommon/CSobManager.h>
00049 #include <wwcommon/CSobFactory.h>
00050 #include <wwcommon/IBaseSimulation.h>
00051 #include <wwcommon/CGameEventServer.h>
00052 #include "CSimulationImpl.h"
00053 #include "controllers/CInteractiveSobController.h"
00054 
00055 //#include "CCharacterManager.h"
00056 #include "tasks/CNetworkTask.h"
00057 #include "tasks/CConfigTask.h"
00058 #include "tasks/CResourceTask.h"
00059 #include "views/CPerformer3DView.h"
00060 #include "views/CPerformerChatView.h"
00061 
00062 #include <wwcommon/CSobHandlerFactory.h>
00063 #include <wwcommon/CMotionController.h>
00064 #include "tasks/CPacsTask.h"
00065 
00066 //
00067 // Namespaces
00068 //
00069 
00070 namespace WWCLIENT {
00071 
00072 CSimulationImpl *getClientSimulation() {
00073     return dynamic_cast<CSimulationImpl *>(getSimulation());
00074 }
00075 
00076 bool CSimulationImpl::attachUser(uint32 uid, uint32 sobid) {
00077     // There is no logic in this method on the client.
00078     return true;
00079 }
00080 
00081 void CSimulationImpl::detachUser(uint32 uid, uint32 sobid) {
00082     // There is no logic in this method on the client.
00083 }
00084 
00085 
00086 void CSimulationImpl::init() {
00087     // get the paths to the retrievers.
00088     std::string retBankName, globRetBank;
00089     retBankName=CConfigTask::instance().configFile().getVar("RetrieverBankName").asString();
00090     globRetBank=CConfigTask::instance().configFile().getVar("GlobalRetrieverName").asString();
00091 
00092     nlinfo("Create Retriever Bank: %s", NLMISC::CPath::lookup(retBankName).c_str());
00093     nlinfo("Create Global Retriever: %s", NLMISC::CPath::lookup(globRetBank).c_str());
00094 
00095     // pacs stuff.
00096     m_RetrieverBank = NLPACS::URetrieverBank::createRetrieverBank(retBankName.c_str());
00097     if(m_RetrieverBank == NULL)
00098         nlinfo("what the fuck bitch.");
00099     m_GlobalRetriever = NLPACS::UGlobalRetriever::createGlobalRetriever(globRetBank.c_str(), m_RetrieverBank);
00100 
00101     nlinfo("Create Move Container.");
00102     m_MoveContainer = NLPACS::UMoveContainer::createMoveContainer(m_GlobalRetriever, 100, 100, 6.0);
00103 
00104     // null out the self-sob to mark a clear simulation
00105     m_SelfSob=NULL;
00106 
00107     WWCOMMON::IBaseSimulation::init();
00108 
00109     // Client lags behind by 100ms
00110     m_SimulationDelay=0.1;
00111     m_PingLatency=0;
00112     m_PingCount=0;
00113     m_PingLocalTimeStamp=0;
00114     // nanosecond accuracy :)
00115     m_Epsilon=0.000001;
00116     m_NoPing=false;
00117     m_NextPingTime=0;
00118 
00119     WWCOMMON::CGameEventServer::instance().setDeltaMultiplier(0.0f);
00120 }
00121 
00122 void CSimulationImpl::update() {
00123     // Check if we need to ping something.
00124     updatePing();
00125 
00126     // Process the basic functions.
00127     WWCOMMON::IBaseSimulation::update();
00128 }
00129 
00130 void CSimulationImpl::spawnSelf(WWCOMMON::CSobSpawnEvent *event) {
00131     // Create a new SOB and set its unique ID to that from the server.
00132     CActorProxy *sob=dynamic_cast<CActorProxy *>(getNewSob("sobActor", event->SourceID));
00133 
00134     // And add it to the manager
00135     m_ActorManager->addSob(sob);
00136     // Record it as the local sob.
00137     m_SelfSob=sob;
00138 
00139     // Make sure out starting position is valid.
00140     if(event->Position == NLMISC::CVector::Null) {
00141         nlwarning("Entity spawned at an invalid position: %d", sob->getSobId());
00142         return;
00143     }
00144 
00145     sob->setPosition(event->Position);
00146     sob->setGlobalPosition(event->Position);
00147     
00148     // Add the presentation view for 3D ifno.
00149     CEntityMedia emd = CResourceTask::instance().getEMD(event->EMD);
00150     WWCOMMON::IView* view = new CPerformer3DView(sob, emd);
00151     view->show();
00152     sob->addView(view);
00153 
00154     // Add the presentationv iew for chat info.
00155     view = new CPerformerChatView(sob);
00156     view->show();
00157     sob->addView(view);
00158 
00159     sob->addController(new CInteractiveSobController(sob));
00160     // handlers are global and should come from the factory
00161     sob->addHandler(WWCOMMON::CSobHandlerFactory::instance().getHandler(WWCOMMON::CSobHandlerFactory::H_CLIENT_MOTION));
00162     sob->addHandler(WWCOMMON::CSobHandlerFactory::instance().getHandler(WWCOMMON::CSobHandlerFactory::H_MOTION));
00163     sob->addHandler(WWCOMMON::CSobHandlerFactory::instance().getHandler(WWCOMMON::CSobHandlerFactory::H_MOTION_REQUEST));
00164 }
00165 
00166 void CSimulationImpl::addSob(WWCOMMON::CSobAddEvent *event) {
00167     // create a new SOB and set its unique ID to that from the server.
00168     CActorProxy *sob=dynamic_cast<CActorProxy *>(getNewSob("sobActor", event->SourceID));
00169 
00170     // and add it to the manager
00171     m_ActorManager->addSob(sob);
00172 
00173     // make sure out starting position is valid.
00174     if(event->Position == NLMISC::CVector::Null) {
00175         nlwarning("Entity spawned at an invalid position: %d", sob->getSobId());
00176         return;
00177     }
00178 
00179     sob->setPosition(event->Position);
00180     sob->getCurrentKey()->setSpeed(event->Speed);
00181     sob->getCurrentKey()->setYaw(event->Yaw);
00182     sob->getCurrentKey()->setYawSpeed(event->YawVelocity);
00183     sob->setGlobalPosition(event->Position);
00184     sob->setActiveStateList(&event->ActiveStateList);
00185 
00186     CEntityMedia emd = CResourceTask::instance().getEMD(event->EMD);
00187     WWCOMMON::IView* view = new CPerformer3DView(sob, emd);
00188     view->show();
00189     sob->addView(view);
00190 
00191     sob->addHandler(WWCOMMON::CSobHandlerFactory::instance().getHandler(WWCOMMON::CSobHandlerFactory::H_CLIENT_MOTION));
00192 
00193     WWCOMMON::CMotionController* controller = new WWCOMMON::CMotionController(sob);
00194     controller->setVisualCollisionEntity(&(CPacsTask::instance().getVisualCollisionManager()));
00195     sob->addController(controller);
00196 }
00197 
00198 void CSimulationImpl::removeSob(uint32 id) {
00199     WWCOMMON::ISimulationObj *sob=m_ActorManager->find(id);
00200     if(sob==NULL) {
00201         nlwarning("Failed to locate sob %d to unspawn.", id);
00202         return;
00203     }
00204 
00205     nlinfo("Removing sob %d from simulation.", id);
00206     m_ActorManager->removeSob(sob);
00207 
00208     delete sob;
00209 }
00210 
00211 void CSimulationImpl::recvPing(double serverTimeStamp, double localTimeStamp) {
00212     // make sure there's a ping in progress.
00213     if(m_PingLocalTimeStamp==0) {
00214         nlwarning("Received a ping response with no ping pending!");
00215         return;
00216     }
00217 
00218     // and make sure it's our ping.
00219     if(m_PingLocalTimeStamp != localTimeStamp) {
00220         nlwarning("Received a ping response for a ping that's not current.");
00221         return;
00222     }
00223 
00224     // Try something a little..simpler..and without STL (faster)
00225     double localRecvTimeStamp = time();
00226     double currentLatency = localRecvTimeStamp - localTimeStamp;
00227 
00228     // Let's do some weighted averages
00229 
00230     ++m_PingCount;
00231     // Since the ping changes all the time let the last sample have the most weight (similar to taking just 5 samples)
00232     unsigned long pingWeight = std::min<unsigned long>(5, m_PingCount-1);
00233     m_PingLatency = (pingWeight*m_PingLatency + currentLatency)/(pingWeight+1);
00234 
00235     // The offset should not change - hence the samples have less and less effect
00236     // until epsilon is reached and further calculations become pointless
00237     double currentOffset = serverTimeStamp - localRecvTimeStamp + m_PingLatency;
00238     currentOffset /= m_PingCount;
00239     if(currentOffset > m_Epsilon) {
00240         unsigned long offsetWeight = m_PingCount-1;
00241         // Improve our accuracy by taking the last 5 samples only during the first 50 pings
00242         if(m_PingCount < 50) {
00243             offsetWeight = std::min<unsigned long>(5, offsetWeight);
00244             currentOffset = serverTimeStamp - localRecvTimeStamp + m_PingLatency;
00245             currentOffset /= (offsetWeight+1);
00246         }
00247         m_OffsetTime = (m_OffsetTime*offsetWeight)/(offsetWeight+1) + currentOffset;
00248     } else {
00249         // no need for pings anymore since we already have what we believe to be the correct offset
00250         // and nothing will change that.
00251         // The difference in server and client time should always stay the same based upon the assumption
00252         // that the clocks of the respective machines run at the same speed.
00253         m_NoPing = true;
00254         nlinfo("Stopped pinging.");
00255     }
00256 
00257     //nlinfo("I think the server time is: %1f", time() + m_OffsetTime);
00258 }
00259 
00260 void CSimulationImpl::sendPing() {
00261     // we can't ping if we're not online.
00262     if(!CNetworkTask::instance().connected())
00263         return;
00264 
00265     m_PingLocalTimeStamp = time();
00266     // schedule the next ping
00267     // if we are just starting out do a few pings real fast
00268     // to get it in the ball park...takes about 10 seconds
00269     if(m_PingCount < 25) {
00270         m_NextPingTime = time() + 0.4;
00271     } else {
00272         m_NextPingTime=time()+ 5.00;
00273     }
00274 
00275     // send the message to the server.
00276     NLNET::CMessage msgout("PINGREQ");
00277     msgout.serial(m_PingLocalTimeStamp);
00278     CNetworkTask::instance().send(msgout);
00279 }
00280 
00281 void CSimulationImpl::updatePing() {
00282     // ping not wanted.
00283     if(m_NoPing)
00284         return;
00285 
00286     // we can't process out of sequence events until the simulation has been started.
00287     if(m_SelfSob == NULL)
00288         return;
00289 
00290     // check for next available time slot.
00291     if(m_NextPingTime <= time())
00292         sendPing();
00293 }
00294 
00295 }; // END NAMESPACE WWCLIENT

Generated on Mon Jan 11 12:03:38 2010 for Werewolf by  doxygen 1.6.1