2026-06-25 18:09:33 +01:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Linq;
|
2026-06-28 09:24:53 +01:00
|
|
|
using GameCult.Mesh;
|
2026-06-25 18:09:33 +01:00
|
|
|
using GameCult.Aetheria.State.Verse;
|
|
|
|
|
|
2026-06-28 09:24:53 +01:00
|
|
|
public sealed class AetheriaUnityObservedTargetQuery : IDisposable
|
2026-06-25 18:09:33 +01:00
|
|
|
{
|
|
|
|
|
private readonly Func<AetheriaClient> _resolveClient;
|
2026-06-28 03:34:08 +01:00
|
|
|
private readonly AetheriaUnityObservedEntityIndex _entityIndex;
|
2026-06-28 09:24:53 +01:00
|
|
|
private CultMeshReactiveDocument<AetheriaRuntimeZoneContactsDocument> _zoneContacts;
|
2026-06-25 18:09:33 +01:00
|
|
|
|
|
|
|
|
public AetheriaUnityObservedTargetQuery(
|
|
|
|
|
Func<AetheriaClient> resolveClient,
|
2026-06-28 03:34:08 +01:00
|
|
|
AetheriaUnityObservedEntityIndex entityIndex)
|
2026-06-25 18:09:33 +01:00
|
|
|
{
|
|
|
|
|
_resolveClient = resolveClient ?? (() => null);
|
2026-06-28 03:34:08 +01:00
|
|
|
_entityIndex = entityIndex ?? throw new ArgumentNullException(nameof(entityIndex));
|
2026-06-25 18:09:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Entity GetObservedTarget(Entity observer)
|
|
|
|
|
{
|
|
|
|
|
if (TryQueryEntityTarget(observer, out var targetEntityIndex) &&
|
2026-06-28 03:34:08 +01:00
|
|
|
_entityIndex.TryResolveEntityByDaemonIndex(targetEntityIndex, out var targetEntity))
|
2026-06-25 18:09:33 +01:00
|
|
|
{
|
|
|
|
|
return targetEntity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public float GetObservedInfoGathered(Entity observer, Entity target)
|
|
|
|
|
{
|
|
|
|
|
return TryQueryEntityContact(observer, target, out var contact)
|
|
|
|
|
? (float)contact.InfoGathered
|
|
|
|
|
: 0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsObservedHostileContact(Entity observer, Entity target)
|
|
|
|
|
{
|
|
|
|
|
return TryQueryEntityContact(observer, target, out var contact) && contact.Hostile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public AetheriaRuntimeZoneContactRow[] GetObservedVisibleContacts(
|
|
|
|
|
Entity observer,
|
|
|
|
|
double minimumInfoGathered,
|
|
|
|
|
bool visibleOnly)
|
|
|
|
|
{
|
|
|
|
|
var contacts = ReadZoneContacts();
|
|
|
|
|
if (observer == null || contacts == null)
|
|
|
|
|
return Array.Empty<AetheriaRuntimeZoneContactRow>();
|
|
|
|
|
|
|
|
|
|
return (contacts.Contacts ?? Array.Empty<AetheriaRuntimeZoneContactRow>())
|
|
|
|
|
.Where(contact =>
|
|
|
|
|
contact.ObserverEntityIndex == observer.DaemonEntityIndex &&
|
|
|
|
|
contact.InfoGathered > minimumInfoGathered &&
|
|
|
|
|
(!visibleOnly || contact.Visible))
|
|
|
|
|
.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool TryQueryEntityContact(
|
|
|
|
|
Entity observer,
|
|
|
|
|
Entity target,
|
|
|
|
|
out AetheriaRuntimeZoneContactRow contact)
|
|
|
|
|
{
|
|
|
|
|
contact = default;
|
|
|
|
|
if (observer == null || target == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
contact = (ReadZoneContacts()?.Contacts ?? Array.Empty<AetheriaRuntimeZoneContactRow>())
|
|
|
|
|
.FirstOrDefault(row =>
|
|
|
|
|
row.ObserverEntityIndex == observer.DaemonEntityIndex &&
|
|
|
|
|
row.TargetEntityIndex == target.DaemonEntityIndex);
|
|
|
|
|
return contact != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool TryQueryEntityTarget(
|
|
|
|
|
Entity observer,
|
|
|
|
|
out int targetEntityIndex)
|
|
|
|
|
{
|
|
|
|
|
targetEntityIndex = -1;
|
|
|
|
|
if (observer == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
targetEntityIndex = (ReadZoneContacts()?.Targets ?? Array.Empty<AetheriaRuntimeZoneTargetRow>())
|
|
|
|
|
.FirstOrDefault(row => row.EntityIndex == observer.DaemonEntityIndex)
|
|
|
|
|
?.TargetEntityIndex ?? -1;
|
|
|
|
|
return targetEntityIndex >= 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private AetheriaRuntimeZoneContactsDocument ReadZoneContacts()
|
|
|
|
|
{
|
2026-06-28 09:24:53 +01:00
|
|
|
if (_zoneContacts != null)
|
|
|
|
|
return _zoneContacts.Current;
|
|
|
|
|
|
2026-06-25 18:09:33 +01:00
|
|
|
try
|
|
|
|
|
{
|
2026-06-28 09:24:53 +01:00
|
|
|
_zoneContacts = _resolveClient()
|
2026-06-27 14:06:30 +01:00
|
|
|
?.Aetheria()
|
2026-06-28 09:24:53 +01:00
|
|
|
.ReactiveZoneContacts();
|
|
|
|
|
return _zoneContacts?.Current;
|
2026-06-25 18:09:33 +01:00
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-06-28 09:24:53 +01:00
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
_zoneContacts?.Dispose();
|
|
|
|
|
_zoneContacts = null;
|
|
|
|
|
}
|
2026-06-25 18:09:33 +01:00
|
|
|
}
|