2026-08-10 14:57:50 +01:00
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
2020-12-22 03:13:43 +00:00
|
|
|
|
* 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/. */
|
|
|
|
|
|
|
Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.
Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.
The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
drew the item's schematic texture and tinted hull hardpoints, which need
the parent document. The tagged Studio hands a drawer only the value, so
those wait on the Studio exposing the open record.
Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
reaches CultMath values and refs. Keyboard layouts need no resolver and
keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.
Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
|
|
|
|
using GameCult.Caching;
|
2020-12-22 03:13:43 +00:00
|
|
|
|
using System;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
2020-11-29 22:50:12 +00:00
|
|
|
|
using System.Linq;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
using Cinemachine;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
using UniRx;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
using UnityEngine;
|
2020-12-03 17:32:34 +00:00
|
|
|
|
using UnityEngine.Serialization;
|
2020-12-22 03:13:43 +00:00
|
|
|
|
using Object = UnityEngine.Object;
|
2020-12-01 20:38:28 +00:00
|
|
|
|
using Random = UnityEngine.Random;
|
2026-09-14 17:39:12 +02:00
|
|
|
|
using CultMath;
|
Convert engine types through CultMath.UnityBridge
CultMath has no implicit conversions to or from Vector*, Quaternion or
Color, so Assembly-CSharp converts explicitly with ToCultMath/ToUnity at
each engine boundary: FieldDriver, GuidedProjectile(Manager),
EntityInstance, ActionGameManager, HullCollider, GridObject, ShipInstance,
ShieldManager, ItemPickup, FieldTester, PlaceUIElementWorldspace,
MapMenuInput, MapRenderer, SectorRenderer and ZoneRenderer. CultMath math
calls that were handed Unity vectors now take converted values;
Vector3.Scale in FieldDriver becomes a float3 product, and ItemPickup's
Vector3.Dot on float3s becomes dot. packages-lock.json records the
cultmath git package at f0605367 and demotes com.unity.mathematics to a
transitive dependency.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 17:47:33 +02:00
|
|
|
|
using CultMath.UnityBridge;
|
2026-09-14 17:39:12 +02:00
|
|
|
|
using static CultMath.math;
|
|
|
|
|
|
using float2 = CultMath.float2;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
|
2021-03-15 11:40:46 +00:00
|
|
|
|
public class ZoneRenderer : MonoBehaviour
|
2020-11-27 22:47:33 +00:00
|
|
|
|
{
|
2022-07-19 18:55:17 +01:00
|
|
|
|
public Camera MainCamera;
|
2021-03-05 14:31:18 +00:00
|
|
|
|
public Transform WormholePrefab;
|
2021-02-26 19:01:47 +00:00
|
|
|
|
public float EntityFadeTime;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
public Transform FogCameraParent;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
public GameSettings Settings;
|
2020-12-03 17:32:34 +00:00
|
|
|
|
public Transform ZoneRoot;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
public Transform SectorBrushes;
|
2026-10-16 05:08:16 +02:00
|
|
|
|
// The ambient tint quad, sized from the zone's populated radius, never under SectorBrushes: FitAmbientLight.
|
|
|
|
|
|
public Transform AmbientLight;
|
2020-12-05 23:43:02 +00:00
|
|
|
|
public CinemachineVirtualCamera SceneCamera;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
public Camera[] FogCameras;
|
|
|
|
|
|
public Camera[] MinimapCameras;
|
|
|
|
|
|
public float FarPlaneDistanceMultiplier = 2;
|
2020-12-01 20:38:28 +00:00
|
|
|
|
public InstancedMesh[] AsteroidMeshes;
|
2020-12-03 17:32:34 +00:00
|
|
|
|
public int AsteroidSpritesheetWidth = 4;
|
|
|
|
|
|
public int AsteroidSpritesheetHeight = 4;
|
2020-12-05 23:43:02 +00:00
|
|
|
|
public LODHandler LODHandler;
|
2021-03-27 10:03:24 +00:00
|
|
|
|
public Slime SlimeRenderer;
|
|
|
|
|
|
public Camera SlimeGravityCamera;
|
Unity draws Zone.FloatingItems and nothing else; the Unity loot roll, collision pickup, tractor pull and GridObject are gone
ZoneRenderer draws one ItemPickup per FloatingItem (load, ObserveAdd, ObserveRemove, ClearZone); ItemPickup.Bind places it
from the sim body and spins it for show. EntityInstance's drop loops, ShieldManager's pickup branch (the whole
OnCollisionEnter, which did nothing else), ZoneRenderer.DropItem/DestroyLoot/_loot, TractorBeam's pull, and
GameSettings' three loot fields are deleted; WireFloatingItems stripped GridObject from the five pickup prefabs and
reassigned ZoneRenderer's four pickup fields in ARPG.unity; FloatingItemsDrawnSmoke (play session, batchmode) pins the
lowering. GridObject and TimedDestroy were deleted in fa911f2d, so fa911f2d and 2565e2c5 do not build in Unity.
Assets/Resources/Settings.asset keeps three stale serialized GameSettings fields Unity ignores (LFS object, not rewritten).
Builds: Unity batchmode compile green at this commit; dotnet green at 2565e2c5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:36:47 +02:00
|
|
|
|
public ItemPickup SimpleCommodityPickup;
|
|
|
|
|
|
public ItemPickup CompoundCommodityPickup;
|
|
|
|
|
|
public ItemPickup GearPickup;
|
|
|
|
|
|
public ItemPickup WeaponPickup;
|
2026-10-08 13:49:23 +02:00
|
|
|
|
public MineInstance MinePrefab;
|
2026-10-12 03:34:50 +02:00
|
|
|
|
public VapourCloudInstance CloudPrefab;
|
2022-07-21 21:40:44 +01:00
|
|
|
|
public Material[] MapGravityMaterials;
|
2026-10-15 07:11:25 +02:00
|
|
|
|
// The gravity field's material (Brushes/Gravity Field): GravityLowering makes the one quad that draws it.
|
|
|
|
|
|
public Material GravityField;
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
|
|
|
|
|
[Header("Tour")] public bool Tour;
|
2020-12-05 23:43:02 +00:00
|
|
|
|
public float TourSwitchTime = 5f;
|
|
|
|
|
|
public float TourFollowDistance = 30f;
|
|
|
|
|
|
public float TourHeightOffset = 15;
|
|
|
|
|
|
public float TourFollowOffsetDegrees;
|
2020-12-01 20:38:28 +00:00
|
|
|
|
|
|
|
|
|
|
// public Mesh[] AsteroidMeshes;
|
|
|
|
|
|
// public Material AsteroidMaterial;
|
2020-12-03 17:32:34 +00:00
|
|
|
|
|
2021-05-11 09:44:01 +01:00
|
|
|
|
[Header("Prefabs")]
|
2026-10-16 23:26:26 +02:00
|
|
|
|
// The map's belt sprites (Aetheria/MapBelt): MapPresenter draws every belt with it.
|
|
|
|
|
|
public Material MapAsteroidMaterial;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
public PlanetObject Planet;
|
|
|
|
|
|
public GasGiantObject GasGiant;
|
|
|
|
|
|
public SunObject Sun;
|
2021-05-12 12:53:16 +02:00
|
|
|
|
public Prototype CompassIconPrototype;
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2021-05-11 09:44:01 +01:00
|
|
|
|
[Header("Icons")]
|
2021-05-12 13:49:04 +01:00
|
|
|
|
public Sprite OrbitalIcon;
|
|
|
|
|
|
public Sprite WormholeIcon;
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
|
|
|
|
|
[HideInInspector] public Dictionary<Entity, EntityInstance> EntityInstances = new Dictionary<Entity, EntityInstance>();
|
Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.
Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.
The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
drew the item's schematic texture and tinted hull hardpoints, which need
the parent document. The tagged Studio hands a drawer only the value, so
those wait on the Studio exposing the open record.
Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
reaches CultMath values and refs. Keyboard layouts need no resolver and
keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.
Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
|
|
|
|
[HideInInspector] public Dictionary<CultRecordKey, PlanetObject> Planets = new Dictionary<CultRecordKey, PlanetObject>();
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.
Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.
The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
drew the item's schematic texture and tinted hull hardpoints, which need
the parent document. The tagged Studio hands a drawer only the value, so
those wait on the Studio exposing the open record.
Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
reaches CultMath values and refs. Keyboard layouts need no resolver and
keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.
Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
|
|
|
|
private Dictionary<CultRecordKey, InstancedMesh[]> _beltMeshes = new Dictionary<CultRecordKey, InstancedMesh[]>();
|
|
|
|
|
|
private Dictionary<CultRecordKey, Matrix4x4[][]> _beltMatrices = new Dictionary<CultRecordKey, Matrix4x4[][]>();
|
Cut 1: belts are evaluated when asked, not simulated every tick
Zone.Update no longer threads a per-belt Task.Run over a double-buffered
Transforms/OrbitPosition pair. AsteroidBelt.Pose/Size are the one place a
chunk pose is computed, a pure function of zone time; Zone.ChunkPose and
Zone.EvaluateBelt read them at the zone's own time. MiningTool,
ResourceScanner and ZoneRenderer (belt matrices and AsteroidBeltUI) all read
through Zone instead of the deleted per-tick buffers; the renderer owns its
own float4[] buffer, filled fresh every frame.
Deleted: System.Threading/.Tasks usings, BeltUpdates, the wait loop, the
per-belt copy+Task.Run, NearestAsteroid (dead/broken reader), the private
UpdateAsteroidTransforms, and AsteroidBelt's four pose fields plus their
allocations. ~65 lines, matching the cut map's estimate.
miningprobe, densest zone of the operator's save (EAC-2265, 809 asteroids,
8 belts), rebuilt against this cut and rerun 10x each side:
before (branch point, 8bd25f6f/e729e6d6):
Zone.Update wall 541-3654 us/tick, CPU 120-391 us/tick (7 clean runs)
3/10 runs crashed: InvalidOperationException from Zone.GetOrbitPosition,
the documented _updatedOrbits/Orbits data race between the main thread's
Clear() and a belt Task.Run
after (this commit):
Zone.Update wall 95-185 us/tick, CPU 99-152 us/tick, in line with the
31-39 us "no belt work" baseline the map recorded -- belts are free per
tick
0/10 races
ChunkPose has no buffer to go stale: ~0.12 u of parent+asteroid motion is
visible across one 17 ms tick instead of being one tick behind
tests/Aetheria.Shared.Tests/MiningCut1Tests.cs (new, 260/260 suite green):
ChunkPoseIsTheOrbitAtZoneTime, ChunkPoseDoesNotDependOnUpdateCadence,
DamagedChunkShrinksAndABrokenOneHasNoSize -- each expected value is the
closed-form orbit/size rule reimplemented in the test, never a call to
AsteroidBelt.Pose/Size.
Negative grep (Zone.cs, "Zone Display", ServerShared/Behaviors) for
Task\.Run|System\.Threading|NewTransforms|\.Transforms\b|BeltUpdates|
NearestAsteroid|\.OrbitPosition\b|NewOrbitPosition: one hit, the commented
line in MineAsteroid that Cut 2 deletes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 01:27:16 +02:00
|
|
|
|
// Cut 1 (docs/mining-cut.md): the renderer's own buffer, filled from Zone.EvaluateBelt each frame. No pose
|
|
|
|
|
|
// is stored on AsteroidBelt any more.
|
|
|
|
|
|
private Dictionary<CultRecordKey, float4[]> _beltTransforms = new Dictionary<CultRecordKey, float4[]>();
|
2020-11-27 22:47:33 +00:00
|
|
|
|
private float _viewDistance;
|
2026-10-15 07:11:25 +02:00
|
|
|
|
private GameObject _gravityField;
|
|
|
|
|
|
private ComputeBuffer _gravityWells;
|
2021-05-12 12:53:16 +02:00
|
|
|
|
private float _minimapDistance;
|
2020-12-05 23:43:02 +00:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
private int _tourIndex = -1;
|
2020-12-05 23:43:02 +00:00
|
|
|
|
private float _tourTimer;
|
|
|
|
|
|
private List<(Transform, Transform)> _tourPlanets = new List<(Transform, Transform)>();
|
|
|
|
|
|
private CinemachineTransposer _transposer;
|
|
|
|
|
|
private PlanetObject _root;
|
|
|
|
|
|
private bool _rootFound;
|
2021-02-26 19:01:47 +00:00
|
|
|
|
private Entity _perspectiveEntity;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
private IDisposable[] _perspectiveSubscriptions = new IDisposable[2];
|
|
|
|
|
|
private List<IDisposable> _zoneSubscriptions = new List<IDisposable>();
|
2021-03-30 01:17:58 +01:00
|
|
|
|
private PlanetObject[] _suns;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
|
|
|
|
|
public Dictionary<Wormhole, (GameObject gravity, CompassIcon icon)> WormholeInstances = new Dictionary<Wormhole, (GameObject, CompassIcon)>();
|
Unity draws Zone.FloatingItems and nothing else; the Unity loot roll, collision pickup, tractor pull and GridObject are gone
ZoneRenderer draws one ItemPickup per FloatingItem (load, ObserveAdd, ObserveRemove, ClearZone); ItemPickup.Bind places it
from the sim body and spins it for show. EntityInstance's drop loops, ShieldManager's pickup branch (the whole
OnCollisionEnter, which did nothing else), ZoneRenderer.DropItem/DestroyLoot/_loot, TractorBeam's pull, and
GameSettings' three loot fields are deleted; WireFloatingItems stripped GridObject from the five pickup prefabs and
reassigned ZoneRenderer's four pickup fields in ARPG.unity; FloatingItemsDrawnSmoke (play session, batchmode) pins the
lowering. GridObject and TimedDestroy were deleted in fa911f2d, so fa911f2d and 2565e2c5 do not build in Unity.
Assets/Resources/Settings.asset keeps three stale serialized GameSettings fields Unity ignores (LFS object, not rewritten).
Builds: Unity batchmode compile green at this commit; dotnet green at 2565e2c5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:36:47 +02:00
|
|
|
|
private Dictionary<FloatingItem, ItemPickup> _floatingItems = new Dictionary<FloatingItem, ItemPickup>();
|
2026-10-08 13:49:23 +02:00
|
|
|
|
private Dictionary<Mine, MineInstance> _mines = new Dictionary<Mine, MineInstance>();
|
2026-10-12 03:34:50 +02:00
|
|
|
|
private Dictionary<VapourCloud, VapourCloudInstance> _clouds = new Dictionary<VapourCloud, VapourCloudInstance>();
|
2021-03-05 14:31:18 +00:00
|
|
|
|
|
2026-10-16 23:26:26 +02:00
|
|
|
|
// The one owner of map-space projection: every map icon and belt sprite is drawn by it.
|
|
|
|
|
|
public MapPresenter Map { get; private set; }
|
2026-08-10 14:57:50 +01:00
|
|
|
|
public Zone Zone { get; private set; }
|
|
|
|
|
|
public ItemManager ItemManager { get; set; }
|
2020-12-05 23:43:02 +00:00
|
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
|
public Entity PerspectiveEntity
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _perspectiveEntity;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
//if (_perspectiveEntity == value) return;
|
2021-02-26 19:01:47 +00:00
|
|
|
|
_perspectiveEntity = value;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
_perspectiveSubscriptions[0]?.Dispose();
|
|
|
|
|
|
_perspectiveSubscriptions[1]?.Dispose();
|
|
|
|
|
|
if (value == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var e in EntityInstances.Values)
|
|
|
|
|
|
e.FadeOut(EntityFadeTime);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var entity in EntityInstances.Values)
|
|
|
|
|
|
entity.FadeOut(EntityFadeTime);
|
|
|
|
|
|
foreach (var entity in value.VisibleEntities)
|
|
|
|
|
|
EntityInstances[entity].FadeIn(EntityFadeTime);
|
|
|
|
|
|
EntityInstances[value].FadeIn(EntityFadeTime);
|
|
|
|
|
|
_perspectiveSubscriptions[0] = value.VisibleEntities.ObserveAdd()
|
|
|
|
|
|
.Subscribe(add => EntityInstances[add.Value].FadeIn(EntityFadeTime));
|
|
|
|
|
|
_perspectiveSubscriptions[1] = value.VisibleEntities.ObserveRemove()
|
|
|
|
|
|
.Where(removeEvent => EntityInstances.ContainsKey(removeEvent.Value))
|
|
|
|
|
|
.Subscribe(removeEvent => EntityInstances[removeEvent.Value].FadeOut(EntityFadeTime));
|
|
|
|
|
|
}
|
2021-02-26 19:01:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-11-27 22:47:33 +00:00
|
|
|
|
public float ViewDistance
|
|
|
|
|
|
{
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_viewDistance = value;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
foreach (var camera in FogCameras)
|
|
|
|
|
|
camera.orthographicSize = value;
|
|
|
|
|
|
SceneCamera.m_Lens.FarClipPlane = value * FarPlaneDistanceMultiplier;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public float MinimapDistance
|
|
|
|
|
|
{
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
2021-05-12 12:53:16 +02:00
|
|
|
|
_minimapDistance = value;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
foreach (var camera in MinimapCameras)
|
|
|
|
|
|
camera.orthographicSize = value;
|
2026-10-16 23:26:26 +02:00
|
|
|
|
Map.SetMinimapScale(value * Settings.MinimapIconSize);
|
2020-12-14 02:56:35 +00:00
|
|
|
|
// MinimapGravityQuad.transform.localScale = value * 2 * Vector3.one;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-16 23:26:26 +02:00
|
|
|
|
void Awake()
|
2022-07-18 08:44:54 +01:00
|
|
|
|
{
|
2026-10-16 23:26:26 +02:00
|
|
|
|
Map = new MapPresenter(MapGravityMaterials, MapAsteroidMaterial, AsteroidSpritesheetWidth,
|
|
|
|
|
|
AsteroidSpritesheetHeight, Settings.MinimapAsteroidSize);
|
2026-06-25 18:09:33 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-11-27 22:47:33 +00:00
|
|
|
|
void Start()
|
|
|
|
|
|
{
|
2022-07-19 18:55:17 +01:00
|
|
|
|
var bigBounds = new Bounds(Vector3.zero, Vector3.one * 1024);
|
|
|
|
|
|
foreach (var mesh in AsteroidMeshes) mesh.Mesh.bounds = bigBounds;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
ViewDistance = Settings.DefaultViewDistance;
|
|
|
|
|
|
MinimapDistance = Settings.MinimapZoomLevels[Settings.DefaultMinimapZoom];
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2020-12-05 23:43:02 +00:00
|
|
|
|
_tourTimer = TourSwitchTime;
|
|
|
|
|
|
_transposer = SceneCamera.GetCinemachineComponent<CinemachineTransposer>();
|
2020-11-27 22:47:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-16 05:08:16 +02:00
|
|
|
|
// The ambient is a gaussian: its brightness at the populated edge is the material's _EdgeBrightness (a shape, authored), and
|
2026-10-16 06:24:36 +02:00
|
|
|
|
// the quad reaches out to where its brightest channel falls to AmbientFloor. Fog Tint is B10G11R11_UFloatPack32 and cannot
|
|
|
|
|
|
// follow a gaussian into its tail: measured, the drawn value stops following it near 4 floors and holds a plateau of
|
|
|
|
|
|
// about 3.2e-5 before dropping to zero (AmbientEdgeVerify asserts the format and measures it). A quad sized to 1e-5 of the
|
|
|
|
|
|
// centre therefore ended in a plateau and a step to zero; sized to the floor it ends at the last value the format holds,
|
|
|
|
|
|
// so the one step to dark is that value. The one writer of the quad's size and _Reach, and the one place the verify
|
|
|
|
|
|
// reads the sizing from.
|
|
|
|
|
|
public const float AmbientFloor = 1f / (1 << 15);
|
2026-10-16 05:08:16 +02:00
|
|
|
|
|
|
|
|
|
|
public static void FitAmbientLight(Transform light, Zone zone)
|
|
|
|
|
|
{
|
|
|
|
|
|
var renderer = light.GetComponent<MeshRenderer>();
|
2026-10-16 06:24:36 +02:00
|
|
|
|
var material = renderer.sharedMaterial;
|
|
|
|
|
|
var tint = material.GetColor("_Color").linear;
|
|
|
|
|
|
var centre = material.GetFloat("_Depth") * Mathf.Max(tint.r, Mathf.Max(tint.g, tint.b));
|
|
|
|
|
|
var reach = Mathf.Sqrt(Mathf.Log(centre / AmbientFloor) / Mathf.Log(1f / material.GetFloat("_EdgeBrightness")));
|
2026-10-16 05:08:16 +02:00
|
|
|
|
light.localScale = 2f * reach * zone.PopulatedRadius * Vector3.one;
|
|
|
|
|
|
var block = new MaterialPropertyBlock();
|
|
|
|
|
|
renderer.GetPropertyBlock(block);
|
|
|
|
|
|
block.SetFloat("_Reach", reach);
|
|
|
|
|
|
renderer.SetPropertyBlock(block);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
public void LoadZone(Zone zone)
|
2020-11-27 22:47:33 +00:00
|
|
|
|
{
|
2021-03-05 21:45:32 +00:00
|
|
|
|
ClearZone();
|
2026-08-10 14:57:50 +01:00
|
|
|
|
Zone = zone;
|
|
|
|
|
|
SectorBrushes.localScale = zone.Pack.Radius * 2 * Vector3.one;
|
2026-10-16 05:08:16 +02:00
|
|
|
|
FitAmbientLight(AmbientLight, zone);
|
2026-08-10 14:57:50 +01:00
|
|
|
|
SlimeGravityCamera.orthographicSize = zone.Pack.Radius;
|
|
|
|
|
|
SlimeRenderer.ZoneRadius = zone.Pack.Radius;
|
2026-10-15 07:11:25 +02:00
|
|
|
|
if (_gravityField == null) _gravityField = GravityLowering.CreateField(GravityField);
|
Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.
Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.
The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
drew the item's schematic texture and tinted hull hardpoints, which need
the parent document. The tagged Studio hands a drawer only the value, so
those wait on the Studio exposing the open record.
Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
reaches CultMath values and refs. Keyboard layouts need no resolver and
keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.
Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
|
|
|
|
foreach (var p in zone.Planets)
|
|
|
|
|
|
LoadPlanet(p.Key, p.Value);
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
_suns = Planets.Values.Where(p => p is SunObject).ToArray();
|
2026-06-21 17:04:07 +01:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
// foreach (var x in Planets)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (!(zone.Planets[x.Key] is GasGiantData))
|
|
|
|
|
|
// {
|
|
|
|
|
|
//
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var entity in zone.Entities)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log($"Loading entity {entity.Name} from existing zone entity collection");
|
|
|
|
|
|
LoadEntity(entity);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_zoneSubscriptions.Add(zone.Entities.ObserveAdd().Subscribe(e =>
|
|
|
|
|
|
{
|
|
|
|
|
|
//Debug.Log($"Loading entity {e.Value.Name} from zone add event");
|
|
|
|
|
|
LoadEntity(e.Value);
|
|
|
|
|
|
}));
|
|
|
|
|
|
_zoneSubscriptions.Add(zone.Entities.ObserveRemove().Subscribe(e =>
|
2026-06-25 18:09:33 +01:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
//Debug.Log($"Unloading entity {e.Value.Name} from zone remove event");
|
|
|
|
|
|
UnloadEntity(e.Value);
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
2026-10-08 13:49:23 +02:00
|
|
|
|
// Every mine, whoever laid it, is drawn through this one subscription. A mine leaves Zone.Mines only by
|
|
|
|
|
|
// its blast, so a removal plays the blast; ClearZone below destroys the rest without one.
|
|
|
|
|
|
foreach (var mine in zone.Mines) LoadMine(zone, mine);
|
|
|
|
|
|
_zoneSubscriptions.Add(zone.Mines.ObserveAdd().Subscribe(e => LoadMine(zone, e.Value)));
|
|
|
|
|
|
_zoneSubscriptions.Add(zone.Mines.ObserveRemove().Subscribe(e =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_mines.Remove(e.Value, out var instance)) return;
|
|
|
|
|
|
instance.Blast();
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
Unity draws Zone.FloatingItems and nothing else; the Unity loot roll, collision pickup, tractor pull and GridObject are gone
ZoneRenderer draws one ItemPickup per FloatingItem (load, ObserveAdd, ObserveRemove, ClearZone); ItemPickup.Bind places it
from the sim body and spins it for show. EntityInstance's drop loops, ShieldManager's pickup branch (the whole
OnCollisionEnter, which did nothing else), ZoneRenderer.DropItem/DestroyLoot/_loot, TractorBeam's pull, and
GameSettings' three loot fields are deleted; WireFloatingItems stripped GridObject from the five pickup prefabs and
reassigned ZoneRenderer's four pickup fields in ARPG.unity; FloatingItemsDrawnSmoke (play session, batchmode) pins the
lowering. GridObject and TimedDestroy were deleted in fa911f2d, so fa911f2d and 2565e2c5 do not build in Unity.
Assets/Resources/Settings.asset keeps three stale serialized GameSettings fields Unity ignores (LFS object, not rewritten).
Builds: Unity batchmode compile green at this commit; dotnet green at 2565e2c5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:36:47 +02:00
|
|
|
|
// Every floating item, whoever released it (a death drop, jettisoned cargo), is drawn through this one
|
|
|
|
|
|
// subscription. An item leaves Zone.FloatingItems by expiry or by pickup, and either way its pickup is gone.
|
|
|
|
|
|
foreach (var floating in zone.FloatingItems) LoadFloatingItem(zone, floating);
|
|
|
|
|
|
_zoneSubscriptions.Add(zone.FloatingItems.ObserveAdd().Subscribe(e => LoadFloatingItem(zone, e.Value)));
|
|
|
|
|
|
_zoneSubscriptions.Add(zone.FloatingItems.ObserveRemove().Subscribe(e =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_floatingItems.Remove(e.Value, out var pickup) && pickup) Destroy(pickup.gameObject);
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
2026-10-12 03:34:50 +02:00
|
|
|
|
// Every vapour cloud, whoever vented it, is drawn through this one subscription. A cloud leaves Zone.Clouds
|
|
|
|
|
|
// when its opacity has reached nothing, so a removal destroys its fog bank with nothing left to show.
|
|
|
|
|
|
foreach (var cloud in zone.Clouds) LoadCloud(zone, cloud);
|
|
|
|
|
|
_zoneSubscriptions.Add(zone.Clouds.ObserveAdd().Subscribe(e => LoadCloud(zone, e.Value)));
|
|
|
|
|
|
_zoneSubscriptions.Add(zone.Clouds.ObserveRemove().Subscribe(e =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_clouds.Remove(e.Value, out var instance)) Destroy(instance.gameObject);
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
if (zone.GalaxyZone != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var adjacentZone in zone.GalaxyZone.AdjacentZones)
|
|
|
|
|
|
{
|
|
|
|
|
|
var dir = normalize(adjacentZone.Position - zone.GalaxyZone.Position);
|
|
|
|
|
|
AddWormhole(new Wormhole
|
|
|
|
|
|
{
|
|
|
|
|
|
Target = adjacentZone,
|
|
|
|
|
|
Position = dir * zone.Pack.Radius * Settings.WormholeDistanceRatio
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-10-07 01:13:09 +02:00
|
|
|
|
|
|
|
|
|
|
// The run's exit gate is presentation only: whether it opens is RunGoal.ExitOpen, read when it is used.
|
|
|
|
|
|
if (zone.GalaxyZone == zone.Galaxy.Exit)
|
|
|
|
|
|
AddWormhole(new Wormhole
|
|
|
|
|
|
{
|
|
|
|
|
|
Exit = true,
|
|
|
|
|
|
Position = RunGoal.ExitGatePosition(zone, Settings.WormholeDistanceRatio)
|
|
|
|
|
|
});
|
2026-06-25 18:09:33 +01:00
|
|
|
|
}
|
2021-03-05 14:31:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-08 13:49:23 +02:00
|
|
|
|
private void LoadMine(Zone zone, Mine mine)
|
|
|
|
|
|
{
|
|
|
|
|
|
var instance = Instantiate(MinePrefab);
|
2026-10-16 02:35:07 +02:00
|
|
|
|
instance.Bind(zone, mine, ItemManager.GameplaySettings);
|
2026-10-08 13:49:23 +02:00
|
|
|
|
_mines.Add(mine, instance);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Unity draws Zone.FloatingItems and nothing else; the Unity loot roll, collision pickup, tractor pull and GridObject are gone
ZoneRenderer draws one ItemPickup per FloatingItem (load, ObserveAdd, ObserveRemove, ClearZone); ItemPickup.Bind places it
from the sim body and spins it for show. EntityInstance's drop loops, ShieldManager's pickup branch (the whole
OnCollisionEnter, which did nothing else), ZoneRenderer.DropItem/DestroyLoot/_loot, TractorBeam's pull, and
GameSettings' three loot fields are deleted; WireFloatingItems stripped GridObject from the five pickup prefabs and
reassigned ZoneRenderer's four pickup fields in ARPG.unity; FloatingItemsDrawnSmoke (play session, batchmode) pins the
lowering. GridObject and TimedDestroy were deleted in fa911f2d, so fa911f2d and 2565e2c5 do not build in Unity.
Assets/Resources/Settings.asset keeps three stale serialized GameSettings fields Unity ignores (LFS object, not rewritten).
Builds: Unity batchmode compile green at this commit; dotnet green at 2565e2c5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:36:47 +02:00
|
|
|
|
private void LoadFloatingItem(Zone zone, FloatingItem floating)
|
|
|
|
|
|
{
|
|
|
|
|
|
var prefab = floating.Item switch
|
|
|
|
|
|
{
|
|
|
|
|
|
SimpleCommodity _ => SimpleCommodityPickup,
|
|
|
|
|
|
CompoundCommodity _ => CompoundCommodityPickup,
|
|
|
|
|
|
EquippableItem equippableItem when ItemManager.GetData(equippableItem) is WeaponItemData => WeaponPickup,
|
|
|
|
|
|
EquippableItem _ => GearPickup,
|
|
|
|
|
|
_ => throw new NotImplementedException()
|
|
|
|
|
|
};
|
|
|
|
|
|
var pickup = Instantiate(prefab, ZoneRoot);
|
2026-10-16 02:35:07 +02:00
|
|
|
|
pickup.Bind(zone, floating, ItemManager.GameplaySettings);
|
Unity draws Zone.FloatingItems and nothing else; the Unity loot roll, collision pickup, tractor pull and GridObject are gone
ZoneRenderer draws one ItemPickup per FloatingItem (load, ObserveAdd, ObserveRemove, ClearZone); ItemPickup.Bind places it
from the sim body and spins it for show. EntityInstance's drop loops, ShieldManager's pickup branch (the whole
OnCollisionEnter, which did nothing else), ZoneRenderer.DropItem/DestroyLoot/_loot, TractorBeam's pull, and
GameSettings' three loot fields are deleted; WireFloatingItems stripped GridObject from the five pickup prefabs and
reassigned ZoneRenderer's four pickup fields in ARPG.unity; FloatingItemsDrawnSmoke (play session, batchmode) pins the
lowering. GridObject and TimedDestroy were deleted in fa911f2d, so fa911f2d and 2565e2c5 do not build in Unity.
Assets/Resources/Settings.asset keeps three stale serialized GameSettings fields Unity ignores (LFS object, not rewritten).
Builds: Unity batchmode compile green at this commit; dotnet green at 2565e2c5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:36:47 +02:00
|
|
|
|
pickup.ScanLabel.text = ItemManager.Title(floating.Item);
|
|
|
|
|
|
if (floating.Item is CraftedItemInstance craftedItemInstance)
|
|
|
|
|
|
{
|
|
|
|
|
|
var c = ItemManager.GetTier(craftedItemInstance).tier.Color.ToColor();
|
|
|
|
|
|
c.a = 0;
|
|
|
|
|
|
pickup.ScanLabel.color = c;
|
|
|
|
|
|
}
|
|
|
|
|
|
else pickup.ScanLabel.color = new Color(.75f, .75f, .75f, 0);
|
|
|
|
|
|
_floatingItems.Add(floating, pickup);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-12 03:34:50 +02:00
|
|
|
|
private void LoadCloud(Zone zone, VapourCloud cloud)
|
|
|
|
|
|
{
|
|
|
|
|
|
var instance = Instantiate(CloudPrefab);
|
|
|
|
|
|
instance.Bind(zone, cloud);
|
|
|
|
|
|
_clouds.Add(cloud, instance);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
public void AddWormhole(Wormhole wormhole)
|
2021-03-05 14:31:18 +00:00
|
|
|
|
{
|
|
|
|
|
|
var instance = Instantiate(WormholePrefab);
|
2026-08-10 14:57:50 +01:00
|
|
|
|
instance.position = new Vector3(wormhole.Position.x, 0, wormhole.Position.y);
|
2021-05-12 13:49:04 +01:00
|
|
|
|
var icon = CompassIconPrototype.Instantiate<CompassIcon>();
|
|
|
|
|
|
icon.Icon.sprite = WormholeIcon;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
WormholeInstances.Add(wormhole, (instance.gameObject, icon));
|
2020-11-29 22:50:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-15 07:11:25 +02:00
|
|
|
|
void OnDestroy()
|
|
|
|
|
|
{
|
|
|
|
|
|
_gravityWells?.Release();
|
|
|
|
|
|
_gravityWells = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-11-29 22:50:12 +00:00
|
|
|
|
public void ClearZone()
|
|
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
if (Zone == null) return;
|
2026-10-15 07:11:25 +02:00
|
|
|
|
_gravityWells?.Release();
|
|
|
|
|
|
_gravityWells = null;
|
2021-05-12 12:53:16 +02:00
|
|
|
|
foreach (var wormhole in WormholeInstances.Values)
|
|
|
|
|
|
{
|
|
|
|
|
|
Destroy(wormhole.gravity);
|
|
|
|
|
|
wormhole.icon.GetComponent<Prototype>().ReturnToPool();
|
|
|
|
|
|
}
|
2021-03-05 14:31:18 +00:00
|
|
|
|
WormholeInstances.Clear();
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
foreach (var subscription in _zoneSubscriptions)
|
|
|
|
|
|
subscription.Dispose();
|
|
|
|
|
|
_zoneSubscriptions.Clear();
|
|
|
|
|
|
|
2026-10-08 13:49:23 +02:00
|
|
|
|
foreach (var instance in _mines.Values)
|
|
|
|
|
|
if (instance) Destroy(instance.gameObject);
|
|
|
|
|
|
_mines.Clear();
|
|
|
|
|
|
|
2026-10-12 03:34:50 +02:00
|
|
|
|
foreach (var instance in _clouds.Values)
|
|
|
|
|
|
if (instance) Destroy(instance.gameObject);
|
|
|
|
|
|
_clouds.Clear();
|
|
|
|
|
|
|
Unity draws Zone.FloatingItems and nothing else; the Unity loot roll, collision pickup, tractor pull and GridObject are gone
ZoneRenderer draws one ItemPickup per FloatingItem (load, ObserveAdd, ObserveRemove, ClearZone); ItemPickup.Bind places it
from the sim body and spins it for show. EntityInstance's drop loops, ShieldManager's pickup branch (the whole
OnCollisionEnter, which did nothing else), ZoneRenderer.DropItem/DestroyLoot/_loot, TractorBeam's pull, and
GameSettings' three loot fields are deleted; WireFloatingItems stripped GridObject from the five pickup prefabs and
reassigned ZoneRenderer's four pickup fields in ARPG.unity; FloatingItemsDrawnSmoke (play session, batchmode) pins the
lowering. GridObject and TimedDestroy were deleted in fa911f2d, so fa911f2d and 2565e2c5 do not build in Unity.
Assets/Resources/Settings.asset keeps three stale serialized GameSettings fields Unity ignores (LFS object, not rewritten).
Builds: Unity batchmode compile green at this commit; dotnet green at 2565e2c5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:36:47 +02:00
|
|
|
|
foreach (var pickup in _floatingItems.Values)
|
|
|
|
|
|
if (pickup) Destroy(pickup.gameObject);
|
|
|
|
|
|
_floatingItems.Clear();
|
2021-03-05 21:45:32 +00:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
foreach (var entity in Zone.Entities)
|
2021-03-05 21:45:32 +00:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
Debug.Log($"Unloading entity {entity.Name} from entities remaining during clear!");
|
2021-03-05 21:45:32 +00:00
|
|
|
|
UnloadEntity(entity);
|
|
|
|
|
|
}
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
if (Planets.Count > 0)
|
2020-11-27 22:47:33 +00:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
foreach (var planet in Planets.Values)
|
2020-11-27 22:47:33 +00:00
|
|
|
|
{
|
2020-11-29 22:50:12 +00:00
|
|
|
|
DestroyImmediate(planet.gameObject);
|
2020-11-27 22:47:33 +00:00
|
|
|
|
}
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
Planets.Clear();
|
2026-10-16 23:26:26 +02:00
|
|
|
|
Map.Clear();
|
2020-12-01 20:38:28 +00:00
|
|
|
|
_beltMeshes.Clear();
|
2020-12-03 17:32:34 +00:00
|
|
|
|
_beltMatrices.Clear();
|
Cut 1: belts are evaluated when asked, not simulated every tick
Zone.Update no longer threads a per-belt Task.Run over a double-buffered
Transforms/OrbitPosition pair. AsteroidBelt.Pose/Size are the one place a
chunk pose is computed, a pure function of zone time; Zone.ChunkPose and
Zone.EvaluateBelt read them at the zone's own time. MiningTool,
ResourceScanner and ZoneRenderer (belt matrices and AsteroidBeltUI) all read
through Zone instead of the deleted per-tick buffers; the renderer owns its
own float4[] buffer, filled fresh every frame.
Deleted: System.Threading/.Tasks usings, BeltUpdates, the wait loop, the
per-belt copy+Task.Run, NearestAsteroid (dead/broken reader), the private
UpdateAsteroidTransforms, and AsteroidBelt's four pose fields plus their
allocations. ~65 lines, matching the cut map's estimate.
miningprobe, densest zone of the operator's save (EAC-2265, 809 asteroids,
8 belts), rebuilt against this cut and rerun 10x each side:
before (branch point, 8bd25f6f/e729e6d6):
Zone.Update wall 541-3654 us/tick, CPU 120-391 us/tick (7 clean runs)
3/10 runs crashed: InvalidOperationException from Zone.GetOrbitPosition,
the documented _updatedOrbits/Orbits data race between the main thread's
Clear() and a belt Task.Run
after (this commit):
Zone.Update wall 95-185 us/tick, CPU 99-152 us/tick, in line with the
31-39 us "no belt work" baseline the map recorded -- belts are free per
tick
0/10 races
ChunkPose has no buffer to go stale: ~0.12 u of parent+asteroid motion is
visible across one 17 ms tick instead of being one tick behind
tests/Aetheria.Shared.Tests/MiningCut1Tests.cs (new, 260/260 suite green):
ChunkPoseIsTheOrbitAtZoneTime, ChunkPoseDoesNotDependOnUpdateCadence,
DamagedChunkShrinksAndABrokenOneHasNoSize -- each expected value is the
closed-form orbit/size rule reimplemented in the test, never a call to
AsteroidBelt.Pose/Size.
Negative grep (Zone.cs, "Zone Display", ServerShared/Behaviors) for
Task\.Run|System\.Threading|NewTransforms|\.Transforms\b|BeltUpdates|
NearestAsteroid|\.OrbitPosition\b|NewOrbitPosition: one hit, the commented
line in MineAsteroid that Cut 2 deletes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 01:27:16 +02:00
|
|
|
|
_beltTransforms.Clear();
|
2020-12-05 23:43:02 +00:00
|
|
|
|
_tourPlanets.Clear();
|
2020-11-27 22:47:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-22 03:13:43 +00:00
|
|
|
|
void LoadEntity(Entity entity)
|
|
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
var hullData = ItemManager.GetData(entity.Hull) as HullData;
|
2026-09-30 06:43:52 +02:00
|
|
|
|
GameObject Body() => hullData.Visual.IsSet()
|
|
|
|
|
|
? ShipModShips.Instantiate(hullData, ZoneRoot)
|
|
|
|
|
|
: Instantiate(EngineAssets.Load<GameObject>(hullData.Prefab), ZoneRoot);
|
2021-01-05 02:56:17 +00:00
|
|
|
|
EntityInstance instance;
|
2021-02-26 19:01:47 +00:00
|
|
|
|
if (entity is Ship)
|
2020-12-22 03:13:43 +00:00
|
|
|
|
{
|
2026-09-30 06:43:52 +02:00
|
|
|
|
instance = Body().GetComponent<ShipInstance>();
|
2021-02-26 19:01:47 +00:00
|
|
|
|
if (instance == null)
|
2021-01-05 02:56:17 +00:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
ItemManager.Log($"Failed to instantiate {hullData.Name} ship with invalid prefab: no ShipInstance component!");
|
2021-02-26 19:01:47 +00:00
|
|
|
|
return;
|
2021-01-05 02:56:17 +00:00
|
|
|
|
}
|
2020-12-22 03:13:43 +00:00
|
|
|
|
}
|
2021-02-26 19:01:47 +00:00
|
|
|
|
else
|
2021-01-05 02:56:17 +00:00
|
|
|
|
{
|
2026-09-30 06:43:52 +02:00
|
|
|
|
instance = Body().GetComponent<EntityInstance>();
|
2021-02-26 19:01:47 +00:00
|
|
|
|
if (instance == null)
|
2021-01-05 02:56:17 +00:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
ItemManager.Log($"Failed to instantiate {hullData.Name} entity with invalid prefab: no EntityInstance component!");
|
2021-02-26 19:01:47 +00:00
|
|
|
|
return;
|
2021-01-05 02:56:17 +00:00
|
|
|
|
}
|
2026-08-10 14:57:50 +01:00
|
|
|
|
if (entity.HullData.HullType == HullType.Station)
|
2021-05-12 13:49:04 +01:00
|
|
|
|
{
|
|
|
|
|
|
instance.CompassIcon = CompassIconPrototype.Instantiate<CompassIcon>();
|
|
|
|
|
|
instance.CompassIcon.Icon.sprite = OrbitalIcon;
|
|
|
|
|
|
}
|
2021-01-05 02:56:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
|
instance.SetEntity(this, entity);
|
2021-05-12 13:49:04 +01:00
|
|
|
|
|
2021-01-05 02:56:17 +00:00
|
|
|
|
EntityInstances.Add(entity, instance);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
|
public void UnloadEntity(Entity entity)
|
2021-01-05 02:56:17 +00:00
|
|
|
|
{
|
2021-01-31 03:52:32 +00:00
|
|
|
|
foreach (var item in entity.Equipment)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var behavior in item.Behaviors)
|
|
|
|
|
|
{
|
2021-04-15 04:25:22 +01:00
|
|
|
|
if (behavior is IEventBehavior eventBehavior)
|
2021-03-21 01:55:25 +00:00
|
|
|
|
eventBehavior.ResetEvents();
|
2021-01-31 03:52:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2026-10-16 23:26:26 +02:00
|
|
|
|
Map.Unregister(entity);
|
2026-08-10 14:57:50 +01:00
|
|
|
|
Destroy(EntityInstances[entity].gameObject);
|
2021-01-05 02:56:17 +00:00
|
|
|
|
EntityInstances.Remove(entity);
|
2026-06-14 19:10:15 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.
Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.
The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
drew the item's schematic texture and tinted hull hardpoints, which need
the parent document. The tagged Studio hands a drawer only the value, so
those wait on the Studio exposing the open record.
Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
reaches CultMath values and refs. Keyboard layouts need no resolver and
keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.
Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
|
|
|
|
void LoadPlanet(CultRecordKey key, BodyData planetData)
|
2020-11-27 22:47:33 +00:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
if (planetData is AsteroidBeltData beltData)
|
2020-11-27 22:47:33 +00:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
var meshes = AsteroidMeshes.ToList();
|
|
|
|
|
|
while (meshes.Count > Settings.AsteroidMeshCount)
|
|
|
|
|
|
meshes.RemoveAt(Random.Range(0, meshes.Count));
|
Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.
Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.
The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
drew the item's schematic texture and tinted hull hardpoints, which need
the parent document. The tagged Studio hands a drawer only the value, so
those wait on the Studio exposing the open record.
Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
reaches CultMath values and refs. Keyboard layouts need no resolver and
keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.
Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
|
|
|
|
_beltMeshes[key] = meshes.ToArray();
|
|
|
|
|
|
_beltMatrices[key] = new Matrix4x4[meshes.Count][];
|
Cut 1: belts are evaluated when asked, not simulated every tick
Zone.Update no longer threads a per-belt Task.Run over a double-buffered
Transforms/OrbitPosition pair. AsteroidBelt.Pose/Size are the one place a
chunk pose is computed, a pure function of zone time; Zone.ChunkPose and
Zone.EvaluateBelt read them at the zone's own time. MiningTool,
ResourceScanner and ZoneRenderer (belt matrices and AsteroidBeltUI) all read
through Zone instead of the deleted per-tick buffers; the renderer owns its
own float4[] buffer, filled fresh every frame.
Deleted: System.Threading/.Tasks usings, BeltUpdates, the wait loop, the
per-belt copy+Task.Run, NearestAsteroid (dead/broken reader), the private
UpdateAsteroidTransforms, and AsteroidBelt's four pose fields plus their
allocations. ~65 lines, matching the cut map's estimate.
miningprobe, densest zone of the operator's save (EAC-2265, 809 asteroids,
8 belts), rebuilt against this cut and rerun 10x each side:
before (branch point, 8bd25f6f/e729e6d6):
Zone.Update wall 541-3654 us/tick, CPU 120-391 us/tick (7 clean runs)
3/10 runs crashed: InvalidOperationException from Zone.GetOrbitPosition,
the documented _updatedOrbits/Orbits data race between the main thread's
Clear() and a belt Task.Run
after (this commit):
Zone.Update wall 95-185 us/tick, CPU 99-152 us/tick, in line with the
31-39 us "no belt work" baseline the map recorded -- belts are free per
tick
0/10 races
ChunkPose has no buffer to go stale: ~0.12 u of parent+asteroid motion is
visible across one 17 ms tick instead of being one tick behind
tests/Aetheria.Shared.Tests/MiningCut1Tests.cs (new, 260/260 suite green):
ChunkPoseIsTheOrbitAtZoneTime, ChunkPoseDoesNotDependOnUpdateCadence,
DamagedChunkShrinksAndABrokenOneHasNoSize -- each expected value is the
closed-form orbit/size rule reimplemented in the test, never a call to
AsteroidBelt.Pose/Size.
Negative grep (Zone.cs, "Zone Display", ServerShared/Behaviors) for
Task\.Run|System\.Threading|NewTransforms|\.Transforms\b|BeltUpdates|
NearestAsteroid|\.OrbitPosition\b|NewOrbitPosition: one hit, the commented
line in MineAsteroid that Cut 2 deletes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 01:27:16 +02:00
|
|
|
|
_beltTransforms[key] = new float4[beltData.Asteroids.Length];
|
2026-08-10 14:57:50 +01:00
|
|
|
|
var count = beltData.Asteroids.Length / meshes.Count;
|
|
|
|
|
|
var remainder = beltData.Asteroids.Length - count * meshes.Count;
|
|
|
|
|
|
for (int i = 0; i < meshes.Count; i++)
|
2020-12-03 17:32:34 +00:00
|
|
|
|
{
|
Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.
Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.
The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
drew the item's schematic texture and tinted hull hardpoints, which need
the parent document. The tagged Studio hands a drawer only the value, so
those wait on the Studio exposing the open record.
Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
reaches CultMath values and refs. Keyboard layouts need no resolver and
keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.
Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
|
|
|
|
_beltMatrices[key][i] = new Matrix4x4[i < meshes.Count - 1 ? count : count + remainder];
|
2020-12-03 17:32:34 +00:00
|
|
|
|
}
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
2026-10-16 23:26:26 +02:00
|
|
|
|
Map.RegisterBelt(key, _beltTransforms[key]);
|
2020-11-27 22:47:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
PlanetObject planet;
|
|
|
|
|
|
if (planetData is GasGiantData gasGiantData)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (planetData is SunData sunData)
|
|
|
|
|
|
{
|
|
|
|
|
|
planet = Instantiate(Sun, ZoneRoot);
|
|
|
|
|
|
var sunObject = (SunObject) planet;
|
Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.
Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.
The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
drew the item's schematic texture and tinted hull hardpoints, which need
the parent document. The tagged Studio hands a drawer only the value, so
those wait on the Studio exposing the open record.
Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
reaches CultMath values and refs. Keyboard layouts need no resolver and
keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.
Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
|
|
|
|
var sun = Zone.PlanetInstances[key] as Sun;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
sunObject.Light.color = sunData.LightColor.ToColor();
|
|
|
|
|
|
sunObject.Light.range = sun.LightRadius;
|
|
|
|
|
|
sunObject.FogTint.transform.localScale = sun.LightRadius * Vector3.one;
|
|
|
|
|
|
sunObject.FogTint.material.SetColor("_Color", sunData.FogTintColor.ToColor());
|
|
|
|
|
|
}
|
|
|
|
|
|
else planet = Instantiate(GasGiant, ZoneRoot);
|
|
|
|
|
|
|
|
|
|
|
|
var gas = (GasGiantObject) planet;
|
|
|
|
|
|
gas.Body.material.SetTexture("_ColorRamp", gasGiantData.Colors.ToGradient(!(planetData is SunData)).ToTexture());
|
|
|
|
|
|
// gasGiantData.AlbedoRotationSpeed.Subscribe(f => gas.SunMaterial.AlbedoRotationSpeed = f);
|
|
|
|
|
|
// gasGiantData.FirstOffsetRotationSpeed.Subscribe(f => gas.SunMaterial.FirstOffsetRotationSpeed = f);
|
|
|
|
|
|
// gasGiantData.SecondOffsetRotationSpeed.Subscribe(f => gas.SunMaterial.SecondOffsetRotationSpeed = f);
|
|
|
|
|
|
// gasGiantData.FirstOffsetDomainRotationSpeed.Subscribe(f => gas.SunMaterial.FirstOffsetDomainRotationSpeed = f);
|
|
|
|
|
|
// gasGiantData.SecondOffsetDomainRotationSpeed.Subscribe(f => gas.SunMaterial.SecondOffsetDomainRotationSpeed = f);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
planet = Instantiate(Planet, ZoneRoot);
|
|
|
|
|
|
var possibleSettings = Settings.BodySettingsCollections
|
|
|
|
|
|
.Where(p => p.MinimumMass < planetData.Mass)
|
|
|
|
|
|
.MaxBy(p => p.MinimumMass).BodySettings;
|
2026-06-22 00:36:28 +01:00
|
|
|
|
planet.Generator.body = possibleSettings[Random.Range(0, possibleSettings.Length)];
|
2026-08-10 14:57:50 +01:00
|
|
|
|
//Debug.Log($"Generating planet with {planetData.Mass} mass! Choosing {planet.Generator.body.name} settings!");
|
|
|
|
|
|
//planet.Icon.material.mainTexture = planetData.Mass > Context.GlobalData.PlanetMass ? PlanetIcon : PlanetoidIcon;
|
|
|
|
|
|
}
|
2020-11-29 22:50:12 +00:00
|
|
|
|
|
Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.
Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.
The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
drew the item's schematic texture and tinted hull hardpoints, which need
the parent document. The tagged Studio hands a drawer only the value, so
those wait on the Studio exposing the open record.
Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
reaches CultMath values and refs. Keyboard layouts need no resolver and
keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.
Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
|
|
|
|
var planetInstance = Zone.PlanetInstances[key];
|
2026-08-10 14:57:50 +01:00
|
|
|
|
planet.Body.transform.localScale = planetInstance.BodyRadius * Vector3.one;
|
2026-10-16 23:26:26 +02:00
|
|
|
|
Map.RegisterPlanet(key, planet.Icon, planet.transform);
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2020-12-01 00:16:11 +00:00
|
|
|
|
|
Replace the Database Tools with the Studio and cut Unity over
Cut 8b. The Unity project compiles with 0 errors in 6000.3.24f1 batchmode.
Packages: manifest.json pins org.gamecult.cultlib at cultlib-unity-v1.0.57
and org.gamecult.caching.unity at caching-unity-v1.2.0, next to the 8a
CultMath tag. Aetheria.Shared.Unity references GameCult.CultLib and keeps
noEngineReferences.
The Database Tools (Assets/Scripts/CultCache/Editor) are deleted in this
commit, alongside their five ported drawers in
Assets/Scripts/Editor/CultCacheDrawers.cs, each an
[CultInspectorDrawer] ICultInspectorDrawer:
- InspectableType: popup of the attribute type's [Union] member names,
writing the string.
- InspectableColor: float3 and float4 through ColorField.
- InspectableAnimationCurve: float4[] and BezierCurve through CurveField.
- InspectableTemperature: Kelvin, Celsius and Fahrenheit fields over one
value.
- InspectableSchematicShape: size and cell toggles. The old drawer also
drew the item's schematic texture and tinted hull hardpoints, which need
the parent document. The tagged Studio hands a drawer only the value, so
those wait on the Studio exposing the open record.
Unity call sites:
- ActionGameManager opens the catalog through AetheriaStores; Cut 10 adds
the run and player stores.
- Refs resolve through ItemManager.GetData or Get(ref); orbit, planet and
belt maps key by CultRecordKey; identity is compared by reference or key.
- The PlayerSettings.msgpack reader and writer, which Cut 10 deletes, pass
CultDocumentMessagePackSerialization.OptionsFor, since the embedded run
reaches CultMath values and refs. Keyboard layouts need no resolver and
keep MessagePack's defaults until Cut 10.
- The input map uses the nested action to binding shape.
- PropertiesPanel reads CultInspectorRangeAttribute.
- NameTools loses its legacy name-file writer.
- Slime compares serialized settings instead of the deleted SHA1 helper.
- FieldDriver drops InspectorHeader.
- .gitignore covers the test project's build output.
Builds: Aetheria.Shared, AetherDb, Aetheria.Shared.Tests (6/6), Unity
batchmode (0 errors).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:15:20 +02:00
|
|
|
|
Planets[key] = planet;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
if (!_rootFound)
|
|
|
|
|
|
{
|
|
|
|
|
|
_rootFound = true;
|
|
|
|
|
|
_root = planet;
|
|
|
|
|
|
}
|
2020-12-05 23:43:02 +00:00
|
|
|
|
}
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2020-12-05 23:43:02 +00:00
|
|
|
|
LODHandler.FindPlanets();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-16 23:26:26 +02:00
|
|
|
|
void LateUpdate()
|
|
|
|
|
|
{
|
|
|
|
|
|
Map.Draw(Zone, ActionGameManager.Clock.Lead);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-22 03:13:43 +00:00
|
|
|
|
void Update()
|
2020-11-29 22:50:12 +00:00
|
|
|
|
{
|
Draw every moving body at the drawn time T = ExactTime + Lead
Planets, belts, wells, loot, mines, stations, the chunk reticle and the flow
clock are evaluated through DrawAhead (Time, Orbit, Height, Position) at one
drawn time; the rail law lives once in Zone.Offset; OrbitPositionAt, GetHeight,
ChunkPose, EvaluateBelt and RideHeight take a time. Fixes the planet jumping
against a co-moving ship at display rates above the step rate.
Not yet built or run (Unity presenter files are verified by compile only on
Starfire).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 21:26:36 +02:00
|
|
|
|
var lead = ActionGameManager.Clock.Lead;
|
|
|
|
|
|
GravityLowering.Lower(Zone, lead, ref _gravityWells);
|
Unity draws Zone.FloatingItems and nothing else; the Unity loot roll, collision pickup, tractor pull and GridObject are gone
ZoneRenderer draws one ItemPickup per FloatingItem (load, ObserveAdd, ObserveRemove, ClearZone); ItemPickup.Bind places it
from the sim body and spins it for show. EntityInstance's drop loops, ShieldManager's pickup branch (the whole
OnCollisionEnter, which did nothing else), ZoneRenderer.DropItem/DestroyLoot/_loot, TractorBeam's pull, and
GameSettings' three loot fields are deleted; WireFloatingItems stripped GridObject from the five pickup prefabs and
reassigned ZoneRenderer's four pickup fields in ARPG.unity; FloatingItemsDrawnSmoke (play session, batchmode) pins the
lowering. GridObject and TimedDestroy were deleted in fa911f2d, so fa911f2d and 2565e2c5 do not build in Unity.
Assets/Resources/Settings.asset keeps three stale serialized GameSettings fields Unity ignores (LFS object, not rewritten).
Builds: Unity batchmode compile green at this commit; dotnet green at 2565e2c5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:36:47 +02:00
|
|
|
|
foreach (var loot in _floatingItems.Values)
|
2021-04-18 05:13:20 +01:00
|
|
|
|
{
|
Presenters read the drawn pose: HUD markers, wells, rounds, ping, shield hit, compass, loot view, guided aim
HUD target, lock, incoming-lock, bearing and sweep markers anchor on DrawAhead.Position / AtBearing at Clock.Lead.
GravityLowering's record fill is DrawAhead.Well (pure, pinned at non-zero lead). Rounds take DrawAhead.Time
instead of float Zone.Time + lead. Sensor ping, shield hit, compass icons, wormhole bearing, loot ViewOrigin and
the guided-projectile aim read the drawn pose. Not built in Unity yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 23:41:49 +02:00
|
|
|
|
loot.ViewOrigin = DrawAhead.Position(PerspectiveEntity, lead);
|
2026-10-07 12:33:20 +02:00
|
|
|
|
loot.ViewDirection = PerspectiveEntity.Aim;
|
2021-04-18 05:13:20 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-07-11 08:14:00 +01:00
|
|
|
|
// if (SlimeRenderer.SpawnPositions.Length != _suns.Length)
|
|
|
|
|
|
// SlimeRenderer.SpawnPositions = new Vector2[_suns.Length];
|
|
|
|
|
|
// for (var i = 0; i < _suns.Length; i++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// SlimeRenderer.SpawnPositions[i] = _suns[i].Body.transform.position.Flatland();
|
|
|
|
|
|
// }
|
2022-07-19 18:55:17 +01:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
Shader.SetGlobalFloat("_AsteroidVerticalOffset", ActionGameManager.Instance.Settings.PlanetSettings.AsteroidVerticalOffset);
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2022-07-19 18:55:17 +01:00
|
|
|
|
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(MainCamera);
|
|
|
|
|
|
bool isVisible(Bounds bounds) => GeometryUtility.TestPlanesAABB(planes, bounds);
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
foreach (var (key, belt) in Zone.AsteroidBelts)
|
2020-11-29 22:50:12 +00:00
|
|
|
|
{
|
Cut 1: belts are evaluated when asked, not simulated every tick
Zone.Update no longer threads a per-belt Task.Run over a double-buffered
Transforms/OrbitPosition pair. AsteroidBelt.Pose/Size are the one place a
chunk pose is computed, a pure function of zone time; Zone.ChunkPose and
Zone.EvaluateBelt read them at the zone's own time. MiningTool,
ResourceScanner and ZoneRenderer (belt matrices and AsteroidBeltUI) all read
through Zone instead of the deleted per-tick buffers; the renderer owns its
own float4[] buffer, filled fresh every frame.
Deleted: System.Threading/.Tasks usings, BeltUpdates, the wait loop, the
per-belt copy+Task.Run, NearestAsteroid (dead/broken reader), the private
UpdateAsteroidTransforms, and AsteroidBelt's four pose fields plus their
allocations. ~65 lines, matching the cut map's estimate.
miningprobe, densest zone of the operator's save (EAC-2265, 809 asteroids,
8 belts), rebuilt against this cut and rerun 10x each side:
before (branch point, 8bd25f6f/e729e6d6):
Zone.Update wall 541-3654 us/tick, CPU 120-391 us/tick (7 clean runs)
3/10 runs crashed: InvalidOperationException from Zone.GetOrbitPosition,
the documented _updatedOrbits/Orbits data race between the main thread's
Clear() and a belt Task.Run
after (this commit):
Zone.Update wall 95-185 us/tick, CPU 99-152 us/tick, in line with the
31-39 us "no belt work" baseline the map recorded -- belts are free per
tick
0/10 races
ChunkPose has no buffer to go stale: ~0.12 u of parent+asteroid motion is
visible across one 17 ms tick instead of being one tick behind
tests/Aetheria.Shared.Tests/MiningCut1Tests.cs (new, 260/260 suite green):
ChunkPoseIsTheOrbitAtZoneTime, ChunkPoseDoesNotDependOnUpdateCadence,
DamagedChunkShrinksAndABrokenOneHasNoSize -- each expected value is the
closed-form orbit/size rule reimplemented in the test, never a call to
AsteroidBelt.Pose/Size.
Negative grep (Zone.cs, "Zone Display", ServerShared/Behaviors) for
Task\.Run|System\.Threading|NewTransforms|\.Transforms\b|BeltUpdates|
NearestAsteroid|\.OrbitPosition\b|NewOrbitPosition: one hit, the commented
line in MineAsteroid that Cut 2 deletes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 01:27:16 +02:00
|
|
|
|
// Cut 1 (docs/mining-cut.md): belts have no stored pose any more. The renderer fills its own buffer
|
Draw every moving body at the drawn time T = ExactTime + Lead
Planets, belts, wells, loot, mines, stations, the chunk reticle and the flow
clock are evaluated through DrawAhead (Time, Orbit, Height, Position) at one
drawn time; the rail law lives once in Zone.Offset; OrbitPositionAt, GetHeight,
ChunkPose, EvaluateBelt and RideHeight take a time. Fixes the planet jumping
against a co-moving ship at display rates above the step rate.
Not yet built or run (Unity presenter files are verified by compile only on
Starfire).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 21:26:36 +02:00
|
|
|
|
// from Zone.EvaluateBelt, at the drawn time (DrawAhead.Time), every frame.
|
|
|
|
|
|
var orbitPosition = DrawAhead.Orbit(Zone, Zone.Orbits[belt.Data.Orbit.Key].Data.Parent.Key, lead);
|
|
|
|
|
|
var height = DrawAhead.Height(Zone, orbitPosition, lead);
|
Cut 1: belts are evaluated when asked, not simulated every tick
Zone.Update no longer threads a per-belt Task.Run over a double-buffered
Transforms/OrbitPosition pair. AsteroidBelt.Pose/Size are the one place a
chunk pose is computed, a pure function of zone time; Zone.ChunkPose and
Zone.EvaluateBelt read them at the zone's own time. MiningTool,
ResourceScanner and ZoneRenderer (belt matrices and AsteroidBeltUI) all read
through Zone instead of the deleted per-tick buffers; the renderer owns its
own float4[] buffer, filled fresh every frame.
Deleted: System.Threading/.Tasks usings, BeltUpdates, the wait loop, the
per-belt copy+Task.Run, NearestAsteroid (dead/broken reader), the private
UpdateAsteroidTransforms, and AsteroidBelt's four pose fields plus their
allocations. ~65 lines, matching the cut map's estimate.
miningprobe, densest zone of the operator's save (EAC-2265, 809 asteroids,
8 belts), rebuilt against this cut and rerun 10x each side:
before (branch point, 8bd25f6f/e729e6d6):
Zone.Update wall 541-3654 us/tick, CPU 120-391 us/tick (7 clean runs)
3/10 runs crashed: InvalidOperationException from Zone.GetOrbitPosition,
the documented _updatedOrbits/Orbits data race between the main thread's
Clear() and a belt Task.Run
after (this commit):
Zone.Update wall 95-185 us/tick, CPU 99-152 us/tick, in line with the
31-39 us "no belt work" baseline the map recorded -- belts are free per
tick
0/10 races
ChunkPose has no buffer to go stale: ~0.12 u of parent+asteroid motion is
visible across one 17 ms tick instead of being one tick behind
tests/Aetheria.Shared.Tests/MiningCut1Tests.cs (new, 260/260 suite green):
ChunkPoseIsTheOrbitAtZoneTime, ChunkPoseDoesNotDependOnUpdateCadence,
DamagedChunkShrinksAndABrokenOneHasNoSize -- each expected value is the
closed-form orbit/size rule reimplemented in the test, never a call to
AsteroidBelt.Pose/Size.
Negative grep (Zone.cs, "Zone Display", ServerShared/Behaviors) for
Task\.Run|System\.Threading|NewTransforms|\.Transforms\b|BeltUpdates|
NearestAsteroid|\.OrbitPosition\b|NewOrbitPosition: one hit, the commented
line in MineAsteroid that Cut 2 deletes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 01:27:16 +02:00
|
|
|
|
var transforms = _beltTransforms[key];
|
Draw every moving body at the drawn time T = ExactTime + Lead
Planets, belts, wells, loot, mines, stations, the chunk reticle and the flow
clock are evaluated through DrawAhead (Time, Orbit, Height, Position) at one
drawn time; the rail law lives once in Zone.Offset; OrbitPositionAt, GetHeight,
ChunkPose, EvaluateBelt and RideHeight take a time. Fixes the planet jumping
against a co-moving ship at display rates above the step rate.
Not yet built or run (Unity presenter files are verified by compile only on
Starfire).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 21:26:36 +02:00
|
|
|
|
Zone.EvaluateBelt(key, transforms, DrawAhead.Time(Zone, lead));
|
2026-08-10 14:57:50 +01:00
|
|
|
|
if(isVisible(new Bounds(
|
Cut 1: belts are evaluated when asked, not simulated every tick
Zone.Update no longer threads a per-belt Task.Run over a double-buffered
Transforms/OrbitPosition pair. AsteroidBelt.Pose/Size are the one place a
chunk pose is computed, a pure function of zone time; Zone.ChunkPose and
Zone.EvaluateBelt read them at the zone's own time. MiningTool,
ResourceScanner and ZoneRenderer (belt matrices and AsteroidBeltUI) all read
through Zone instead of the deleted per-tick buffers; the renderer owns its
own float4[] buffer, filled fresh every frame.
Deleted: System.Threading/.Tasks usings, BeltUpdates, the wait loop, the
per-belt copy+Task.Run, NearestAsteroid (dead/broken reader), the private
UpdateAsteroidTransforms, and AsteroidBelt's four pose fields plus their
allocations. ~65 lines, matching the cut map's estimate.
miningprobe, densest zone of the operator's save (EAC-2265, 809 asteroids,
8 belts), rebuilt against this cut and rerun 10x each side:
before (branch point, 8bd25f6f/e729e6d6):
Zone.Update wall 541-3654 us/tick, CPU 120-391 us/tick (7 clean runs)
3/10 runs crashed: InvalidOperationException from Zone.GetOrbitPosition,
the documented _updatedOrbits/Orbits data race between the main thread's
Clear() and a belt Task.Run
after (this commit):
Zone.Update wall 95-185 us/tick, CPU 99-152 us/tick, in line with the
31-39 us "no belt work" baseline the map recorded -- belts are free per
tick
0/10 races
ChunkPose has no buffer to go stale: ~0.12 u of parent+asteroid motion is
visible across one 17 ms tick instead of being one tick behind
tests/Aetheria.Shared.Tests/MiningCut1Tests.cs (new, 260/260 suite green):
ChunkPoseIsTheOrbitAtZoneTime, ChunkPoseDoesNotDependOnUpdateCadence,
DamagedChunkShrinksAndABrokenOneHasNoSize -- each expected value is the
closed-form orbit/size rule reimplemented in the test, never a call to
AsteroidBelt.Pose/Size.
Negative grep (Zone.cs, "Zone Display", ServerShared/Behaviors) for
Task\.Run|System\.Threading|NewTransforms|\.Transforms\b|BeltUpdates|
NearestAsteroid|\.OrbitPosition\b|NewOrbitPosition: one hit, the commented
line in MineAsteroid that Cut 2 deletes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 01:27:16 +02:00
|
|
|
|
new Vector3(orbitPosition.x,height,orbitPosition.y),
|
2026-08-10 14:57:50 +01:00
|
|
|
|
new Vector3(belt.Radius * 2,100,belt.Radius * 2))))
|
2020-11-29 22:50:12 +00:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
var meshes = _beltMeshes[key];
|
|
|
|
|
|
var matrices = _beltMatrices[key];
|
Cut 1: belts are evaluated when asked, not simulated every tick
Zone.Update no longer threads a per-belt Task.Run over a double-buffered
Transforms/OrbitPosition pair. AsteroidBelt.Pose/Size are the one place a
chunk pose is computed, a pure function of zone time; Zone.ChunkPose and
Zone.EvaluateBelt read them at the zone's own time. MiningTool,
ResourceScanner and ZoneRenderer (belt matrices and AsteroidBeltUI) all read
through Zone instead of the deleted per-tick buffers; the renderer owns its
own float4[] buffer, filled fresh every frame.
Deleted: System.Threading/.Tasks usings, BeltUpdates, the wait loop, the
per-belt copy+Task.Run, NearestAsteroid (dead/broken reader), the private
UpdateAsteroidTransforms, and AsteroidBelt's four pose fields plus their
allocations. ~65 lines, matching the cut map's estimate.
miningprobe, densest zone of the operator's save (EAC-2265, 809 asteroids,
8 belts), rebuilt against this cut and rerun 10x each side:
before (branch point, 8bd25f6f/e729e6d6):
Zone.Update wall 541-3654 us/tick, CPU 120-391 us/tick (7 clean runs)
3/10 runs crashed: InvalidOperationException from Zone.GetOrbitPosition,
the documented _updatedOrbits/Orbits data race between the main thread's
Clear() and a belt Task.Run
after (this commit):
Zone.Update wall 95-185 us/tick, CPU 99-152 us/tick, in line with the
31-39 us "no belt work" baseline the map recorded -- belts are free per
tick
0/10 races
ChunkPose has no buffer to go stale: ~0.12 u of parent+asteroid motion is
visible across one 17 ms tick instead of being one tick behind
tests/Aetheria.Shared.Tests/MiningCut1Tests.cs (new, 260/260 suite green):
ChunkPoseIsTheOrbitAtZoneTime, ChunkPoseDoesNotDependOnUpdateCadence,
DamagedChunkShrinksAndABrokenOneHasNoSize -- each expected value is the
closed-form orbit/size rule reimplemented in the test, never a call to
AsteroidBelt.Pose/Size.
Negative grep (Zone.cs, "Zone Display", ServerShared/Behaviors) for
Task\.Run|System\.Threading|NewTransforms|\.Transforms\b|BeltUpdates|
NearestAsteroid|\.OrbitPosition\b|NewOrbitPosition: one hit, the commented
line in MineAsteroid that Cut 2 deletes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 01:27:16 +02:00
|
|
|
|
var count = transforms.Length / meshes.Length;
|
2022-07-19 18:55:17 +01:00
|
|
|
|
for (int i = 0; i < meshes.Length; i++)
|
2020-12-03 17:32:34 +00:00
|
|
|
|
{
|
2022-07-19 18:55:17 +01:00
|
|
|
|
for (int t = 0; t < matrices[i].Length; t++)
|
|
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
var tx = t + i * count;
|
Cut 1: belts are evaluated when asked, not simulated every tick
Zone.Update no longer threads a per-belt Task.Run over a double-buffered
Transforms/OrbitPosition pair. AsteroidBelt.Pose/Size are the one place a
chunk pose is computed, a pure function of zone time; Zone.ChunkPose and
Zone.EvaluateBelt read them at the zone's own time. MiningTool,
ResourceScanner and ZoneRenderer (belt matrices and AsteroidBeltUI) all read
through Zone instead of the deleted per-tick buffers; the renderer owns its
own float4[] buffer, filled fresh every frame.
Deleted: System.Threading/.Tasks usings, BeltUpdates, the wait loop, the
per-belt copy+Task.Run, NearestAsteroid (dead/broken reader), the private
UpdateAsteroidTransforms, and AsteroidBelt's four pose fields plus their
allocations. ~65 lines, matching the cut map's estimate.
miningprobe, densest zone of the operator's save (EAC-2265, 809 asteroids,
8 belts), rebuilt against this cut and rerun 10x each side:
before (branch point, 8bd25f6f/e729e6d6):
Zone.Update wall 541-3654 us/tick, CPU 120-391 us/tick (7 clean runs)
3/10 runs crashed: InvalidOperationException from Zone.GetOrbitPosition,
the documented _updatedOrbits/Orbits data race between the main thread's
Clear() and a belt Task.Run
after (this commit):
Zone.Update wall 95-185 us/tick, CPU 99-152 us/tick, in line with the
31-39 us "no belt work" baseline the map recorded -- belts are free per
tick
0/10 races
ChunkPose has no buffer to go stale: ~0.12 u of parent+asteroid motion is
visible across one 17 ms tick instead of being one tick behind
tests/Aetheria.Shared.Tests/MiningCut1Tests.cs (new, 260/260 suite green):
ChunkPoseIsTheOrbitAtZoneTime, ChunkPoseDoesNotDependOnUpdateCadence,
DamagedChunkShrinksAndABrokenOneHasNoSize -- each expected value is the
closed-form orbit/size rule reimplemented in the test, never a call to
AsteroidBelt.Pose/Size.
Negative grep (Zone.cs, "Zone Display", ServerShared/Behaviors) for
Task\.Run|System\.Threading|NewTransforms|\.Transforms\b|BeltUpdates|
NearestAsteroid|\.OrbitPosition\b|NewOrbitPosition: one hit, the commented
line in MineAsteroid that Cut 2 deletes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 01:27:16 +02:00
|
|
|
|
var transform = transforms[tx];
|
2026-08-10 14:57:50 +01:00
|
|
|
|
matrices[i][t] = Matrix4x4.TRS(new Vector3(transform.x,0,transform.y),
|
2022-07-19 18:55:17 +01:00
|
|
|
|
Quaternion.Euler(
|
2026-08-10 14:57:50 +01:00
|
|
|
|
cos(transform.z + (float)i / meshes.Length) * 100,
|
|
|
|
|
|
sin(transform.z + (float)i / meshes.Length) * 100,
|
Cut 1: belts are evaluated when asked, not simulated every tick
Zone.Update no longer threads a per-belt Task.Run over a double-buffered
Transforms/OrbitPosition pair. AsteroidBelt.Pose/Size are the one place a
chunk pose is computed, a pure function of zone time; Zone.ChunkPose and
Zone.EvaluateBelt read them at the zone's own time. MiningTool,
ResourceScanner and ZoneRenderer (belt matrices and AsteroidBeltUI) all read
through Zone instead of the deleted per-tick buffers; the renderer owns its
own float4[] buffer, filled fresh every frame.
Deleted: System.Threading/.Tasks usings, BeltUpdates, the wait loop, the
per-belt copy+Task.Run, NearestAsteroid (dead/broken reader), the private
UpdateAsteroidTransforms, and AsteroidBelt's four pose fields plus their
allocations. ~65 lines, matching the cut map's estimate.
miningprobe, densest zone of the operator's save (EAC-2265, 809 asteroids,
8 belts), rebuilt against this cut and rerun 10x each side:
before (branch point, 8bd25f6f/e729e6d6):
Zone.Update wall 541-3654 us/tick, CPU 120-391 us/tick (7 clean runs)
3/10 runs crashed: InvalidOperationException from Zone.GetOrbitPosition,
the documented _updatedOrbits/Orbits data race between the main thread's
Clear() and a belt Task.Run
after (this commit):
Zone.Update wall 95-185 us/tick, CPU 99-152 us/tick, in line with the
31-39 us "no belt work" baseline the map recorded -- belts are free per
tick
0/10 races
ChunkPose has no buffer to go stale: ~0.12 u of parent+asteroid motion is
visible across one 17 ms tick instead of being one tick behind
tests/Aetheria.Shared.Tests/MiningCut1Tests.cs (new, 260/260 suite green):
ChunkPoseIsTheOrbitAtZoneTime, ChunkPoseDoesNotDependOnUpdateCadence,
DamagedChunkShrinksAndABrokenOneHasNoSize -- each expected value is the
closed-form orbit/size rule reimplemented in the test, never a call to
AsteroidBelt.Pose/Size.
Negative grep (Zone.cs, "Zone Display", ServerShared/Behaviors) for
Task\.Run|System\.Threading|NewTransforms|\.Transforms\b|BeltUpdates|
NearestAsteroid|\.OrbitPosition\b|NewOrbitPosition: one hit, the commented
line in MineAsteroid that Cut 2 deletes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 01:27:16 +02:00
|
|
|
|
(float)tx / transforms.Length * 360),
|
2026-08-10 14:57:50 +01:00
|
|
|
|
Vector3.one * transform.w);
|
2022-07-19 18:55:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Graphics.DrawMeshInstanced(meshes[i].Mesh, 0, meshes[i].Material, matrices[i]);
|
2020-12-03 17:32:34 +00:00
|
|
|
|
}
|
2020-11-29 22:50:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-04-15 04:25:22 +01:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
foreach (var planet in Planets)
|
2020-11-27 22:47:33 +00:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
var planetInstance = Zone.PlanetInstances[planet.Key];
|
Draw every moving body at the drawn time T = ExactTime + Lead
Planets, belts, wells, loot, mines, stations, the chunk reticle and the flow
clock are evaluated through DrawAhead (Time, Orbit, Height, Position) at one
drawn time; the rail law lives once in Zone.Offset; OrbitPositionAt, GetHeight,
ChunkPose, EvaluateBelt and RideHeight take a time. Fixes the planet jumping
against a co-moving ship at display rates above the step rate.
Not yet built or run (Unity presenter files are verified by compile only on
Starfire).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 21:26:36 +02:00
|
|
|
|
var p = DrawAhead.Orbit(Zone, planetInstance.BodyData.Orbit.Key, lead);
|
|
|
|
|
|
var height = DrawAhead.Height(Zone, p, lead);
|
2020-12-18 13:48:03 +00:00
|
|
|
|
planet.Value.transform.position = new Vector3(p.x, 0, p.y);
|
2026-08-10 14:57:50 +01:00
|
|
|
|
planet.Value.Body.transform.localPosition = new Vector3(0, height + planetInstance.BodyRadius * 2, 0);
|
2021-04-15 04:25:22 +01:00
|
|
|
|
if (planet.Value is GasGiantObject gasGiantObject)
|
2020-12-01 00:16:11 +00:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
if (!(planet.Value is SunObject))
|
2020-12-01 20:38:28 +00:00
|
|
|
|
{
|
Draw every moving body at the drawn time T = ExactTime + Lead
Planets, belts, wells, loot, mines, stations, the chunk reticle and the flow
clock are evaluated through DrawAhead (Time, Orbit, Height, Position) at one
drawn time; the rail law lives once in Zone.Offset; OrbitPositionAt, GetHeight,
ChunkPose, EvaluateBelt and RideHeight take a time. Fixes the planet jumping
against a co-moving ship at display rates above the step rate.
Not yet built or run (Unity presenter files are verified by compile only on
Starfire).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 21:26:36 +02:00
|
|
|
|
var toParent = normalize(DrawAhead.Orbit(Zone, Zone.Orbits[planetInstance.BodyData.Orbit.Key].Data.Parent.Key, lead) - p);
|
2020-12-01 20:38:28 +00:00
|
|
|
|
gasGiantObject.SunMaterial.LightingDirection = new Vector3(toParent.x, 0, toParent.y);
|
|
|
|
|
|
}
|
2020-12-01 00:16:11 +00:00
|
|
|
|
}
|
2026-08-10 14:57:50 +01:00
|
|
|
|
else planet.Value.Body.transform.rotation *= Quaternion.AngleAxis(Settings.PlanetRotationSpeed, Vector3.up);
|
2020-11-27 22:47:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
foreach (var entityInstance in EntityInstances.Values)
|
2021-05-12 13:49:04 +01:00
|
|
|
|
{
|
|
|
|
|
|
if(entityInstance.CompassIcon)
|
|
|
|
|
|
{
|
Presenters read the drawn pose: HUD markers, wells, rounds, ping, shield hit, compass, loot view, guided aim
HUD target, lock, incoming-lock, bearing and sweep markers anchor on DrawAhead.Position / AtBearing at Clock.Lead.
GravityLowering's record fill is DrawAhead.Well (pure, pinned at non-zero lead). Rounds take DrawAhead.Time
instead of float Zone.Time + lead. Sensor ping, shield hit, compass icons, wormhole bearing, loot ViewOrigin and
the guided-projectile aim read the drawn pose. Not built in Unity yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 23:41:49 +02:00
|
|
|
|
var difference = DrawAhead.Position(entityInstance.Entity, lead).xz - DrawAhead.Position(PerspectiveEntity, lead).xz;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
var distance = length(difference);
|
|
|
|
|
|
|
|
|
|
|
|
entityInstance.CompassIcon.gameObject.SetActive(
|
2026-10-13 07:13:55 +02:00
|
|
|
|
PerspectiveEntity.ContactOf(entityInstance.Entity).Tracked &&
|
2026-08-10 14:57:50 +01:00
|
|
|
|
distance > _minimapDistance);
|
|
|
|
|
|
entityInstance.CompassIcon.transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg - 90);
|
2021-05-12 13:49:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-05-12 12:53:16 +02:00
|
|
|
|
foreach (var wormhole in WormholeInstances.Values)
|
|
|
|
|
|
{
|
Presenters read the drawn pose: HUD markers, wells, rounds, ping, shield hit, compass, loot view, guided aim
HUD target, lock, incoming-lock, bearing and sweep markers anchor on DrawAhead.Position / AtBearing at Clock.Lead.
GravityLowering's record fill is DrawAhead.Well (pure, pinned at non-zero lead). Rounds take DrawAhead.Time
instead of float Zone.Time + lead. Sensor ping, shield hit, compass icons, wormhole bearing, loot ViewOrigin and
the guided-projectile aim read the drawn pose. Not built in Unity yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 23:41:49 +02:00
|
|
|
|
var difference = wormhole.gravity.transform.position.Flatland() - DrawAhead.Position(PerspectiveEntity, lead).xz.ToUnity();
|
2021-05-12 12:53:16 +02:00
|
|
|
|
var distance = difference.magnitude;
|
|
|
|
|
|
wormhole.icon.gameObject.SetActive(distance > _minimapDistance);
|
2021-05-12 13:49:04 +01:00
|
|
|
|
wormhole.icon.transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg - 90);
|
2021-05-12 12:53:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-14 02:56:35 +00:00
|
|
|
|
// var gravPos = MinimapGravityQuad.transform.position;
|
|
|
|
|
|
// MinimapGravityQuad.transform.position = gravPos;
|
|
|
|
|
|
// MinimapTintQuad.transform.position = gravPos - Vector3.up*10;
|
2020-11-27 22:47:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-12-01 20:38:28 +00:00
|
|
|
|
|
2020-12-22 03:13:43 +00:00
|
|
|
|
|
2020-12-01 20:38:28 +00:00
|
|
|
|
[Serializable]
|
|
|
|
|
|
public class InstancedMesh
|
|
|
|
|
|
{
|
|
|
|
|
|
public Mesh Mesh;
|
|
|
|
|
|
public Material Material;
|
|
|
|
|
|
}
|