This repository has been archived by the owner on Apr 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
/
MDGameInstance.cs
326 lines (278 loc) · 12 KB
/
MDGameInstance.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
using Godot;
using System;
namespace MD
{
/// <summary>
/// Single-instance class that persists throughout the life-time of the game application.
/// </summary>
public class MDGameInstance : Node
{
private const string LOG_CAT = "LogGameInstance";
public MDReplicator Replicator { get; private set; }
public MDConfiguration Configuration { get; private set; }
public MDGameSession GameSession { get; private set; }
public MDGameClock GameClock { get; private set; }
public MDGameSynchronizer GameSynchronizer { get; private set; }
public MDInterfaceManager InterfaceManager { get; private set; }
// TODO - There should be an InputState for each local player
public MDInput InputState { get; protected set; } = new MDInput();
public override void _Ready()
{
MDStatics.GI = this;
// Configuration first
CreateConfiguration();
// Init static classes first
MDLog.Initialize(GetLogDirectory());
MDArguments.PopulateArgs();
MDProfiler.Initialize();
MDOnScreenDebug.Initialize();
// Hook up events
GetTree().Connect("node_added", this, nameof(OnNodeAdded_Internal));
GetTree().Connect("node_removed", this, nameof(OnNodeRemoved_Internal));
// Init instances
CreateGameSession();
CreateGameSynchronizer();
CreateReplicator();
CreateInterfaceManager();
RegisterNodeAndChildren(GetTree().Root);
}
public override void _Notification(int NotificationType)
{
base._Notification(NotificationType);
switch (NotificationType)
{
case MainLoop.NotificationWmQuitRequest:
MDLog.Info(LOG_CAT, "Quit notification received.");
GameSession?.Disconnect();
break;
}
}
public override void _Input(InputEvent Event)
{
InputState.OnInputEvent(Event);
}
/// <summary>
/// Called whenever a new node is added to the scene
/// </summary>
/// <param name="AddedNode">The node that was added</param>
protected virtual void OnNodeAdded(Node AddedNode)
{
}
/// <summary>
/// Called whenever a node is removed to the scene
/// </summary>
/// <param name="RemovedNode">The node that was removed</param>
protected virtual void OnNodeRemoved(Node RemovedNode)
{
}
// Travels the tree and registers the existing nodes
private void RegisterNodeAndChildren(Node RootNode)
{
if (RootNode == null)
{
return;
}
OnNodeAdded_Internal(RootNode);
int ChildCount = RootNode.GetChildCount();
for (int i = 0; i < ChildCount; ++i)
{
RegisterNodeAndChildren(RootNode.GetChild(i));
}
}
// Bound to SceneTree.node_added
private void OnNodeAdded_Internal(Godot.Object NodeObj)
{
Node AddedNode = NodeObj as Node;
if (AddedNode != null)
{
RegisterNewNode(AddedNode);
OnNodeAdded(AddedNode);
}
}
// Bound to SceneTree.node_removed
private void OnNodeRemoved_Internal(Godot.Object NodeObj)
{
Node RemovedNode = NodeObj as Node;
if (RemovedNode == null)
{
return;
}
UnregisterNode(RemovedNode);
OnNodeRemoved(RemovedNode);
if (GameSession != null && GameSession != RemovedNode)
{
GameSession.OnNodeRemoved(RemovedNode);
}
}
// Registers a new node to MDFramework systems
private void RegisterNewNode(Node Instance)
{
Type type = Instance.GetType();
// Ignore nodes in Godot namespace as they won't have any attributes
if (MDStatics.IsInGodotNamespace(type))
{
return;
}
MDAutoRegister AutoRegAtr = MDStatics.FindClassAttributeInNode<MDAutoRegister>(Instance.GetType());
if (RequireAutoRegister() && AutoRegAtr == null ||
AutoRegAtr != null && AutoRegAtr.RegisterType == MDAutoRegisterType.None)
{
return;
}
Instance.PopulateBindNodes();
Instance.RegisterReplicatedAttributes();
if (AutoRegAtr != null && AutoRegAtr.RegisterType == MDAutoRegisterType.Debug)
{
Instance.RegisterCommandAttributes();
}
}
// Unregisters a removed node from MDFramework systems
private void UnregisterNode(Node Instance)
{
// We automatically unregister commands even though we don't automatically register them to avoid relying on the user to do so
Instance.UnregisterCommandAttributes();
Instance.UnregisterReplicatedAttributes();
}
// Ensure Replicator is created
private void CreateReplicator()
{
if (Replicator == null)
{
Replicator = MDStatics.CreateTypeInstance<MDReplicator>(GetReplicatorType());
Replicator.Name = "Replicator";
this.AddNodeToRoot(Replicator, true);
Replicator.Initialize();
GameSession.Replicator = Replicator;
}
}
// Ensure Replicator is created
private void CreateConfiguration()
{
if (Configuration == null)
{
Configuration = MDStatics.CreateTypeInstance<MDConfiguration>(GetConfigurationType());
Configuration.Name = "MDConfiguration";
Configuration.LoadConfiguration();
this.AddNodeToRoot(Configuration, true);
}
}
// Ensure GameSession is created
private void CreateGameSession()
{
if (GameSession == null)
{
GameSession = MDStatics.CreateTypeInstance<MDGameSession>(GetGameSessionType());
GameSession.Name = "GameSession";
GameSession.GameInstance = this;
this.AddNodeToRoot(GameSession, true);
}
}
private void CreateGameSynchronizer()
{
if (GameSynchronizer == null)
{
GameSynchronizer = MDStatics.CreateTypeInstance<MDGameSynchronizer>(GetGameSynchronizerType());
GameSynchronizer.Name = "GameSynchronizer";
GameSynchronizer.GameInstance = this;
this.AddNodeToRoot(GameSynchronizer, true);
// Check if we should create the game clock as well
CreateGameClock();
}
}
private void CreateGameClock()
{
if (GameClock == null)
{
GameClock = MDStatics.CreateTypeInstance<MDGameClock>(GetGameClockType());
GameClock.Name = "GameClock";
GameSynchronizer.GameClock = GameClock;
this.AddNodeToRoot(GameClock, true);
}
}
// Ensure InterfaceManager is created
private void CreateInterfaceManager()
{
if (InterfaceManager == null)
{
InterfaceManager = new MDInterfaceManager
{
Name = "InterfaceManager"
};
this.AddNodeToRoot(InterfaceManager, true);
}
}
#region Configuration
/// <summary>Override this to provide the your GameSession subclass type</summary>
protected virtual Type GetGameSessionType()
{
return Configuration.GetType(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.GAME_SESSION_TYPE, typeof(MDGameSession));
}
/// <summary>Override this to provide the your GameSynchronizer subclass type</summary>
protected virtual Type GetGameSynchronizerType()
{
return Configuration.GetType(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.GAME_SYNCHRONIZER_TYPE, typeof(MDGameSynchronizer));
}
/// <summary>Override this to provide the your GameClock subclass type</summary>
protected virtual Type GetGameClockType()
{
return Configuration.GetType(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.GAME_CLOCK_TYPE, typeof(MDGameClock));
}
/// <summary>Override this to provide your Replicator subclass type</summary>
protected virtual Type GetReplicatorType()
{
return Configuration.GetType(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.REPLICATOR_TYPE, typeof(MDReplicator));
}
/// <summary>Override this to provide your Configuration subclass type</summary>
protected virtual Type GetConfigurationType()
{
return typeof(MDConfiguration);
}
// Override this to provide your own Player class type
public virtual Type GetPlayerInfoType()
{
return Configuration.GetType(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.PLAYER_INFO_TYPE, typeof(MDPlayerInfo));
}
/// <summary>Override to change when the console is available (Default: Only in debug mode)</summary>
public virtual bool IsConsoleAvailable()
{
return Configuration.GetBool(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.CONSOLE_ENABLED, false);
}
/// <summary>Override to change when the on screen debug is available (Default: Only in debug mode)</summary>
public virtual bool IsOnScreenDebugAvailable()
{
return Configuration.GetBool(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.ON_SCREEN_DEBUG_ENABLED, false);
}
/// <summary>Override to change when UPNP is used for the server (Default: True)</summary>
public virtual bool UseUPNP()
{
return Configuration.GetBool(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.USE_UPNP, false);
}
/// <summary>Override to change is MDAutoRegister is required (Default: False)</summary>
public virtual bool RequireAutoRegister()
{
return Configuration.GetBool(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.REQUIRE_AUTO_REGISTER, false);
}
///<summary>Get the key used to open the console. (Default: KeyList.QuoteLeft)</summary>
public virtual int GetConsoleKey()
{
return Configuration.GetInt(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.CONSOLE_KEY, (int)KeyList.Quoteleft);
}
///<summary>Get the key used to open the on screen debug. (Default: KeyList.F12)</summary>
public virtual int GetOnScreenDebugKey()
{
return Configuration.GetInt(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.ON_SCREEN_DEBUG_KEY, (int)KeyList.F12);
}
///<summary>Get the directory for MDLog log files
///<para>Official documentation for the user path: https://docs.godotengine.org/en/stable/tutorials/io/data_paths.html</para></summary>
public virtual string GetLogDirectory()
{
return Configuration.GetString(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.LOG_DIRECTORY, "user://logs/");
}
///<summary>If true we will keep a reference to all loaded scenes around so we don't need to load the resource from disc every time</summary>
public virtual bool UseSceneBuffer(string NodePath)
{
return Configuration.GetBool(MDConfiguration.ConfigurationSections.GameInstance, MDConfiguration.USE_SCENE_BUFFER, true);
}
#endregion
}
}