-
Notifications
You must be signed in to change notification settings - Fork 0
/
Apian.cs
92 lines (74 loc) · 4.22 KB
/
Apian.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
using System;
using System.Collections.Generic;
using P2pNet;
using UniLog;
namespace Apian
{
public abstract class ApianBase
{
// public API
// ReSharper disable MemberCanBePrivate.Global,UnusedMember.Global,FieldCanBeMadeReadOnly.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global,AutoPropertyCanBeMadeGetOnly.Local,NotAccessedField.Global
protected Dictionary<string, Action<string, string, ApianMessage, long>> ApMsgHandlers;
// Args are fromId, toId, ApianMsg, msDelay
public UniLogger Logger;
public IApianGroupManager ApianGroup {get; protected set;}
public IApianClock ApianClock {get; protected set;}
public IApianGameNet GameNet {get; private set;}
public IApianAppCore Client {get; private set;}
protected long SysMs { get => DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;}
public string GroupId { get => ApianGroup.GroupId; }
public string GameId { get => GameNet.CurrentGameId(); }
// Command-related stuff
// protected Dictionary<long, ApianCommand> PendingCommands; // Commands received but not yet applied to the state
// protected long ExpectedCommandNum { get; set;} // starts at 0 - there should be no skipping unles a data checkpoint is loaded
protected ApianBase(IApianGameNet gn, IApianAppCore cl) {
GameNet = gn;
Client = cl;
Client.SetApianReference(this);
Logger = UniLogger.GetLogger("Apian");
ApMsgHandlers = new Dictionary<string, Action<string, string, ApianMessage, long>>();
// Add any truly generic handlers here
}
public abstract bool Update(); // Returns TRUE is local peer is in active state
// Apian Messages
public abstract void OnApianMessage(string fromId, string toId, ApianMessage msg, long lagMs);
public abstract void SendApianMessage(string toChannel, ApianMessage msg);
// Group-related
public void CreateNewGroup(string groupId, string groupName) => ApianGroup.CreateNewGroup(groupId, groupName);
public void InitExistingGroup(ApianGroupInfo info) => ApianGroup.InitExistingGroup(info);
public void JoinGroup(string groupId, string localMemberJson) => ApianGroup.JoinGroup(groupId, localMemberJson);
public abstract void ApplyCheckpointStateData(long seqNum, long timeStamp, string stateHash, string stateData);
// FROM GroupManager
public virtual void OnGroupMemberJoined(ApianGroupMember member)
{
// By default just helps getting ApianClock set up.
// App-specific Apian instance needs to field this if it cares for any other reason.
// Note that the local gameinstance usually doesn't care about a remote peer joining a group until a Player Joins the gameInst
// But it usually DOES care about the LOCAL peer's group membership status.
if (member.PeerId != GameNet.LocalP2pId() && ApianClock != null)
{
PeerClockSyncData syncData = GameNet.GetP2pPeerClockSyncData(member.PeerId);
if (syncData == null)
Logger.Warn($"ApianBase.OnGroupMemberJoined(): peer {member.PeerId} has no P2pClockSync data");
else
{
ApianClock.OnP2pPeerSync(member.PeerId, syncData.clockOffsetMs, syncData.networkLagMs);
if (!ApianClock.IsIdle)
ApianClock.SendApianClockOffset();
}
}
}
public abstract void OnGroupMemberStatusChange(ApianGroupMember member, ApianGroupMember.Status oldStatus);
public abstract void ApplyStashedApianCommand(ApianCommand cmd);
public abstract void SendCheckpointState(long timeStamp, long seqNum, string serializedState); // called by client app
// Other stuff
public void OnP2pPeerSync(string remotePeerId, long clockOffsetMs, long netLagMs) // sys + offset = apian
{
// TODO: This is awkward.
ApianClock?.OnP2pPeerSync( remotePeerId, clockOffsetMs, netLagMs);
}
// public API
// ReSharper enable MemberCanBePrivate.Global,UnusedMember.Global,FieldCanBeMadeReadOnly.Global
}
}