Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / gpm_service / move_checker.cpp
blob3884204413eee716c1db56a7577410f37696a398
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdpch.h"
19 #include "nel/misc/common.h"
21 #include "game_share/utils.h"
23 #include "move_checker.h"
26 /****************************************************************\
27 Static Stats Stuff (temp)
28 \****************************************************************/
30 class CStatsRecord
32 private:
33 std::vector<uint32> _Distances;
34 uint32 _Counter;
35 uint32 _LastTick;
36 bool _Teleporting;
37 uint32 _X,_Y;
38 uint32 _MaxDist;
39 uint32 _MaxDistTime;
41 public:
42 CStatsRecord()
44 _Distances.resize(50);
45 _Counter=0;
46 _LastTick=0;
47 _Teleporting=true;
48 _X=0;
49 _Y=0;
50 _MaxDist=0;
51 _MaxDistTime=(uint32)_Distances.size()/2;
54 void start(TDataSetRow entityIndex, sint32 x, sint32 y, uint32 tick)
56 std::fill(_Distances.begin(),_Distances.end(),0);
57 _Counter=0;
58 _LastTick=tick;
59 _Teleporting=true;
60 _X=x;
61 _Y=y;
62 _MaxDist=0;
63 _MaxDistTime=(uint32)_Distances.size()/2;
66 void add(TDataSetRow entityIndex, sint32 x, sint32 y, uint32 tick)
68 // if we've just teleported then there's no point worrying about the time since last update...
69 if (_Teleporting)
71 // flag teleporting as finished
72 _Teleporting= false;
74 else
76 // check whether entity has been updated recently
77 // if((tick-_LastTick)!=1)
78 // {
79 // nlwarning("Move Checker Stats: entity %s has only received position update after %d ticks",entityIndex.toString().c_str(),tick-_LastTick);
80 // }
83 // calculate the distance moved and check whether its a new record
84 uint32 squaredist= (_X-x)*(_X-x) + (_Y-y)*(_Y-y);
85 if (squaredist>_MaxDist)
87 _MaxDist=squaredist;
88 _MaxDistTime= std::max((uint32)_Counter,(uint32)_Distances.size()/2);
90 _Distances[_Counter%_Distances.size()]= squaredist;
92 // store away basic info for next time round
93 _X=x;
94 _Y=y;
95 _LastTick=tick;
97 // increment our counter...
98 ++_Counter;
100 // if we've hit a new record recently then display a log message
101 if ( (_Counter-_MaxDistTime) == (_Distances.size()/2) )
103 std::string s;
104 for (uint32 i=(uint32)_Distances.size();i!=0;--i)
106 s+=NLMISC::toString(" %d",_Distances[(_Counter-i)%_Distances.size()]);
108 nlinfo("SpeedStats record for %s: %d (%.2f m/s): %s",entityIndex.toString().c_str(),_MaxDist,sqrt((double)_MaxDist)/200,s.c_str());
113 typedef std::map<TDataSetRow,CStatsRecord> TStats;
114 TStats Stats;
116 static void startStats(TDataSetRow entityIndex, sint32 x, sint32 y, uint32 tick)
118 Stats[entityIndex].start(entityIndex,x,y,tick);
121 static void addStats(TDataSetRow entityIndex, sint32 x, sint32 y, uint32 tick)
123 Stats[entityIndex].add(entityIndex,x,y,tick);
126 static void endStats(TDataSetRow entityIndex)
128 Stats.erase(entityIndex);
132 /****************************************************************\
133 CMoveChecker Methods
134 \****************************************************************/
136 void CMoveChecker::teleport(TDataSetRow entityIndex, sint32 x, sint32 y, uint32 tick)
138 // get hold of the entity's record in the move checker (and creat a new entry if need be)
139 SPosition& thePosition= _Positions[entityIndex];
141 nlinfo("Move checker teleporting player: %s from (%d,%d) @tick: %d to (%d,%d) @tick: %d",
142 entityIndex.toString().c_str(),thePosition.X,thePosition.Y,thePosition.Tick,x,y,tick);
144 // record the new position
145 thePosition.X= x;
146 thePosition.Y= y;
147 thePosition.Tick= tick;
149 // generate a few stats
150 startStats(entityIndex,x,y,tick);
153 bool CMoveChecker::checkMove(TDataSetRow entityIndex, sint32& x, sint32& y, uint32 tick)
155 // setup a refference to the entity's position record, and bomb if it can't be found
156 TPositions::iterator positionIt= _Positions.find(entityIndex);
157 BOMB_IF(positionIt==_Positions.end(),"Ignoring call to 'checkMove' for an entity who doesn't exist in the move checker",return false);
158 SPosition& thePosition= positionIt->second;
160 // if the character hasn't moved then just return
161 if ( (x==thePosition.X) && (y==thePosition.Y) )
163 return true;
166 // nlinfo("Checking player move: %s from (%d,%d) @tick: %d to (%d,%d) @tick: %d",
167 // entityIndex.toString().c_str(),thePosition.X,thePosition.Y,thePosition.Tick,x,y,tick);
169 // if the tick value is out of order (for instance, after an advanced tp request) then ignore the move
170 DROP_IF(sint32(tick-thePosition.Tick)<0,"Ignoring out of order move for character "+entityIndex.toString(),return false);
172 // *** todo: perform a speed test here
173 // *** todo: perform collision test here
174 // *** NOTE: If move not legal then we need to change values of x and y and return false
176 // record the new position
177 thePosition.X= x;
178 thePosition.Y= y;
179 thePosition.Tick= tick;
181 // generate a few stats
182 addStats(entityIndex,x,y,tick);
184 return true;
187 void CMoveChecker::remove(TDataSetRow entityIndex)
189 // remove the entity from our positions map
190 _Positions.erase(entityIndex);
192 // generate a few stats
193 endStats(entityIndex);