src/engine/eNetGameObject.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023   
00024 ***************************************************************************
00025 
00026 */
00027 
00028 #include "eNetGameObject.h"
00029 #include "ePlayer.h"
00030 #include "eLagCompensation.h"
00031 #include "eTimer.h"
00032 #include "uInput.h"
00033 #include "eGrid.h"
00034 #include "eTeam.h"
00035 #include "eTess2.h"
00036 
00037 //static nNOInitialisator<eNetGameObject> eNetGameObject_Init("eNetGameObject");
00038 
00039 #define MAX_PING_OVERFLOW 3
00040 #define PING_OVERFLOW_TS .1
00041 
00042 // determines the effective ping of a player, taking ping charity into account
00043 static REAL se_GetPing( ePlayerNetID * player )
00044 {
00045     REAL peer_ping=0;
00046     REAL my_ping=0;
00047 
00048     if (bool(player) && player->Owner()!=::sn_myNetID)
00049     {
00050         if (sn_GetNetState()!=nSERVER)
00051             peer_ping+=player->ping;
00052         else
00053             peer_ping+=sn_Connections[player->Owner()].ping;
00054     }
00055     if (sn_GetNetState()!=nSERVER && (!player || player->Owner()!=::sn_myNetID))
00056         my_ping+=sn_Connections[0].ping;
00057 
00058     REAL ping = (peer_ping+my_ping)*.5;
00059 
00060     if (ping>my_ping+sn_pingCharityServer*.001)
00061         ping=my_ping+sn_pingCharityServer*.001;
00062 
00063     if (ping<my_ping-sn_pingCharityServer*.001)
00064         ping=my_ping-sn_pingCharityServer*.001;
00065 
00066     return ping;
00067 }
00068 
00069 void eNetGameObject::MyInitAfterCreation(){
00070     laggometer=laggometerSmooth=0;
00071 
00072     if (player){
00073         player->ControlObject(this);
00074     }
00075     clientside_action();
00076 
00077     pingOverflow=0;
00078 }
00079 
00080 void eNetGameObject::InitAfterCreation(){
00081     nNetObject::InitAfterCreation();
00082     MyInitAfterCreation();
00083 }
00084 
00085 eNetGameObject::eNetGameObject(eGrid *grid, const eCoord &pos,const eCoord &dir,
00086                                ePlayerNetID* p,bool autodelete)
00087         :eGameObject(grid, pos,dir,NULL,autodelete),
00088 nNetObject(p->Owner()),player(p){
00089     lastClientsideAction=0;
00090     if (sn_GetNetState()!=nCLIENT)
00091         RequestSync();
00092     MyInitAfterCreation();
00093 }
00094 
00095 
00096 
00097 eNetGameObject::eNetGameObject(nMessage &m)
00098         :eGameObject(eGrid::CurrentGrid(), eCoord(0,0), eCoord(0,0), NULL),
00099 nNetObject(m){
00100     tASSERT(grid);
00101 
00102     lastClientsideAction=0;
00103     unsigned short pid;
00104     m.Read(pid);
00105     player=static_cast<ePlayerNetID *>(Object(pid));
00106     m.Read(pid);
00107     autodelete=pid;
00108 
00109     laggometerSmooth=laggometer=0;
00110 
00111     pingOverflow=0;
00112 }
00113 
00114 void eNetGameObject::DoRemoveFromGame(){
00115     // let the object get deleted on exit if nobody else is interested
00116     tControlledPTR< eNetGameObject > bounce;
00117     if ( this->GetRefcount() >= 0 )
00118         bounce = this;
00119 
00120     // unregister from player
00121     if ( player && this == player->object )
00122     {
00123         player->object = NULL;
00124     }
00125 
00126     team = NULL;
00127 }
00128 
00129 eNetGameObject::~eNetGameObject(){
00130     if (player){
00131 #ifdef DEBUG
00132         //con << "Player " << ePlayer->name << " controls no object.\n";
00133 #endif
00134         if (player->object==this){
00135             player->object=NULL;
00136         }
00137     }
00138 }
00139 
00140 
00141 
00142 bool eNetGameObject::SyncIsNew(nMessage &m){
00143     bool ret=nNetObject::SyncIsNew(m);
00144     m >> lastAttemptedSyncTime;
00145 
00146 #ifdef DEBUG
00147     if (Owner()==::sn_myNetID && lastAttemptedSyncTime>lastClientsideAction+100){
00148         con << "Warning! time overflow!\n";
00149     }
00150 #endif
00151 
00152     eCoord dummy;
00153     m >> dummy;
00154     m >> dummy;
00155     return (ret);       // && lastAttemptedSyncTime>lastClientsideAction); // test for time no longer needed
00156 }
00157 
00158 void eNetGameObject::AddRef()
00159 {
00160     nNetObject::AddRef();
00161 }
00162 
00163 void eNetGameObject::Release()
00164 {
00165     nNetObject::Release();
00166 }
00167 
00168 // control functions:
00169 void eNetGameObject::ReceiveControlNet(nMessage &m){
00170     REAL time;
00171     unsigned short act_id;
00172     REAL x;
00173 
00174     m >> time;
00175     m.Read(act_id);
00176     m >> x;
00177 
00178     REAL backdate=Lag();//sn_ping[m.SenderID()]*.5;
00179     if (backdate>sn_pingCharityServer*.001)
00180         backdate=sn_pingCharityServer*.001;
00181 
00182     REAL mintime=se_GameTime()-backdate*1.5-.1;
00183     if (time<mintime){
00184         con << "mintime\n";
00185         REAL pov_needed=mintime-time;
00186         if (pov_needed+pingOverflow > MAX_PING_OVERFLOW*backdate){
00187             pov_needed = MAX_PING_OVERFLOW*backdate-pingOverflow;
00188             con << "Mintime\n";
00189         }
00190         if (pov_needed<0)
00191             pov_needed=0;
00192 
00193         time=mintime-pov_needed;
00194         pingOverflow+=pov_needed;
00195     }
00196 
00197     if (time>se_GameTime()+1)
00198         time=se_GameTime()+1;
00199 
00200     uActionPlayer *Act=uActionPlayer::Find(act_id);
00201 
00202     ReceiveControl(time,Act,x);
00203 }
00204 
00205 
00206 void eNetGameObject::SetPlayer(ePlayerNetID* a_player)
00207 {
00208     tASSERT( !a_player || Owner() == player->Owner() );
00209     player  = a_player;
00210     if ( laggometerSmooth == 0 && sn_GetNetState() != nCLIENT )
00211         laggometerSmooth = laggometer = se_GetPing( player );
00212 }
00213 
00214 void eNetGameObject::SendControl(REAL time,uActionPlayer *Act,REAL x){
00215     if (sn_GetNetState()==nCLIENT && Owner()==::sn_myNetID){
00216         //con << "sending control at " << time << "\n";
00217         nMessage *m=NewControlMessage();
00218         *m << time;
00219         m->Write(Act->ID());
00220         *m << x;
00221         m->BroadCast();
00222     }
00223 }
00224 
00225 void eNetGameObject::ReceiveControl(REAL time,uActionPlayer *Act,REAL x){
00226 #ifdef DEBUG
00227     if (sn_GetNetState()==nCLIENT)
00228         tERR_ERROR("rec_cont should not be called client-side!");
00229 #endif
00230 
00231     // after control is received, we better sync this object with
00232     // the clients:
00233 
00234     RequestSync();
00235 }
00236 
00237 
00238 void eNetGameObject::WriteCreate(nMessage &m){
00239     nNetObject::WriteCreate(m);
00240     m.Write(player->ID());
00241     m.Write(autodelete);
00242 }
00243 
00244 void eNetGameObject::WriteSync(nMessage &m){
00245     nNetObject::WriteSync(m);
00246     //con << lastTime << '\n';
00247     m << lastTime;
00248     m << Direction();
00249     m << Position();
00250 }
00251 
00252 void eNetGameObject::ReadSync(nMessage &m){
00253     nNetObject::ReadSync(m);
00254     m >> lastTime;
00255     m >> dir;
00256 
00257     m >> pos;
00258 }
00259 
00260 /*
00261 nDescriptor &eNetGameObject::CreatorDescriptor() const{
00262   return eNetGameObject_init.desc;
00263   } */
00264 
00265 bool eNetGameObject::ClearToTransmit(int user) const{
00266 #ifdef DEBUG
00267     if (nNetObject::DoDebugPrint())
00268     {
00269         if (eTransferInhibitor::no_transfer(user))
00270         {
00271             con << "Not transfering eNetGameObject " << ID()
00272             << " for user " << user << " because of some obscure reason.\n";
00273             st_Breakpoint();
00274             eTransferInhibitor::no_transfer(user);
00275         }
00276         else if (!player)
00277             con << "Not transfering eNetGameObject " << ID()
00278             << " for user " << user << " because it has no player!\n";
00279         else if (!player->HasBeenTransmitted(user))
00280         {
00281             tString s;
00282             s << "No transfering eNetGameObject " << ID()
00283             << " for user " << user << " because ";
00284             player->PrintName(s);
00285             s << " has not been transmitted.\n";
00286             con << s;
00287         }
00288     }
00289 #endif
00290 
00291 
00292     return
00293         nNetObject::ClearToTransmit(user) &&
00294         !eTransferInhibitor::no_transfer(user) &&
00295         (!player ||
00296          player->HasBeenTransmitted(user));
00297 }
00298 
00299 bool eNetGameObject::Timestep(REAL currentTime){
00300     // calculate new sr_laggometer
00301     if (sn_GetNetState() == nSTANDALONE){
00302         laggometerSmooth=0;
00303         return false;
00304     }
00305 
00306     REAL animts=(currentTime-lastTime);
00307     if (animts<0)
00308         animts=0;
00309 
00310     if (sn_GetNetState() == nSERVER || Owner() == ::sn_myNetID ||
00311             ( player && laggometer <= 0 ) )
00312     {
00313         // calculate laggometer from ping
00314         laggometer = se_GetPing( player );
00315     }
00316 
00317     // legitimate, but does not look good:
00318     // if ( laggometerSmooth <= 0 )
00319     //    laggometerSmooth = laggometer;
00320 
00321     laggometerSmooth=(laggometerSmooth+laggometer*animts)/(1 + animts);
00322     lastTime=currentTime;
00323 
00324     // Update ping overflow
00325     pingOverflow/=(1+animts*PING_OVERFLOW_TS);
00326 
00327     return false;
00328 }
00329 
00330 REAL eNetGameObject::Lag() const{
00331     return laggometerSmooth;
00332 }
00333 
00334 REAL eNetGameObject::LagThreshold() const{
00335     // ask the lag compensation framework
00336     if ( sn_GetNetState() != nSERVER )
00337         return 0;
00338     if ( Owner() == 0 )
00339         return 0;
00340     return eLag::Threshold();
00341 }
00342 
00343 static tCallbackOr* transfer_anchor;
00344 
00345 eTransferInhibitor::eTransferInhibitor(BOOLRETFUNC *f)
00346     :tCallbackOr(transfer_anchor,f){}
00347 
00348 bool eTransferInhibitor::no_transfer(int u){
00349     user = u;
00350     return Exec(transfer_anchor);
00351 }
00352 
00353 int eTransferInhibitor::user;
00354 
00355 nMessage & operator<< (nMessage &m, const eCoord &x){
00356     m << x.x;
00357     m << x.y;
00358 
00359     return m;
00360 }
00361 
00362 nMessage & operator>> (nMessage &m, eCoord &x){
00363     m >> x.x;
00364     m >> x.y;
00365 
00366     return m;
00367 }
00368 // *******************************************************************************
00369 // *
00370 // *    DoGetMachine
00371 // *
00372 // *******************************************************************************
00376 // *******************************************************************************
00377 
00378 nMachine & eNetGameObject::DoGetMachine( void ) const
00379 {
00380     if ( Player() )
00381         return Player()->GetMachine();
00382     else
00383         return nNetObject::DoGetMachine();
00384 }
00385 
00386 

Generated on Sat Mar 15 22:55:45 2008 for Armagetron Advanced by  doxygen 1.5.4