Query daemon presentation entities by viewport
This commit is contained in:
parent
eb038607e2
commit
74b3b3d72a
3 changed files with 153 additions and 13 deletions
|
|
@ -1910,6 +1910,10 @@ static void RequireDaemonRenderQueryAuthority(string root)
|
|||
"public static int QueryCompassMarkers(",
|
||||
"public static int[] QueryVisibleEntityIndices(",
|
||||
"public static int QueryVisibleEntityIndices(",
|
||||
"public static int[] QueryPresentationEntityIndices(",
|
||||
"public static int QueryPresentationEntityIndices(",
|
||||
"TryParseEntityIndex(run?.CurrentEntityKey)",
|
||||
"ContainsPoint(viewport, entity.PositionX, entity.PositionZ)",
|
||||
"AetheriaRuntimeDaemonEntityContact",
|
||||
"public static bool TryQueryEntityContact(",
|
||||
"public static AetheriaRuntimeDaemonEntityContact[] QueryEntityContacts(",
|
||||
|
|
@ -2141,6 +2145,9 @@ static void RequireDaemonRenderQueryAuthority(string root)
|
|||
"private readonly List<AetheriaRuntimeDaemonAsteroidBeltPose> _daemonAsteroidBeltPoses",
|
||||
"private readonly List<AetheriaRuntimeDaemonCompassMarker> _daemonCompassMarkers",
|
||||
"private readonly Dictionary<int, AetheriaRuntimeDaemonCompassMarker> _daemonCompassMarkersByEntityIndex",
|
||||
"private IReadOnlyDictionary<int, Entity> _observedEntityFacadesByDaemonIndex",
|
||||
"private readonly List<int> _daemonPresentationEntityIndices",
|
||||
"private readonly HashSet<int> _daemonPresentationEntityIndicesSet",
|
||||
"private readonly List<int> _daemonVisibleEntityIndices",
|
||||
"private readonly HashSet<int> _daemonVisibleEntityIndicesSet",
|
||||
"private readonly HashSet<int> _visibleDaemonEntityIndices",
|
||||
|
|
@ -2155,6 +2162,7 @@ static void RequireDaemonRenderQueryAuthority(string root)
|
|||
"AetheriaRuntimeRunCheckpointCommit daemonRun)",
|
||||
"_daemonZoneSnapshot = daemonZone;",
|
||||
"_daemonRunSnapshot = daemonRun;",
|
||||
"_observedEntityFacadesByDaemonIndex = observedEntityFacadesByDaemonIndex;",
|
||||
"AetheriaRuntimeDaemonRenderQueries.EvaluateGravityTerrainHeight(",
|
||||
"AetheriaRuntimeDaemonRenderQueries.ResolveZoneRenderRadius(",
|
||||
" 2000);",
|
||||
|
|
@ -2174,8 +2182,11 @@ static void RequireDaemonRenderQueryAuthority(string root)
|
|||
"beltPosesByBodyKey.TryGetValue(bodyKey, out var beltPose)",
|
||||
"LoadAsteroidBelt(beltPose)",
|
||||
"void LoadAsteroidBelt(AetheriaRuntimeDaemonAsteroidBeltPose beltPose)",
|
||||
"foreach (var entitySnapshot in daemonZone?.Entities ?? Array.Empty<AetheriaRuntimeEntitySnapshotCommit>())",
|
||||
"observedEntityFacadesByDaemonIndex.TryGetValue(entitySnapshot.EntityIndex, out var entity)",
|
||||
"private void SyncDaemonEntityInstances()",
|
||||
"AetheriaRuntimeDaemonRenderQueries.QueryPresentationEntityIndices(",
|
||||
"_observedEntityFacadesByDaemonIndex.TryGetValue(entityIndex, out var entity)",
|
||||
"Loading entity {entity.Name} from daemon presentation query",
|
||||
"UnloadEntity(pair.Value.Entity)",
|
||||
"private readonly Dictionary<int, EntityInstance> _entityInstancesByDaemonIndex",
|
||||
"public IReadOnlyDictionary<int, EntityInstance> DaemonEntityInstances => _entityInstancesByDaemonIndex;",
|
||||
"public bool TryGetEntityInstance(int daemonEntityIndex, out EntityInstance instance)",
|
||||
|
|
@ -2229,6 +2240,13 @@ static void RequireDaemonRenderQueryAuthority(string root)
|
|||
"ZoneRenderer still accepts the whole Unity GameSettings object instead of explicit renderer asset/tuning inputs.");
|
||||
}
|
||||
|
||||
if (zoneRenderer.Contains("foreach (var entitySnapshot in daemonZone?.Entities", StringComparison.Ordinal) ||
|
||||
zoneRenderer.Contains("Loading entity {entity.Name} from daemon entity snapshot", StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"ZoneRenderer must query daemon presentation entities instead of loading every daemon entity snapshot into a mirrored Unity level.");
|
||||
}
|
||||
|
||||
var entityInstancePath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "EntityInstance.cs");
|
||||
var entityInstance = File.Exists(entityInstancePath)
|
||||
? File.ReadAllText(entityInstancePath)
|
||||
|
|
|
|||
|
|
@ -98,6 +98,9 @@ public class ZoneRenderer : MonoBehaviour
|
|||
new List<AetheriaRuntimeDaemonCompassMarker>();
|
||||
private readonly Dictionary<int, AetheriaRuntimeDaemonCompassMarker> _daemonCompassMarkersByEntityIndex =
|
||||
new Dictionary<int, AetheriaRuntimeDaemonCompassMarker>();
|
||||
private IReadOnlyDictionary<int, Entity> _observedEntityFacadesByDaemonIndex;
|
||||
private readonly List<int> _daemonPresentationEntityIndices = new List<int>();
|
||||
private readonly HashSet<int> _daemonPresentationEntityIndicesSet = new HashSet<int>();
|
||||
private readonly List<int> _daemonVisibleEntityIndices = new List<int>();
|
||||
private readonly HashSet<int> _daemonVisibleEntityIndicesSet = new HashSet<int>();
|
||||
private readonly HashSet<int> _visibleDaemonEntityIndices = new HashSet<int>();
|
||||
|
|
@ -221,21 +224,13 @@ public class ZoneRenderer : MonoBehaviour
|
|||
AetheriaRuntimeRunCheckpointCommit daemonRun = null)
|
||||
{
|
||||
ClearZone();
|
||||
_observedEntityFacadesByDaemonIndex = observedEntityFacadesByDaemonIndex;
|
||||
ApplyDaemonFrame(daemonZone, daemonRun);
|
||||
RefreshDaemonBodyPoses();
|
||||
RefreshDaemonAsteroidBeltPoses();
|
||||
SyncDaemonBodyViews();
|
||||
|
||||
foreach (var entitySnapshot in daemonZone?.Entities ?? Array.Empty<AetheriaRuntimeEntitySnapshotCommit>())
|
||||
{
|
||||
if (entitySnapshot != null &&
|
||||
observedEntityFacadesByDaemonIndex != null &&
|
||||
observedEntityFacadesByDaemonIndex.TryGetValue(entitySnapshot.EntityIndex, out var entity))
|
||||
{
|
||||
Debug.Log($"Loading entity {entity.Name} from daemon entity snapshot {entitySnapshot.EntityIndex}");
|
||||
LoadEntity(entity);
|
||||
}
|
||||
}
|
||||
RefreshDaemonVisibleEntityInstances();
|
||||
SyncDaemonEntityInstances();
|
||||
|
||||
foreach (var exit in _daemonWormholeExits)
|
||||
AddWormhole(exit);
|
||||
|
|
@ -529,6 +524,7 @@ public class ZoneRenderer : MonoBehaviour
|
|||
RefreshDaemonAsteroidBeltPoses();
|
||||
SyncDaemonBodyViews();
|
||||
RefreshDaemonVisibleEntityInstances();
|
||||
SyncDaemonEntityInstances();
|
||||
RefreshDaemonCompassMarkers();
|
||||
|
||||
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(MainCamera);
|
||||
|
|
@ -792,6 +788,39 @@ public class ZoneRenderer : MonoBehaviour
|
|||
_visibleDaemonEntityIndices.Add(entityIndex);
|
||||
}
|
||||
|
||||
private void SyncDaemonEntityInstances()
|
||||
{
|
||||
AetheriaRuntimeDaemonRenderQueries.QueryPresentationEntityIndices(
|
||||
_daemonRunSnapshot,
|
||||
_daemonZoneSnapshot,
|
||||
PerspectiveEntity?.DaemonEntityIndex ?? -1,
|
||||
RenderSettings.TargetDetectionInfoThreshold,
|
||||
ResolveDaemonRenderViewport(),
|
||||
_daemonPresentationEntityIndices);
|
||||
_daemonPresentationEntityIndicesSet.Clear();
|
||||
foreach (var entityIndex in _daemonPresentationEntityIndices)
|
||||
_daemonPresentationEntityIndicesSet.Add(entityIndex);
|
||||
|
||||
foreach (var entityIndex in _daemonPresentationEntityIndices)
|
||||
{
|
||||
if (_entityInstancesByDaemonIndex.ContainsKey(entityIndex) ||
|
||||
_observedEntityFacadesByDaemonIndex == null ||
|
||||
!_observedEntityFacadesByDaemonIndex.TryGetValue(entityIndex, out var entity))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Debug.Log($"Loading entity {entity.Name} from daemon presentation query {entityIndex}");
|
||||
LoadEntity(entity);
|
||||
}
|
||||
|
||||
foreach (var pair in _entityInstancesByDaemonIndex.ToArray())
|
||||
{
|
||||
if (!_daemonPresentationEntityIndicesSet.Contains(pair.Key))
|
||||
UnloadEntity(pair.Value.Entity);
|
||||
}
|
||||
}
|
||||
|
||||
private float GetTerrainHeight(float2 position)
|
||||
{
|
||||
return (float)AetheriaRuntimeDaemonRenderQueries.EvaluateGravityTerrainHeight(
|
||||
|
|
|
|||
|
|
@ -978,6 +978,71 @@ namespace GameCult.Aetheria.State.Verse
|
|||
return entityIndices.Count;
|
||||
}
|
||||
|
||||
public static int[] QueryPresentationEntityIndices(
|
||||
AetheriaRuntimeRunCheckpointCommit? run,
|
||||
AetheriaRuntimeZoneSnapshotCommit? zone,
|
||||
int observerEntityIndex,
|
||||
double minimumInfoGathered,
|
||||
AetheriaRuntimeXzRect viewport)
|
||||
{
|
||||
var entityIndices = new List<int>();
|
||||
QueryPresentationEntityIndices(run, zone, observerEntityIndex, minimumInfoGathered, viewport, entityIndices);
|
||||
return entityIndices.Count == 0 ? Array.Empty<int>() : entityIndices.ToArray();
|
||||
}
|
||||
|
||||
public static int QueryPresentationEntityIndices(
|
||||
AetheriaRuntimeRunCheckpointCommit? run,
|
||||
AetheriaRuntimeZoneSnapshotCommit? zone,
|
||||
int observerEntityIndex,
|
||||
double minimumInfoGathered,
|
||||
AetheriaRuntimeXzRect viewport,
|
||||
List<int> entityIndices)
|
||||
{
|
||||
if (entityIndices == null) throw new ArgumentNullException(nameof(entityIndices));
|
||||
entityIndices.Clear();
|
||||
if (zone == null)
|
||||
return 0;
|
||||
|
||||
var selected = new HashSet<int>();
|
||||
var currentEntityIndex = TryParseEntityIndex(run?.CurrentEntityKey);
|
||||
if (currentEntityIndex >= 0)
|
||||
selected.Add(currentEntityIndex);
|
||||
|
||||
var entities = BuildEntityMap(zone);
|
||||
if (observerEntityIndex >= 0)
|
||||
{
|
||||
if (entities.TryGetValue(observerEntityIndex, out var observer))
|
||||
{
|
||||
selected.Add(observer.EntityIndex);
|
||||
foreach (var contact in observer.Contacts ?? Array.Empty<AetheriaRuntimeEntityContactCommit>())
|
||||
{
|
||||
if (contact != null &&
|
||||
contact.Visible &&
|
||||
contact.InfoGathered > minimumInfoGathered &&
|
||||
entities.ContainsKey(contact.TargetEntityIndex))
|
||||
{
|
||||
selected.Add(contact.TargetEntityIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entity in zone.Entities ?? Array.Empty<AetheriaRuntimeEntitySnapshotCommit>())
|
||||
{
|
||||
if (entity != null &&
|
||||
entity.EntityIndex >= 0 &&
|
||||
ContainsPoint(viewport, entity.PositionX, entity.PositionZ))
|
||||
{
|
||||
selected.Add(entity.EntityIndex);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entityIndex in selected.OrderBy(index => index))
|
||||
entityIndices.Add(entityIndex);
|
||||
|
||||
return entityIndices.Count;
|
||||
}
|
||||
|
||||
public static bool TryQueryEntityContact(
|
||||
AetheriaRuntimeZoneSnapshotCommit? zone,
|
||||
int observerEntityIndex,
|
||||
|
|
@ -1345,6 +1410,34 @@ namespace GameCult.Aetheria.State.Verse
|
|||
return dx * dx + dz * dz <= radius * radius;
|
||||
}
|
||||
|
||||
private static bool ContainsPoint(AetheriaRuntimeXzRect rect, double x, double z)
|
||||
{
|
||||
return x >= rect.MinX &&
|
||||
x <= rect.MaxX &&
|
||||
z >= rect.MinZ &&
|
||||
z <= rect.MaxZ;
|
||||
}
|
||||
|
||||
private static int TryParseEntityIndex(string? key)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(key))
|
||||
return -1;
|
||||
|
||||
var marker = ".entity.";
|
||||
var markerIndex = key.LastIndexOf(marker, StringComparison.Ordinal);
|
||||
if (markerIndex < 0)
|
||||
return -1;
|
||||
|
||||
var start = markerIndex + marker.Length;
|
||||
var end = start;
|
||||
while (end < key.Length && char.IsDigit(key[end]))
|
||||
end++;
|
||||
|
||||
return int.TryParse(key.Substring(start, end - start), out var value)
|
||||
? value
|
||||
: -1;
|
||||
}
|
||||
|
||||
private static bool IntersectsBounds(
|
||||
AetheriaRuntimeDaemonRenderGroupDocument group,
|
||||
double minX,
|
||||
|
|
|
|||
Loading…
Reference in a new issue