Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / client / src / time_client.cpp
blob1a2b6972b8330e783572da42e7441d53777d73fe
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdpch.h"
25 /////////////
26 // INCLUDE //
27 /////////////
28 // Misc;
29 #include "nel/misc/debug.h"
30 // client.
31 #include "time_client.h"
32 #include "interface_v3/interface_manager.h"
33 #include "nel/gui/interface_property.h"
34 #include "client_cfg.h"
35 #include "net_manager.h"
36 #include "game_share/zc_shard_common.h"
37 #include "weather.h"
38 #include "game_share/light_cycle.h"
40 #ifdef DEBUG_NEW
41 #define new DEBUG_NEW
42 #endif
44 ///////////
45 // USING //
46 ///////////
47 using namespace std;
50 ////////////
51 // GLOBAL //
52 ////////////
53 sint64 T0 = 0; // Time for the last frame.
54 sint64 T1 = 0; // Time for the current frame.
55 sint64 TS = 0; // Time since the really first Frame.
56 sint64 DT64 = 0; // Diff time with current and last frame in ms.
57 float DT = 0.f; // Diff time with current and last frame in sec.
58 TTime TSend = 0; // Next Time to send motions.
59 TTime DTSend = 100; // Delta of time to generate the next time to send motions.
60 double TimeInSec = 0.0; // Time for the current frame in second.
61 double FirstTimeInSec = 0.0; // Game local origin time
62 float TimeFactor = 1.f; // Factor applied to current date (local mode only)
65 TTime LCT = 1000; // Default LCT (Lag Compensation time).
66 TTime LocalTimeStep = 100; // Time Step factor on the client.
67 TTime CurrentPacketTime = 0; // Local Time for the current packet.
68 uint8 CurrentPacket = 0; // Packet currently valid.
69 uint8 LastPacketReceived = 0; // Last received packet.
70 uint8 LastPacketAck = 0; // Last acknowledged packet.
72 NLMISC::TGameCycle LastGameCycle = 0;
74 CRyzomTime RT;
75 CClientDate SmoothedClientDate;
77 // Hierarchical timer
78 H_AUTO_DECL ( RZ_Client_Update_Time )
81 ///////////
82 // LOCAL //
83 ///////////
84 // Map with all time for each packet sent to the server.
85 map<uint8, TTime> PacketTime;
86 // Map with all Infos for each packet received.
87 map<uint8, CPacketInfos> PacketInfos;
90 ///////////////
91 // FUNCTIONS //
92 ///////////////
93 //-----------------------------------------------
94 // removePacketTime :
95 // Remove the packet 'numPacket' from the 'PacketTime' list.
96 //-----------------------------------------------
97 void removePacketTime(uint8 numPacket)
99 PacketTime.erase(numPacket);
100 }// removePacketTime //
102 //-----------------------------------------------
103 // insertPacketTime :
104 // Insert a packet in the PacketTime map.
105 //-----------------------------------------------
106 void insertPacketTime(uint8 numPacket, TTime time)
108 PacketTime.insert(make_pair(numPacket, time));
109 }// insertPacketTime //
112 //-----------------------------------------------
113 // checkLocalTimeStep :
114 // Check if the Local Time Step is still valid with the new packet.
115 //-----------------------------------------------
116 void checkLocalTimeStep(const CPacketInfos &packetInfos)
118 // Compute how many packets there are since the current packet.
119 sint nbPacket = packetInfos.Num - CurrentPacket;
120 if(nbPacket < 0)
121 nbPacket += 256;
123 // \todo GUIGUI : check why this happen.
124 if(nbPacket==0)
125 return;
127 // Compute the predicted Local Time for this packet.
128 TTime predictedTime = CurrentPacketTime + LocalTimeStep*nbPacket;
130 TTime localTimeStep = LocalTimeStep;
132 // If the predicted time is too small according to the min time computed for the packet -> increase 'LocalTimeStep'.
133 if(predictedTime < packetInfos.Min)
135 // nlwarning("packetInfos.Min : %f", (double)packetInfos.Min);
136 // nlwarning("CurrentPacketTime : %f", (double)CurrentPacketTime);
137 // nlwarning("packetInfos.Min - CurrentPacketTime : %f", (double)((double)packetInfos.Min - (double)CurrentPacketTime));
139 LocalTimeStep = (packetInfos.Min - CurrentPacketTime)/nbPacket;
141 // nlwarning("LocalTimeStep : %f", (double)LocalTimeStep);
143 // If the predicted time is too big according to the max time computed for the packet -> increase 'LocalTimeStep'.
144 else if(predictedTime > packetInfos.Max)
146 // nlwarning("packetInfos.Max : %f", (double)packetInfos.Max);
147 // nlwarning("CurrentPacketTime : %f", (double)CurrentPacketTime);
148 // nlwarning("packetInfos.Max - CurrentPacketTime : %f", (double)((double)packetInfos.Max - (double)CurrentPacketTime));
150 LocalTimeStep = (packetInfos.Max - CurrentPacketTime)/nbPacket;
152 // nlwarning("LocalTimeStep : %f", (double)LocalTimeStep);
155 if(LocalTimeStep == 0)
157 LocalTimeStep = localTimeStep;
158 // nlwarning("LocalTimeStep (corrected): %f", (double)LocalTimeStep);
160 }// checkLocalTimeStep //
162 //-----------------------------------------------
163 // removePacket :
164 // Remove the packet 'numPacket' from the 'PacketInfos' list.
165 //-----------------------------------------------
166 void removePacket(uint8 numPacket)
168 PacketInfos.erase(numPacket);
169 }// removePacket //
171 //-----------------------------------------------
172 // insertPacket :
173 // Insert the packet received information in a list.
174 //-----------------------------------------------
175 void insertPacket(const CPacketInfos &packetInfos)
177 // Upadte the last packet received.
178 LastPacketReceived = packetInfos.Num;
180 // Insert the packet information.
181 PacketInfos.insert(make_pair(LastPacketReceived, packetInfos));
183 // Check Local Time Step with the new packet.
184 checkLocalTimeStep(packetInfos);
185 }// insertPacket //
188 //-----------------------------------------------
189 // getSentPacketTime :
190 // Return the sent time for a given packet or 0 if the packet is not found
191 //-----------------------------------------------
192 TTime getSentPacketTime(uint8 numPacket)
194 map<uint8, TTime>::iterator it = PacketTime.find(numPacket);
195 if(it != PacketTime.end())
196 return (*it).second;
197 else
198 return 0;
199 }// getSentPacketTime //
201 //-----------------------------------------------
202 // ackPacketTimeBefore :
204 //-----------------------------------------------
205 void ackPacketTimeBefore(uint8 ackPacketNumber)
207 // If the acknowledged packet is not in the list -> player do not have send any packet for the time.
208 map<uint8, TTime>::iterator itEnd = PacketTime.find(ackPacketNumber);
209 if(itEnd != PacketTime.end())
211 // If the packet cannot be found -> First valid packet the server is acknowledging
212 map<uint8, TTime>::iterator itBegin = PacketTime.find(LastPacketAck);
213 if(itBegin != PacketTime.end())
215 while(itBegin != itEnd)
218 map<uint8, TTime>::iterator itTmp = itBegin;
219 itBegin++;
220 // Destroy packets between the last acknowledged packet and the recent one.
221 PacketTime.erase(itTmp);
223 if(itBegin == PacketTime.end())
224 itBegin = PacketTime.begin();
229 LastPacketAck = ackPacketNumber;
230 }// ackPacketTimeBefore //
232 static CInterfaceProperty *InterfaceTime = NULL;
233 static CInterfaceProperty *InterfaceServerTick = NULL;
234 static CInterfaceProperty *InterfaceSmoothServerTick = NULL;
235 static CInterfaceProperty *InterfaceDay = NULL;
236 static CInterfaceProperty *InterfaceDayBeforeNextZCDistrib = NULL;
238 //-----------------------------------------------
239 // initClientTime
241 //-----------------------------------------------
242 void initClientTime()
244 nlassert (InterfaceTime == NULL);
245 nlassert (InterfaceServerTick == NULL);
246 nlassert (InterfaceSmoothServerTick == NULL);
247 nlassert (InterfaceDay== NULL);
248 nlassert (InterfaceDayBeforeNextZCDistrib== NULL);
250 InterfaceTime = new CInterfaceProperty;
251 InterfaceServerTick = new CInterfaceProperty;
252 InterfaceSmoothServerTick = new CInterfaceProperty;
253 InterfaceDay = new CInterfaceProperty;
254 InterfaceDayBeforeNextZCDistrib = new CInterfaceProperty;
256 CInterfaceManager *pIM= CInterfaceManager::getInstance();
258 // get a direct link to the database
259 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CURRENT_TIME");
260 InterfaceTime->link("UI:VARIABLES:CURRENT_TIME");
261 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CURRENT_SERVER_TICK");
262 InterfaceServerTick->link("UI:VARIABLES:CURRENT_SERVER_TICK");
263 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CURRENT_SMOOTH_SERVER_TICK");
264 InterfaceSmoothServerTick->link("UI:VARIABLES:CURRENT_SMOOTH_SERVER_TICK");
265 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CURRENT_DAY");
266 InterfaceDay->link("UI:VARIABLES:CURRENT_DAY");
267 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:DAY_BEFORE_ZC_DISTRIB");
268 InterfaceDayBeforeNextZCDistrib->link("UI:VARIABLES:DAY_BEFORE_ZC_DISTRIB");
271 //-----------------------------------------------
273 void releaseClientTime()
275 if (InterfaceTime)
277 delete InterfaceTime;
278 InterfaceTime = NULL;
280 if (InterfaceServerTick)
282 delete InterfaceServerTick;
283 InterfaceServerTick = NULL;
285 if (InterfaceSmoothServerTick)
287 delete InterfaceSmoothServerTick;
288 InterfaceSmoothServerTick = NULL;
290 if (InterfaceDay)
292 delete InterfaceDay;
293 InterfaceDay = NULL;
295 if (InterfaceDayBeforeNextZCDistrib)
297 delete InterfaceDayBeforeNextZCDistrib;
298 InterfaceDayBeforeNextZCDistrib = NULL;
305 //-----------------------------------------------
306 // updateClientTime :
308 //-----------------------------------------------
309 CWidgetManager::SInterfaceTimes times;
311 void updateClientTime()
313 H_AUTO_USE ( RZ_Client_Update_Time )
315 // Last T0
316 T0 = T1;
318 // Constant delta time ?
319 if (ClientCfg.ForceDeltaTime == 0)
321 T1 = ryzomGetLocalTime();
322 if (T1 <= T0)
324 // This case is known to occurs if the framerate is very fast (e.g. during the
325 // loading stage) or if the machine has got a heavy load (e.g. lots of AGP data)
326 // delaying the timer updates.
327 //nlwarning ("getLocalTime has returned the same time! START");
328 while (T1 <= T0)
330 T1 = ryzomGetLocalTime();
331 // give up the time slice to let time to other process
332 NLMISC::nlSleep(0);
334 //nlwarning ("getLocalTime has returned the same time! END");
337 else
339 // First time ?
340 static bool firstTime = true;
341 if (firstTime)
343 T1 = ryzomGetLocalTime();
344 firstTime = false;
346 else
348 T1 += ClientCfg.ForceDeltaTime;
352 if(T0 == T1)
353 nlwarning("updateClientTime: T0 should not be = T1.");
355 // Update time variables
356 DT64 = T1-T0;
357 TS += DT64;
358 DT = ((float)DT64)*0.001f;
360 TimeInSec = T1*0.001;
362 // First time ?
363 if (FirstTimeInSec == 0.0)
364 FirstTimeInSec = TimeInSec;
366 // Set the InterfaceManager current time.
367 if (InterfaceTime)
368 InterfaceTime->setSInt64(T1);
369 if (InterfaceServerTick)
370 InterfaceServerTick->setSInt64(NetMngr.getCurrentServerTick());
371 // Set the Smooth ServerTick
372 if (InterfaceSmoothServerTick)
373 InterfaceSmoothServerTick->setSInt64(NetMngr.getCurrentSmoothServerTick());
375 // Day, and Day before ZC distrib
376 if(InterfaceDay)
377 InterfaceDay->setSInt64(RT.getRyzomDay());
378 if(InterfaceDayBeforeNextZCDistrib)
380 sint d= RT.getRyzomDay()%ZCSTATE::ZCDistribPeriod;
381 // Must dispaly at least "1".
382 d= ZCSTATE::ZCDistribPeriod - d;
383 InterfaceDayBeforeNextZCDistrib->setSInt64(d);
386 #ifdef ENABLE_INCOMING_MSG_RECORDER
387 // Init For the Replay.
388 if(NetMngr.isReplayStarting())
389 NetMngr.startReplay();
390 #endif
392 times.lastFrameMs = T0;
393 times.thisFrameMs = T1;
394 times.frameDiffMs = DT64;
396 CWidgetManager::getInstance()->updateInterfaceTimes( times );
398 }// updateClientTime //
401 // update smoothed time
402 void updateSmoothedTime()
404 #define REAL_SECONDS_TO_RYZOM_HOUR(s) (double(s) * 10 / double(RYZOM_HOURS_IN_TICKS))
406 CClientDate oldSmoothedClientDate = SmoothedClientDate;
407 double dHour = REAL_SECONDS_TO_RYZOM_HOUR(DT);
408 SmoothedClientDate.Hour += (float) dHour;
409 if (SmoothedClientDate.Hour > WorldLightCycle.NumHours)
411 SmoothedClientDate.Day += (sint32) ceil(dHour / WorldLightCycle.NumHours);
412 SmoothedClientDate.Hour = (float) fmod(SmoothedClientDate.Hour, WorldLightCycle.NumHours);
414 double smoothedClientDateInHour = (double) SmoothedClientDate.Day * 24 + SmoothedClientDate.Hour;
415 double ryzomDateInHour = (double) RT.getRyzomDay() * 24 + (double) RT.getRyzomTime();
416 const double SMOOTHED_DATE_MAX_ERROR_IN_RYZOM_HOUR = REAL_SECONDS_TO_RYZOM_HOUR(10);
417 double hourError = fabs(smoothedClientDateInHour - ryzomDateInHour);
418 if (hourError > SMOOTHED_DATE_MAX_ERROR_IN_RYZOM_HOUR)
420 if (smoothedClientDateInHour < ryzomDateInHour)
422 // smoothed time is late
423 SmoothedClientDate.Day = RT.getRyzomDay();
424 SmoothedClientDate.Hour = RT.getRyzomTime();
426 else
428 if (hourError > (2 * SMOOTHED_DATE_MAX_ERROR_IN_RYZOM_HOUR))
430 // if difference is too big, rescale smoothed time on server time
431 SmoothedClientDate.Day = RT.getRyzomDay();
432 SmoothedClientDate.Hour = RT.getRyzomTime();
434 else
436 // cancel time increment (wait until server time is up with smoothed client time)
437 SmoothedClientDate = oldSmoothedClientDate;