Files
RobustToolbox/Robust.Shared/GameObjects/Systems/SharedMapSystem.Map.cs
Leon Friedrich d5c4981648 Partial MapManager refactor (#5042)
* MapManager rejig

* Update Tests

* A
2024-04-18 14:05:02 +10:00

189 lines
6.6 KiB
C#

using System;
using System.Diagnostics.CodeAnalysis;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Utility;
namespace Robust.Shared.GameObjects;
public abstract partial class SharedMapSystem
{
protected int LastMapId;
private void InitializeMap()
{
SubscribeLocalEvent<MapComponent, ComponentAdd>(OnComponentAdd);
SubscribeLocalEvent<MapComponent, ComponentInit>(OnCompInit);
SubscribeLocalEvent<MapComponent, ComponentStartup>(OnCompStartup);
SubscribeLocalEvent<MapComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<MapComponent, ComponentShutdown>(OnMapRemoved);
SubscribeLocalEvent<MapComponent, ComponentHandleState>(OnMapHandleState);
SubscribeLocalEvent<MapComponent, ComponentGetState>(OnMapGetState);
}
public bool MapExists([NotNullWhen(true)] MapId? mapId)
{
return mapId != null && Maps.ContainsKey(mapId.Value);
}
public EntityUid GetMap(MapId mapId)
{
return Maps[mapId];
}
public bool TryGetMap([NotNullWhen(true)] MapId? mapId, [NotNullWhen(true)] out EntityUid? uid)
{
if (mapId == null || !Maps.TryGetValue(mapId.Value, out var map))
{
uid = null;
return false;
}
uid = map;
return true;
}
private void OnMapHandleState(EntityUid uid, MapComponent component, ref ComponentHandleState args)
{
if (args.Current is not MapComponentState state)
return;
if (component.MapId == MapId.Nullspace)
{
if (state.MapId == MapId.Nullspace)
throw new Exception($"Received invalid map state? {ToPrettyString(uid)}");
component.MapId = state.MapId;
Maps.Add(component.MapId, uid);
RecursiveMapIdUpdate(uid, uid, component.MapId);
}
DebugTools.AssertEqual(component.MapId, state.MapId);
component.LightingEnabled = state.LightingEnabled;
component.MapInitialized = state.Initialized;
if (LifeStage(uid) >= EntityLifeStage.Initialized)
SetPaused(uid, state.MapPaused);
else
component.MapPaused = state.MapPaused;
}
private void RecursiveMapIdUpdate(EntityUid uid, EntityUid mapUid, MapId mapId)
{
// This is required only in the event where an entity becomes a map AFTER children have already been attached to it.
// AFAIK, this currently only happens when the client applies entity states out of order (i.e., ignoring transform hierarchy),
// which itself only happens if PVS is disabled.
// TODO MAPS remove this
var xform = Transform(uid);
xform.MapUid = mapUid;
xform.MapID = mapId;
xform._mapIdInitialized = true;
foreach (var child in xform._children)
{
RecursiveMapIdUpdate(child, mapUid, mapId);
}
}
private void OnMapGetState(EntityUid uid, MapComponent component, ref ComponentGetState args)
{
args.State = new MapComponentState(component.MapId, component.LightingEnabled, component.MapPaused, component.MapInitialized);
}
protected abstract MapId GetNextMapId();
private void OnComponentAdd(EntityUid uid, MapComponent component, ComponentAdd args)
{
// ordered startups when
EnsureComp<PhysicsMapComponent>(uid);
EnsureComp<GridTreeComponent>(uid);
EnsureComp<MovedGridsComponent>(uid);
}
private void OnCompInit(EntityUid uid, MapComponent component, ComponentInit args)
{
if (component.MapId == MapId.Nullspace)
component.MapId = GetNextMapId();
DebugTools.AssertEqual(component.MapId.IsClientSide, IsClientSide(uid));
if (!Maps.TryAdd(component.MapId, uid))
{
if (Maps[component.MapId] != uid)
throw new Exception($"Attempted to initialize a map {ToPrettyString(uid)} with a duplicate map id {component.MapId}");
}
var msg = new MapChangedEvent(uid, component.MapId, true);
RaiseLocalEvent(uid, msg, true);
}
private void OnCompStartup(EntityUid uid, MapComponent component, ComponentStartup args)
{
if (component.MapPaused)
RecursiveSetPaused(uid, true);
}
private void OnMapRemoved(EntityUid uid, MapComponent component, ComponentShutdown args)
{
DebugTools.Assert(component.MapId != MapId.Nullspace);
Maps.Remove(component.MapId);
var msg = new MapChangedEvent(uid, component.MapId, false);
RaiseLocalEvent(uid, msg, true);
}
/// <summary>
/// Creates a new map, automatically assigning a map id.
/// </summary>
public EntityUid CreateMap(out MapId mapId, bool runMapInit = true)
{
mapId = GetNextMapId();
var uid = CreateMap(mapId, runMapInit);
return uid;
}
/// <inheritdoc cref="CreateMap(out Robust.Shared.Map.MapId,bool)"/>
public EntityUid CreateMap(bool runMapInit = true) => CreateMap(out _, runMapInit);
/// <summary>
/// Creates a new map with the specified map id.
/// </summary>
/// <exception cref="ArgumentException">Throws if an invalid or already existing map id is provided.</exception>
public EntityUid CreateMap(MapId mapId, bool runMapInit = true)
{
if (Maps.ContainsKey(mapId))
throw new ArgumentException($"Map with id {mapId} already exists");
if (mapId == MapId.Nullspace)
throw new ArgumentException($"Cannot create a null-space map");
if (_netManager.IsServer && mapId.IsClientSide)
throw new ArgumentException($"Attempted to create a client-side map on the server?");
if (_netManager.IsClient && _netManager.IsConnected && !mapId.IsClientSide)
throw new ArgumentException($"Attempted to create a client-side map entity with a non client-side map ID?");
var uid = EntityManager.CreateEntityUninitialized(null);
var map = _factory.GetComponent<MapComponent>();
map.MapId = mapId;
AddComp(uid, map);
// Give the entity a name, mainly for debugging. Content can always override this with a localized name.
var meta = MetaData(uid);
_meta.SetEntityName(uid, $"Map Entity", meta);
// Initialize components. this should add the map id to the collections.
EntityManager.InitializeComponents(uid, meta);
EntityManager.StartComponents(uid);
DebugTools.Assert(Maps[mapId] == uid);
if (runMapInit)
InitializeMap((uid, map));
else
SetPaused((uid, map), true);
return uid;
}
}