Files
RobustToolbox/Robust.Shared/GameObjects/Systems/MetaDataSystem.cs
2023-08-10 14:17:57 +10:00

172 lines
5.5 KiB
C#

using System;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Robust.Shared.GameObjects;
public abstract class MetaDataSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
private EntityPausedEvent _pausedEvent;
private EntityQuery<MetaDataComponent> _metaQuery;
public override void Initialize()
{
_metaQuery = GetEntityQuery<MetaDataComponent>();
SubscribeLocalEvent<MetaDataComponent, ComponentHandleState>(OnMetaDataHandle);
SubscribeLocalEvent<MetaDataComponent, ComponentGetState>(OnMetaDataGetState);
}
private void OnMetaDataGetState(EntityUid uid, MetaDataComponent component, ref ComponentGetState args)
{
args.State = new MetaDataComponentState(component._entityName, component._entityDescription, component._entityPrototype?.ID, component.PauseTime);
}
private void OnMetaDataHandle(EntityUid uid, MetaDataComponent component, ref ComponentHandleState args)
{
if (args.Current is not MetaDataComponentState state)
return;
component._entityName = state.Name;
component._entityDescription = state.Description;
if(state.PrototypeId != null && state.PrototypeId != component._entityPrototype?.ID)
component._entityPrototype = _proto.Index<EntityPrototype>(state.PrototypeId);
component.PauseTime = state.PauseTime;
}
public void SetEntityName(EntityUid uid, string value, MetaDataComponent? metadata = null)
{
if (!_metaQuery.Resolve(uid, ref metadata) || value.Equals(metadata.EntityName))
return;
metadata._entityName = value;
Dirty(uid, metadata, metadata);
}
public void SetEntityDescription(EntityUid uid, string value, MetaDataComponent? metadata = null)
{
if (!_metaQuery.Resolve(uid, ref metadata) || value.Equals(metadata.EntityDescription))
return;
metadata._entityDescription = value;
Dirty(uid, metadata, metadata);
}
internal void SetEntityPrototype(EntityUid uid, EntityPrototype? value, MetaDataComponent? metadata = null)
{
if (!_metaQuery.Resolve(uid, ref metadata) || value?.Equals(metadata._entityPrototype) == true)
return;
// The ID string should never change after an entity has been created.
// Otherwise this breaks networking in multiplayer games.
DebugTools.Assert(value?.ID == metadata._entityPrototype?.ID);
metadata._entityPrototype = value;
}
public bool EntityPaused(EntityUid uid, MetaDataComponent? metadata = null)
{
if (!_metaQuery.Resolve(uid, ref metadata))
return true;
return metadata.EntityPaused;
}
public void SetEntityPaused(EntityUid uid, bool value, MetaDataComponent? metadata = null)
{
if (!_metaQuery.Resolve(uid, ref metadata)) return;
if (metadata.EntityPaused == value) return;
if (value)
{
DebugTools.Assert(metadata.PauseTime == null);
metadata.PauseTime = _timing.CurTime;
RaiseLocalEvent(uid, ref _pausedEvent);
}
else
{
DebugTools.Assert(metadata.PauseTime != null);
var ev = new EntityUnpausedEvent(_timing.CurTime - metadata.PauseTime!.Value);
metadata.PauseTime = null;
RaiseLocalEvent(uid, ref ev);
}
Dirty(uid, metadata, metadata);
}
/// <summary>
/// Gets how long this entity has been paused.
/// </summary>
public TimeSpan GetPauseTime(EntityUid uid, MetaDataComponent? metadata = null)
{
if (!_metaQuery.Resolve(uid, ref metadata))
return TimeSpan.Zero;
return (_timing.CurTime - metadata.PauseTime) ?? TimeSpan.Zero;
}
/// <summary>
/// Offsets the specified time by how long the entity has been paused.
/// </summary>
public void PauseOffset(EntityUid uid, ref TimeSpan time, MetaDataComponent? metadata = null)
{
var paused = GetPauseTime(uid, metadata);
time += paused;
}
public void AddFlag(EntityUid uid, MetaDataFlags flags, MetaDataComponent? component = null)
{
if (!_metaQuery.Resolve(uid, ref component)) return;
component.Flags |= flags;
}
/// <summary>
/// Attempts to remove the specific flag from metadata.
/// Other systems can choose not to allow the removal if it's still relevant.
/// </summary>
public void RemoveFlag(EntityUid uid, MetaDataFlags flags, MetaDataComponent? component = null)
{
if (!_metaQuery.Resolve(uid, ref component))
return;
var toRemove = component.Flags & flags;
if (toRemove == 0x0)
return;
var ev = new MetaFlagRemoveAttemptEvent(toRemove);
RaiseLocalEvent(uid, ref ev, true);
component.Flags &= ~ev.ToRemove;
}
public virtual void SetVisibilityMask(EntityUid uid, int value, MetaDataComponent? meta = null)
{
if (Resolve(uid, ref meta))
meta.VisibilityMask = value;
}
}
/// <summary>
/// Raised if <see cref="MetaDataSystem"/> is trying to remove a particular flag.
/// </summary>
[ByRefEvent]
public struct MetaFlagRemoveAttemptEvent
{
public MetaDataFlags ToRemove;
public MetaFlagRemoveAttemptEvent(MetaDataFlags toRemove)
{
ToRemove = toRemove;
}
}