Skip to content

Commit 9fc2eac

Browse files
authored
feat: (Day) Add an instance controller for prep for future work (AscensionGameDev#2093)
* feat: (Day) Add an instance controller for prep for future work * chore: (Day) Switch to hashset for instancecontroller player collection * chore: (Day) Code review for instance controller * chore: (Day) Code review for instance controller * fix: (Day) Fix my broken PR * chore: (Day) Code review * chore: (Day) CR
1 parent 9aa9c47 commit 9fc2eac

File tree

7 files changed

+176
-40
lines changed

7 files changed

+176
-40
lines changed

Intersect.Server.Core/Core/LogicService.LogicThread.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Intersect.Server.Database.PlayerData.Players;
1212
using Intersect.Utilities;
1313
using Intersect.Server.Database.PlayerData.Api;
14+
using Intersect.Server.Core.MapInstancing;
1415

1516
namespace Intersect.Server.Core
1617
{
@@ -152,22 +153,31 @@ protected override void ThreadStart(ServerContext serverContext)
152153
}
153154

154155
//Refresh list of active maps & their instances
155-
foreach (var layerId in ActiveMapInstances.Keys.ToArray())
156+
foreach (var (instanceId, mapInstance) in ActiveMapInstances.ToArray())
156157
{
157-
if (!processedMapInstances.Contains(layerId))
158+
if (processedMapInstances.Contains(instanceId) || mapInstance.ShouldBeActive())
158159
{
159-
// Remove the map entirely from the update queue
160-
if (ActiveMapInstances[layerId] != null && ActiveMapInstances[layerId].ShouldBeCleaned())
160+
continue;
161+
}
162+
163+
if (mapInstance != default)
164+
{
165+
if (mapInstance.ShouldBeCleaned())
161166
{
162-
ActiveMapInstances[layerId].RemoveLayerFromController();
163-
ActiveMapInstances.Remove(layerId);
164-
} else if (ActiveMapInstances[layerId] == null || !ActiveMapInstances[layerId].ShouldBeActive())
167+
mapInstance.RemoveLayerFromController();
168+
}
169+
else if (!mapInstance.ShouldBeActive())
165170
{
166-
ActiveMapInstances.Remove(layerId);
171+
mapInstance.ResetNpcSpawns();
167172
}
168173
}
174+
175+
ActiveMapInstances.Remove(instanceId);
169176
}
170177

178+
// Allow our instance controllers to keep their instances up to date
179+
InstanceProcessor.UpdateInstanceControllers(ActiveMapInstances.Values.ToArray());
180+
171181
if (Options.Instance.Metrics.Enable)
172182
{
173183
MetricsRoot.Instance.Game.ActiveEntities.Record(globalEntities);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Intersect.Server.Entities;
7+
8+
namespace Intersect.Server.Core.MapInstancing.Controllers;
9+
public class InstanceController
10+
{
11+
public Guid InstanceId { get; set; }
12+
13+
public HashSet<Player> Players { get; set; } = new();
14+
15+
public InstanceController(Guid instanceId, Player creator)
16+
{
17+
InstanceId = instanceId;
18+
AddPlayer(creator);
19+
}
20+
21+
public void AddPlayer(Player player)
22+
{
23+
if (player == null || !player.Online)
24+
{
25+
return;
26+
}
27+
Players.Add(player);
28+
}
29+
30+
public void RemovePlayer(Guid playerId)
31+
{
32+
Players.RemoveWhere(pl => pl.Id == playerId);
33+
}
34+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Intersect.Server.Core.MapInstancing.Controllers;
7+
using Intersect.Server.Entities;
8+
using Intersect.Server.Maps;
9+
10+
namespace Intersect.Server.Core.MapInstancing;
11+
public static class InstanceProcessor
12+
{
13+
private static Dictionary<Guid, InstanceController> InstanceControllers = new();
14+
15+
public static Guid[] CurrentControllers => InstanceControllers.Keys.ToArray();
16+
17+
public static bool TryGetInstanceController(Guid instanceId, out InstanceController controller)
18+
{
19+
return InstanceControllers.TryGetValue(instanceId, out controller);
20+
}
21+
22+
private static void CleanupOrphanedControllers(IEnumerable<Guid> activeInstanceIds)
23+
{
24+
var processingInstances = InstanceControllers.Keys
25+
.Except(activeInstanceIds)
26+
.Except(new Guid[1] { default }) // Never cleanup the overworld instance
27+
.ToArray();
28+
29+
foreach (var id in processingInstances)
30+
{
31+
InstanceControllers.Remove(id);
32+
Logging.Log.Debug($"Removing instance controller {id}");
33+
}
34+
}
35+
36+
public static bool TryAddInstanceController(Guid mapInstanceId, Player creator)
37+
{
38+
if (InstanceControllers.ContainsKey(mapInstanceId))
39+
{
40+
return false;
41+
}
42+
43+
InstanceControllers[mapInstanceId] = new InstanceController(mapInstanceId, creator);
44+
return true;
45+
}
46+
47+
public static void UpdateInstanceControllers(MapInstance[] activeMaps)
48+
{
49+
if (activeMaps == null || activeMaps.Length == 0)
50+
{
51+
return;
52+
}
53+
54+
// Cleanup inactive instances
55+
CleanupOrphanedControllers(activeMaps.Select(map => map.MapInstanceId));
56+
57+
Dictionary<Guid, MapInstance[]> mapsAndInstances = activeMaps
58+
.GroupBy(m => m.MapInstanceId)
59+
.ToDictionary(m => m.Key, m => m.ToArray());
60+
61+
// For each instance...
62+
foreach (var (instanceId, mapsInInstance) in mapsAndInstances)
63+
{
64+
// Fetch our instance controller...
65+
if (!InstanceControllers.TryGetValue(instanceId, out var instanceController))
66+
{
67+
continue;
68+
}
69+
70+
// TODO do update-y things in here, i.e processing permadead NPCs. Keeping empty for initial code review
71+
}
72+
}
73+
}

Intersect.Server.Core/Entities/Events/CommandProcessing.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Intersect.GameObjects.Events;
88
using Intersect.GameObjects.Events.Commands;
99
using Intersect.GameObjects.Switches_and_Variables;
10+
using Intersect.Server.Core.MapInstancing;
1011
using Intersect.Server.Database;
1112
using Intersect.Server.Database.PlayerData.Players;
1213
using Intersect.Server.Database.PlayerData.Security;
@@ -330,9 +331,9 @@ Stack<CommandInstance> callStack
330331
return;
331332
}
332333

333-
if (command.AllInInstance)
334+
if (command.AllInInstance && InstanceProcessor.TryGetInstanceController(player.MapInstanceId, out var instanceController))
334335
{
335-
foreach (var instanceMember in Globals.OnlineList.ToArray())
336+
foreach (var instanceMember in instanceController.Players.ToArray())
336337
{
337338
if (instanceMember.Id == player.Id || !instanceMember.Online)
338339
{

Intersect.Server.Core/Entities/Player.cs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Intersect.Logging;
1212
using Intersect.Network;
1313
using Intersect.Network.Packets.Server;
14+
using Intersect.Server.Core.MapInstancing;
1415
using Intersect.Server.Database;
1516
using Intersect.Server.Database.Logging.Entities;
1617
using Intersect.Server.Database.PlayerData;
@@ -389,6 +390,14 @@ public override void Dispose()
389390
base.Dispose();
390391
}
391392

393+
private void RemoveFromInstanceController(Guid mapInstanceId)
394+
{
395+
if (InstanceProcessor.TryGetInstanceController(mapInstanceId, out var instanceController))
396+
{
397+
instanceController.RemovePlayer(Id);
398+
}
399+
}
400+
392401
public void TryLogout(bool force = false, bool softLogout = false)
393402
{
394403
LastOnline = DateTime.Now;
@@ -418,6 +427,8 @@ private void Logout(bool softLogout = false)
418427
instance.RemoveEntity(this);
419428
}
420429

430+
RemoveFromInstanceController(MapInstanceId);
431+
421432
//Update parties
422433
LeaveParty();
423434

@@ -750,7 +761,7 @@ public override void Update(long timeMs)
750761
{
751762
if (!surrMap.TryGetInstance(MapInstanceId, out mapInstance))
752763
{
753-
surrMap.TryCreateInstance(MapInstanceId, out mapInstance);
764+
surrMap.TryCreateInstance(MapInstanceId, out mapInstance, this);
754765
}
755766
}
756767

@@ -1791,12 +1802,21 @@ public override void Warp(Guid newMapId,
17911802
if (!newMap.TryGetInstance(MapInstanceId, out newMapInstance))
17921803
{
17931804
// Create a new instance for the map we're on
1794-
newMap.TryCreateInstance(MapInstanceId, out newMapInstance);
1805+
newMap.TryCreateInstance(MapInstanceId, out newMapInstance, this);
1806+
// ...and its surroundings
17951807
foreach (var surrMap in newSurroundingMaps)
17961808
{
1797-
MapController.Get(surrMap).TryCreateInstance(MapInstanceId, out var surrMapInstance);
1809+
if (!MapController.TryGet(surrMap, out var map))
1810+
{
1811+
continue;
1812+
}
1813+
map.TryCreateInstance(MapInstanceId, out _, this);
17981814
}
17991815
}
1816+
else
1817+
{
1818+
_ = TryAddToInstanceController();
1819+
}
18001820
}
18011821

18021822
// An instance of the map MUST exist. Otherwise, head to spawn.
@@ -2108,6 +2128,7 @@ private void SendToNewMapInstance(MapController newMap)
21082128
{
21092129
PacketSender.SendMapInstanceChangedPacket(this, oldMap, PreviousMapInstanceId);
21102130
oldMapInstance.ClearEntityTargetsOf(this); // Remove targets of this entity
2131+
RemoveFromInstanceController(PreviousMapInstanceId);
21112132
}
21122133
// Clear events - we'll get them again from the map instance's event cache
21132134
EventTileLookup.Clear();
@@ -7172,6 +7193,17 @@ public bool TryChangeName(string newName)
71727193

71737194
}
71747195

7196+
public bool TryAddToInstanceController()
7197+
{
7198+
if (InstanceProcessor.TryGetInstanceController(MapInstanceId, out var instanceController))
7199+
{
7200+
instanceController.AddPlayer(this);
7201+
return true;
7202+
}
7203+
7204+
return false;
7205+
}
7206+
71757207
//TODO: Clean all of this stuff up
71767208

71777209
#region Temporary Values

Intersect.Server.Core/Maps/MapController.cs

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
44
using System.ComponentModel.DataAnnotations.Schema;
@@ -152,13 +152,12 @@ public static bool TryGet(Guid id, out MapController mapController)
152152
/// <param name="mapControllerId">The id of the <see cref="MapController"/></param>
153153
/// <param name="instanceId">The instance ID we want - crucially, NOT the unique ID of the <see cref="MapInstance"/>. Matches with some entity's InstanceId</param>
154154
/// <param name="mapInstance">Out value for the successfully found <see cref="MapInstance"/></param>
155-
/// <param name="createIfNew">(Default: false) Whether or not to create an instance of a controller if we can't find an instance with the requested ID</param>
156155
/// <returns>True if successful in retrieving a <see cref="MapInstance"/>, false otherwise</returns>
157-
public static bool TryGetInstanceFromMap(Guid mapControllerId, Guid instanceId, out MapInstance mapInstance, bool createIfNew = false)
156+
public static bool TryGetInstanceFromMap(Guid mapControllerId, Guid instanceId, out MapInstance mapInstance)
158157
{
159158
mapInstance = null;
160159
var controller = Get(mapControllerId);
161-
if (controller != null && controller.TryGetInstance(instanceId, out mapInstance, createIfNew))
160+
if (controller != null && controller.TryGetInstance(instanceId, out mapInstance))
162161
{
163162
return mapInstance != null;
164163
}
@@ -415,17 +414,18 @@ public void RespawnAllInstances()
415414
/// </summary>
416415
/// <param name="instanceId"></param>
417416
/// <returns>Whether or not we needed to create a new map instance</returns>
418-
public bool TryCreateInstance(Guid instanceId, out MapInstance newLayer)
417+
public bool TryCreateInstance(Guid instanceId, out MapInstance newLayer, Player creator)
419418
{
420419
newLayer = null;
421420
lock (GetMapLock())
422421
{
423422
if (!mInstances.ContainsKey(instanceId))
424423
{
425424
Log.Debug($"Creating new instance with ID {instanceId} for map {Name}");
426-
mInstances[instanceId] = new MapInstance(this, instanceId);
427-
mInstances[instanceId].Initialize();
428-
newLayer = mInstances[instanceId];
425+
newLayer = new MapInstance(this, instanceId, creator);
426+
newLayer.Initialize();
427+
mInstances[instanceId] = newLayer;
428+
429429
return true;
430430
}
431431

@@ -438,26 +438,10 @@ public bool TryCreateInstance(Guid instanceId, out MapInstance newLayer)
438438
/// </summary>
439439
/// <param name="mapInstanceId">The id of the instance - NOT the unique id of a <see cref="MapInstance"/></param>
440440
/// <param name="instance">Out value - the mapInstance we find. Null if not found</param>
441-
/// <param name="createIfNew">Whether or not to create an instance if we can't find one</param>
442441
/// <returns>True if successful in finding the requested instance, false otherwise</returns>
443-
public bool TryGetInstance(Guid mapInstanceId, out MapInstance instance, bool createIfNew = false)
442+
public bool TryGetInstance(Guid mapInstanceId, out MapInstance instance)
444443
{
445-
instance = null;
446-
if (mInstances.TryGetValue(mapInstanceId, out instance))
447-
{
448-
return true;
449-
}
450-
else
451-
{
452-
if (createIfNew)
453-
{
454-
if (TryCreateInstance(mapInstanceId, out instance))
455-
{
456-
return true;
457-
}
458-
}
459-
}
460-
return false;
444+
return mInstances.TryGetValue(mapInstanceId, out instance) ? instance != default : false;
461445
}
462446

463447
/// <summary>

Intersect.Server.Core/Maps/MapInstance.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using Intersect.Server.Entities;
1616
using Intersect.Server.Classes.Maps;
1717
using MapAttribute = Intersect.Enums.MapAttribute;
18+
using Intersect.Server.Core.MapInstancing;
1819

1920
namespace Intersect.Server.Maps
2021
{
@@ -144,11 +145,12 @@ public partial class MapInstance : IDisposable
144145
private MapActionMessages mActionMessages = new MapActionMessages();
145146
private MapAnimations mMapAnimations = new MapAnimations();
146147

147-
public MapInstance(MapController map, Guid mapInstanceId)
148+
public MapInstance(MapController map, Guid mapInstanceId, Player creator)
148149
{
149150
mMapController = map;
150151
MapInstanceId = mapInstanceId;
151152
Id = Guid.NewGuid();
153+
_ = InstanceProcessor.TryAddInstanceController(MapInstanceId, creator);
152154
}
153155

154156
public bool IsDisposed { get; protected set; }

0 commit comments

Comments
 (0)