Restore daemon-backed Unity launch
This commit is contained in:
parent
7c46cd1060
commit
023a35944c
28 changed files with 130 additions and 93 deletions
|
|
@ -1,6 +1,7 @@
|
|||
using Aetheria.State;
|
||||
using Aetheria.State.Documents;
|
||||
using Aetheria.State.Migration;
|
||||
using System.Buffers.Binary;
|
||||
using GameCult.Caching;
|
||||
using GameCult.Aetheria.State.Verse;
|
||||
using GameCult.Mesh;
|
||||
|
|
@ -1277,7 +1278,6 @@ static async Task ProveDirectSoaPublicationPipeline()
|
|||
}
|
||||
};
|
||||
|
||||
using var liveBodies = new CultMeshNetworkBodyStore();
|
||||
using var publisher = new AetheriaRuntimeDaemonSoaFramePublisher(producerEpoch: 9);
|
||||
var built = publisher.BuildCurrentZoneEntities(frame);
|
||||
var payloadIdentity = built.View.Identities.SingleOrDefault(identity =>
|
||||
|
|
@ -1301,7 +1301,7 @@ static async Task ProveDirectSoaPublicationPipeline()
|
|||
if (cache.Get<EveEntitySoaViewDocument>(AetheriaRuntimeVerseRecordKeys.EveEntitySoaViewLatest) != null)
|
||||
throw new InvalidOperationException("SoA view became visible before its body publication.");
|
||||
|
||||
var published = await publisher.PublishAsync(built);
|
||||
var published = await publisher.PublishAsync(built, includeRealtimePayload: true);
|
||||
if (cache.Get<EveEntitySoaViewDocument>(AetheriaRuntimeVerseRecordKeys.EveEntitySoaViewLatest) != null)
|
||||
throw new InvalidOperationException("Building a CultMesh body publication made the Eve view visible before commit.");
|
||||
if (cache.GetAll<CultMeshCdnArtifactManifest>().Any() || cache.GetAll<CultMeshCdnArtifactChunk>().Any())
|
||||
|
|
@ -1353,11 +1353,10 @@ static async Task ProveDirectSoaPublicationPipeline()
|
|||
?? throw new InvalidOperationException("Typed Eve SoA view did not become visible after body publication.");
|
||||
var localRepresentation = body.Representations.SingleOrDefault(candidate =>
|
||||
candidate.TransportKind == CultMeshBodyTransportKind.SharedMemory);
|
||||
var networkRepresentation = body.Representations.SingleOrDefault(candidate =>
|
||||
candidate.TransportKind == CultMeshBodyTransportKind.Network);
|
||||
if (localRepresentation == null || networkRepresentation == null ||
|
||||
if (localRepresentation == null || published.RealtimePayload.IsEmpty ||
|
||||
body.Representations.Any(candidate => candidate.TransportKind == CultMeshBodyTransportKind.Network) ||
|
||||
body.Representations.Any(candidate => candidate.TransportKind == CultMeshBodyTransportKind.SharedFileMapping))
|
||||
throw new InvalidOperationException("Direct SoA publication did not expose shared memory plus direct network representations.");
|
||||
throw new InvalidOperationException("Direct SoA publication did not expose shared memory plus an explicit realtime payload.");
|
||||
|
||||
var request = new CultMeshBodyValidationRequest
|
||||
{
|
||||
|
|
@ -1373,34 +1372,25 @@ static async Task ProveDirectSoaPublicationPipeline()
|
|||
using var localLease = new CultMeshBodyPublicationResolver(new CultMeshBodyTransportService(
|
||||
new ICultMeshBodyTransportAdapter[]
|
||||
{
|
||||
new CultMeshSharedMemoryBodyAdapter(),
|
||||
new CultMeshNetworkBodyAdapter(descriptor => ReadLiveBody(liveBodies, descriptor))
|
||||
},
|
||||
(producerId, _) => producerId == AetheriaRuntimeDaemonSoaFramePublisher.ProducerId))
|
||||
.ResolveReadOnly(body, request);
|
||||
using var networkLease = new CultMeshBodyPublicationResolver(new CultMeshBodyTransportService(
|
||||
new ICultMeshBodyTransportAdapter[]
|
||||
{
|
||||
new CultMeshNetworkBodyAdapter(descriptor => ReadLiveBody(liveBodies, descriptor))
|
||||
new CultMeshSharedMemoryBodyAdapter()
|
||||
},
|
||||
(producerId, _) => producerId == AetheriaRuntimeDaemonSoaFramePublisher.ProducerId))
|
||||
.ResolveReadOnly(body, request);
|
||||
|
||||
var localEntityIndex = ReadInt32(view, localLease, "entity.index", 0);
|
||||
var networkEntityIndex = ReadInt32(view, networkLease, "entity.index", 0);
|
||||
var networkEntityIndex = ReadInt32Bytes(view, published.RealtimePayload.Span, "entity.index", 0);
|
||||
var localPosition = ReadFloat3(view, localLease, "transform.position", 0);
|
||||
var networkPosition = ReadFloat3(view, networkLease, "transform.position", 0);
|
||||
var networkPosition = ReadFloat3Bytes(view, published.RealtimePayload.Span, "transform.position", 0);
|
||||
var localPayloadEntityIndex = ReadInt32(view, localLease, "entity.index", 2);
|
||||
var networkPayloadEntityIndex = ReadInt32(view, networkLease, "entity.index", 2);
|
||||
var networkPayloadEntityIndex = ReadInt32Bytes(view, published.RealtimePayload.Span, "entity.index", 2);
|
||||
var localPayloadPosition = ReadFloat3(view, localLease, "transform.position", 2);
|
||||
var networkPayloadPosition = ReadFloat3(view, networkLease, "transform.position", 2);
|
||||
var networkPayloadPosition = ReadFloat3Bytes(view, published.RealtimePayload.Span, "transform.position", 2);
|
||||
var localSunPosition = ReadFloat3(view, localLease, "transform.position", 3);
|
||||
var networkSunPosition = ReadFloat3(view, networkLease, "transform.position", 3);
|
||||
var networkSunPosition = ReadFloat3Bytes(view, published.RealtimePayload.Span, "transform.position", 3);
|
||||
var localAsteroidPosition = ReadFloat3(view, localLease, "transform.position", 4);
|
||||
var networkAsteroidPosition = ReadFloat3(view, networkLease, "transform.position", 4);
|
||||
var networkAsteroidPosition = ReadFloat3Bytes(view, published.RealtimePayload.Span, "transform.position", 4);
|
||||
var identity = view.Identities.Single(candidate => candidate.Index == localEntityIndex);
|
||||
if (localLease.TransportKind != CultMeshBodyTransportKind.SharedMemory ||
|
||||
networkLease.TransportKind != CultMeshBodyTransportKind.Network ||
|
||||
localEntityIndex != 12 || networkEntityIndex != localEntityIndex ||
|
||||
localPosition != (1.25f, -2.5f, 7.75f) || networkPosition != localPosition ||
|
||||
localPayloadEntityIndex != payloadIdentity.EntityIndex ||
|
||||
|
|
@ -1410,7 +1400,7 @@ static async Task ProveDirectSoaPublicationPipeline()
|
|||
localAsteroidPosition.X != 45f || localAsteroidPosition.Z != 50f ||
|
||||
networkAsteroidPosition != localAsteroidPosition ||
|
||||
identity.EntityId != "ship:soa-witness" || identity.Label != "SoA Witness")
|
||||
throw new InvalidOperationException("Local and network SoA views were not logically equivalent.");
|
||||
throw new InvalidOperationException("Shared-memory and realtime SoA payloads were not logically equivalent.");
|
||||
|
||||
frame.Run.Zones[0].PhysicalPayloads[0].Active = false;
|
||||
var withoutPayload = publisher.BuildCurrentZoneEntities(frame);
|
||||
|
|
@ -1419,25 +1409,6 @@ static async Task ProveDirectSoaPublicationPipeline()
|
|||
throw new InvalidOperationException("Inactive physical payload remained in SoA or disturbed a surviving synthetic identity.");
|
||||
}
|
||||
|
||||
static byte[] ReadLiveBody(CultMeshNetworkBodyStore bodies, CultMeshBodyDescriptor descriptor)
|
||||
{
|
||||
var request = new CultMeshBodyReadRequestMessage
|
||||
{
|
||||
MessageId = Guid.NewGuid().ToString("N"),
|
||||
CapabilityToken = descriptor.CapabilityToken,
|
||||
BodyId = descriptor.BodyId,
|
||||
BodySchemaId = descriptor.SchemaId,
|
||||
LayoutVersion = descriptor.LayoutVersion,
|
||||
ProducerEpoch = descriptor.ProducerEpoch,
|
||||
Sequence = descriptor.Sequence,
|
||||
ExpectedSizeBytes = descriptor.ByteSize,
|
||||
SemanticHash = descriptor.SemanticHash
|
||||
};
|
||||
if (!bodies.TryRead(request, DateTimeOffset.UtcNow, out _, out var body))
|
||||
throw new InvalidOperationException("Ephemeral SoA network generation could not be resolved.");
|
||||
return body;
|
||||
}
|
||||
|
||||
static IEnumerable<AetheriaRuntimeSurfaceComponent> Flatten(AetheriaRuntimeSurfaceComponent component)
|
||||
{
|
||||
yield return component;
|
||||
|
|
@ -1453,6 +1424,14 @@ static int ReadInt32(EveEntitySoaViewDocument view, ICultMeshBodyReadLease lease
|
|||
return lease.ReadInt32(buffer.ByteOffset + column.ByteOffset + (long)row * column.ElementStride);
|
||||
}
|
||||
|
||||
static int ReadInt32Bytes(EveEntitySoaViewDocument view, ReadOnlySpan<byte> body, string semantic, int row)
|
||||
{
|
||||
var column = view.Columns.Single(candidate => candidate.Semantic == semantic);
|
||||
var buffer = view.Buffers.Single(candidate => candidate.BufferId == column.BufferId);
|
||||
var offset = checked((int)(buffer.ByteOffset + column.ByteOffset + (long)row * column.ElementStride));
|
||||
return BinaryPrimitives.ReadInt32LittleEndian(body.Slice(offset, sizeof(int)));
|
||||
}
|
||||
|
||||
static (float X, float Y, float Z) ReadFloat3(
|
||||
EveEntitySoaViewDocument view,
|
||||
ICultMeshBodyReadLease lease,
|
||||
|
|
@ -1464,3 +1443,18 @@ static (float X, float Y, float Z) ReadFloat3(
|
|||
var offset = buffer.ByteOffset + column.ByteOffset + (long)row * column.ElementStride;
|
||||
return (lease.ReadSingle(offset), lease.ReadSingle(offset + 4), lease.ReadSingle(offset + 8));
|
||||
}
|
||||
|
||||
static (float X, float Y, float Z) ReadFloat3Bytes(
|
||||
EveEntitySoaViewDocument view,
|
||||
ReadOnlySpan<byte> body,
|
||||
string semantic,
|
||||
int row)
|
||||
{
|
||||
var column = view.Columns.Single(candidate => candidate.Semantic == semantic);
|
||||
var buffer = view.Buffers.Single(candidate => candidate.BufferId == column.BufferId);
|
||||
var offset = checked((int)(buffer.ByteOffset + column.ByteOffset + (long)row * column.ElementStride));
|
||||
return (
|
||||
BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(offset, sizeof(float)))),
|
||||
BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(offset + 4, sizeof(float)))),
|
||||
BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(body.Slice(offset + 8, sizeof(float)))));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"com.gamecult.brokkr": "file:E:/Projects/Brokkr/surfaces/unity/Packages/com.gamecult.brokkr",
|
||||
"com.unity.ide.rider": "3.0.39",
|
||||
"com.unity.test-framework": "1.6.0",
|
||||
"com.unity.modules.assetbundle": "1.0.0",
|
||||
|
|
|
|||
|
|
@ -1,13 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"com.gamecult.brokkr": {
|
||||
"version": "file:E:/Projects/Brokkr/surfaces/unity/Packages/com.gamecult.brokkr",
|
||||
"depth": 0,
|
||||
"source": "local",
|
||||
"dependencies": {
|
||||
"org.gamecult.cultlib": "1.0.16"
|
||||
}
|
||||
},
|
||||
"com.unity.burst": {
|
||||
"version": "1.8.29",
|
||||
"depth": 2,
|
||||
|
|
|
|||
|
|
@ -36,8 +36,11 @@ namespace Aetheria.Editor
|
|||
foreach (var stale in Directory.GetFiles(output, "*", SearchOption.TopDirectoryOnly))
|
||||
File.Delete(stale);
|
||||
|
||||
var catalog = AetheriaRuntimeCatalogStore.OpenReadOnly(
|
||||
Path.GetFullPath(Path.Combine("GameData", "aetheria-world.cc")));
|
||||
var configuredCatalog = Environment.GetEnvironmentVariable("AETHERIA_ASSET_CATALOG_STATE");
|
||||
var catalogPath = string.IsNullOrWhiteSpace(configuredCatalog)
|
||||
? Path.GetFullPath(Path.Combine("GameData", "aetheria-world.cc"))
|
||||
: Path.GetFullPath(configuredCatalog);
|
||||
var catalog = AetheriaRuntimeCatalogStore.OpenReadOnly(catalogPath);
|
||||
var assets = AetheriaRuntimeAssets.ProjectManifest(catalog).Assets;
|
||||
foreach (var entry in assets.Where(entry =>
|
||||
string.Equals(entry.Ref.Kind, AetheriaRuntimeAssetKinds.Prefab, StringComparison.Ordinal)))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"com.gamecult.brokkr": "file:../../Brokkr/surfaces/unity/Packages/com.gamecult.brokkr/",
|
||||
"com.unity.2d.sprite": "1.0.0",
|
||||
"com.unity.2d.tilemap": "1.0.0",
|
||||
"com.unity.ai.navigation": "2.0.12",
|
||||
|
|
@ -20,7 +19,7 @@
|
|||
"com.unity.xr.legacyinputhelpers": "3.0.1",
|
||||
"org.gamecult.aetheria.eve-runtime": "file:org.gamecult.aetheria.eve-runtime",
|
||||
"org.gamecult.aetheria.state": "file:org.gamecult.aetheria.state",
|
||||
"org.gamecult.cultmath": "https://github.com/GameCult/CultMath.git?path=/unity/org.gamecult.cultmath#cultmath-unity-v0.1.1",
|
||||
"org.gamecult.cultmath": "https://github.com/GameCult/CultMath.git?path=/unity/org.gamecult.cultmath#cultmath-unity-v0.1.2",
|
||||
"org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.43",
|
||||
"org.gamecult.eve.surface": "file:../../EveUnity/packages/org.gamecult.eve.surface",
|
||||
"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",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5f127e58b7fe83d41aae3d2c07e92b93
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c014edb10e374064983c53c270e56b25
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 65b37579114393648b8c881ae488399b
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aeffd152980489d42a76727ed45cadcb
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 479d0ef759b333b4dae8052bad70eca7
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7a04293019e69804188e0fd89165928e
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 56b9ad6cb6412fb43a3bca09816f3c1e
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d6d7dacec60ca5541b27d4edc3e71b67
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 59cfb14aacc657e42840ff07db266e6d
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: efde765b290564a448c25d1d21635889
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e4f402f9be2534446ae0532a197acd5c
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5437add74c5d2fb45b81299b41aa999d
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aa7945f476afeed42887ab43de504d89
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7250563f73fb3f0489c35f3bac88a8ce
|
||||
|
|
@ -256,6 +256,9 @@ namespace GameCult.Aetheria.State.Verse
|
|||
var fullPath = Path.GetFullPath(statePath);
|
||||
var effectiveRuntimeId = string.IsNullOrWhiteSpace(runtimeId) ? DefaultRuntimeId : runtimeId;
|
||||
var registry = AetheriaRuntimeVerseContractRegistry.CreateCultCacheRegistry();
|
||||
var runtimeSchemaIds = new HashSet<string>(
|
||||
registry.AllDescriptors.Select(descriptor => descriptor.SchemaId),
|
||||
StringComparer.Ordinal);
|
||||
var node = await CultMesh.CreateNodeAsync(
|
||||
fullPath,
|
||||
new CultMeshNodeOptions
|
||||
|
|
@ -267,7 +270,12 @@ namespace GameCult.Aetheria.State.Verse
|
|||
Registry = registry,
|
||||
PullOnOpen = pullOnOpen,
|
||||
StoreFlushOnDispose = true,
|
||||
UseDirectoryStore = true
|
||||
UseDirectoryStore = true,
|
||||
// A thin runtime shares the daemon's physical CultCache, but it does not
|
||||
// own or understand catalog, migration, Hangar, or other daemon schemas.
|
||||
// Hydrate only the contract it can deserialize; untouched records remain
|
||||
// owned by the backing store and are not projected into this client cache.
|
||||
DirectoryStoreHydrationFilter = metadata => runtimeSchemaIds.Contains(metadata.SchemaId)
|
||||
},
|
||||
DatabaseOptions = new CultNetDatabaseOptions
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 13dee70f7b1b8ef4eabd7f3d572b02f1
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"ConcurrentCollections.dll",
|
||||
"CultMath.dll",
|
||||
"GameCult.Caching.MessagePack.dll",
|
||||
"GameCult.Caching.dll",
|
||||
"GameCult.Logging.dll",
|
||||
|
|
@ -28,6 +29,7 @@
|
|||
"Microsoft.NET.StringTools.dll",
|
||||
"MessagePack.Annotations.dll",
|
||||
"MessagePack.CultMesh.dll",
|
||||
"MessagePack.dll",
|
||||
"R3.dll",
|
||||
"System.Collections.Immutable.dll",
|
||||
"System.ComponentModel.Annotations.dll",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
"unity": "2021.3",
|
||||
"description": "Unity runtime boundary for Aetheria typed CultCache/CultMesh state.",
|
||||
"dependencies": {
|
||||
"com.gamecult.brokkr": "0.1.0",
|
||||
"org.gamecult.eve.surface": "0.1.0"
|
||||
},
|
||||
"keywords": [
|
||||
|
|
|
|||
|
|
@ -1,13 +1,5 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"com.gamecult.brokkr": {
|
||||
"version": "file:../../Brokkr/surfaces/unity/Packages/com.gamecult.brokkr/",
|
||||
"depth": 0,
|
||||
"source": "local",
|
||||
"dependencies": {
|
||||
"org.gamecult.cultlib": "1.0.16"
|
||||
}
|
||||
},
|
||||
"com.unity.2d.sprite": {
|
||||
"version": "1.0.0",
|
||||
"depth": 0,
|
||||
|
|
@ -308,7 +300,6 @@
|
|||
"depth": 0,
|
||||
"source": "embedded",
|
||||
"dependencies": {
|
||||
"com.gamecult.brokkr": "0.1.0",
|
||||
"org.gamecult.eve.surface": "0.1.0"
|
||||
}
|
||||
},
|
||||
|
|
@ -320,11 +311,11 @@
|
|||
"hash": "f67f5122ed1bd11da016e7b820ed60145ccd0299"
|
||||
},
|
||||
"org.gamecult.cultmath": {
|
||||
"version": "https://github.com/GameCult/CultMath.git?path=/unity/org.gamecult.cultmath#cultmath-unity-v0.1.1",
|
||||
"version": "https://github.com/GameCult/CultMath.git?path=/unity/org.gamecult.cultmath#cultmath-unity-v0.1.2",
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {},
|
||||
"hash": "c4543b9443e96d848260ef00254d2d3c0fa6a9d2"
|
||||
"hash": "fcdddda72f6aa33ae6eeff3bce6a2d3e26eb16f3"
|
||||
},
|
||||
"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",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Status: the shared Hangar, deployment admission, and portable Hangar surface
|
||||
contracts exist. Mode session bootstrap still has to consume accepted deployment
|
||||
receipts; the old generic New Game path remains live until that cut is complete.
|
||||
The state assembly and viewport queries compile against CultMath `0.1.1`, whose
|
||||
The state assembly and viewport queries compile against CultMath `0.1.2`, whose
|
||||
canonical `rect` stores normalized `min`/`max` bounds.
|
||||
|
||||
The Hangar is the launcher and durable preparation space for Terminus,
|
||||
|
|
|
|||
|
|
@ -15,37 +15,41 @@ $state = Join-Path $project "Build\aetheria-unity.cc"
|
|||
$stateRecords = "$state.records"
|
||||
New-Item -ItemType Directory -Force $artifacts | Out-Null
|
||||
|
||||
if (-not $SkipBuild) {
|
||||
$assetLog = Join-Path $artifacts "asset-bundles.log"
|
||||
$assets = Start-Process $UnityExe -ArgumentList @(
|
||||
"-batchmode", "-quit", "-projectPath", $root,
|
||||
"-executeMethod", "Aetheria.Editor.EveAssetBundleBuilder.BuildWindows",
|
||||
"-logFile", $assetLog
|
||||
) -PassThru -WindowStyle Hidden
|
||||
Write-Host "Asset build PID: $($assets.Id)"
|
||||
Write-Host "Asset build log: $assetLog"
|
||||
if (-not $assets.WaitForExit(240000)) { Stop-Process $assets.Id -Force; throw "Asset build timed out." }
|
||||
if ($assets.ExitCode -ne 0) { Get-Content $assetLog -Tail 120; throw "Asset build failed." }
|
||||
|
||||
$clientLog = Join-Path $artifacts "client-build.log"
|
||||
$build = Start-Process $UnityExe -ArgumentList @(
|
||||
"-batchmode", "-quit", "-projectPath", $project,
|
||||
"-executeMethod", "AetheriaUnityBuild.BuildWindows",
|
||||
"-logFile", $clientLog
|
||||
) -PassThru -WindowStyle Hidden
|
||||
Write-Host "Client build PID: $($build.Id)"
|
||||
Write-Host "Client build log: $clientLog"
|
||||
if (-not $build.WaitForExit(300000)) { Stop-Process $build.Id -Force; throw "Client build timed out." }
|
||||
if ($build.ExitCode -ne 0 -or -not (Test-Path $clientExe)) { Get-Content $clientLog -Tail 120; throw "Client build failed." }
|
||||
}
|
||||
|
||||
if (-not (Test-Path $clientExe)) { throw "Client executable not found. Run without -SkipBuild first." }
|
||||
if (-not (Test-Path $stateRecords)) {
|
||||
dotnet run --project $importProject -- $root $state
|
||||
if ($LASTEXITCODE -ne 0 -or -not (Test-Path $stateRecords)) {
|
||||
throw "Aetheria typed state import failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $SkipBuild) {
|
||||
$env:AETHERIA_ASSET_CATALOG_STATE = $state
|
||||
$assetLog = Join-Path $artifacts "asset-bundles.log"
|
||||
$assets = Start-Process $UnityExe -ArgumentList @(
|
||||
"-batchmode", "-quit", "-projectPath", $root,
|
||||
"-cacheServerEnableDownload", "false", "-cacheServerEnableUpload", "false",
|
||||
"-executeMethod", "Aetheria.Editor.EveAssetBundleBuilder.BuildWindows",
|
||||
"-logFile", $assetLog
|
||||
) -PassThru -WindowStyle Hidden
|
||||
Write-Host "Asset build PID: $($assets.Id)"
|
||||
Write-Host "Asset build log: $assetLog"
|
||||
if (-not $assets.WaitForExit(600000)) { Stop-Process $assets.Id -Force; throw "Asset build timed out." }
|
||||
if ($assets.ExitCode -ne 0) { Get-Content $assetLog -Tail 120; throw "Asset build failed." }
|
||||
|
||||
$clientLog = Join-Path $artifacts "client-build.log"
|
||||
$build = Start-Process $UnityExe -ArgumentList @(
|
||||
"-batchmode", "-quit", "-projectPath", $project,
|
||||
"-cacheServerEnableDownload", "false", "-cacheServerEnableUpload", "false",
|
||||
"-executeMethod", "AetheriaUnityBuild.BuildWindows",
|
||||
"-logFile", $clientLog
|
||||
) -PassThru -WindowStyle Hidden
|
||||
Write-Host "Client build PID: $($build.Id)"
|
||||
Write-Host "Client build log: $clientLog"
|
||||
if (-not $build.WaitForExit(600000)) { Stop-Process $build.Id -Force; throw "Client build timed out." }
|
||||
if ($build.ExitCode -ne 0 -or -not (Test-Path $clientExe)) { Get-Content $clientLog -Tail 120; throw "Client build failed." }
|
||||
}
|
||||
|
||||
if (-not (Test-Path $clientExe)) { throw "Client executable not found. Run without -SkipBuild first." }
|
||||
$daemonLog = Join-Path $artifacts "daemon.log"
|
||||
$daemon = Start-Process dotnet -ArgumentList @(
|
||||
"run", "--project", $daemonProject, "--",
|
||||
|
|
@ -56,6 +60,7 @@ $daemon = Start-Process dotnet -ArgumentList @(
|
|||
"--client-cultmesh-port", $Port,
|
||||
"--tick-interval-ms", 20,
|
||||
"--fixed-delta-ms", 20,
|
||||
"--terminus-scenario", "standard",
|
||||
"--no-odin-announcements"
|
||||
) -PassThru -WindowStyle Hidden -RedirectStandardOutput $daemonLog -RedirectStandardError "$daemonLog.error"
|
||||
Write-Host "Daemon PID: $($daemon.Id)"
|
||||
|
|
@ -63,7 +68,11 @@ Write-Host "Daemon log: $daemonLog"
|
|||
|
||||
try {
|
||||
$ready = $false
|
||||
for ($i = 0; $i -lt 60; $i++) {
|
||||
# A cold daemon build can take several minutes because the state schema
|
||||
# generator and the Ymir/CultMesh dependency graph compile before Program
|
||||
# publishes the endpoint. Readiness belongs to the endpoint, not an
|
||||
# arbitrary 30-second process lifetime.
|
||||
for ($i = 0; $i -lt 600; $i++) {
|
||||
if ($daemon.HasExited) { throw "Aetheria daemon exited. See $daemonLog" }
|
||||
if ((Test-Path $daemonLog) -and (Select-String $daemonLog -Pattern "Aetheria client CultMesh endpoint: cultnet\+tcp://127.0.0.1:$Port" -Quiet)) { $ready = $true; break }
|
||||
Start-Sleep -Milliseconds 500
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
param(
|
||||
[string] $CultLibRoot = "E:\Projects\CultLib",
|
||||
[string] $EveUnityRoot = "E:\Projects\EveUnity",
|
||||
[string] $YmirRoot = "E:\Projects\Ymir"
|
||||
[string] $CultLibRoot = "",
|
||||
[string] $EveUnityRoot = "",
|
||||
[string] $YmirRoot = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$repoRoot = Split-Path -Parent $PSScriptRoot
|
||||
$projectsRoot = Split-Path -Parent $repoRoot
|
||||
if ([string]::IsNullOrWhiteSpace($CultLibRoot)) { $CultLibRoot = Join-Path $projectsRoot "CultLib" }
|
||||
if ([string]::IsNullOrWhiteSpace($EveUnityRoot)) { $EveUnityRoot = Join-Path $projectsRoot "EveUnity" }
|
||||
if ([string]::IsNullOrWhiteSpace($YmirRoot)) { $YmirRoot = Join-Path $projectsRoot "Ymir" }
|
||||
$project = Join-Path $repoRoot "Aetheria.State.Daemon.Smoke\Aetheria.State.Daemon.Smoke.csproj"
|
||||
|
||||
foreach ($dependency in @(
|
||||
|
|
@ -18,6 +22,17 @@ foreach ($dependency in @(
|
|||
}
|
||||
}
|
||||
|
||||
$ymirSession = Join-Path $YmirRoot "src\Ymir.Core\YmirSession.cs"
|
||||
$box2DProject = Join-Path $YmirRoot "src\Ymir.Box3D\Ymir.Box3D.csproj"
|
||||
$box2DSource = Join-Path $YmirRoot "extern\box3d\CMakeLists.txt"
|
||||
if (-not (Test-Path -LiteralPath $ymirSession -PathType Leaf) -or
|
||||
-not (Test-Path -LiteralPath $box2DProject -PathType Leaf)) {
|
||||
throw "Ymir does not expose the retained Box2D session API required by Aetheria. Use the current Aetheria integration revision."
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $box2DSource -PathType Leaf)) {
|
||||
throw "Ymir's pinned Box2D submodule is missing. Run 'git -C $YmirRoot submodule update --init --recursive'."
|
||||
}
|
||||
|
||||
$properties = @(
|
||||
"-p:CultLibRoot=$CultLibRoot",
|
||||
"-p:EveUnityRoot=$EveUnityRoot",
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ $manifest = Get-Content (Join-Path $ProjectPath "Packages/manifest.json") -Raw |
|
|||
$lock = Get-Content (Join-Path $ProjectPath "Packages/packages-lock.json") -Raw | ConvertFrom-Json
|
||||
$expected = @{
|
||||
"org.gamecult.cultlib" = @(
|
||||
"https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.30",
|
||||
"0ef59b50c27ac019929f5e68bcd602983a190062")
|
||||
"https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.43",
|
||||
"f67f5122ed1bd11da016e7b820ed60145ccd0299")
|
||||
"org.gamecult.eve.surface" = @(
|
||||
"https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.4",
|
||||
"e08fa08335f99e9edddeb706912eecfad07cb281")
|
||||
"org.gamecult.eve.unity-scene" = @(
|
||||
"https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.88",
|
||||
"3ce813e29dcc5342b51985187de26c62eb8c90b4")
|
||||
"https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.103",
|
||||
"050b2019bd6faa4275013516870d1ded245ee391")
|
||||
}
|
||||
|
||||
foreach ($packageName in $expected.Keys) {
|
||||
|
|
@ -34,9 +34,9 @@ foreach ($packageName in $expected.Keys) {
|
|||
|
||||
$cultLibPackage = Get-ChildItem (Join-Path $ProjectPath "Library/PackageCache") -Directory |
|
||||
Where-Object Name -Like "org.gamecult.cultlib@*" |
|
||||
Where-Object { (Get-Content (Join-Path $_.FullName "package.json") -Raw | ConvertFrom-Json).version -eq "1.0.30" } |
|
||||
Where-Object { (Get-Content (Join-Path $_.FullName "package.json") -Raw | ConvertFrom-Json).version -eq "1.0.43" } |
|
||||
Select-Object -First 1
|
||||
if (-not $cultLibPackage) { throw "Resolved CultLib package is missing from Library/PackageCache." }
|
||||
if (-not $cultLibPackage) { throw "Resolved CultLib 1.0.43 package is missing from Library/PackageCache." }
|
||||
|
||||
$meshAssembly = Join-Path $cultLibPackage.FullName "Runtime/Plugins/GameCult.Mesh.dll"
|
||||
if (-not (Test-Path $meshAssembly)) { throw "Resolved GameCult.Mesh.dll is missing." }
|
||||
|
|
@ -46,8 +46,8 @@ $requiredMeshApiNames = @(
|
|||
"CultMeshBodyPublicationDocument",
|
||||
"CultMeshBodyPublicationHandle",
|
||||
"CultMeshFrameBodyPublisher",
|
||||
"CultMeshContentServer",
|
||||
"CultMeshSessionContentProviderOptions")
|
||||
"CultMeshTcpContentServer",
|
||||
"CultMeshSessionContentProvider")
|
||||
foreach ($apiName in $requiredMeshApiNames) {
|
||||
if (-not ($meshApi | Where-Object { $_ -eq $apiName })) {
|
||||
throw "Resolved GameCult.Mesh.dll does not expose $apiName."
|
||||
|
|
@ -68,9 +68,9 @@ foreach ($requiredInputContract in @("PayloadKeys", "CurrentValue", "ActionBar",
|
|||
|
||||
$scenePackage = Get-ChildItem (Join-Path $ProjectPath "Library/PackageCache") -Directory |
|
||||
Where-Object Name -Like "org.gamecult.eve.unity-scene@*" |
|
||||
Where-Object { (Get-Content (Join-Path $_.FullName "package.json") -Raw | ConvertFrom-Json).version -eq "0.3.88" } |
|
||||
Where-Object { (Get-Content (Join-Path $_.FullName "package.json") -Raw | ConvertFrom-Json).version -eq "0.3.103" } |
|
||||
Select-Object -First 1
|
||||
if (-not $scenePackage) { throw "Resolved Eve Unity scene 0.3.88 package is missing from Library/PackageCache." }
|
||||
if (-not $scenePackage) { throw "Resolved Eve Unity scene 0.3.103 package is missing from Library/PackageCache." }
|
||||
$advertisedInputSource = Get-Content (Join-Path $scenePackage.FullName "Runtime/EveUnityAdvertisedInputAction.cs") -Raw
|
||||
$inputDriverSource = Get-Content (Join-Path $scenePackage.FullName "Runtime/EveUnityPlayableWorldInputDriver.cs") -Raw
|
||||
$actionBarSource = Get-Content (Join-Path $scenePackage.FullName "Runtime/EveUnityInputActionBar.cs") -Raw
|
||||
|
|
|
|||
Loading…
Reference in a new issue