Prove cold lowering and destruction loot lifecycle

This commit is contained in:
Meta Vens 2026-07-16 03:34:47 +01:00
commit 8d628a6599
7 changed files with 290 additions and 123 deletions

View file

@ -210,6 +210,21 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
int pickupCollectionEventCount = 0;
int initialPickupEntityCount = 0;
int finalPickupEntityCount = -1;
bool destructionPickupObserved = false;
int maximumTrajectoryCount = 0;
bool hitMarkerObserved = false;
var witnessProfile = Environment.GetEnvironmentVariable("EVEUNITY_WITNESS_PROFILE") ??
"full-session-gameplay";
Assert.That(witnessProfile,
Is.EqualTo("cold-start-lowering").Or.EqualTo("full-session-gameplay"),
"The witness profile must name an explicit proof boundary.");
var requireSessionGameplay = string.Equals(
witnessProfile,
"full-session-gameplay",
StringComparison.Ordinal);
EveUnityAimPresentationRenderer aimRenderer = null;
EveUnityBeamPresentation beamPresentation = null;
EveUnityBeamPresentationRenderer beamRenderer = null;
try
{
@ -280,8 +295,9 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(host.PresentedEntities.CurrentGeneration.Entities.Count, Is.GreaterThan(0));
initialPickupEntityCount = host.PresentedEntities.CurrentGeneration.Entities.Count(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
Assert.That(initialPickupEntityCount, Is.GreaterThan(0),
"The daemon fixture did not publish its physical starter pickup through the entity SoA.");
if (requireSessionGameplay)
Assert.That(initialPickupEntityCount, Is.Zero,
"The witness scenario must obtain salvage from daemon-owned destruction, not a boot-seeded pickup.");
runtime.FeedbackAvailable += feedback =>
{
if (!string.Equals(feedback.Kind, "pickup.collected", StringComparison.Ordinal)) return;
@ -343,6 +359,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
AssertReconciledProviderReceipt(runtime.LastReceipt, release.CommandId,
provider.Selection.ProviderId, provider.Selection.SurfaceId, releaseVersion);
if (requireSessionGameplay)
{
var movementVersion = runtime.ActiveVersion;
var focus = runtime.SubmitFocusIntent(playerId);
var focusDeadline = Time.realtimeSinceStartup + 12f;
@ -399,10 +417,10 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
provider.Selection.ProviderId, provider.Selection.SurfaceId, lookVersion);
Assert.That(Vector3.Dot(FindMarker(root, playerId).transform.forward, aim), Is.GreaterThan(0.99f));
lookReceipt = WitnessReceipt.From("look", runtime.LastReceipt);
var aimRenderer = root.GetComponent<EveUnityAimPresentationRenderer>();
aimRenderer = root.GetComponent<EveUnityAimPresentationRenderer>();
Assert.That(aimRenderer, Is.Not.Null);
var beamPresentation = EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).SingleOrDefault();
beamPresentation = EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).SingleOrDefault();
Assert.That(beamPresentation, Is.Not.Null,
"The provider did not advertise its continuous beam presentation.");
Assert.That(beamPresentation.ActivationActionId, Is.Not.Empty,
@ -429,7 +447,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(provider.ResolvePrefab(new EveUnityPlayableWorldAssetBinding(
beamPresentation.AssetRole, beamPresentation.AssetRole, "provider-asset-ref")), Is.Not.Null,
$"The provider asset catalog did not resolve beam role '{beamPresentation.AssetRole}'.");
var beamRenderer = root.GetComponent<EveUnityBeamPresentationRenderer>();
beamRenderer = root.GetComponent<EveUnityBeamPresentationRenderer>();
Assert.That(beamRenderer, Is.Not.Null);
beamRenderer.RefreshNow();
Assert.That(beamRenderer.ActiveBeamCount, Is.EqualTo(1));
@ -439,28 +457,6 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
tractorBeamParticleSystemCount = beamRenderer.ActiveParticleSystemCount;
Assert.That(tractorBeamParticleSystemCount, Is.GreaterThan(0),
"The generic beam lowerer did not instantiate the provider-owned effect prefab.");
var pickupDeadline = Time.realtimeSinceStartup + 12f;
while (Time.realtimeSinceStartup < pickupDeadline &&
(pickupCollection == null ||
host.PresentedEntities.CurrentGeneration.Entities.Any(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal))))
{
yield return new WaitForSecondsRealtime(0.1f);
runtime.Refresh();
}
finalPickupEntityCount = host.PresentedEntities.CurrentGeneration.Entities.Count(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
Assert.That(pickupCollection, Is.Not.Null,
"The released client did not observe provider-owned feedback for Ymir contact collection.");
Assert.That(pickupCollectionEventCount, Is.EqualTo(1),
"One Ymir contact transaction must emit one client-visible collection event.");
Assert.That(pickupCollection.ItemKey, Is.EqualTo("scrap-metal"));
Assert.That(pickupCollection.ScalarValue, Is.EqualTo(1));
Assert.That(pickupCollection.CargoQuantityBefore, Is.Zero);
Assert.That(pickupCollection.CargoQuantityAfter, Is.EqualTo(1));
Assert.That(finalPickupEntityCount, Is.EqualTo(initialPickupEntityCount - 1),
"Collected pickup remained in the provider-authored entity generation.");
targetFact = host.PresentedEntities.CurrentGeneration.Entities
.Single(entity => entity.EntityId == targetEntityId);
playerFact = host.PresentedEntities.CurrentGeneration.Entities
@ -511,22 +507,74 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(runtime.ActiveVersion, Is.GreaterThanOrEqualTo(runtime.LastReceipt.SourceVersion));
actionReceipt = WitnessReceipt.From("action", runtime.LastReceipt);
var shotDeadline = Time.realtimeSinceStartup + 15f;
while (Time.realtimeSinceStartup < shotDeadline && observedShot == null)
{
yield return new WaitForSecondsRealtime(0.05f);
runtime.Refresh();
}
Assert.That(observedShot, Is.Not.Null,
"A reconciled fire request never reached daemon-owned lock acquisition and shot resolution.");
observedCombat = EveUnityCombatPresentation.Find(runtime.ActiveProjection);
Assert.That(observedShot.TargetEntityIndex, Is.EqualTo(targetEntityIndex));
Assert.That(observedShot.LockQuality, Is.GreaterThanOrEqualTo(0.99));
var trajectories = root.GetComponent<EveUnityShotTrajectoryRenderer>();
var combatRenderer = root.GetComponent<EveUnityCombatPresentationRenderer>();
Assert.That(trajectories, Is.Not.Null);
Assert.That(trajectories.ActiveTrajectoryCount, Is.GreaterThan(0));
Assert.That(combatRenderer, Is.Not.Null);
var shotDeadline = Time.realtimeSinceStartup + 20f;
while (Time.realtimeSinceStartup < shotDeadline &&
(observedShot == null ||
host.PresentedEntities.CurrentGeneration.Entities.Any(entity =>
entity.EntityId == targetEntityId) ||
(!destructionPickupObserved && pickupCollection == null)))
{
yield return new WaitForSecondsRealtime(0.05f);
runtime.Refresh();
destructionPickupObserved |= host.PresentedEntities.CurrentGeneration.Entities.Any(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
maximumTrajectoryCount = Math.Max(maximumTrajectoryCount, trajectories.ActiveTrajectoryCount);
combatRenderer.RefreshNow();
hitMarkerObserved |= combatRenderer.HitMarkerVisible;
}
Assert.That(observedShot, Is.Not.Null,
"A reconciled fire request never reached daemon-owned lock acquisition and shot resolution.");
Assert.That(host.PresentedEntities.CurrentGeneration.Entities.Any(entity =>
entity.EntityId == targetEntityId), Is.False,
"The low-hull witness raider was not destroyed by daemon combat.");
Assert.That(destructionPickupObserved || pickupCollection != null, Is.True,
"Daemon destruction did not publish its guaranteed cargo as a pickup.");
var collectionDeadline = Time.realtimeSinceStartup + 15f;
var nextTractorAimAt = 0f;
while (Time.realtimeSinceStartup < collectionDeadline && pickupCollection == null)
{
yield return new WaitForSecondsRealtime(0.05f);
runtime.Refresh();
maximumTrajectoryCount = Math.Max(maximumTrajectoryCount, trajectories.ActiveTrajectoryCount);
combatRenderer.RefreshNow();
hitMarkerObserved |= combatRenderer.HitMarkerVisible;
var pickupFact = host.PresentedEntities.CurrentGeneration.Entities.FirstOrDefault(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
if (pickupFact == null || Time.realtimeSinceStartup < nextTractorAimAt)
continue;
playerFact = host.PresentedEntities.CurrentGeneration.Entities
.Single(entity => entity.EntityId == playerId);
var tractorAim = pickupFact.Position - playerFact.Position;
tractorAim.y = 0;
if (tractorAim.sqrMagnitude <= 0.0001f)
continue;
tractorAim.Normalize();
runtime.SubmitLookDirectionIntent(playerId, tractorAim.x, 0f, tractorAim.z);
nextTractorAimAt = Time.realtimeSinceStartup + 0.25f;
}
finalPickupEntityCount = host.PresentedEntities.CurrentGeneration.Entities.Count(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
Assert.That(pickupCollection, Is.Not.Null,
"Destruction-created salvage never reached cargo through a Ymir contact fact.");
Assert.That(pickupCollectionEventCount, Is.EqualTo(1),
"One destruction-loot Ymir contact transaction must emit one collection event.");
Assert.That(pickupCollection.ItemKey, Is.Not.Empty,
"Destruction loot must retain its canonical typed item identity.");
Assert.That(pickupCollection.EventId, Does.StartWith("ymir-fact:"),
"Collection feedback must retain the consumed Ymir fact identity.");
Assert.That(pickupCollection.ScalarValue, Is.EqualTo(1));
Assert.That(pickupCollection.CargoQuantityBefore, Is.Zero);
Assert.That(pickupCollection.CargoQuantityAfter, Is.EqualTo(1));
Assert.That(finalPickupEntityCount, Is.Zero,
"Collected destruction loot remained in the provider-authored entity generation.");
observedCombat = EveUnityCombatPresentation.Find(runtime.ActiveProjection);
Assert.That(observedShot.TargetEntityIndex, Is.EqualTo(targetEntityIndex));
Assert.That(observedShot.LockQuality, Is.GreaterThanOrEqualTo(0.99));
Assert.That(maximumTrajectoryCount, Is.GreaterThan(0));
combatRenderer.RefreshNow();
if (observedCombat != null && !string.IsNullOrWhiteSpace(observedCombat.SelectedTargetEntityId))
{
@ -534,7 +582,16 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(combatRenderer.LockVisible, Is.True);
}
if (observedShot.Hit && (observedShot.AppliedDamage > 0 || observedShot.ShieldAbsorbedDamage > 0))
Assert.That(combatRenderer.HitMarkerVisible, Is.True);
Assert.That(hitMarkerObserved, Is.True);
}
aimRenderer ??= root.GetComponent<EveUnityAimPresentationRenderer>();
Assert.That(aimRenderer, Is.Not.Null);
beamPresentation ??= EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).SingleOrDefault();
Assert.That(beamPresentation, Is.Not.Null,
"The provider did not advertise its continuous beam presentation.");
beamRenderer ??= root.GetComponent<EveUnityBeamPresentationRenderer>();
finalPickupEntityCount = Math.Max(0, finalPickupEntityCount);
var camera = cameraObject.AddComponent<Camera>();
camera.clearFlags = CameraClearFlags.SolidColor;
@ -715,6 +772,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(fieldViewport, Is.Not.Null);
Assert.That(fieldSplats, Is.Not.Null);
WriteWitnessFacts(
witnessProfile,
initialVersion,
runtime.ActiveVersion,
movementDistance,
@ -739,7 +797,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
observedCombat?.ShieldRatio ?? shieldRatioBefore,
hullRatioBefore,
observedCombat?.HullRatio ?? hullRatioBefore,
(float)observedShot.LockQuality,
(float)(observedShot?.LockQuality ?? 0),
aimDotDistance,
playerViewportWidth,
playerViewportHeight,
@ -754,6 +812,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
initialPickupEntityCount,
finalPickupEntityCount,
pickupCollectionEventCount,
destructionPickupObserved,
pickupCollection,
camera.transform.position,
camera.transform.forward,
@ -783,6 +842,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
}
private static void WriteWitnessFacts(
string witnessProfile,
long initialVersion,
long finalVersion,
float movementDistance,
@ -822,6 +882,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
int initialPickupEntityCount,
int finalPickupEntityCount,
int pickupCollectionEventCount,
bool destructionPickupObserved,
EveUnityFeedbackEvent pickupCollection,
Vector3 cameraPosition,
Vector3 cameraForward,
@ -838,6 +899,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
if (string.IsNullOrWhiteSpace(path)) return;
var document = new WitnessFacts
{
witnessProfile = witnessProfile,
providerAdvertisement = true,
providerAssets = true,
environmentPresentation = environmentPresentation,
@ -879,9 +941,12 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
tractorBeamParticleSystemCount = tractorBeamParticleSystemCount,
pickupCollection = pickupCollection != null && pickupCollectionEventCount == 1 &&
pickupCollection.CargoQuantityAfter - pickupCollection.CargoQuantityBefore == pickupCollection.ScalarValue,
destructionLoot = destructionPickupObserved && pickupCollection != null &&
pickupCollection.EventId.StartsWith("ymir-fact:", StringComparison.Ordinal),
initialPickupEntityCount = initialPickupEntityCount,
finalPickupEntityCount = finalPickupEntityCount,
pickupCollectionEventCount = pickupCollectionEventCount,
pickupEventId = pickupCollection?.EventId ?? "",
pickupItemKey = pickupCollection?.ItemKey ?? "",
pickupQuantity = (float)(pickupCollection?.ScalarValue ?? 0),
cargoQuantityBeforePickup = (float)(pickupCollection?.CargoQuantityBefore ?? 0),
@ -909,6 +974,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
[Serializable]
private sealed class WitnessFacts
{
public string witnessProfile;
public bool providerAdvertisement;
public bool providerAssets;
public bool environmentPresentation;
@ -949,9 +1015,11 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
public float tractorReleasedPower;
public int tractorBeamParticleSystemCount;
public bool pickupCollection;
public bool destructionLoot;
public int initialPickupEntityCount;
public int finalPickupEntityCount;
public int pickupCollectionEventCount;
public string pickupEventId;
public string pickupItemKey;
public float pickupQuantity;
public float cargoQuantityBeforePickup;

View file

@ -6,10 +6,10 @@
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.render-pipelines.universal": "17.4.0",
"org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.13",
"org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.14",
"org.gamecult.eve.plugin-fields": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.3",
"org.gamecult.eve.surface": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.2",
"org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.49",
"org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.50",
"org.gamecult.eve.unity-uitoolkit": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-uitoolkit#eveunity-uitoolkit-v0.1.1"
},
"testables": [

View file

@ -119,11 +119,11 @@
}
},
"org.gamecult.cultlib": {
"version": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.13",
"version": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.14",
"depth": 0,
"source": "git",
"dependencies": {},
"hash": "feb5c71513e71d681699f462fe3682b3168c6f73"
"hash": "4b7162022a8976f7941b5a7a69acf50f1b6d532b"
},
"org.gamecult.eve.plugin-fields": {
"version": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.3",
@ -144,18 +144,18 @@
"hash": "140e1bd963a0033e66777a3b2c5fe6e9c97dfe32"
},
"org.gamecult.eve.unity-scene": {
"version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.49",
"version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.50",
"depth": 0,
"source": "git",
"dependencies": {
"org.gamecult.cultlib": "1.0.13",
"org.gamecult.cultlib": "1.0.14",
"org.gamecult.eve.plugin-fields": "0.2.3",
"org.gamecult.eve.surface": "0.2.2",
"com.unity.mathematics": "1.3.2",
"com.unity.render-pipelines.universal": "17.4.0",
"com.unity.modules.particlesystem": "1.0.0"
},
"hash": "e6ba1a36f6f0bce8df2c9834c25a8a980f03413c"
"hash": "7c8442e12264806a53a9e0e08b7b090dcddb8c90"
},
"org.gamecult.eve.unity-uitoolkit": {
"version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-uitoolkit#eveunity-uitoolkit-v0.1.1",

View file

@ -210,6 +210,21 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
int pickupCollectionEventCount = 0;
int initialPickupEntityCount = 0;
int finalPickupEntityCount = -1;
bool destructionPickupObserved = false;
int maximumTrajectoryCount = 0;
bool hitMarkerObserved = false;
var witnessProfile = Environment.GetEnvironmentVariable("EVEUNITY_WITNESS_PROFILE") ??
"full-session-gameplay";
Assert.That(witnessProfile,
Is.EqualTo("cold-start-lowering").Or.EqualTo("full-session-gameplay"),
"The witness profile must name an explicit proof boundary.");
var requireSessionGameplay = string.Equals(
witnessProfile,
"full-session-gameplay",
StringComparison.Ordinal);
EveUnityAimPresentationRenderer aimRenderer = null;
EveUnityBeamPresentation beamPresentation = null;
EveUnityBeamPresentationRenderer beamRenderer = null;
try
{
@ -280,8 +295,9 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(host.PresentedEntities.CurrentGeneration.Entities.Count, Is.GreaterThan(0));
initialPickupEntityCount = host.PresentedEntities.CurrentGeneration.Entities.Count(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
Assert.That(initialPickupEntityCount, Is.GreaterThan(0),
"The daemon fixture did not publish its physical starter pickup through the entity SoA.");
if (requireSessionGameplay)
Assert.That(initialPickupEntityCount, Is.Zero,
"The witness scenario must obtain salvage from daemon-owned destruction, not a boot-seeded pickup.");
runtime.FeedbackAvailable += feedback =>
{
if (!string.Equals(feedback.Kind, "pickup.collected", StringComparison.Ordinal)) return;
@ -343,6 +359,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
AssertReconciledProviderReceipt(runtime.LastReceipt, release.CommandId,
provider.Selection.ProviderId, provider.Selection.SurfaceId, releaseVersion);
if (requireSessionGameplay)
{
var movementVersion = runtime.ActiveVersion;
var focus = runtime.SubmitFocusIntent(playerId);
var focusDeadline = Time.realtimeSinceStartup + 12f;
@ -399,10 +417,10 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
provider.Selection.ProviderId, provider.Selection.SurfaceId, lookVersion);
Assert.That(Vector3.Dot(FindMarker(root, playerId).transform.forward, aim), Is.GreaterThan(0.99f));
lookReceipt = WitnessReceipt.From("look", runtime.LastReceipt);
var aimRenderer = root.GetComponent<EveUnityAimPresentationRenderer>();
aimRenderer = root.GetComponent<EveUnityAimPresentationRenderer>();
Assert.That(aimRenderer, Is.Not.Null);
var beamPresentation = EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).SingleOrDefault();
beamPresentation = EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).SingleOrDefault();
Assert.That(beamPresentation, Is.Not.Null,
"The provider did not advertise its continuous beam presentation.");
Assert.That(beamPresentation.ActivationActionId, Is.Not.Empty,
@ -429,7 +447,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(provider.ResolvePrefab(new EveUnityPlayableWorldAssetBinding(
beamPresentation.AssetRole, beamPresentation.AssetRole, "provider-asset-ref")), Is.Not.Null,
$"The provider asset catalog did not resolve beam role '{beamPresentation.AssetRole}'.");
var beamRenderer = root.GetComponent<EveUnityBeamPresentationRenderer>();
beamRenderer = root.GetComponent<EveUnityBeamPresentationRenderer>();
Assert.That(beamRenderer, Is.Not.Null);
beamRenderer.RefreshNow();
Assert.That(beamRenderer.ActiveBeamCount, Is.EqualTo(1));
@ -439,28 +457,6 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
tractorBeamParticleSystemCount = beamRenderer.ActiveParticleSystemCount;
Assert.That(tractorBeamParticleSystemCount, Is.GreaterThan(0),
"The generic beam lowerer did not instantiate the provider-owned effect prefab.");
var pickupDeadline = Time.realtimeSinceStartup + 12f;
while (Time.realtimeSinceStartup < pickupDeadline &&
(pickupCollection == null ||
host.PresentedEntities.CurrentGeneration.Entities.Any(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal))))
{
yield return new WaitForSecondsRealtime(0.1f);
runtime.Refresh();
}
finalPickupEntityCount = host.PresentedEntities.CurrentGeneration.Entities.Count(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
Assert.That(pickupCollection, Is.Not.Null,
"The released client did not observe provider-owned feedback for Ymir contact collection.");
Assert.That(pickupCollectionEventCount, Is.EqualTo(1),
"One Ymir contact transaction must emit one client-visible collection event.");
Assert.That(pickupCollection.ItemKey, Is.EqualTo("scrap-metal"));
Assert.That(pickupCollection.ScalarValue, Is.EqualTo(1));
Assert.That(pickupCollection.CargoQuantityBefore, Is.Zero);
Assert.That(pickupCollection.CargoQuantityAfter, Is.EqualTo(1));
Assert.That(finalPickupEntityCount, Is.EqualTo(initialPickupEntityCount - 1),
"Collected pickup remained in the provider-authored entity generation.");
targetFact = host.PresentedEntities.CurrentGeneration.Entities
.Single(entity => entity.EntityId == targetEntityId);
playerFact = host.PresentedEntities.CurrentGeneration.Entities
@ -511,22 +507,74 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(runtime.ActiveVersion, Is.GreaterThanOrEqualTo(runtime.LastReceipt.SourceVersion));
actionReceipt = WitnessReceipt.From("action", runtime.LastReceipt);
var shotDeadline = Time.realtimeSinceStartup + 15f;
while (Time.realtimeSinceStartup < shotDeadline && observedShot == null)
{
yield return new WaitForSecondsRealtime(0.05f);
runtime.Refresh();
}
Assert.That(observedShot, Is.Not.Null,
"A reconciled fire request never reached daemon-owned lock acquisition and shot resolution.");
observedCombat = EveUnityCombatPresentation.Find(runtime.ActiveProjection);
Assert.That(observedShot.TargetEntityIndex, Is.EqualTo(targetEntityIndex));
Assert.That(observedShot.LockQuality, Is.GreaterThanOrEqualTo(0.99));
var trajectories = root.GetComponent<EveUnityShotTrajectoryRenderer>();
var combatRenderer = root.GetComponent<EveUnityCombatPresentationRenderer>();
Assert.That(trajectories, Is.Not.Null);
Assert.That(trajectories.ActiveTrajectoryCount, Is.GreaterThan(0));
Assert.That(combatRenderer, Is.Not.Null);
var shotDeadline = Time.realtimeSinceStartup + 20f;
while (Time.realtimeSinceStartup < shotDeadline &&
(observedShot == null ||
host.PresentedEntities.CurrentGeneration.Entities.Any(entity =>
entity.EntityId == targetEntityId) ||
(!destructionPickupObserved && pickupCollection == null)))
{
yield return new WaitForSecondsRealtime(0.05f);
runtime.Refresh();
destructionPickupObserved |= host.PresentedEntities.CurrentGeneration.Entities.Any(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
maximumTrajectoryCount = Math.Max(maximumTrajectoryCount, trajectories.ActiveTrajectoryCount);
combatRenderer.RefreshNow();
hitMarkerObserved |= combatRenderer.HitMarkerVisible;
}
Assert.That(observedShot, Is.Not.Null,
"A reconciled fire request never reached daemon-owned lock acquisition and shot resolution.");
Assert.That(host.PresentedEntities.CurrentGeneration.Entities.Any(entity =>
entity.EntityId == targetEntityId), Is.False,
"The low-hull witness raider was not destroyed by daemon combat.");
Assert.That(destructionPickupObserved || pickupCollection != null, Is.True,
"Daemon destruction did not publish its guaranteed cargo as a pickup.");
var collectionDeadline = Time.realtimeSinceStartup + 15f;
var nextTractorAimAt = 0f;
while (Time.realtimeSinceStartup < collectionDeadline && pickupCollection == null)
{
yield return new WaitForSecondsRealtime(0.05f);
runtime.Refresh();
maximumTrajectoryCount = Math.Max(maximumTrajectoryCount, trajectories.ActiveTrajectoryCount);
combatRenderer.RefreshNow();
hitMarkerObserved |= combatRenderer.HitMarkerVisible;
var pickupFact = host.PresentedEntities.CurrentGeneration.Entities.FirstOrDefault(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
if (pickupFact == null || Time.realtimeSinceStartup < nextTractorAimAt)
continue;
playerFact = host.PresentedEntities.CurrentGeneration.Entities
.Single(entity => entity.EntityId == playerId);
var tractorAim = pickupFact.Position - playerFact.Position;
tractorAim.y = 0;
if (tractorAim.sqrMagnitude <= 0.0001f)
continue;
tractorAim.Normalize();
runtime.SubmitLookDirectionIntent(playerId, tractorAim.x, 0f, tractorAim.z);
nextTractorAimAt = Time.realtimeSinceStartup + 0.25f;
}
finalPickupEntityCount = host.PresentedEntities.CurrentGeneration.Entities.Count(entity =>
string.Equals(entity.EntityKind, "pickup", StringComparison.Ordinal));
Assert.That(pickupCollection, Is.Not.Null,
"Destruction-created salvage never reached cargo through a Ymir contact fact.");
Assert.That(pickupCollectionEventCount, Is.EqualTo(1),
"One destruction-loot Ymir contact transaction must emit one collection event.");
Assert.That(pickupCollection.ItemKey, Is.Not.Empty,
"Destruction loot must retain its canonical typed item identity.");
Assert.That(pickupCollection.EventId, Does.StartWith("ymir-fact:"),
"Collection feedback must retain the consumed Ymir fact identity.");
Assert.That(pickupCollection.ScalarValue, Is.EqualTo(1));
Assert.That(pickupCollection.CargoQuantityBefore, Is.Zero);
Assert.That(pickupCollection.CargoQuantityAfter, Is.EqualTo(1));
Assert.That(finalPickupEntityCount, Is.Zero,
"Collected destruction loot remained in the provider-authored entity generation.");
observedCombat = EveUnityCombatPresentation.Find(runtime.ActiveProjection);
Assert.That(observedShot.TargetEntityIndex, Is.EqualTo(targetEntityIndex));
Assert.That(observedShot.LockQuality, Is.GreaterThanOrEqualTo(0.99));
Assert.That(maximumTrajectoryCount, Is.GreaterThan(0));
combatRenderer.RefreshNow();
if (observedCombat != null && !string.IsNullOrWhiteSpace(observedCombat.SelectedTargetEntityId))
{
@ -534,7 +582,16 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(combatRenderer.LockVisible, Is.True);
}
if (observedShot.Hit && (observedShot.AppliedDamage > 0 || observedShot.ShieldAbsorbedDamage > 0))
Assert.That(combatRenderer.HitMarkerVisible, Is.True);
Assert.That(hitMarkerObserved, Is.True);
}
aimRenderer ??= root.GetComponent<EveUnityAimPresentationRenderer>();
Assert.That(aimRenderer, Is.Not.Null);
beamPresentation ??= EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).SingleOrDefault();
Assert.That(beamPresentation, Is.Not.Null,
"The provider did not advertise its continuous beam presentation.");
beamRenderer ??= root.GetComponent<EveUnityBeamPresentationRenderer>();
finalPickupEntityCount = Math.Max(0, finalPickupEntityCount);
var camera = cameraObject.AddComponent<Camera>();
camera.clearFlags = CameraClearFlags.SolidColor;
@ -715,6 +772,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(fieldViewport, Is.Not.Null);
Assert.That(fieldSplats, Is.Not.Null);
WriteWitnessFacts(
witnessProfile,
initialVersion,
runtime.ActiveVersion,
movementDistance,
@ -739,7 +797,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
observedCombat?.ShieldRatio ?? shieldRatioBefore,
hullRatioBefore,
observedCombat?.HullRatio ?? hullRatioBefore,
(float)observedShot.LockQuality,
(float)(observedShot?.LockQuality ?? 0),
aimDotDistance,
playerViewportWidth,
playerViewportHeight,
@ -754,6 +812,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
initialPickupEntityCount,
finalPickupEntityCount,
pickupCollectionEventCount,
destructionPickupObserved,
pickupCollection,
camera.transform.position,
camera.transform.forward,
@ -783,6 +842,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
}
private static void WriteWitnessFacts(
string witnessProfile,
long initialVersion,
long finalVersion,
float movementDistance,
@ -822,6 +882,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
int initialPickupEntityCount,
int finalPickupEntityCount,
int pickupCollectionEventCount,
bool destructionPickupObserved,
EveUnityFeedbackEvent pickupCollection,
Vector3 cameraPosition,
Vector3 cameraForward,
@ -838,6 +899,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
if (string.IsNullOrWhiteSpace(path)) return;
var document = new WitnessFacts
{
witnessProfile = witnessProfile,
providerAdvertisement = true,
providerAssets = true,
environmentPresentation = environmentPresentation,
@ -879,9 +941,12 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
tractorBeamParticleSystemCount = tractorBeamParticleSystemCount,
pickupCollection = pickupCollection != null && pickupCollectionEventCount == 1 &&
pickupCollection.CargoQuantityAfter - pickupCollection.CargoQuantityBefore == pickupCollection.ScalarValue,
destructionLoot = destructionPickupObserved && pickupCollection != null &&
pickupCollection.EventId.StartsWith("ymir-fact:", StringComparison.Ordinal),
initialPickupEntityCount = initialPickupEntityCount,
finalPickupEntityCount = finalPickupEntityCount,
pickupCollectionEventCount = pickupCollectionEventCount,
pickupEventId = pickupCollection?.EventId ?? "",
pickupItemKey = pickupCollection?.ItemKey ?? "",
pickupQuantity = (float)(pickupCollection?.ScalarValue ?? 0),
cargoQuantityBeforePickup = (float)(pickupCollection?.CargoQuantityBefore ?? 0),
@ -909,6 +974,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
[Serializable]
private sealed class WitnessFacts
{
public string witnessProfile;
public bool providerAdvertisement;
public bool providerAssets;
public bool environmentPresentation;
@ -949,9 +1015,11 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
public float tractorReleasedPower;
public int tractorBeamParticleSystemCount;
public bool pickupCollection;
public bool destructionLoot;
public int initialPickupEntityCount;
public int finalPickupEntityCount;
public int pickupCollectionEventCount;
public string pickupEventId;
public string pickupItemKey;
public float pickupQuantity;
public float cargoQuantityBeforePickup;

View file

@ -2,22 +2,24 @@
## Current result
The warm-cache released-package witness passes with:
The released-package witness passes in separate cold-lowering and warm-gameplay
profiles with:
- `org.gamecult.eve.unity-scene` `0.3.44`, commit
`03ce78031f28d7bfae4dcdc477a7273c6ecae55b`;
- `org.gamecult.eve.unity-scene` `0.3.50`, commit
`7c8442e12264806a53a9e0e08b7b090dcddb8c90`;
- `org.gamecult.eve.plugin-fields` `0.2.3`, commit
`c5a4a75c1b727499b16c2dae1895f29e2a9f72f0`;
- `org.gamecult.eve.surface` `0.2.2`, commit
`140e1bd963a0033e66777a3b2c5fe6e9c97dfe32`;
- `org.gamecult.eve.unity-uitoolkit` `0.1.1`, commit
`4d0cbe0185bdc4fc65eb63503a7c5cb578539669`;
- `org.gamecult.cultlib` `1.0.13`, commit
`feb5c71513e71d681699f462fe3682b3168c6f73`;
- `org.gamecult.cultlib` `1.0.14`, commit
`4b7162022a8976f7941b5a7a69acf50f1b6d532b`;
- the generic `ReleaseConsumerProject` client connected directly to the
Aetheria daemon.
Evidence is in `artifacts/aetheria-daemon-fossil-fog-producers`. The PlayMode test
Evidence is in `artifacts/aetheria-daemon-cultlib-1014-cold-final` and
`artifacts/aetheria-daemon-cultlib-1014-warm-final`. The warm PlayMode test
passed and recorded provider-owned reconciled movement, look, targeting,
tractor press, tractor release, contact-gated cargo collection, and action
receipts. The daemon-owned look direction reached the SoA body rotation,
@ -50,7 +52,7 @@ Fields splat layers. Its surface contract contains logical ports such as
names or pass indices. The selected `unity-scene` provider asset variant owns
that concrete shader ABI through `unity.volume.*` metadata. The released
generic lowerer resolved the provider shader and dither texture, rasterized all
four layers, and composited `21` pilot-camera frames from daemon frame `223`.
four layers, and composited `91` pilot-camera frames through daemon frame `643`.
The provider variant advertises the fossil shader's raymarch, temporal-history,
and composite passes plus their logical ports. EveUnity allocates and resets the
history targets generically; a partial temporal ABI fails closed.
@ -64,19 +66,20 @@ daemon lock progress `1.0`; Unity does not manufacture or smooth that value.
Camera-channel facts:
- provider-authored player renderers: `13`, including the lowered tractor effect;
- pilot changed pixels: `191,353`;
- pilot average luminance: `0.0283105`;
- pilot bright pixels: `705`;
- map-channel renderers: `11`;
- map changed pixels: `4,444`;
- pilot changed pixels: `196,179`;
- pilot average luminance: `0.0993295`;
- pilot bright pixels: `1,348`;
- map-channel renderers: `10`;
- map changed pixels: `4,627`;
- native cockpit progress bars: `7`;
- daemon tractor power at capture: `1.0` after the held input completed its
authored ramp;
- daemon tractor power after the advertised release: `0`;
- provider tractor particle systems: `1`;
- pickup entities before/after collection: `1` / `0`;
- pickup entities before/after destruction and collection: `0` / `0`;
- provider `pickup.collected` events: exactly `1`;
- collected item and quantity: `scrap-metal`, `1`;
- collected item and quantity: one canonical `aetheria.item_definition:*` key,
quantity `1`;
- authoritative cargo quantity before/after: `0` / `1`;
- the pilot camera excludes the advertised map layer;
- the player prefab's embedded layer-14 map icon contributes exactly `0` pilot
@ -87,7 +90,7 @@ Visual inspection confirms that map glyphs are absent from the pilot frame and
present in the map-only frame. This is transport, authority, field-production,
and lowering proof, not visual parity: the current pilot capture is nearly black
with sparse clipped geometry instead of the fossil's bright blue gravity-shaped
fog sea. Release `0.3.44` adds generic lowering for Eve Fields `0.2.3`'s
fog sea. Release `0.3.50` includes generic lowering for Eve Fields `0.2.3`'s
`AnimatedRadialCosine` source alongside `PowerPulse`, dither-scale,
temporal-history, and finite-look-at semantics. Aetheria publishes the fossil
global animated simplex/cellular/ambient producer stack, body-owned radial wave
@ -119,10 +122,12 @@ build removes the fossil's embedded tractor object from player/ship prefabs, so
the standalone `beam.presentation` prefab is the only tractor renderer. Its
cyan/yellow dotted band is visible in the pilot capture and absent from the map
capture.
The same released run begins with one provider-owned pickup in the entity SoA.
Held tractor input produces a Ymir Begin contact fact; the daemon consumes that
fact once, removes the pickup once, changes cargo from `0` to `1`, and emits one
`pickup.collected` feedback event carrying the exact delta. Aetheria's Ymir body
The warm gameplay run begins with no pickup. A daemon-authoritative shot destroys
the deterministic salvage target and creates one provider-owned pickup carrying
a canonical generated cargo item. Held tractor input produces a Ymir Begin
contact fact; the daemon consumes that fact once, removes the pickup once,
changes cargo from `0` to `1`, and emits one `pickup.collected` feedback event
whose identity begins with `ymir-fact:`. Aetheria's Ymir body
mapping excludes stations and non-ship world bodies from pickup collision facts,
so ambient station contact cannot become a cargo writer. Capacity rejection and
its `cargo-capacity` reason are covered by the daemon smoke, not claimed as a
@ -138,19 +143,23 @@ Primary artifacts:
- `aetheria-daemon-world.png`: pilot-camera capture;
- `aetheria-daemon-map.png`: map-only capture.
## Cold delivery is not currently proven
## Cold delivery proof
The current `46,412,252` byte Unity bundle (SHA-256
`bc45d84b54666e813bfccca12496ba4a3533ed08896dfc57de726749574fa796`)
times out from an empty cache. Its bytes are
still transported through batched snapshot records rather than the intended
mapped/network body transport. Increasing the Unity timeout would hide the
transport fault and is not an accepted fix.
The `cold-start-lowering` profile starts with zero bodies and zero partials. It
receives the `46,412,384` byte Unity bundle through the managed
`cultmesh.content.v1` session, verifies SHA-256
`f5960f240ecfd56de417e8e51fde34cfb962fc6fcf0840cc373190e7dbc6048f`,
atomically promotes one `.body`, and leaves zero partials under the unchanged
300-second deadline. The full witness took `84.991` seconds; the Unity test took
`43.212` seconds. It then lowered provider assets, movement, environment, four
field layers across `127` composites, and both camera channels. The pilot camera
excluded map objects and the map camera included them.
A cold witness may be claimed only when an empty cache receives the bundle over
the intended body transport, atomically promotes the hash-addressed `.body`,
leaves no `.partial` file, and completes the same released-client assertions.
`artifacts/render-channel-witness-gravity-cold-4` records a historical 0.3.18
cold run. It remains useful regression evidence, but it does not describe the
health of the current transport path.
Cold asset acquisition and transient gameplay are deliberately separate proof
profiles. Starting Unity before the provider means download time is not a
stable lifetime for a boot-seeded enemy or pickup. The cold profile proves
delivery and lowering; `full-session-gameplay` starts a fresh warm authoritative
session and proves combat, destruction-created loot, Ymir contact collection,
and exactly-once receipts. Neither profile claims negotiated mapped/zero-copy
CDN delivery: the released path is the managed network content session and
still copies/fragments bytes in process.

View file

@ -13,10 +13,10 @@ param(
)
$ErrorActionPreference = "Stop"
$expectedEveUnityCommit = "e6ba1a36f6f0bce8df2c9834c25a8a980f03413c"
$expectedEveUnityCommit = "7c8442e12264806a53a9e0e08b7b090dcddb8c90"
$expectedEveFieldsCommit = "c5a4a75c1b727499b16c2dae1895f29e2a9f72f0"
$expectedEveUnityUiToolkitCommit = "4d0cbe0185bdc4fc65eb63503a7c5cb578539669"
$expectedCultLibCommit = "feb5c71513e71d681699f462fe3682b3168c6f73"
$expectedCultLibCommit = "4b7162022a8976f7941b5a7a69acf50f1b6d532b"
$repoRoot = Split-Path -Parent $PSScriptRoot
$projectRoot = $ClientProject
$outputRoot = if ([IO.Path]::IsPathRooted($OutputDirectory)) { $OutputDirectory } else { Join-Path $repoRoot $OutputDirectory }
@ -65,6 +65,11 @@ if ($CacheState -eq "warm" -and -not $cacheWasWarm) {
throw "Warm witness requested without an existing verified bundle cache at $assetCachePath"
}
$observedCacheState = if ($cacheWasWarm) { "warm" } else { "cold" }
$witnessProfile = if ($observedCacheState -eq "cold") {
"cold-start-lowering"
} else {
"full-session-gameplay"
}
$witnessStartedAt = [DateTimeOffset]::UtcNow
foreach ($ephemeralPath in @(
$replicaPath,
@ -161,7 +166,7 @@ $daemonArguments = @(
"--client-cultmesh-host", "127.0.0.1",
"--client-cultmesh-advertise-host", "127.0.0.1",
"--client-cultmesh-port", $Port,
"--tick-interval-ms", 250,
"--tick-interval-ms", 20,
"--fixed-delta-ms", 20,
"--no-odin-announcements"
)
@ -177,6 +182,7 @@ $env:EVEUNITY_DISABLE_AUTO_LAUNCHER = "1"
$env:EVEUNITY_ASSET_CACHE_PATH = $assetCachePath
$env:EVEUNITY_WITNESS_FACTS_PATH = $factsPath
$env:EVEUNITY_PROVIDER_READY_PATH = $providerReadyPath
$env:EVEUNITY_WITNESS_PROFILE = $witnessProfile
$arguments = @(
"-batchmode", "-projectPath", $projectRoot,
"-runTests", "-testPlatform", "PlayMode",
@ -231,9 +237,20 @@ try {
}
}
$facts = Get-Content -LiteralPath $factsPath -Raw | ConvertFrom-Json
if (-not $facts.combatPresentation -or [string]::IsNullOrWhiteSpace($facts.shotId) -or
[double]$facts.lockProgress -le 0.99) {
throw "Live witness did not observe daemon-owned selection, completed lock, and a resolved shot."
if ($facts.witnessProfile -ne $witnessProfile) {
throw "Live witness ran the wrong proof profile. expected=$witnessProfile actual=$($facts.witnessProfile)"
}
if (-not $facts.providerAssets -or -not $facts.environmentPresentation -or
-not $facts.movement -or -not $facts.pilotCameraExcludesMapChannel -or
-not $facts.mapCameraIncludesMapChannel -or [int]$facts.fieldVolumeLayerCount -le 0 -or
[long]$facts.fieldVolumeCompositeCount -le 0) {
throw "Live witness did not prove provider assets, movement, Fields lowering, and camera-channel separation."
}
if ($witnessProfile -eq "full-session-gameplay" -and
(-not $facts.combatPresentation -or [string]::IsNullOrWhiteSpace($facts.shotId) -or
[double]$facts.lockProgress -le 0.99 -or -not $facts.pickupCollection -or
-not $facts.destructionLoot -or [int]$facts.pickupCollectionEventCount -ne 1)) {
throw "Full-session witness did not prove combat and exactly-once destruction-loot Ymir contact collection."
}
$releaseLock = Get-Content -LiteralPath (Join-Path $repoRoot "ReleaseConsumerProject\Packages\packages-lock.json") -Raw | ConvertFrom-Json
$releasedPackageClient = $projectRoot -eq "ReleaseConsumerProject"
@ -297,6 +314,7 @@ try {
generatedAtUtc = [DateTimeOffset]::UtcNow.ToString("O")
execution = [ordered]@{
cacheState = $observedCacheState
profile = $witnessProfile
durationMs = $durationMs
testDurationMs = $testDurationMs
}
@ -335,7 +353,11 @@ try {
sizeBytes = $resultsArtifact.Length
}
)
authority = "released-generic-runtime-observes-provider-assets-authoritative-combat-receipts-and-camera-channel-separation"
authority = if ($witnessProfile -eq "full-session-gameplay") {
"released-generic-runtime-observes-provider-assets-authoritative-gameplay-receipts-ymir-contact-collection-and-camera-channel-separation"
} else {
"released-generic-runtime-cold-loads-provider-assets-lowers-playable-world-and-preserves-camera-channel-separation"
}
}
$witness | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath $witnessPath -Encoding UTF8
$stateWitnessPath = Join-Path $outputRoot "runtime-witness.$observedCacheState.json"
@ -349,6 +371,6 @@ try {
finally {
if ($null -ne $unity -and -not $unity.HasExited) { Stop-Process -Id $unity.Id -Force -ErrorAction SilentlyContinue }
if ($null -ne $daemon -and -not $daemon.HasExited) { Stop-Process -Id $daemon.Id -Force }
Remove-Item Env:EVEUNITY_RENDEZVOUS_ENDPOINT, Env:EVEUNITY_PROVIDER_ENDPOINT, Env:EVEUNITY_PROVIDER_ID, Env:EVEUNITY_SURFACE_ID, Env:EVEUNITY_REPLICA_PATH, Env:EVEUNITY_AETHERIA_CAPTURE_PATH, Env:EVEUNITY_AETHERIA_MAP_CAPTURE_PATH, Env:EVEUNITY_DISABLE_AUTO_LAUNCHER, Env:EVEUNITY_ASSET_CACHE_PATH, Env:EVEUNITY_WITNESS_FACTS_PATH, Env:EVEUNITY_PROVIDER_READY_PATH -ErrorAction SilentlyContinue
Remove-Item Env:EVEUNITY_RENDEZVOUS_ENDPOINT, Env:EVEUNITY_PROVIDER_ENDPOINT, Env:EVEUNITY_PROVIDER_ID, Env:EVEUNITY_SURFACE_ID, Env:EVEUNITY_REPLICA_PATH, Env:EVEUNITY_AETHERIA_CAPTURE_PATH, Env:EVEUNITY_AETHERIA_MAP_CAPTURE_PATH, Env:EVEUNITY_DISABLE_AUTO_LAUNCHER, Env:EVEUNITY_ASSET_CACHE_PATH, Env:EVEUNITY_WITNESS_FACTS_PATH, Env:EVEUNITY_PROVIDER_READY_PATH, Env:EVEUNITY_WITNESS_PROFILE -ErrorAction SilentlyContinue
Remove-Item Env:AETHERIA_TRACE_EVE_SNAPSHOTS -ErrorAction SilentlyContinue
}

View file

@ -85,7 +85,7 @@ $daemon = Start-Process dotnet -ArgumentList @(
"--client-cultmesh-host", "127.0.0.1",
"--client-cultmesh-advertise-host", "127.0.0.1",
"--client-cultmesh-port", $Port,
"--tick-interval-ms", 250,
"--tick-interval-ms", 20,
"--fixed-delta-ms", 20,
"--no-odin-announcements"
) -PassThru -WindowStyle Hidden -RedirectStandardOutput $daemonLog -RedirectStandardError "$daemonLog.error"