Dirty PVS chunk when visibility mask changes (#3045)

* Dirty PVS chunk when visibility mask changes

* fix tests?

* aaaaaa

* maybe sorta finally fix tests

* directly return vis mask,

Also defaults to 1 only if visibility component does not exist.

* make sure everything has first bit set
This commit is contained in:
Leon Friedrich
2022-07-17 08:23:35 +12:00
committed by GitHub
parent a38cbc7188
commit 557de01532
9 changed files with 102 additions and 29 deletions

View File

@@ -0,0 +1,8 @@
using Robust.Shared.GameObjects;
namespace Robust.Client.GameObjects;
public sealed class ClientMetaDataSystem : MetaDataSystem
{
// Howdy.
}

View File

@@ -0,0 +1,19 @@
using Robust.Server.GameStates;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Robust.Server.GameObjects;
public sealed class ServerMetaDataSystem : MetaDataSystem
{
[Dependency] private readonly PVSSystem _pvsSystem = default!;
public override void SetVisibilityMask(EntityUid uid, int value, MetaDataComponent? meta = null)
{
if (!Resolve(uid, ref meta) || meta.VisibilityMask == value)
return;
base.SetVisibilityMask(uid, value, meta);
_pvsSystem.MarkDirty(uid);
}
}

View File

@@ -1,9 +1,12 @@
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Robust.Server.GameObjects
{
public sealed class VisibilitySystem : EntitySystem
{
[Dependency] private readonly MetaDataSystem _metaSys = default!;
public override void Initialize()
{
base.Initialize();
@@ -56,32 +59,24 @@ namespace Robust.Server.GameObjects
public void RefreshVisibility(EntityUid uid, MetaDataComponent? metaDataComponent = null, VisibilityComponent? visibilityComponent = null)
{
if (!Resolve(uid, ref metaDataComponent, false))
{
// This means it's deleting or some shit; I'd love to make it a GetComponent<T> in future.
return;
}
var visMask = 1;
metaDataComponent.VisibilityMask = GetVisibilityMask(uid, ref visMask, visibilityComponent);
if (Resolve(uid, ref metaDataComponent, false))
_metaSys.SetVisibilityMask(uid, GetVisibilityMask(uid, visibilityComponent), metaDataComponent);
}
public void RefreshVisibility(VisibilityComponent visibilityComponent)
{
RefreshVisibility(visibilityComponent.Owner);
RefreshVisibility(visibilityComponent.Owner, null, visibilityComponent);
}
private int GetVisibilityMask(EntityUid uid, ref int visMask, VisibilityComponent? visibilityComponent = null, TransformComponent? xform = null)
private int GetVisibilityMask(EntityUid uid, VisibilityComponent? visibilityComponent = null, TransformComponent? xform = null)
{
int visMask = 1; // apparently some content expects everything to have the first bit/flag set to true.
if (Resolve(uid, ref visibilityComponent, false))
{
visMask |= visibilityComponent.Layer;
}
// Include parent vis masks
if (Resolve(uid, ref xform) && xform.ParentUid.IsValid())
{
GetVisibilityMask(xform.ParentUid, ref visMask);
}
visMask |= GetVisibilityMask(xform.ParentUid);
return visMask;
}

View File

@@ -44,7 +44,8 @@ namespace Robust.Server.GameStates
private void OnEntityAdd(EntityUid e)
{
DebugTools.Assert(_currentIndex == _gameTiming.CurTick.Value % DirtyBufferSize);
DebugTools.Assert(_currentIndex == _gameTiming.CurTick.Value % DirtyBufferSize ||
_gameTiming.GetType().Name == "IGameTimingProxy");// Look I have NFI how best to excuse this assert if the game timing isn't real (a Mock<IGameTiming>).
_addEntities[_currentIndex].Add(e);
}

View File

@@ -128,16 +128,25 @@ internal sealed partial class PVSSystem : EntitySystem
private void OnParentChange(ref EntParentChangedMessage ev)
{
if (_mapManager.IsGrid(ev.Entity) || _mapManager.IsMap(ev.Entity)) return;
if (ev.Transform.GridUid == ev.Entity || _mapManager.IsMap(ev.Entity)) return;
// If parent changes then the RobustTree for that chunk will no longer be valid and we need to force it as dirty.
// Should still be at its old location as moveevent is called after.
var xform = Transform(ev.Entity);
var coordinates = _transform.GetMoverCoordinates(xform);
var coordinates = _transform.GetMoverCoordinates(ev.Transform);
var index = _entityPvsCollection.GetChunkIndex(coordinates);
_entityPvsCollection.MarkDirty(index);
}
/// <summary>
/// Marks an entity's current chunk as drity.
/// </summary>
internal void MarkDirty(EntityUid uid)
{
var xform = Transform(uid);
var coordinates = _transform.GetMoverCoordinates(xform);
_entityPvsCollection.MarkDirty(_entityPvsCollection.GetChunkIndex(coordinates));
}
public override void Shutdown()
{
base.Shutdown();

View File

@@ -1,4 +1,5 @@
using System;
using JetBrains.Annotations;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Players;
@@ -137,10 +138,19 @@ namespace Robust.Shared.GameObjects
/// <summary>
/// The sum of our visibility layer and our parent's visibility layers.
/// Server-only.
/// </summary>
[ViewVariables]
public int VisibilityMask { get; internal set; }
/// <remarks>
/// Every entity will always have the first bit set to true.
/// </remarks>
[Access(typeof(MetaDataSystem))]
public int VisibilityMask = 1;
[UsedImplicitly, ViewVariables(VVAccess.ReadWrite)]
private int VVVisibilityMask
{
get => VisibilityMask;
set => IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<MetaDataSystem>().SetVisibilityMask(Owner, value, this);
}
[ViewVariables]
public bool EntityPaused

View File

@@ -4,7 +4,7 @@ using Robust.Shared.Prototypes;
namespace Robust.Shared.GameObjects;
public sealed class MetaDataSystem : EntitySystem
public abstract class MetaDataSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
@@ -66,6 +66,12 @@ public sealed class MetaDataSystem : EntitySystem
component.Flags &= ~ev.ToRemove;
}
public virtual void SetVisibilityMask(EntityUid uid, int value, MetaDataComponent? meta = null)
{
if (Resolve(uid, ref meta))
meta.VisibilityMask = value;
}
}
/// <summary>

View File

@@ -1,10 +1,12 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using Robust.Client.GameObjects;
using Robust.Server.Containers;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Server.Physics;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
@@ -76,10 +78,22 @@ namespace Robust.UnitTesting
var systems = IoCManager.Resolve<IEntitySystemManager>();
// Required systems
systems.LoadExtraSystemType<ContainerSystem>();
systems.LoadExtraSystemType<TransformSystem>();
systems.LoadExtraSystemType<EntityLookupSystem>();
systems.LoadExtraSystemType<MetaDataSystem>();
// uhhh so maybe these are the wrong system for the client, but I CBF adding sprite system and all the rest,
// and it was like this when I found it.
systems.LoadExtraSystemType<Robust.Server.Containers.ContainerSystem>();
systems.LoadExtraSystemType<Robust.Server.GameObjects.TransformSystem>();
if (Project == UnitTestProject.Client)
{
systems.LoadExtraSystemType<ClientMetaDataSystem>();
}
else
{
systems.LoadExtraSystemType<ServerMetaDataSystem>();
systems.LoadExtraSystemType<PVSSystem>();
}
var entMan = IoCManager.Resolve<IEntityManager>();
var mapMan = IoCManager.Resolve<IMapManager>();

View File

@@ -6,7 +6,9 @@ using Moq;
using Robust.Server;
using Robust.Server.Containers;
using Robust.Server.GameObjects;
using Robust.Server.GameStates;
using Robust.Server.Physics;
using Robust.Server.Player;
using Robust.Server.Reflection;
using Robust.Shared;
using Robust.Shared.Asynchronous;
@@ -214,6 +216,14 @@ namespace Robust.UnitTesting.Server
container.Register<INetManager, NetManager>();
container.Register<IAuthManager, AuthManager>();
// I just wanted to load pvs system
container.Register<IServerEntityManager, ServerEntityManager>();
container.Register<INetConfigurationManager, NetConfigurationManager>();
container.Register<IServerNetManager, NetManager>();
// god help you if you actually need to test pvs functions
container.RegisterInstance<IPlayerManager>(new Mock<IPlayerManager>().Object);
container.RegisterInstance<IServerGameStateManager>(new Mock<IServerGameStateManager>().Object);
_diFactory?.Invoke(container);
container.BuildGraph();
@@ -265,7 +275,8 @@ namespace Robust.UnitTesting.Server
entitySystemMan.LoadExtraSystemType<GridFixtureSystem>();
entitySystemMan.LoadExtraSystemType<TransformSystem>();
entitySystemMan.LoadExtraSystemType<EntityLookupSystem>();
entitySystemMan.LoadExtraSystemType<MetaDataSystem>();
entitySystemMan.LoadExtraSystemType<ServerMetaDataSystem>();
entitySystemMan.LoadExtraSystemType<PVSSystem>();
_systemDelegate?.Invoke(entitySystemMan);