Skip to content

Commit 8de69bd

Browse files
committed
Implement SyncTime and Ping
1 parent 9c30257 commit 8de69bd

File tree

6 files changed

+86
-43
lines changed

6 files changed

+86
-43
lines changed

src/MHServerEmu/Common/Clock.cs

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
namespace MHServerEmu.Common
2+
{
3+
/// <summary>
4+
/// Provides Gazillion time functionality.
5+
/// </summary>
6+
public static class Clock
7+
{
8+
private const long GameTimeEpochTimestamp = 1348306278045983; // Sep 22 2012 09:31:18 GMT+0000, calculated from packet dumps
9+
10+
private static readonly DateTime UnixEpoch = new(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
11+
private static readonly DateTime GameTimeEpoch = UnixEpoch.AddTicks(GameTimeEpochTimestamp * 10L);
12+
13+
/// <summary>
14+
/// Returns the current calendar time (epoch at Jan 01 1970 00:00:00 GMT+0000) as a <see cref="TimeSpan"/>.
15+
/// </summary>
16+
public static TimeSpan GetDateTime()
17+
{
18+
return DateTime.UtcNow - UnixEpoch;
19+
}
20+
21+
/// <summary>
22+
/// Returns the current game time (epoch at Sep 22 2012 09:31:18 GMT+0000) as a <see cref="TimeSpan"/>.
23+
/// </summary>
24+
public static TimeSpan GetGameTime()
25+
{
26+
return DateTime.UtcNow - GameTimeEpoch;
27+
}
28+
29+
/// <summary>
30+
/// Returns <see cref="DateTime"/> corresponding to the provided millisecond game time timestamp.
31+
/// </summary>
32+
public static DateTime GameTimeMillisecondsToDateTime(long timestamp)
33+
{
34+
return GameTimeEpoch.AddMilliseconds(timestamp);
35+
}
36+
37+
/// <summary>
38+
/// Returns <see cref="DateTime"/> corresponding to the provided microsecond game time timestamp.
39+
/// </summary>
40+
public static DateTime GameTimeMicrosecondsToDateTime(long timestamp)
41+
{
42+
return GameTimeEpoch.AddTicks(timestamp * 10);
43+
}
44+
}
45+
}

src/MHServerEmu/Games/Game.Loading.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Gazillion;
2+
using MHServerEmu.Common;
23
using MHServerEmu.Common.Config;
34
using MHServerEmu.Frontend;
45
using MHServerEmu.Games.Entities;
@@ -22,7 +23,7 @@ private GameMessage[] GetBeginLoadingMessages(FrontendClient client)
2223

2324
// Add server info messages
2425
messageList.Add(new(NetMessageMarkFirstGameFrame.CreateBuilder()
25-
.SetCurrentservergametime(161351682950)
26+
.SetCurrentservergametime((ulong)Clock.GetGameTime().TotalMilliseconds)
2627
.SetCurrentservergameid(1150669705055451881)
2728
.SetGamestarttime(1)
2829
.Build()));
@@ -104,7 +105,7 @@ private GameMessage[] LoadPlayerEntityMessages(DBAccount account)
104105
.SetLeaderboardsEnabled(ConfigManager.GameOptions.LeaderboardsEnabled)
105106
.SetNewPlayerExperienceEnabled(ConfigManager.GameOptions.NewPlayerExperienceEnabled)
106107
.SetServerTimeOffsetUTC(-7)
107-
.SetUseServerTimeOffset(false)
108+
.SetUseServerTimeOffset(true) // Although originally this was set to false, it needs to be true because auto offset doesn't work past 2019
108109
.SetMissionTrackerV2Enabled(ConfigManager.GameOptions.MissionTrackerV2Enabled)
109110
.SetGiftingAccountAgeInDaysRequired(ConfigManager.GameOptions.GiftingAccountAgeInDaysRequired)
110111
.SetGiftingAvatarLevelRequired(ConfigManager.GameOptions.GiftingAvatarLevelRequired)

src/MHServerEmu/Games/Regions/RegionManager.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ private static byte[] GetArchiveData(RegionPrototypeId prototype)
557557
// Widget: UI/MetaGame/TimeRemainingStoryMode2.prototype
558558
// Context: Missions/Prototypes/PVEEndgame/PatrolMidtown/Events/MidtownEventMegaSentinel.prototype
559559
new UIWidgetGenericFraction((PrototypeId)11932510257277768241, (PrototypeId)10490887443555427166, Array.Empty<PrototypeId>(),
560-
1, 1, 0, 161351934500, false)
560+
1, 1, 0, (long)Clock.GetGameTime().TotalMilliseconds + 251550, false) // 161351934500 (Currentservergametime) - 161351682950 = 251550
561561
});
562562

563563
break;

src/MHServerEmu/Networking/GameMessage.cs

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public class GameMessage
1212

1313
public byte Id { get; }
1414
public byte[] Payload { get; }
15+
public TimeSpan GameTimeReceived { get; set; }
16+
public TimeSpan DateTimeReceived { get; set; }
1517

1618
/// <summary>
1719
/// Constructs a new <see cref="GameMessage"/> from raw data.

src/MHServerEmu/PlayerManagement/PlayerManagerService.cs

+34-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Gazillion;
22
using Google.ProtocolBuffers;
33
using MHServerEmu.Auth;
4+
using MHServerEmu.Common;
45
using MHServerEmu.Common.Config;
56
using MHServerEmu.Common.Logging;
67
using MHServerEmu.Frontend;
@@ -115,6 +116,13 @@ public void BroadcastMessage(GameMessage message)
115116

116117
public void Handle(FrontendClient client, ushort muxId, GameMessage message)
117118
{
119+
// Timestamp sync messages
120+
if (message.Id == (byte)ClientToGameServerMessage.NetMessageSyncTimeRequest || message.Id == (byte)ClientToGameServerMessage.NetMessagePing)
121+
{
122+
message.GameTimeReceived = Clock.GetGameTime();
123+
message.DateTimeReceived = Clock.GetDateTime();
124+
}
125+
118126
switch ((ClientToGameServerMessage)message.Id)
119127
{
120128
// Self-handled messages
@@ -136,12 +144,12 @@ public void Handle(FrontendClient client, ushort muxId, GameMessage message)
136144

137145
case ClientToGameServerMessage.NetMessageSyncTimeRequest:
138146
if (message.TryDeserialize<NetMessageSyncTimeRequest>(out var syncTimeRequest))
139-
OnSyncTimeRequest(client, syncTimeRequest);
147+
OnSyncTimeRequest(client, syncTimeRequest, message.GameTimeReceived, message.DateTimeReceived);
140148
break;
141149

142150
case ClientToGameServerMessage.NetMessagePing:
143151
if (message.TryDeserialize<NetMessagePing>(out var ping))
144-
OnPing(client, ping);
152+
OnPing(client, ping, message.GameTimeReceived);
145153
break;
146154

147155
case ClientToGameServerMessage.NetMessageFPS:
@@ -257,39 +265,44 @@ private void OnReadyForGameJoin(FrontendClient client, NetMessageReadyForGameJoi
257265

258266
// Sync time
259267
client.SendMessage(MuxChannel, new(NetMessageInitialTimeSync.CreateBuilder()
260-
.SetGameTimeServerSent(161351679299542) // dumped - Gazillion time?
261-
.SetDateTimeServerSent(1509657957345525) // dumped - unix time stamp in microseconds
268+
.SetGameTimeServerSent(Clock.GetGameTime().Ticks / 10)
269+
.SetDateTimeServerSent(Clock.GetDateTime().Ticks / 10)
262270
.Build()));
263271
}
264272

265-
private void OnSyncTimeRequest(FrontendClient client, NetMessageSyncTimeRequest syncTimeRequest)
273+
private void OnSyncTimeRequest(FrontendClient client, NetMessageSyncTimeRequest syncTimeRequest, TimeSpan gameTimeReceived, TimeSpan dateTimeReceived)
266274
{
267-
// NOTE: this is old experimental code
268-
/*
269-
Logger.Info($"Received NetMessageSyncTimeRequest:");
270-
Logger.Trace(syncTimeRequest.ToString());
275+
//Logger.Debug($"NetMessageSyncTimeRequest:");
276+
//Logger.Debug(syncTimeRequest.ToString());
271277

272-
Logger.Info("Sending NetMessageSyncTimeReply");
273-
client.SendMessage(1, new(NetMessageSyncTimeReply.CreateBuilder()
278+
client.SendMessage(MuxChannel, new(NetMessageSyncTimeReply.CreateBuilder()
274279
.SetGameTimeClientSent(syncTimeRequest.GameTimeClientSent)
275-
.SetGameTimeServerReceived(_serverManager.GetGameTime())
276-
.SetGameTimeServerSent(_serverManager.GetGameTime())
277-
280+
.SetGameTimeServerReceived(gameTimeReceived.Ticks / 10)
281+
.SetGameTimeServerSent(Clock.GetGameTime().Ticks / 10)
278282
.SetDateTimeClientSent(syncTimeRequest.DateTimeClientSent)
279-
.SetDateTimeServerReceived(_serverManager.GetDateTime())
280-
.SetDateTimeServerSent(_serverManager.GetDateTime())
281-
283+
.SetDateTimeServerReceived(dateTimeReceived.Ticks / 10)
284+
.SetDateTimeServerSent(Clock.GetDateTime().Ticks / 10)
282285
.SetDialation(1.0f)
283286
.SetGametimeDialationStarted(0)
284287
.SetDatetimeDialationStarted(0)
285288
.Build()));
286-
*/
287289
}
288290

289-
private void OnPing(FrontendClient client, NetMessagePing ping)
291+
private void OnPing(FrontendClient client, NetMessagePing ping, TimeSpan gameTimeReceived)
290292
{
291-
//Logger.Info($"Received ping:");
292-
//Logger.Trace(ping.ToString());
293+
//Logger.Debug($"NetMessagePing:");
294+
//Logger.Debug(ping.ToString());
295+
296+
client.SendMessage(MuxChannel, new(NetMessagePingResponse.CreateBuilder()
297+
.SetDisplayOutput(ping.DisplayOutput)
298+
.SetRequestSentClientTime(ping.SendClientTime)
299+
.SetRequestSentGameTime(ping.SendGameTime)
300+
.SetRequestNetReceivedGameTime((ulong)gameTimeReceived.TotalMilliseconds)
301+
.SetResponseSendTime((ulong)Clock.GetGameTime().TotalMilliseconds)
302+
.SetServerTickforecast(0)
303+
.SetGameservername("BOPR-MHVGIS2")
304+
.SetFrontendname("bopr-mhfes2")
305+
.Build()));
293306
}
294307

295308
private void OnFps(FrontendClient client, NetMessageFPS fps)

src/MHServerEmu/ServerManager.cs

+1-19
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,9 @@ namespace MHServerEmu
1111
{
1212
public class ServerManager : IGameService
1313
{
14-
private static readonly Logger Logger = LogManager.CreateLogger();
15-
1614
public const string GameVersion = "1.52.0.1700";
1715

18-
// Reference point for counting game time (1348306278045983 == Sep 22 2012 09:31:18 GMT+0000)
19-
public static readonly DateTime GameTimeEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddTicks(1348306278045983 * 10L);
16+
private static readonly Logger Logger = LogManager.CreateLogger();
2017

2118
public static ServerManager Instance { get; } = new();
2219

@@ -156,21 +153,6 @@ public string GetServerStatus()
156153
return $"Server Status\nUptime: {DateTime.Now - StartupTime:hh\\:mm\\:ss}\nSessions: {PlayerManagerService.SessionCount}";
157154
}
158155

159-
/// <summary>
160-
/// Returns current calendar time in microseconds (epoch at Jan 01 1970 00:00:00 GMT+0000).
161-
/// </summary>
162-
public static long GetDateTimeMicroseconds()
163-
{
164-
return DateTime.UtcNow.Ticks / 10;
165-
}
166-
167-
/// <summary>
168-
/// Returns current game time in microseconds (epoch at Sep 22 2012 09:31:18 GMT+0000).
169-
/// </summary>
170-
public static long GetGameTimeMicroseconds()
171-
{
172-
return (DateTime.UtcNow - GameTimeEpoch).Ticks / 10;
173-
}
174156

175157
#endregion
176158
}

0 commit comments

Comments
 (0)