From a2b54889b4f4cf2f9aae4efc7de1f7d732974935 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 14 Sep 2026 19:00:42 +0200 Subject: [PATCH] Move the ServerShared data model onto CultLib's CultCache Cut 8b. Aetheria.Shared builds headless against GameCult.Caching and GameCult.Caching.MessagePack at the pinned CultLib; the pin guard also checks the Caching project exists. Documents: [CultDocument("aetheria.", "1")] with [MessagePackObject] and integer [Key]s on the Q7 concrete types (the eight ItemData leaves, Faction, FactionProductData, PersonalityAttribute, NameFile, OrbitData, the four BodyData leaves, SavedZone, SavedGame, PlayerSettings, InputLayout). SavedGame and PlayerSettings are [CultGlobal]; Name members are [CultName]. ItemData, CraftedItemData, EquippableItemData, BodyData and AgentTask lose [MessagePackObject]; BodyData and AgentTask lose their [Union]s. InputLayout moves into ServerShared so AetheriaStores can route it. References: Guid and DatabaseLink members become CultRecordRef; Guid-keyed maps become ref-keyed with [CultReference(..., many: true)]; ZonePack holds refs to orbit and body records. Runtime maps (Zone orbits, bodies and belts, cargo ItemsOfType, agent targets) key by CultRecordKey. Identity is the record key: ID comparisons become reference or key comparisons. StatModifierData.RequireBehavior is a simple type name. AetheriaStores.Open composes the catalog (read-only unless writable), run and player stores, one home per type. CultRecordRefs carries IsSet, a null-safe Get(ref), RefOf (key from TryGetHandle) and Upsert. ItemManager.GetData is the one item resolution path. MathResolver is declared by [assembly: CultCacheFormatterResolver]. Inspector attributes: text, range and asset path map onto CultLib's CultInspector attributes (asset path only on string members); every replaced Aetheria attribute keeps [Inspectable] for the runtime panel. Builds: Aetheria.Shared. Does not build: AetherDb and the Unity project, which follow. Co-Authored-By: Claude Opus 5 --- Aetheria.Shared/Aetheria.Shared.csproj | 2 + Assets/Scripts/ServerShared/AetheriaStores.cs | 57 +++++++ .../ServerShared/AetheriaStores.cs.meta | 11 ++ .../ServerShared/Agents/States/MoveTo.cs | 3 +- .../ServerShared/Agents/Tasks/AgentTask.cs | 20 +-- .../ServerShared/Agents/Tasks/HaulingTask.cs | 3 +- .../ServerShared/Agents/Tasks/Mining.cs | 6 +- .../ServerShared/Agents/Tasks/PatrolOrbits.cs | 5 +- .../Agents/Tasks/StationTowing.cs | 6 +- .../ServerShared/Agents/Tasks/Survey.cs | 6 +- Assets/Scripts/ServerShared/AssemblyInfo.cs | 4 + .../Scripts/ServerShared/AssemblyInfo.cs.meta | 11 ++ .../ServerShared/Behaviors/AetherDrive.cs | 7 +- .../ServerShared/Behaviors/Behaviors.cs | 6 +- .../ServerShared/Behaviors/ConstantWeapon.cs | 8 +- .../ServerShared/Behaviors/Cooldown.cs | 2 +- .../ServerShared/Behaviors/EnergyDraw.cs | 2 +- Assets/Scripts/ServerShared/Behaviors/Heat.cs | 2 +- .../ServerShared/Behaviors/InstantWeapon.cs | 8 +- .../ServerShared/Behaviors/ItemUsage.cs | 11 +- .../ServerShared/Behaviors/MiningTool.cs | 7 +- .../ServerShared/Behaviors/ResourceScanner.cs | 9 +- .../ServerShared/Behaviors/StatModifier.cs | 28 ++-- .../Scripts/ServerShared/Behaviors/Switch.cs | 2 +- .../ServerShared/Behaviors/Thermotoggle.cs | 2 +- .../ServerShared/Behaviors/Thruster.cs | 3 +- .../Scripts/ServerShared/Behaviors/Trigger.cs | 2 +- .../ServerShared/Behaviors/VelocityLimit.cs | 1 - .../Scripts/ServerShared/Behaviors/Weapon.cs | 23 +-- Assets/Scripts/ServerShared/Behaviors/Wear.cs | 2 +- Assets/Scripts/ServerShared/Corporations.cs | 66 ++++---- Assets/Scripts/ServerShared/Entity.cs | 54 ++++--- .../Scripts/ServerShared/EntitySerializer.cs | 31 ++-- Assets/Scripts/ServerShared/Extensions.cs | 3 - Assets/Scripts/ServerShared/FactionProduct.cs | 24 ++- Assets/Scripts/ServerShared/Galaxy.cs | 24 +-- .../InputLayout.cs | 16 +- .../InputLayout.cs.meta | 0 Assets/Scripts/ServerShared/ItemData.cs | 68 ++++---- Assets/Scripts/ServerShared/ItemInstance.cs | 16 +- Assets/Scripts/ServerShared/ItemManager.cs | 75 +++------ .../Scripts/ServerShared/LoadoutGenerator.cs | 16 +- .../ServerShared/Narrative/ZoneConstraints.cs | 14 +- Assets/Scripts/ServerShared/OrbitalEntity.cs | 13 +- Assets/Scripts/ServerShared/PlayerSettings.cs | 3 +- Assets/Scripts/ServerShared/SavedGame.cs | 63 ++++---- Assets/Scripts/ServerShared/Zone.cs | 98 +++++------ Assets/Scripts/ServerShared/ZoneData.cs | 81 +++++----- Assets/Scripts/ServerShared/ZoneGenerator.cs | 153 ++++++++---------- Directory.Build.targets | 2 + 50 files changed, 537 insertions(+), 542 deletions(-) create mode 100644 Assets/Scripts/ServerShared/AetheriaStores.cs create mode 100644 Assets/Scripts/ServerShared/AetheriaStores.cs.meta create mode 100644 Assets/Scripts/ServerShared/AssemblyInfo.cs create mode 100644 Assets/Scripts/ServerShared/AssemblyInfo.cs.meta rename Assets/Scripts/{UI/InputScreen => ServerShared}/InputLayout.cs (91%) rename Assets/Scripts/{UI/InputScreen => ServerShared}/InputLayout.cs.meta (100%) diff --git a/Aetheria.Shared/Aetheria.Shared.csproj b/Aetheria.Shared/Aetheria.Shared.csproj index 3783e7469..5274558da 100644 --- a/Aetheria.Shared/Aetheria.Shared.csproj +++ b/Aetheria.Shared/Aetheria.Shared.csproj @@ -25,6 +25,8 @@ + + diff --git a/Assets/Scripts/ServerShared/AetheriaStores.cs b/Assets/Scripts/ServerShared/AetheriaStores.cs new file mode 100644 index 000000000..4394e89d6 --- /dev/null +++ b/Assets/Scripts/ServerShared/AetheriaStores.cs @@ -0,0 +1,57 @@ +using System; +using System.Linq; +using GameCult.Caching; +using GameCult.Caching.MessagePack; + +// Aetheria's stores: one home store per type, composed here and nowhere else. +public static class AetheriaStores +{ + public static readonly Type[] CatalogTypes = { typeof(ItemData), typeof(Faction), typeof(FactionProductData), typeof(PersonalityAttribute), typeof(NameFile) }; + public static readonly Type[] RunTypes = { typeof(OrbitData), typeof(BodyData), typeof(SavedZone), typeof(SavedGame) }; + public static readonly Type[] PlayerTypes = { typeof(PlayerSettings), typeof(InputLayout) }; + + // Attaches (hydrates) the catalog read-only unless catalogWritable, then the run and player stores when given. + // A read-only catalog throws when a [CultGlobal] type routed to it has no record. A writable catalog is being + // authored (the importer starts from an empty file), so it is not held to that. + public static CultCache Open(string catalogPath, string runPath = null, string playerPath = null, bool catalogWritable = false) + { + var cache = new CultCache(); + try + { + cache.AddBackingStore(new SingleFileMessagePackBackingStore(catalogPath, !catalogWritable), CatalogTypes); + if (runPath != null) cache.AddBackingStore(new SingleFileMessagePackBackingStore(runPath), RunTypes); + if (playerPath != null) cache.AddBackingStore(new SingleFileMessagePackBackingStore(playerPath), PlayerTypes); + var missing = catalogWritable ? null : cache.Registry.AllDescriptors.FirstOrDefault(descriptor => + descriptor.IsGlobal && + CatalogTypes.Any(home => home.IsAssignableFrom(descriptor.DocumentType)) && + cache.AllStoredDocuments.All(stored => stored.Descriptor != descriptor)); + if (missing != null) + throw new InvalidOperationException($"Catalog {catalogPath} has no {missing.SchemaName} record; catalog globals are authored, never invented."); + return cache; + } + catch + { + cache.Dispose(); + throw; + } + } +} + +public static class CultRecordRefs +{ + public static bool IsSet(this CultRecordKey key) => !string.IsNullOrEmpty(key.Value); + public static bool IsSet(this CultRecordRef reference) => reference.Key.IsSet(); + + // The document a reference names, or null when it is unset or names nothing this cache holds. + public static T Get(this CultCache cache, CultRecordRef reference) where T : class => + reference.IsSet() ? cache.Get(reference.Key) : null; + + // A reference to a document this cache holds. The key comes from the cache, never from the document. + public static CultRecordRef RefOf(this CultCache cache, T document) where T : class => + new CultRecordRef(cache.TryGetHandle(document)?.Key ?? + throw new InvalidOperationException($"This cache holds no such {document.GetType().Name}.")); + + // Writes a document to its home store; the cache mints its key the first time. + public static CultRecordRef Upsert(this CultCache cache, T document) where T : class => + new CultRecordRef(cache.UpsertAsync(document).Result.Key); +} diff --git a/Assets/Scripts/ServerShared/AetheriaStores.cs.meta b/Assets/Scripts/ServerShared/AetheriaStores.cs.meta new file mode 100644 index 000000000..7e8c26029 --- /dev/null +++ b/Assets/Scripts/ServerShared/AetheriaStores.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a37c91e4d05b4f8e82c6b1d9e4f0a2c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/ServerShared/Agents/States/MoveTo.cs b/Assets/Scripts/ServerShared/Agents/States/MoveTo.cs index 5aa1925fd..39c4e1135 100644 --- a/Assets/Scripts/ServerShared/Agents/States/MoveTo.cs +++ b/Assets/Scripts/ServerShared/Agents/States/MoveTo.cs @@ -1,4 +1,5 @@ +using GameCult.Caching; using System; using CultMath; using static CultMath.math; @@ -29,7 +30,7 @@ public abstract class MoveToState : BaseState public class MoveToOrbitState : MoveToState { - public Guid Orbit { get; set; } + public CultRecordKey Orbit { get; set; } public MoveToOrbitState(Agent agent) : base(agent) { } protected override float2 TargetPosition => _agent.Ship.Zone.GetOrbitPosition(Orbit); diff --git a/Assets/Scripts/ServerShared/Agents/Tasks/AgentTask.cs b/Assets/Scripts/ServerShared/Agents/Tasks/AgentTask.cs index 1e6e86fb8..26b70716c 100644 --- a/Assets/Scripts/ServerShared/Agents/Tasks/AgentTask.cs +++ b/Assets/Scripts/ServerShared/Agents/Tasks/AgentTask.cs @@ -1,31 +1,23 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; using System.Collections; using System.Collections.Generic; -using JsonKnownTypes; using MessagePack; using Newtonsoft.Json; -[MessagePackObject, - Union(0, typeof(StationTowing)), - Union(1, typeof(Mining)), - Union(2, typeof(Survey)), - Union(3, typeof(HaulingTask)), - JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] -public abstract class AgentTask : DatabaseEntry +// Agent tasks are owned by their Agent and not persisted. +[JsonObject(MemberSerialization.OptIn)] +public abstract class AgentTask { [JsonProperty("priority"), Key(1)] public int Priority; - - [JsonProperty("zone"), Key(2)] - public Guid Zone; - + [JsonProperty("reserved"), Key(3)] public bool Reserved; - + [IgnoreMember] public abstract TaskType Type { get; } } diff --git a/Assets/Scripts/ServerShared/Agents/Tasks/HaulingTask.cs b/Assets/Scripts/ServerShared/Agents/Tasks/HaulingTask.cs index 137fca75f..e657ef0aa 100644 --- a/Assets/Scripts/ServerShared/Agents/Tasks/HaulingTask.cs +++ b/Assets/Scripts/ServerShared/Agents/Tasks/HaulingTask.cs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using System; using System.Collections; using System.Collections.Generic; @@ -19,7 +20,7 @@ public class HaulingTask : AgentTask public Entity Target; [JsonProperty("itemType"), Key(6)] - public Guid ItemType; + public CultRecordKey ItemType; [JsonProperty("quantity"), Key(7)] public int Quantity; diff --git a/Assets/Scripts/ServerShared/Agents/Tasks/Mining.cs b/Assets/Scripts/ServerShared/Agents/Tasks/Mining.cs index d61cf31fa..e4e935519 100644 --- a/Assets/Scripts/ServerShared/Agents/Tasks/Mining.cs +++ b/Assets/Scripts/ServerShared/Agents/Tasks/Mining.cs @@ -2,19 +2,19 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using System; using System.Collections; using System.Collections.Generic; -using JsonKnownTypes; using MessagePack; using Newtonsoft.Json; [MessagePackObject, - JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] + JsonObject(MemberSerialization.OptIn)] public class Mining : AgentTask { [IgnoreMember] public override TaskType Type => TaskType.Mine; [JsonProperty("asteroids"), Key(4)] - public Guid Asteroids; + public CultRecordKey Asteroids; } \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/Agents/Tasks/PatrolOrbits.cs b/Assets/Scripts/ServerShared/Agents/Tasks/PatrolOrbits.cs index 653764217..f2a26771d 100644 --- a/Assets/Scripts/ServerShared/Agents/Tasks/PatrolOrbits.cs +++ b/Assets/Scripts/ServerShared/Agents/Tasks/PatrolOrbits.cs @@ -1,15 +1,16 @@ +using GameCult.Caching; using System; public class PatrolOrbitsTask : AgentTask { public override TaskType Type => TaskType.Defend; - public Guid[] Circuit; + public CultRecordKey[] Circuit; } public class PatrolOrbitsState : BaseState { public PatrolOrbitsTask Task; - public Guid CurrentTarget + public CultRecordKey CurrentTarget { get => Task.Circuit[_currentTargetIndex]; } diff --git a/Assets/Scripts/ServerShared/Agents/Tasks/StationTowing.cs b/Assets/Scripts/ServerShared/Agents/Tasks/StationTowing.cs index 926fc3cf8..e37eadaa5 100644 --- a/Assets/Scripts/ServerShared/Agents/Tasks/StationTowing.cs +++ b/Assets/Scripts/ServerShared/Agents/Tasks/StationTowing.cs @@ -2,15 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using System; using System.Collections; using System.Collections.Generic; -using JsonKnownTypes; using MessagePack; using Newtonsoft.Json; [MessagePackObject, - JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] + JsonObject(MemberSerialization.OptIn)] public class StationTowing : AgentTask { [IgnoreMember] public override TaskType Type => TaskType.Tow; @@ -19,7 +19,7 @@ public class StationTowing : AgentTask public OrbitalEntity Station; [JsonProperty("orbitParent"), Key(5)] - public Guid OrbitParent; + public CultRecordKey OrbitParent; [JsonProperty("orbitDistance"), Key(6)] public float OrbitDistance; diff --git a/Assets/Scripts/ServerShared/Agents/Tasks/Survey.cs b/Assets/Scripts/ServerShared/Agents/Tasks/Survey.cs index 5d43dcebc..787ee0a4f 100644 --- a/Assets/Scripts/ServerShared/Agents/Tasks/Survey.cs +++ b/Assets/Scripts/ServerShared/Agents/Tasks/Survey.cs @@ -2,19 +2,19 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using System; using System.Collections; using System.Collections.Generic; -using JsonKnownTypes; using MessagePack; using Newtonsoft.Json; [MessagePackObject, - JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] + JsonObject(MemberSerialization.OptIn)] public class Survey : AgentTask { [IgnoreMember] public override TaskType Type => TaskType.Explore; [JsonProperty("station"), Key(4)] - public List Planets; + public List Planets; } \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/AssemblyInfo.cs b/Assets/Scripts/ServerShared/AssemblyInfo.cs new file mode 100644 index 000000000..d632eca81 --- /dev/null +++ b/Assets/Scripts/ServerShared/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using GameCult.Caching.MessagePack; + +// CultCache serializes this assembly's documents with MathResolver ahead of MessagePack's standard resolvers. +[assembly: CultCacheFormatterResolver(typeof(MathResolver))] diff --git a/Assets/Scripts/ServerShared/AssemblyInfo.cs.meta b/Assets/Scripts/ServerShared/AssemblyInfo.cs.meta new file mode 100644 index 000000000..fd4671abe --- /dev/null +++ b/Assets/Scripts/ServerShared/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d8e2b7a1c4f4e3a9b6d0f2c8a1e7b43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/ServerShared/Behaviors/AetherDrive.cs b/Assets/Scripts/ServerShared/Behaviors/AetherDrive.cs index dd104f7f2..3e43ebc92 100644 --- a/Assets/Scripts/ServerShared/Behaviors/AetherDrive.cs +++ b/Assets/Scripts/ServerShared/Behaviors/AetherDrive.cs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using MessagePack; using Newtonsoft.Json; using CultMath; @@ -40,13 +41,13 @@ public class AetherDriveData : BehaviorData [Inspectable, JsonProperty("passiveCoupling"), Key(10), RuntimeInspectable] public PerformanceStat PassiveCoupling; - [InspectableAudioParameter, JsonProperty("rpmAudio"), Key(11), RuntimeInspectable] + [Inspectable, JsonProperty("rpmAudio"), Key(11), RuntimeInspectable] public uint RpmAudioParameter; - [InspectableAudioParameter, JsonProperty("torqueAudio"), Key(12), RuntimeInspectable] + [Inspectable, JsonProperty("torqueAudio"), Key(12), RuntimeInspectable] public uint TorqueRatioAudioParameter; - [InspectablePrefab, JsonProperty("particles"), Key(13)] + [Inspectable, CultInspectorAssetPath, JsonProperty("particles"), Key(13)] public string Particles; public override Behavior CreateInstance(EquippedItem item) diff --git a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs index 6fe54a95b..cd0cc98ec 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs @@ -6,7 +6,6 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using JsonKnownTypes; using MessagePack; using Newtonsoft.Json; using CultMath; @@ -142,8 +141,7 @@ public interface IPopulationAssignment } [MessagePackObject, - JsonObject(MemberSerialization.OptIn), - JsonConverter(typeof(JsonKnownTypesConverter))] + JsonObject(MemberSerialization.OptIn)] public abstract class PersistentBehaviorData { } @@ -187,7 +185,7 @@ public abstract class PersistentBehaviorData Union(36, typeof(ConstantWeaponData)), Union(37, typeof(ChargedWeaponData)), Union(38, typeof(AutoWeaponData)), - JsonConverter(typeof(JsonKnownTypesConverter)), JsonObject(MemberSerialization.OptIn)] + JsonObject(MemberSerialization.OptIn)] public abstract class BehaviorData { [Inspectable, JsonProperty("group"), Key(0)] diff --git a/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs b/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs index 2b2a1bbaa..7e4eaf1d5 100644 --- a/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs @@ -11,7 +11,7 @@ using static CultMath.math; [Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class ConstantWeaponData : WeaponData { - [InspectablePrefab, JsonProperty("ammoInterval"), Key(17)] + [Inspectable, JsonProperty("ammoInterval"), Key(17)] public float AmmoInterval = 1; public override Behavior CreateInstance(EquippedItem item) @@ -83,7 +83,7 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior OnStopFiring?.Invoke(); return false; } - if (_data.AmmoType != Guid.Empty) + if (_data.AmmoType.IsSet()) { if (_reloading) { @@ -103,10 +103,10 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior if (_data.MagazineSize > 1 && _ammo > 0) _ammo--; else { - var cargo = Entity.FindItemInCargo(_data.AmmoType); + var cargo = Entity.FindItemInCargo(_data.AmmoType.Key); if (cargo != null) { - var item = cargo.ItemsOfType[_data.AmmoType][0]; + var item = cargo.ItemsOfType[_data.AmmoType.Key][0]; if (item is SimpleCommodity simpleCommodity) cargo.Remove(simpleCommodity, 1); diff --git a/Assets/Scripts/ServerShared/Behaviors/Cooldown.cs b/Assets/Scripts/ServerShared/Behaviors/Cooldown.cs index 4d046db1d..88336cfe5 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Cooldown.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Cooldown.cs @@ -9,7 +9,7 @@ using Newtonsoft.Json; using CultMath; using static CultMath.math; -[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(-10), RuntimeInspectable] +[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), RuntimeInspectable] public class CooldownData : BehaviorData { [Inspectable, JsonProperty("cooldown"), Key(1), RuntimeInspectable] diff --git a/Assets/Scripts/ServerShared/Behaviors/EnergyDraw.cs b/Assets/Scripts/ServerShared/Behaviors/EnergyDraw.cs index faf8ae709..5fd4b9277 100644 --- a/Assets/Scripts/ServerShared/Behaviors/EnergyDraw.cs +++ b/Assets/Scripts/ServerShared/Behaviors/EnergyDraw.cs @@ -7,7 +7,7 @@ using System.Linq; using MessagePack; using Newtonsoft.Json; -[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(-20), RuntimeInspectable] +[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), RuntimeInspectable] public class EnergyDrawData : BehaviorData { [Inspectable, JsonProperty("draw"), Key(1), RuntimeInspectable] diff --git a/Assets/Scripts/ServerShared/Behaviors/Heat.cs b/Assets/Scripts/ServerShared/Behaviors/Heat.cs index e507d2b28..3d8914880 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Heat.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Heat.cs @@ -7,7 +7,7 @@ using System.Linq; using MessagePack; using Newtonsoft.Json; -[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(10)] +[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class HeatData : BehaviorData { [Inspectable, JsonProperty("heat"), Key(1), RuntimeInspectable] diff --git a/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs b/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs index aa59411d5..cf50f7494 100644 --- a/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs @@ -18,7 +18,7 @@ public class InstantWeaponData : WeaponData [Inspectable, JsonProperty("cooldown"), Key(19), RuntimeInspectable] public PerformanceStat Cooldown = new PerformanceStat(); - [InspectablePrefab, JsonProperty("ammoInterval"), Key(20)] + [Inspectable, JsonProperty("ammoInterval"), Key(20)] public bool SingleAmmoBurst; public override Behavior CreateInstance(EquippedItem item) @@ -124,12 +124,12 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior } var hasAmmo = true; - if (_data.AmmoType != Guid.Empty) + if (_data.AmmoType.IsSet()) { - var cargo = Entity.FindItemInCargo(_data.AmmoType); + var cargo = Entity.FindItemInCargo(_data.AmmoType.Key); if (cargo != null) { - var item = cargo.ItemsOfType[_data.AmmoType][0]; + var item = cargo.ItemsOfType[_data.AmmoType.Key][0]; if (item is SimpleCommodity simpleCommodity) cargo.Remove(simpleCommodity, 1); } diff --git a/Assets/Scripts/ServerShared/Behaviors/ItemUsage.cs b/Assets/Scripts/ServerShared/Behaviors/ItemUsage.cs index f5dda8a5f..e8c5e7dd0 100644 --- a/Assets/Scripts/ServerShared/Behaviors/ItemUsage.cs +++ b/Assets/Scripts/ServerShared/Behaviors/ItemUsage.cs @@ -2,16 +2,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using System; using System.Linq; using MessagePack; using Newtonsoft.Json; -[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(-5), RuntimeInspectable] +[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), RuntimeInspectable] public class ItemUsageData : BehaviorData { - [InspectableDatabaseLink(typeof(SimpleCommodityData)), JsonProperty("item"), Key(1), RuntimeInspectable] - public Guid Item; + [Inspectable, JsonProperty("item"), Key(1), RuntimeInspectable] + public CultRecordRef Item; public override Behavior CreateInstance(EquippedItem item) { @@ -40,10 +41,10 @@ public class ItemUsage : Behavior public override bool Execute(float dt) { - var cargo = Entity.FindItemInCargo(_data.Item); + var cargo = Entity.FindItemInCargo(_data.Item.Key); if (cargo == null) return false; - var item = cargo.ItemsOfType[_data.Item][0]; + var item = cargo.ItemsOfType[_data.Item.Key][0]; if (item is SimpleCommodity simpleCommodity) cargo.Remove(simpleCommodity, 1); if (item is CraftedItemInstance craftedItemInstance) diff --git a/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs b/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs index d13dc765c..f03c12fac 100644 --- a/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs +++ b/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using System; using System.Linq; using MessagePack; @@ -9,7 +10,7 @@ using Newtonsoft.Json; using CultMath; using static CultMath.math; -[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(10)] +[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class MiningToolData : BehaviorData { [Inspectable, JsonProperty("dps"), Key(1)] @@ -36,7 +37,7 @@ public class MiningToolData : BehaviorData public class MiningTool : Behavior { - public Guid AsteroidBelt; + public CultRecordKey AsteroidBelt; public int Asteroid; private MiningToolData _data; @@ -56,7 +57,7 @@ public class MiningTool : Behavior { Range = Evaluate(_data.Range); var belt = Entity.Zone.AsteroidBelts[AsteroidBelt]; - if (AsteroidBelt != Guid.Empty && + if (AsteroidBelt.IsSet() && Entity.Zone.AsteroidExists(AsteroidBelt, Asteroid) && length(Entity.Position.xz - belt.Transforms[Asteroid].xy) - belt.Transforms[Asteroid].w < Range) { diff --git a/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs b/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs index c7035c8ef..0b708cd96 100644 --- a/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs +++ b/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using System; using System.Linq; using MessagePack; @@ -38,18 +39,18 @@ public class ResourceScanner : Behavior, IAlwaysUpdatedBehavior private ResourceScannerData _data; private float _scanTime; - private Guid _scanTarget; + private CultRecordKey _scanTarget; public float Range { get; private set; } public float MinimumDensity { get; private set; } public float ScanDuration { get; private set; } - public Guid ScanTarget + public CultRecordKey ScanTarget { get => _scanTarget; set { - if (value != _scanTarget) + if (!value.Equals(_scanTarget)) { _scanTarget = value; _scanTime = 0; @@ -90,7 +91,7 @@ public class ResourceScanner : Behavior, IAlwaysUpdatedBehavior } else { - if(length(Entity.Position.xz - Entity.Zone.GetOrbitPosition(planetData.Orbit)) < Range) + if(length(Entity.Position.xz - Entity.Zone.GetOrbitPosition(planetData.Orbit.Key)) < Range) { _scanTime += dt; if (_scanTime > ScanDuration) diff --git a/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs b/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs index 6d29d5472..6f1f506c5 100644 --- a/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs +++ b/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs @@ -1,4 +1,4 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ @@ -10,18 +10,19 @@ using Newtonsoft.Json; [Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class StatModifierData : BehaviorData { - [Inspectable, JsonProperty("stat"), Key(1)] + [Inspectable, JsonProperty("stat"), Key(1)] public StatReference Stat = new StatReference(); - - [Inspectable, JsonProperty("modifier"), Key(2)] + + [Inspectable, JsonProperty("modifier"), Key(2)] public PerformanceStat Modifier = new PerformanceStat(); - - [Inspectable, JsonProperty("type"), Key(3)] + + [Inspectable, JsonProperty("type"), Key(3)] public StatModifierType Type; + // The simple name of a BehaviorData type, as InspectableType writes it [InspectableType(typeof(BehaviorData)), JsonProperty("requireBehavior"), Key(4)] - public Type RequireBehavior; - + public string RequireBehavior; + public override Behavior CreateInstance(EquippedItem item) { return new StatModifier(this, item); @@ -33,13 +34,12 @@ public class StatModifierData : BehaviorData } } -[Order(-4)] public class StatModifier : Behavior, IInitializableBehavior, IDisposable, IAlwaysUpdatedBehavior { private StatModifierData _data; private PerformanceStat[] _stats; - + private static Type[] _statObjects; private bool _applied; @@ -70,14 +70,14 @@ public class StatModifier : Behavior, IInitializableBehavior, IDisposable, IAlwa if (typeof(EquippableItemData).IsAssignableFrom(targetType)) _stats = Entity.Equipment .Select(hp => hp.EquippableItem) - .Where(gear => _data.RequireBehavior == null || ItemManager.GetData(gear).Behaviors.Any(behavior => behavior.GetType() == _data.RequireBehavior)) + .Where(gear => string.IsNullOrEmpty(_data.RequireBehavior) || ItemManager.GetData(gear).Behaviors.Any(behavior => behavior.GetType().Name == _data.RequireBehavior)) .Where(gear => ItemManager.GetData(gear).GetType() == targetType) .Select(gear => statField.GetValue(ItemManager.GetData(gear)) as PerformanceStat) .ToArray(); else _stats = Entity.Equipment .Select(hp => hp.EquippableItem) - .Where(gear => _data.RequireBehavior == null || ItemManager.GetData(gear).Behaviors.Any(behavior => behavior.GetType() == _data.RequireBehavior)) + .Where(gear => string.IsNullOrEmpty(_data.RequireBehavior) || ItemManager.GetData(gear).Behaviors.Any(behavior => behavior.GetType().Name == _data.RequireBehavior)) .SelectMany(gear => ItemManager.GetData(gear).Behaviors) .Where(behaviorData => behaviorData.GetType() == targetType) .Select(behaviorData => statField.GetValue(behaviorData) as PerformanceStat) @@ -135,7 +135,7 @@ public class StatReference { [InspectableType(typeof(BehaviorData)), JsonProperty("behavior"), Key(1)] public string Target; - + [Inspectable, JsonProperty("stat"), Key(2)] public string Stat; -} \ No newline at end of file +} diff --git a/Assets/Scripts/ServerShared/Behaviors/Switch.cs b/Assets/Scripts/ServerShared/Behaviors/Switch.cs index 4795a2b2e..47990c4b2 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Switch.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Switch.cs @@ -7,7 +7,7 @@ using System.Linq; using MessagePack; using Newtonsoft.Json; -[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(-25)] +[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class SwitchData : BehaviorData { public override Behavior CreateInstance(EquippedItem item) diff --git a/Assets/Scripts/ServerShared/Behaviors/Thermotoggle.cs b/Assets/Scripts/ServerShared/Behaviors/Thermotoggle.cs index 009a04c9e..05a354d8b 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Thermotoggle.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Thermotoggle.cs @@ -7,7 +7,7 @@ using System.Linq; using MessagePack; using Newtonsoft.Json; -[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(-22)] +[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class ThermotoggleData : BehaviorData { [InspectableTemperature, JsonProperty("targetTemp"), Key(1)] diff --git a/Assets/Scripts/ServerShared/Behaviors/Thruster.cs b/Assets/Scripts/ServerShared/Behaviors/Thruster.cs index 79dac790b..54aa39c34 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Thruster.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Thruster.cs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using MessagePack; using Newtonsoft.Json; using CultMath; @@ -22,7 +23,7 @@ public class ThrusterData : BehaviorData [Inspectable, JsonProperty("energy"), Key(4), RuntimeInspectable] public PerformanceStat EnergyUsage = new PerformanceStat(); - [InspectablePrefab, JsonProperty("Particles"), Key(5)] + [Inspectable, CultInspectorAssetPath, JsonProperty("Particles"), Key(5)] public string ParticlesPrefab; public override Behavior CreateInstance(EquippedItem item) diff --git a/Assets/Scripts/ServerShared/Behaviors/Trigger.cs b/Assets/Scripts/ServerShared/Behaviors/Trigger.cs index 26262d8a7..be7c9b9dc 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Trigger.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Trigger.cs @@ -7,7 +7,7 @@ using System.Linq; using MessagePack; using Newtonsoft.Json; -[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(-20)] +[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class TriggerData : BehaviorData { public override Behavior CreateInstance(EquippedItem item) diff --git a/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs b/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs index 64a312478..407e5f949 100644 --- a/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs +++ b/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs @@ -23,7 +23,6 @@ public class VelocityLimitData : BehaviorData } } -[Order(100)] public class VelocityLimit : Behavior { public float Limit { get; private set; } diff --git a/Assets/Scripts/ServerShared/Behaviors/Weapon.cs b/Assets/Scripts/ServerShared/Behaviors/Weapon.cs index 73e733b5d..417751b4c 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Weapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Weapon.cs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using System; using System.Collections.Generic; using System.Linq; @@ -24,10 +25,10 @@ public abstract class WeaponData : BehaviorData [Inspectable, JsonProperty("damage"), Key(2), RuntimeInspectable] public PerformanceStat Damage = new PerformanceStat(); - [InspectableRangedFloat(0,1), JsonProperty("penetration"), Key(3), RuntimeInspectable] + [Inspectable, CultInspectorRange(0, 1), JsonProperty("penetration"), Key(3), RuntimeInspectable] public PerformanceStat Penetration = new PerformanceStat(); - [InspectableRangedFloat(0,1), JsonProperty("damageSpread"), Key(4)] + [Inspectable, CultInspectorRange(0, 1), JsonProperty("damageSpread"), Key(4)] public PerformanceStat DamageSpread = new PerformanceStat(); [Inspectable, JsonProperty("minRange"), Key(5)] @@ -39,28 +40,28 @@ public abstract class WeaponData : BehaviorData [InspectableAnimationCurve, JsonProperty("damageCurve"), Key(7)] public BezierCurve DamageCurve; - [InspectablePrefab, JsonProperty("effect"), Key(8)] + [Inspectable, CultInspectorAssetPath, JsonProperty("effect"), Key(8)] public string EffectPrefab; - [InspectablePrefab, JsonProperty("energy"), Key(9), RuntimeInspectable] + [Inspectable, JsonProperty("energy"), Key(9), RuntimeInspectable] public PerformanceStat Energy = new PerformanceStat(); - [InspectablePrefab, JsonProperty("heat"), Key(10), RuntimeInspectable] + [Inspectable, JsonProperty("heat"), Key(10), RuntimeInspectable] public PerformanceStat Heat = new PerformanceStat(); - [InspectablePrefab, JsonProperty("visibility"), Key(11), RuntimeInspectable] + [Inspectable, JsonProperty("visibility"), Key(11), RuntimeInspectable] public PerformanceStat Visibility = new PerformanceStat(); - [InspectableDatabaseLink(typeof(SimpleCommodityData)), JsonProperty("ammo"), Key(12), RuntimeInspectable] - public Guid AmmoType; + [Inspectable, JsonProperty("ammo"), Key(12), RuntimeInspectable] + public CultRecordRef AmmoType; - [InspectablePrefab, JsonProperty("magSize"), Key(13)] + [Inspectable, JsonProperty("magSize"), Key(13)] public int MagazineSize; - [InspectablePrefab, JsonProperty("reloadTime"), Key(14)] + [Inspectable, JsonProperty("reloadTime"), Key(14)] public float ReloadTime = 1; - [InspectablePrefab, JsonProperty("spread"), Key(15)] + [Inspectable, JsonProperty("spread"), Key(15)] public PerformanceStat Spread = new PerformanceStat(); [Inspectable, JsonProperty("velocity"), Key(16)] diff --git a/Assets/Scripts/ServerShared/Behaviors/Wear.cs b/Assets/Scripts/ServerShared/Behaviors/Wear.cs index e6ea327ee..e2e0b1f53 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Wear.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Wear.cs @@ -8,7 +8,7 @@ using Newtonsoft.Json; using CultMath; using static CultMath.math; -[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(1000), RuntimeInspectable] +[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), RuntimeInspectable] public class WearData : BehaviorData { [InspectableTemperature, JsonProperty("perSecond"), Key(1)] diff --git a/Assets/Scripts/ServerShared/Corporations.cs b/Assets/Scripts/ServerShared/Corporations.cs index fea1a4be8..23f9ba337 100644 --- a/Assets/Scripts/ServerShared/Corporations.cs +++ b/Assets/Scripts/ServerShared/Corporations.cs @@ -1,79 +1,67 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; using System.Collections; using System.Collections.Generic; +using GameCult.Caching; using MessagePack; using Newtonsoft.Json; using CultMath; -[DatabaseCategory("Galaxy"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class Faction : DatabaseEntry, INamedEntry +[CultDocument("aetheria.faction", "1"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] +public class Faction { - [Inspectable, JsonProperty("name"), Key(1)] + [Inspectable, CultName, JsonProperty("name"), Key(1)] public string Name; - + [Inspectable, JsonProperty("shortName"), Key(2)] public string ShortName; - - [InspectableText, JsonProperty("description"), Key(3)] + + [Inspectable, CultInspectorTextArea, JsonProperty("description"), Key(3)] public string Description; - - [InspectableTexture, JsonProperty("logo"), Key(4)] + + [Inspectable, CultInspectorAssetPath, JsonProperty("logo"), Key(4)] public string Logo; - - [InspectableDatabaseLink(typeof(PersonalityAttribute)), JsonProperty("personality"), Key(5)] - public Dictionary Personality = new Dictionary(); + + [Inspectable, CultReference(typeof(PersonalityAttribute), many: true), JsonProperty("personality"), Key(5)] + public Dictionary, float> Personality = new Dictionary, float>(); // [Inspectable, JsonProperty("hostile"), Key(6)] // public bool PlayerHostile; [InspectableColor, JsonProperty("primaryColor"), Key(7)] public float3 PrimaryColor; - + [InspectableColor, JsonProperty("secondaryColor"), Key(8)] public float3 SecondaryColor; - [InspectableDatabaseLink(typeof(NameFile)), JsonProperty("nameFile"), Key(9)] - public Guid GeonameFile; + [Inspectable, JsonProperty("nameFile"), Key(9)] + public CultRecordRef GeonameFile; - [InspectableDatabaseLink(typeof(HullData)), JsonProperty("bossHull"), Key(10)] - public Guid BossHull; + [Inspectable, JsonProperty("bossHull"), Key(10)] + public CultRecordRef BossHull; [Inspectable, JsonProperty("influence"), Key(11)] public int InfluenceDistance = 4; - - [InspectableDatabaseLink(typeof(Faction)), RangedFloat(0, 1), JsonProperty("allegiance"), Key(12)] - public Dictionary Allegiance = new Dictionary(); - [InspectableSoundBank, JsonProperty("overworldMusic"), Key(13)] + [Inspectable, CultReference(typeof(Faction), many: true), CultInspectorRange(0, 1), JsonProperty("allegiance"), Key(12)] + public Dictionary, float> Allegiance = new Dictionary, float>(); + + [Inspectable, JsonProperty("overworldMusic"), Key(13)] public uint OverworldMusic; - [InspectableSoundBank, JsonProperty("combatMusic"), Key(14)] + [Inspectable, JsonProperty("combatMusic"), Key(14)] public uint CombatMusic; - [InspectableSoundBank, JsonProperty("bossMusic"), Key(15)] + [Inspectable, JsonProperty("bossMusic"), Key(15)] public uint BossMusic; - - [IgnoreMember] public string EntryName - { - get => Name; - set => Name = value; - } } -[Inspectable, MessagePackObject] -public class NameFile : DatabaseEntry, INamedEntry +[CultDocument("aetheria.namefile", "1"), Inspectable, MessagePackObject] +public class NameFile { - [Key(1)] public string Name; + [CultName, Key(1)] public string Name; [Key(2)] public string[] Names; - - [IgnoreMember] - public string EntryName - { - get => Name; - set => Name = value; - } } diff --git a/Assets/Scripts/ServerShared/Entity.cs b/Assets/Scripts/ServerShared/Entity.cs index 798522793..016b2bd4f 100644 --- a/Assets/Scripts/ServerShared/Entity.cs +++ b/Assets/Scripts/ServerShared/Entity.cs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +using GameCult.Caching; using System; using System.Collections.Generic; using System.Linq; @@ -288,7 +289,7 @@ public abstract class Entity // TODO: Inter-faction hostility // When the entity faction owns the zone, they are hostile to trespassers or those hostile to them - if (Faction.ID == Zone.GalaxyZone.Owner?.ID) + if (Faction == Zone.GalaxyZone.Owner) return recursive ? !(other.PresencePermitted?.Value ?? true) : !(other.PresencePermitted?.Value ?? true)|| other.IsHostileTo(this, true); return !recursive && other.IsHostileTo(this, true); @@ -301,7 +302,7 @@ public abstract class Entity return FactionRelationship.Neutral; if (this is Ship {IsPlayerShip: true}) return Zone.Galaxy.FactionRelationships[faction]; - return faction.ID == Faction.ID ? FactionRelationship.Beloved : FactionRelationship.Neutral; + return faction == Faction ? FactionRelationship.Beloved : FactionRelationship.Neutral; } public static bool IsPresencePermitted(FactionRelationship relationship, SecurityLevel securityLevel) => @@ -316,7 +317,7 @@ public abstract class Entity public ConsumableItemEffect FindActiveConsumable(ConsumableItemData data) { - return _activeConsumables.FirstOrDefault(ac => ac.Data.ID == data.ID); + return _activeConsumables.FirstOrDefault(ac => ac.Data == data); } public bool CanActivateConsumable(ConsumableItemData data) @@ -328,10 +329,11 @@ public abstract class Entity { if (!CanActivateConsumable(data)) return false; - var bay = FindItemInCargo(data.ID); + var key = ItemManager.ItemData.RefOf(data).Key; + var bay = FindItemInCargo(key); if (bay == null) return false; - var item = (ConsumableItem) bay.ItemsOfType[data.ID].First(); + var item = (ConsumableItem) bay.ItemsOfType[key].First(); ActivateConsumable(item); bay.Remove(item); return true; @@ -377,7 +379,7 @@ public abstract class Entity public void GenerateWeaponGroups() { foreach (var group in Weapons - .GroupBy(w => w.Item.EquippableItem.Data.LinkID) + .GroupBy(w => w.Item.EquippableItem.Data.Key) .OrderBy(wg=>wg.Average(w=>w.Range)) .Select((weapons, index) => (weapons, index))) { @@ -394,7 +396,7 @@ public abstract class Entity Temperature[position.x, position.y] += heat / ThermalMass[position.x, position.y]; } - public int CountItemsInCargo(Guid itemDataID) + public int CountItemsInCargo(CultRecordKey itemDataID) { int sum = 0; foreach (var x in CargoBays) @@ -408,7 +410,7 @@ public abstract class Entity return sum; } - public EquippedCargoBay FindItemInCargo(Guid itemDataID) + public EquippedCargoBay FindItemInCargo(CultRecordKey itemDataID) { return CargoBays.FirstOrDefault(c => c.ItemsOfType.ContainsKey(itemDataID)); } @@ -431,7 +433,7 @@ public abstract class Entity // Attempts to move a given number of items of the given type to the target Entity // Returns the number of items successfully transferred - public int TryTransferItems(Entity target, Guid itemDataID, int quantity) + public int TryTransferItems(Entity target, CultRecordKey itemDataID, int quantity) { int quantityTransferred = 0; while (quantityTransferred < quantity) @@ -1052,7 +1054,7 @@ public class ConsumableItemEffect { Item = item; Entity = entity; - Data = (ConsumableItemData) item.Data.Value; + Data = (ConsumableItemData) entity.ItemManager.GetData(item); RemainingDuration = Data.Duration; Behaviors = Data.Behaviors @@ -1329,7 +1331,7 @@ public class EquippedCargoBay : EquippedItem public readonly ItemInstance[,] Occupancy; - public readonly Dictionary> ItemsOfType = new Dictionary>(); + public readonly Dictionary> ItemsOfType = new Dictionary>(); public new readonly CargoBayData Data; @@ -1362,7 +1364,7 @@ public class EquippedCargoBay : EquippedItem // Check whether the given item will fit when its origin is placed at the given coordinate public bool ItemFits(ItemInstance item, int2 cargoCoord) { - var itemData = item.Data.Value; + var itemData = ItemManager.GetData(item); // Check every cell of the item's shape foreach (var i in itemData.Shape.Coordinates) { @@ -1395,7 +1397,7 @@ public class EquippedCargoBay : EquippedItem // For simple commodities, search for existing item stacks to add to foreach (var cargoItem in Cargo.Keys) { - if (item.Data != cargoItem.Data) continue; + if (!item.Data.Key.Equals(cargoItem.Data.Key)) continue; var cargoCommodity = (SimpleCommodity) cargoItem; if (cargoCommodity.Quantity >= itemData.MaxStack) continue; @@ -1486,11 +1488,11 @@ public class EquippedCargoBay : EquippedItem } Cargo[item] = cargoCoord; - if(!ItemsOfType.ContainsKey(item.Data.LinkID)) - ItemsOfType[item.Data.LinkID] = new List(); - ItemsOfType[item.Data.LinkID].Add(item); + if(!ItemsOfType.ContainsKey(item.Data.Key)) + ItemsOfType[item.Data.Key] = new List(); + ItemsOfType[item.Data.Key].Add(item); } - else if (Occupancy[cargoCoord.x, cargoCoord.y] is SimpleCommodity cargoCommodity && cargoCommodity.Data == item.Data) + else if (Occupancy[cargoCoord.x, cargoCoord.y] is SimpleCommodity cargoCommodity && cargoCommodity.Data.Key.Equals(item.Data.Key)) { if (cargoCommodity.Quantity + item.Quantity <= itemData.MaxStack) { @@ -1530,9 +1532,9 @@ public class EquippedCargoBay : EquippedItem } Cargo[item] = cargoCoord; - if(!ItemsOfType.ContainsKey(item.Data.LinkID)) - ItemsOfType[item.Data.LinkID] = new List(); - ItemsOfType[item.Data.LinkID].Add(item); + if(!ItemsOfType.ContainsKey(item.Data.Key)) + ItemsOfType[item.Data.Key] = new List(); + ItemsOfType[item.Data.Key].Add(item); Mass += ItemManager.GetMass(item); ThermalMass += ItemManager.GetThermalMass(item); @@ -1555,9 +1557,9 @@ public class EquippedCargoBay : EquippedItem Occupancy[v.x, v.y] = null; Cargo.Remove(item); - ItemsOfType[item.Data.LinkID].Remove(item); - if (!ItemsOfType[item.Data.LinkID].Any()) - ItemsOfType.Remove(item.Data.LinkID); + ItemsOfType[item.Data.Key].Remove(item); + if (!ItemsOfType[item.Data.Key].Any()) + ItemsOfType.Remove(item.Data.Key); Mass -= ItemManager.GetMass(item); ThermalMass -= ItemManager.GetThermalMass(item); @@ -1584,9 +1586,9 @@ public class EquippedCargoBay : EquippedItem Occupancy[v.x, v.y] = null; Cargo.Remove(item); - ItemsOfType[item.Data.LinkID].Remove(item); - if (!ItemsOfType[item.Data.LinkID].Any()) - ItemsOfType.Remove(item.Data.LinkID); + ItemsOfType[item.Data.Key].Remove(item); + if (!ItemsOfType[item.Data.Key].Any()) + ItemsOfType.Remove(item.Data.Key); Mass -= ItemManager.GetMass(item); ThermalMass -= ItemManager.GetThermalMass(item); diff --git a/Assets/Scripts/ServerShared/EntitySerializer.cs b/Assets/Scripts/ServerShared/EntitySerializer.cs index ea276a60a..75a0e5c23 100644 --- a/Assets/Scripts/ServerShared/EntitySerializer.cs +++ b/Assets/Scripts/ServerShared/EntitySerializer.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using GameCult.Caching; using MessagePack; using CultMath; @@ -13,7 +14,7 @@ public static class EntitySerializer if (entity is OrbitalEntity orbital) pack = new OrbitalEntityPack { - Orbit = orbital.OrbitData, + Orbit = new CultRecordRef(orbital.OrbitData), SecurityLevel = orbital.SecurityLevel, SecurityRadius = orbital.SecurityRadius }; @@ -27,7 +28,7 @@ public static class EntitySerializer else throw new ArgumentException("Attempted to pack an instance of abstract class Entity!"); pack.Settings = entity.Settings; - + // Filter item behavior collections by those with any persistent behaviors // For each item create an object containing the item position and a list of persistent behaviors // Then turn that into a dictionary mapping from item position to an array of every behaviors persistent data @@ -40,7 +41,7 @@ public static class EntitySerializer pack.Hull = entity.Hull; pack.Name = entity.Name; - pack.Faction = entity.Faction?.ID ?? Guid.Empty; + pack.Faction = entity.Faction == null ? default : entity.ItemManager.ItemData.RefOf(entity.Faction); pack.Equipment = entity.Equipment.Select(e => (e.Position, e.EquippableItem)).ToArray(); pack.CargoBays = entity.CargoBays.Select(e => (e.Position, e.EquippableItem)).ToArray(); pack.DockingBays = entity.DockingBays.Select(e => (e.Position, e.EquippableItem)).ToArray(); @@ -70,7 +71,7 @@ public static class EntitySerializer private static Ship Unpack(ItemManager itemManager, Zone zone, ShipPack pack, bool instantiate = false) { - + var entity = new Ship(itemManager, zone, instantiate ? (EquippableItem) itemManager.Instantiate(pack.Hull) : pack.Hull, pack.Settings); Restore(itemManager, zone, pack, entity, instantiate); entity.Position = pack.Position; @@ -81,7 +82,7 @@ public static class EntitySerializer private static OrbitalEntity Unpack(ItemManager itemManager, Zone zone, OrbitalEntityPack pack, bool instantiate = false) { - var entity = new OrbitalEntity(itemManager, zone, instantiate ? (EquippableItem) itemManager.Instantiate(pack.Hull) : pack.Hull, pack.Orbit, pack.Settings); + var entity = new OrbitalEntity(itemManager, zone, instantiate ? (EquippableItem) itemManager.Instantiate(pack.Hull) : pack.Hull, pack.Orbit.Key, pack.Settings); Restore(itemManager, zone, pack, entity, instantiate); entity.SecurityLevel = pack.SecurityLevel; entity.SecurityRadius = pack.SecurityRadius; @@ -92,7 +93,7 @@ public static class EntitySerializer private static void Restore(ItemManager itemManager, Zone zone, EntityPack pack, Entity entity, bool instantiate = false) { entity.Name = pack.Name; - entity.Faction = itemManager.ItemData.Get(pack.Faction); + entity.Faction = itemManager.ItemData.Get(pack.Faction); entity.Children = pack.Children.Select(c => { var child = Unpack(itemManager, zone, c, instantiate); @@ -131,12 +132,12 @@ public static class EntitySerializer if(!instantiate) entity.Temperature = pack.Temperature; - + if(!instantiate) entity.Armor = pack.Armor; - + var hullData = itemManager.GetData(entity.Hull); - + foreach(var v in hullData.Shape.Coordinates) entity.HullConductivity[v.x,v.y] = pack.Conductivity[v.x,v.y]; @@ -166,13 +167,13 @@ public class ShipPack : EntityPack [MessagePackObject] public class OrbitalEntityPack : EntityPack { - [Key(17)] public Guid Orbit; + [Key(17)] public CultRecordRef Orbit; [Key(18)] public int Story = -1; [Key(19)] public SecurityLevel SecurityLevel; [Key(20)] public float SecurityRadius; } -[MessagePackObject, +[MessagePackObject, Union(0, typeof(OrbitalEntityPack)), Union(1, typeof(ShipPack))] public abstract class EntityPack @@ -191,7 +192,7 @@ public abstract class EntityPack [Key(12)] public (int2 position, ItemInstance item)[][] DockingBayContents; [Key(13)] public EntityPack[] Children; [Key(14)] public EntitySettings Settings; - [Key(15)] public Guid Faction; + [Key(15)] public CultRecordRef Faction; [Key(16)] public int[][] WeaponGroups; private int _price; @@ -199,7 +200,7 @@ public abstract class EntityPack public int Price(ItemManager itemManager) { if (_price != 0) return _price; - + var hullData = itemManager.GetData(Hull); _price = hullData.Price; @@ -223,7 +224,7 @@ public abstract class EntityPack { foreach (var (_, item) in t) { - var itemData = item.Data.Value; + var itemData = itemManager.GetData(item); if (item is SimpleCommodity s) _price += itemData.Price * s.Quantity; else @@ -235,7 +236,7 @@ public abstract class EntityPack { foreach (var (_, item) in t) { - var itemData = item.Data.Value; + var itemData = itemManager.GetData(item); if (item is SimpleCommodity s) _price += itemData.Price * s.Quantity; else diff --git a/Assets/Scripts/ServerShared/Extensions.cs b/Assets/Scripts/ServerShared/Extensions.cs index a3a111556..e264af2c2 100644 --- a/Assets/Scripts/ServerShared/Extensions.cs +++ b/Assets/Scripts/ServerShared/Extensions.cs @@ -15,9 +15,6 @@ using float2 = CultMath.float2; public static class Extensions { - //public static IDatabaseEntry Get(this Guid entry) => Database.Get(entry); - //public static T Get(this Guid entry) where T : class, IDatabaseEntry => Database.Get(entry) as T; - public static bool IsImplementationOf(this Type baseType, Type interfaceType) { return baseType.GetInterfaces().Any(interfaceType.Equals); diff --git a/Assets/Scripts/ServerShared/FactionProduct.cs b/Assets/Scripts/ServerShared/FactionProduct.cs index 335045452..a0770304a 100644 --- a/Assets/Scripts/ServerShared/FactionProduct.cs +++ b/Assets/Scripts/ServerShared/FactionProduct.cs @@ -4,36 +4,30 @@ using System; using System.Collections.Generic; +using GameCult.Caching; using MessagePack; using Newtonsoft.Json; // A manufacturer's branded variant of a generic design: its name, its flavor text, and how it builds each of // the design's roles. Which products exist is what a faction makes, so market segmentation and regional // progression are authored here rather than as duplicate item entries. -[DatabaseCategory("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class FactionProductData : DatabaseEntry, INamedEntry +[CultDocument("aetheria.factionproductdata", "1"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] +public class FactionProductData { - [Inspectable, JsonProperty("name"), Key(1)] + [Inspectable, CultName, JsonProperty("name"), Key(1)] public string Name; - [InspectableText, JsonProperty("description"), Key(2)] + [Inspectable, CultInspectorTextArea, JsonProperty("description"), Key(2)] public string Description; - [InspectableDatabaseLink(typeof(CraftedItemData)), JsonProperty("design"), Key(3)] - public Guid Design; + [Inspectable, JsonProperty("design"), Key(3)] + public CultRecordRef Design; - [InspectableDatabaseLink(typeof(Faction)), JsonProperty("manufacturer"), Key(4)] - public Guid Manufacturer; + [Inspectable, JsonProperty("manufacturer"), Key(4)] + public CultRecordRef Manufacturer; [Inspectable, JsonProperty("roles"), Key(5)] public List Roles = new List(); - - [IgnoreMember] - public string EntryName - { - get => Name; - set => Name = value; - } } // How good this product's part is in one of its design's roles: a pseudo-gaussian distribution whose mean is diff --git a/Assets/Scripts/ServerShared/Galaxy.cs b/Assets/Scripts/ServerShared/Galaxy.cs index a103000d8..730daadf0 100644 --- a/Assets/Scripts/ServerShared/Galaxy.cs +++ b/Assets/Scripts/ServerShared/Galaxy.cs @@ -1,3 +1,4 @@ +using GameCult.Caching; using System; using System.Collections.Generic; using System.IO; @@ -29,7 +30,7 @@ public class Galaxy private Action Log { get; } public bool IsPrelude { get; } - private HashSet _containedFactions; + private HashSet _containedFactions; private GalaxyZone[] _exitPath; private Dictionary _nameGenerators = new Dictionary(); private readonly CultCache _cache; @@ -51,13 +52,14 @@ public class Galaxy Log = log; Background = savedGame.Background; - Factions = savedGame.Factions.Select(cultCache.Get).ToArray(); + Factions = savedGame.Factions.Select(faction => cultCache.Get(faction)).ToArray(); for (var i = 0; i < Factions.Length; i++) { FactionRelationships[Factions[i]] = savedGame.Relationships[i]; } - Zones = savedGame.Zones.Select(zone => + var savedZones = savedGame.Zones.Select(zone => cultCache.Get(zone)).ToArray(); + Zones = savedZones.Select(zone => { return new GalaxyZone { @@ -69,9 +71,9 @@ public class Galaxy foreach (var i in savedGame.DiscoveredZones) DiscoveredZones.Add(Zones[i]); for (var i = 0; i < Zones.Length; i++) { - Zones[i].AdjacentZones = savedGame.Zones[i].AdjacentZones.Select(azi => Zones[azi]).ToList(); - Zones[i].Factions = savedGame.Zones[i].Factions.Select(mi => Factions[mi]).ToArray(); - Zones[i].Owner = savedGame.Zones[i].Owner < 0 ? null : Factions[savedGame.Zones[i].Owner]; + Zones[i].AdjacentZones = savedZones[i].AdjacentZones.Select(azi => Zones[azi]).ToList(); + Zones[i].Factions = savedZones[i].Factions.Select(mi => Factions[mi]).ToArray(); + Zones[i].Owner = savedZones[i].Owner < 0 ? null : Factions[savedZones[i].Owner]; } HomeZones = savedGame.HomeZones.ToDictionary( @@ -269,7 +271,7 @@ public class Galaxy // Choose some megas to have bosses placed based on whether a boss hull is assigned var bossMegas = Factions - .Where(m => m.BossHull != Guid.Empty) + .Where(m => m.BossHull.IsSet()) .Take(bossCount) .ToArray(); @@ -335,7 +337,7 @@ public class Galaxy progressCallback?.Invoke($"Feeding Markov Chains: {i + 1} / {Factions.Length}"); //if(progressCallback!=null) Thread.Sleep(250); // Inserting Delay to make it seem like it's doing more work lmao var faction = Factions[i]; - _nameGenerators[faction] = new MarkovNameGenerator(ref random, cache.Get(faction.GeonameFile).Names, nameGeneratorSettings); + _nameGenerators[faction] = new MarkovNameGenerator(ref random, cache.Get(faction.GeonameFile).Names, nameGeneratorSettings); } // Generate zone name using the owner's name generator, otherwise assign catalogue ID @@ -435,10 +437,10 @@ public class Galaxy } } - public bool ContainsFaction(Guid factionID) + public bool ContainsFaction(CultRecordRef faction) { - _containedFactions ??= new HashSet(Factions.Select(f => f.ID)); - return _containedFactions.Contains(factionID); + _containedFactions ??= new HashSet(Factions.Select(f => _cache.RefOf(f).Key)); + return _containedFactions.Contains(faction.Key); } class DijkstraVertex diff --git a/Assets/Scripts/UI/InputScreen/InputLayout.cs b/Assets/Scripts/ServerShared/InputLayout.cs similarity index 91% rename from Assets/Scripts/UI/InputScreen/InputLayout.cs rename to Assets/Scripts/ServerShared/InputLayout.cs index 994d0d148..a688598b2 100644 --- a/Assets/Scripts/UI/InputScreen/InputLayout.cs +++ b/Assets/Scripts/ServerShared/InputLayout.cs @@ -1,8 +1,9 @@ using System.Collections.Generic; -using JsonKnownTypes;using MessagePack; +using GameCult.Caching; +using MessagePack; using Newtonsoft.Json; -[MessagePackObject, JsonObject(MemberSerialization.OptIn)] +[CultDocument("aetheria.inputlayout", "1"), MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class InputLayout { [Key(0), JsonProperty("rows")] public InputLayoutRow[] Rows; @@ -12,7 +13,7 @@ public class InputLayout foreach (var row in Rows) { if (!(row is InputLayoutKeyRow keyRow)) continue; - + foreach (var column in keyRow.Columns) { if (column is InputLayoutBindableKey bindableKey) @@ -24,8 +25,7 @@ public class InputLayout } } -[JsonConverter(typeof(JsonKnownTypesConverter)), - MessagePackObject, +[MessagePackObject, Union(0, typeof(InputLayoutRowSpacer)), Union(1, typeof(InputLayoutKeyRow)) ] @@ -43,8 +43,7 @@ public class InputLayoutKeyRow : InputLayoutRow [Key(0), JsonProperty("columns")] public InputLayoutColumn[] Columns; } -[JsonConverter(typeof(JsonKnownTypesConverter)), - MessagePackObject, +[MessagePackObject, Union(0, typeof(InputLayoutColumnSpacer)), Union(1, typeof(InputLayoutKey)), Union(2, typeof(InputLayoutBindableKey)), @@ -82,6 +81,7 @@ public class InputLayoutBindableKey : InputLayoutKey, IBindableButton } } +[MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class InputLayoutMultiRowKey : InputLayoutBindableKey { [Key(4), JsonProperty("height")] public int Height; @@ -100,4 +100,4 @@ public class InputLayoutMouseButton : IBindableButton public interface IBindableButton { public string InputSystemPath { get; set; } -} \ No newline at end of file +} diff --git a/Assets/Scripts/UI/InputScreen/InputLayout.cs.meta b/Assets/Scripts/ServerShared/InputLayout.cs.meta similarity index 100% rename from Assets/Scripts/UI/InputScreen/InputLayout.cs.meta rename to Assets/Scripts/ServerShared/InputLayout.cs.meta diff --git a/Assets/Scripts/ServerShared/ItemData.cs b/Assets/Scripts/ServerShared/ItemData.cs index 208b0d9e8..e2bc01fb2 100644 --- a/Assets/Scripts/ServerShared/ItemData.cs +++ b/Assets/Scripts/ServerShared/ItemData.cs @@ -6,7 +6,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using JsonKnownTypes; +using GameCult.Caching; using MessagePack; using Newtonsoft.Json; using CultMath; @@ -268,17 +268,17 @@ public class Shape } -[MessagePackObject, JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] -public abstract class ItemData : DatabaseEntry, INamedEntry +[JsonObject(MemberSerialization.OptIn)] +public abstract class ItemData { - [Inspectable, JsonProperty("name"), Key(1)] + [Inspectable, CultName, JsonProperty("name"), Key(1)] public string Name; - [InspectableText, JsonProperty("description"), Key(2)] + [Inspectable, CultInspectorTextArea, JsonProperty("description"), Key(2)] public string Description; - [InspectableDatabaseLink(typeof(Faction)), JsonProperty("creator"), Key(3)] - public Guid Manufacturer; + [Inspectable, JsonProperty("creator"), Key(3)] + public CultRecordRef Manufacturer; [Inspectable, JsonProperty("mass"), Key(4)] public float Mass; @@ -295,16 +295,9 @@ public abstract class ItemData : DatabaseEntry, INamedEntry [Inspectable, JsonProperty("price"), Key(8)] public int Price = 0; - - [IgnoreMember] public string EntryName - { - get => Name; - set => Name = value; - } - } -[DatabaseCategory("Items"), Inspectable, MessagePackObject] +[CultDocument("aetheria.simplecommoditydata", "1"), Inspectable, MessagePackObject] public class SimpleCommodityData : ItemData { // MessagePack keys 6, 7, 8 and 11 belonged to removed resource-distribution fields; do not reuse them. @@ -316,7 +309,7 @@ public class SimpleCommodityData : ItemData public SimpleCommodityCategory Category; } -[MessagePackObject, JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] +[JsonObject(MemberSerialization.OptIn)] public abstract class CraftedItemData : ItemData { // The named slots this design is assembled from. A stat may read the quality of the part filling one. @@ -334,17 +327,17 @@ public class ItemRole public string Name; } -[DatabaseCategory("Items"), Inspectable, MessagePackObject] +[CultDocument("aetheria.compoundcommoditydata", "1"), Inspectable, MessagePackObject] public class CompoundCommodityData : CraftedItemData { - [InspectableDatabaseLink(typeof(PersonalityAttribute)), JsonProperty("demandProfile"), Key(10)] - public Dictionary DemandProfile = new Dictionary(); + [Inspectable, CultReference(typeof(PersonalityAttribute), many: true), JsonProperty("demandProfile"), Key(10)] + public Dictionary, float> DemandProfile = new Dictionary, float>(); [Inspectable, JsonProperty("category"), Key(11)] public CompoundCommodityCategory Category; } -[DatabaseCategory("Items"), Inspectable, MessagePackObject] +[CultDocument("aetheria.consumableitemdata", "1"), Inspectable, MessagePackObject] public class ConsumableItemData : CraftedItemData { [Inspectable, JsonProperty("behaviors"), Key(10)] @@ -356,7 +349,7 @@ public class ConsumableItemData : CraftedItemData [Inspectable, JsonProperty("duration"), Key(12)] public float Duration; - [InspectableTexture, JsonProperty("icon"), Key(13)] + [Inspectable, CultInspectorAssetPath, JsonProperty("icon"), Key(13)] public string Icon; [Inspectable, JsonProperty("effectiveness"), Key(14)] @@ -366,7 +359,7 @@ public class ConsumableItemData : CraftedItemData [JsonObject(MemberSerialization.OptIn)] public abstract class EquippableItemData : CraftedItemData { - [InspectableTexture, JsonProperty("schematic"), Key(10)] + [Inspectable, CultInspectorAssetPath, JsonProperty("schematic"), Key(10)] public string Schematic; [Inspectable, JsonProperty("behaviors"), Key(11)] @@ -396,10 +389,10 @@ public abstract class EquippableItemData : CraftedItemData // [Inspectable, JsonProperty("sfx"), Key(19)] // public string SoundEffectTrigger; - [InspectableTexture, JsonProperty("actionIcon"), Key(20)] + [Inspectable, CultInspectorAssetPath, JsonProperty("actionIcon"), Key(20)] public string ActionBarIcon; - [InspectableSoundBank, JsonProperty("soundBank"), Key(21)] + [Inspectable, JsonProperty("soundBank"), Key(21)] public uint SoundBank; [Inspectable, JsonProperty("audioStats"), Key(22)] @@ -446,14 +439,14 @@ public abstract class EquippableItemData : CraftedItemData [Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class AudioStat { - [InspectableAudioParameter, JsonProperty("parameter"), Key(0)] + [Inspectable, JsonProperty("parameter"), Key(0)] public uint Parameter; [Inspectable, JsonProperty("stat"), Key(1)] public PerformanceStat Stat = new PerformanceStat(); } -[DatabaseCategory("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] +[CultDocument("aetheria.geardata", "1"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class GearData : EquippableItemData { [Inspectable, JsonProperty("hardpointType"), Key(23)] @@ -462,7 +455,7 @@ public class GearData : EquippableItemData [IgnoreMember] public override HardpointType HardpointType => Hardpoint; } -[DatabaseCategory("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] +[CultDocument("aetheria.cargobaydata", "1"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class CargoBayData : EquippableItemData { [Inspectable, JsonProperty("interiorShape"), Key(24)] @@ -471,14 +464,14 @@ public class CargoBayData : EquippableItemData [IgnoreMember] public override HardpointType HardpointType => HardpointType.Tool; } -[DatabaseCategory("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] +[CultDocument("aetheria.dockingbaydata", "1"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class DockingBayData : CargoBayData { [Inspectable, JsonProperty("maxSize"), Key(25)] public int2 MaxSize; } -[DatabaseCategory("Items"), MessagePackObject, JsonObject(MemberSerialization.OptIn)] +[CultDocument("aetheria.weaponitemdata", "1"), MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class WeaponItemData : GearData { [Inspectable, JsonProperty("range"), Key(24)] @@ -497,13 +490,13 @@ public class WeaponItemData : GearData public WeaponModifiers WeaponModifiers; } -[DatabaseCategory("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] +[CultDocument("aetheria.hulldata", "1"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class HullData : EquippableItemData { [Inspectable, JsonProperty("hardpoints"), Key(23)] public List Hardpoints = new List(); - [InspectablePrefab, JsonProperty("prefab"), Key(24)] + [Inspectable, CultInspectorAssetPath, JsonProperty("prefab"), Key(24)] public string Prefab; [Inspectable, JsonProperty("hullType"), Key(25)] @@ -541,7 +534,7 @@ public class HullData : EquippableItemData } [Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class HardpointData : ITintInspector +public class HardpointData { [Inspectable, JsonProperty("type"), Key(0)] public HardpointType Type; [Inspectable, JsonProperty("position"), Key(1)] public int2 Position; @@ -628,10 +621,10 @@ public class PerformanceStat } } -[DatabaseCategory("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class PersonalityAttribute : DatabaseEntry, INamedEntry +[CultDocument("aetheria.personalityattribute", "1"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)] +public class PersonalityAttribute { - [Inspectable, JsonProperty("name"), Key(1)] + [Inspectable, CultName, JsonProperty("name"), Key(1)] public string Name; [Inspectable, JsonProperty("low"), Key(2)] @@ -640,9 +633,4 @@ public class PersonalityAttribute : DatabaseEntry, INamedEntry [Inspectable, JsonProperty("high"), Key(3)] public string HighName; - [IgnoreMember] public string EntryName - { - get => Name; - set => Name = value; - } } \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/ItemInstance.cs b/Assets/Scripts/ServerShared/ItemInstance.cs index 71c2dabb7..8021501f1 100644 --- a/Assets/Scripts/ServerShared/ItemInstance.cs +++ b/Assets/Scripts/ServerShared/ItemInstance.cs @@ -7,7 +7,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; -using JsonKnownTypes; +using GameCult.Caching; //using JM.LinqFaster; using MessagePack; using MessagePack.Formatters; @@ -19,34 +19,28 @@ using static CultMath.math; Union(1, typeof(CompoundCommodity)), Union(2, typeof(EquippableItem)), Union(3, typeof(ConsumableItem)), - JsonObject(MemberSerialization.OptIn), - JsonConverter(typeof(JsonKnownTypesConverter))] + JsonObject(MemberSerialization.OptIn)] public abstract class ItemInstance { - [JsonProperty("data"), Key(0)] public DatabaseLink Data; + [JsonProperty("data"), Key(0)] public CultRecordRef Data; [JsonProperty("rotation"), Key(1)] public ItemRotation Rotation; } [Union(0, typeof(CompoundCommodity)), Union(1, typeof(EquippableItem)), Union(2, typeof(ConsumableItem)), - JsonObject(MemberSerialization.OptIn), - JsonConverter(typeof(JsonKnownTypesConverter))] + JsonObject(MemberSerialization.OptIn)] public abstract class CraftedItemInstance : ItemInstance { // The workmanship of this particular unit, as distinct from the parts that went into it. [JsonProperty("quality"), Key(2)] public float Quality; - // Keys 9 and 10, past every key the derived instances use: an item saved before these existed has no - // element there at all. Keys 3 to 6 sit inside the old range and read back as nil, which a non-nullable - // Guid cannot deserialize, so nothing new may go there. - // How good the part filling each of the design's roles turned out. Empty on items made before roles // existed; stats then read Quality as they always did. [JsonProperty("ingredients"), Key(9)] public List Ingredients = new List(); // The manufacturer's branded product this was built as, naming it and carrying its flavor text. - [JsonProperty("product"), Key(10)] public Guid Product; + [JsonProperty("product"), Key(10)] public CultRecordRef Product; // The quality a stat reads for one of the design's roles. An unnamed role, a design without roles, and an // item built before roles existed all fall back to this item's own workmanship. diff --git a/Assets/Scripts/ServerShared/ItemManager.cs b/Assets/Scripts/ServerShared/ItemManager.cs index be7b8a7fb..51ba2f2be 100644 --- a/Assets/Scripts/ServerShared/ItemManager.cs +++ b/Assets/Scripts/ServerShared/ItemManager.cs @@ -1,4 +1,4 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ @@ -6,6 +6,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using GameCult.Caching; using CultMath; using static CultMath.math; using float2 = CultMath.float2; @@ -17,36 +18,12 @@ using float4 = CultMath.float4; public class ItemManager { public Random Random = new Random((uint) (DateTime.Now.Ticks%uint.MaxValue)); - // public Dictionary MapLayers = new Dictionary(); - // public SimpleCommodityData[] Resources; - // public Dictionary> CorporationControllers = new Dictionary>(); - // public Dictionary GalaxyZones; - + private Action _logger; - private double _time; - private float _deltaTime; - private Dictionary _zones = new Dictionary(); - - // private Guid _forceLoadZone; - - // public GlobalData GlobalData => _globalData ?? (_globalData = ItemData.GetAll().FirstOrDefault()); public CultCache ItemData { get; } public GameplaySettings GameplaySettings { get; } - // public double Time - // { - // get => _time; - // set - // { - // _deltaTime = (float) (value - _time); - // _time = value; - // //Log($"GameContext delta time: {_deltaTime}"); - // } - // } - - // private readonly Dictionary Tier = new Dictionary(); - public ItemManager(CultCache itemData, GameplaySettings settings, Action logger) { ItemData = itemData; @@ -59,34 +36,28 @@ public class ItemManager _logger(s); } - public SimpleCommodityData GetData(SimpleCommodity item) - { - return item.Data.Value as SimpleCommodityData; - } + // The one resolution path from an item instance to its design + public ItemData GetData(ItemInstance item) => ItemData.Get(item.Data); - public CraftedItemData GetData(CraftedItemInstance item) - { - return item.Data.Value as CraftedItemData; - } + public SimpleCommodityData GetData(SimpleCommodity item) => GetData((ItemInstance) item) as SimpleCommodityData; - public EquippableItemData GetData(EquippableItem item) - { - return item.Data.Value as EquippableItemData; - } + public CraftedItemData GetData(CraftedItemInstance item) => GetData((ItemInstance) item) as CraftedItemData; + + public EquippableItemData GetData(EquippableItem item) => GetData((ItemInstance) item) as EquippableItemData; public float GetMass(ItemInstance item) { return item switch { - CraftedItemInstance _ => item.Data.Value.Mass, - SimpleCommodity commodity => item.Data.Value.Mass * commodity.Quantity, + CraftedItemInstance _ => GetData(item).Mass, + SimpleCommodity commodity => GetData(item).Mass * commodity.Quantity, _ => 0 }; } public float GetThermalMass(ItemInstance item) { - var data = item.Data.Value; + var data = GetData(item); return item switch { CraftedItemInstance _ => data.Mass * data.SpecificHeat, @@ -106,7 +77,7 @@ public class ItemManager pow(item.Quality, GameplaySettings.DurabilityQualityExponent)); var durability = pow(item.Durability / data.Durability, durabilityExponent * stat.DurabilityExponentMultiplier); var result = lerp(stat.Min, stat.Max, quality * durability); - if (float.IsNaN(result)) + if (float.IsNaN(result)) throw new InvalidOperationException($"Performance Stat on {data.Name} evaluating as NaN: input data is invalid! Durability: {item.Durability} / {data.Durability}"); return result; @@ -124,20 +95,19 @@ public class ItemManager { var newItem = new SimpleCommodity { - Data = new DatabaseLink{LinkID = item.ID}, + Data = ItemData.RefOf(item), Quantity = count }; - //ItemData.Add(newItem); return newItem; } - + _logger("Attempted to create Simple Commodity instance using missing or incorrect item id"); return null; } public ItemInstance Instantiate(ItemInstance item) { - var data = item.Data.Value; + var data = GetData(item); if(data is CraftedItemData c) { var i = CreateInstance(c); @@ -159,24 +129,23 @@ public class ItemManager { return new EquippableItem { - Data = new DatabaseLink {LinkID = item.ID}, Quality = quality, Durability = equippableItemData.Durability + Data = ItemData.RefOf(item), Quality = quality, Durability = equippableItemData.Durability }; } var newCommodity = new CompoundCommodity { - Data = new DatabaseLink{LinkID = item.ID}, + Data = ItemData.RefOf(item), Quality = quality }; return newCommodity; } - + public CraftedItemInstance CreateInstance(CraftedItemData item) { if (item == null) { throw new NullReferenceException("Attempted to create crafted item instance using missing or incorrect item data!"); - return null; } var quality = Random.NextFloat(); @@ -194,7 +163,7 @@ public class ItemManager // the design's roles filled with a part whose quality is drawn from that manufacturer's distribution for it. public CraftedItemInstance CreateInstance(FactionProductData product) { - var design = ItemData.Get(product.Design); + var design = ItemData.Get(product.Design); if (design == null) { _logger($"Product {product.Name} names a design that does not exist!"); @@ -202,7 +171,7 @@ public class ItemManager } var instance = CreateInstance(design); - instance.Product = product.ID; + instance.Product = ItemData.RefOf(product); if (design.Roles == null) return instance; foreach (var role in design.Roles) { @@ -226,4 +195,4 @@ public class ItemManager int upgrades = (int) ((item.Quality - tier.Quality) / .0499f); return (tier, upgrades); } -} \ No newline at end of file +} diff --git a/Assets/Scripts/ServerShared/LoadoutGenerator.cs b/Assets/Scripts/ServerShared/LoadoutGenerator.cs index 473071fa0..571c52d15 100644 --- a/Assets/Scripts/ServerShared/LoadoutGenerator.cs +++ b/Assets/Scripts/ServerShared/LoadoutGenerator.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using GameCult.Caching; using CultMath; using static CultMath.math; using Random = CultMath.Random; @@ -57,7 +58,7 @@ public class LoadoutGenerator return null; } var hull = ItemManager.CreateInstance(hullProduct) as EquippableItem; - var entity = new OrbitalEntity(ItemManager, null, hull, Guid.Empty, ItemManager.GameplaySettings.DefaultEntitySettings); + var entity = new OrbitalEntity(ItemManager, null, hull, default, ItemManager.GameplaySettings.DefaultEntitySettings); entity.Faction = Faction; OutfitEntity(entity); return EntitySerializer.Pack(entity) as OrbitalEntityPack; @@ -72,7 +73,7 @@ public class LoadoutGenerator return null; } var hull = ItemManager.CreateInstance(hullProduct) as EquippableItem; - var entity = new OrbitalEntity(ItemManager, null, hull, Guid.Empty, ItemManager.GameplaySettings.DefaultEntitySettings); + var entity = new OrbitalEntity(ItemManager, null, hull, default, ItemManager.GameplaySettings.DefaultEntitySettings); entity.Faction = Faction; // Hardpoint gear goes in first so the docking bay can only take space that gear left free @@ -123,11 +124,11 @@ public class LoadoutGenerator public (FactionProductData product, T design)[] RandomProducts(int count, float sizeExponent, Predicate filter = null, bool required = false) where T : EquippableItemData { var candidates = ItemManager.ItemData.GetAll() - .Select(product => (product, design: ItemManager.ItemData.Get(product.Design) as T)) + .Select(product => (product, design: ItemManager.ItemData.Get(product.Design) as T)) .Where(entry => entry.design != null && entry.design.Price > 0 && - entry.product.Manufacturer != Guid.Empty && + entry.product.Manufacturer.IsSet() && (filter?.Invoke(entry.design) ?? true)) .ToArray(); var available = candidates.Where(entry => IsAvailable(entry.product)).ToArray(); @@ -153,12 +154,13 @@ public class LoadoutGenerator Galaxy.ContainsFaction(product.Manufacturer) && (Faction == null || Faction.Allegiance.ContainsKey(product.Manufacturer)); // Prioritize products from the zone faction and its allies, penalizing distance to the manufacturer's headquarters - private float ManufacturerPreference(Guid manufacturer) + private float ManufacturerPreference(CultRecordRef manufacturer) { if (Faction == null || Galaxy == null) return 1; - var allegiance = manufacturer == Faction.ID ? 1 : + var maker = ItemManager.ItemData.Get(manufacturer); + var allegiance = maker == Faction ? 1 : Faction.Allegiance.TryGetValue(manufacturer, out var a) ? a : 0; - var home = Galaxy.HomeZones.FirstOrDefault(h => h.Key.ID == manufacturer).Value; + var home = maker != null && Galaxy.HomeZones.TryGetValue(maker, out var h) ? h : null; var distance = home != null && Zone?.Distance != null && Zone.Distance.TryGetValue(home, out var d) ? d : 0; return allegiance / (1 + distance); } diff --git a/Assets/Scripts/ServerShared/Narrative/ZoneConstraints.cs b/Assets/Scripts/ServerShared/Narrative/ZoneConstraints.cs index f707dc399..4c3d52688 100644 --- a/Assets/Scripts/ServerShared/Narrative/ZoneConstraints.cs +++ b/Assets/Scripts/ServerShared/Narrative/ZoneConstraints.cs @@ -15,12 +15,12 @@ public interface IFactionResolver public abstract class ZoneConstraint { public bool Flip = false; - + public bool Test(GalaxyZone zone) { return Flip ^ TestZone(zone); } - + protected abstract bool TestZone(GalaxyZone zone); } @@ -34,14 +34,14 @@ public class FactionPresenceConstraint : ZoneConstraint protected override bool TestZone(GalaxyZone zone) { - return zone.Factions.Any(f=>f.ID == TargetFaction?.ID); + return zone.Factions.Any(f => f == TargetFaction); } } public class FactionOwnerConstraint : ZoneConstraint { private Faction TargetFaction { get; } - + public FactionOwnerConstraint(string[] args, IFactionResolver resolver) { TargetFaction = resolver.ResolveFaction(args[0]); @@ -49,7 +49,7 @@ public class FactionOwnerConstraint : ZoneConstraint protected override bool TestZone(GalaxyZone zone) { - return zone.Owner.ID == TargetFaction?.ID; + return TargetFaction != null && zone.Owner == TargetFaction; } } @@ -57,7 +57,7 @@ public class DistanceConstraint : ZoneConstraint { private GalaxyZone _targetZone; private Predicate _test; - + public DistanceConstraint(string[] args, IZoneResolver zoneResolver) { if (args.Length == 3) @@ -86,4 +86,4 @@ public class DistanceConstraint : ZoneConstraint { return _targetZone != null && _test(zone.Distance[_targetZone]); } -} \ No newline at end of file +} diff --git a/Assets/Scripts/ServerShared/OrbitalEntity.cs b/Assets/Scripts/ServerShared/OrbitalEntity.cs index 47121eb16..93f055804 100644 --- a/Assets/Scripts/ServerShared/OrbitalEntity.cs +++ b/Assets/Scripts/ServerShared/OrbitalEntity.cs @@ -1,35 +1,36 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; using System.Collections; using System.Collections.Generic; +using GameCult.Caching; using CultMath; using static CultMath.math; using float2 = CultMath.float2; public class OrbitalEntity : Entity { - public Guid OrbitData; + public CultRecordKey OrbitData; public SecurityLevel SecurityLevel; public float SecurityRadius; public LocationStory Story; public bool CanTow; - - public OrbitalEntity(ItemManager itemManager, Zone zone, EquippableItem hull, Guid orbit, EntitySettings settings) : base(itemManager, zone, hull, settings) + + public OrbitalEntity(ItemManager itemManager, Zone zone, EquippableItem hull, CultRecordKey orbit, EntitySettings settings) : base(itemManager, zone, hull, settings) { OrbitData = orbit; } public override void Update(float delta) { - if (OrbitData != Guid.Empty) + if (OrbitData.IsSet()) { Position.xz = Zone.GetOrbitPosition(OrbitData); Velocity = Zone.GetOrbitVelocity(OrbitData); } - + base.Update(delta); } diff --git a/Assets/Scripts/ServerShared/PlayerSettings.cs b/Assets/Scripts/ServerShared/PlayerSettings.cs index 6280b06b2..0476a1491 100644 --- a/Assets/Scripts/ServerShared/PlayerSettings.cs +++ b/Assets/Scripts/ServerShared/PlayerSettings.cs @@ -1,9 +1,10 @@ +using GameCult.Caching; using System; using System.Collections.Generic; using System.Globalization; using MessagePack; -[MessagePackObject] +[CultDocument("aetheria.playersettings", "1"), CultGlobal, MessagePackObject] public class PlayerSettings { [Key(0)] public string Name = "Anonymous"; diff --git a/Assets/Scripts/ServerShared/SavedGame.cs b/Assets/Scripts/ServerShared/SavedGame.cs index 2f0579fb2..4cd91e52c 100644 --- a/Assets/Scripts/ServerShared/SavedGame.cs +++ b/Assets/Scripts/ServerShared/SavedGame.cs @@ -1,34 +1,35 @@ using System; using System.Collections.Generic; using System.Linq; +using GameCult.Caching; using MessagePack; using CultMath; using static CultMath.math; -[MessagePackObject] +[CultDocument("aetheria.savedgame", "1"), CultGlobal, MessagePackObject] public class SavedGame { [Key(0)] - public SavedZone[] Zones; - + public CultRecordRef[] Zones; + [Key(1)] - public Guid[] Factions; - + public CultRecordRef[] Factions; + [Key(2)] public Dictionary HomeZones; - + [Key(3)] public Dictionary BossZones; - + [Key(4)] public int Entrance; - + [Key(5)] public int Exit; - + [Key(6)] public int CurrentZone; - + [Key(7)] public int CurrentZoneEntity; @@ -46,59 +47,61 @@ public class SavedGame [Key(12)] public FactionRelationship[] Relationships; - + public SavedGame() { } - public SavedGame(Galaxy galaxy, Zone currentZone, Entity currentEntity) + // Writes a SavedZone record for every galaxy zone through the cache. + public SavedGame(CultCache cache, Galaxy galaxy, Zone currentZone, Entity currentEntity) { DiscoveredZones = galaxy.DiscoveredZones.Select(dz => Array.IndexOf(galaxy.Zones, dz)).ToArray(); Background = galaxy.Background; - Factions = galaxy.HomeZones.Keys.Select(f => f.ID).ToArray(); + var factions = galaxy.HomeZones.Keys.ToArray(); + Factions = factions.Select(f => cache.RefOf(f)).ToArray(); Relationships = galaxy.Factions.Select(f => galaxy.FactionRelationships[f]).ToArray(); - + HomeZones = galaxy.HomeZones.ToDictionary( - x => Array.IndexOf(Factions, x.Key.ID), + x => Array.IndexOf(factions, x.Key), x => Array.IndexOf(galaxy.Zones, x.Value)); BossZones = galaxy.BossZones.ToDictionary( - x => Array.IndexOf(Factions, x.Key.ID), + x => Array.IndexOf(factions, x.Key), x => Array.IndexOf(galaxy.Zones, x.Value)); - - Zones = galaxy.Zones.Select(zone => new SavedZone + + Zones = galaxy.Zones.Select(zone => cache.Upsert(new SavedZone { Name = zone.Name, Position = zone.Position, AdjacentZones = zone.AdjacentZones.Select(az=> Array.IndexOf(galaxy.Zones, az)).ToArray(), - Factions = zone.Factions.Select(f=> Array.IndexOf(Factions, f.ID)).ToArray(), + Factions = zone.Factions.Select(f=> Array.IndexOf(factions, f)).ToArray(), Contents = zone.Contents?.PackZone(), - Owner = zone.Owner == null ? -1 : Array.IndexOf(Factions, zone.Owner.ID) - }).ToArray(); + Owner = zone.Owner == null ? -1 : Array.IndexOf(factions, zone.Owner) + })).ToArray(); CurrentZone = Array.FindIndex(galaxy.Zones, zone => zone.Contents == currentZone); CurrentZoneEntity = currentZone.Entities.IndexOf(currentEntity); - + Entrance = Array.IndexOf(galaxy.Zones, galaxy.Entrance); Exit = Array.IndexOf(galaxy.Zones, galaxy.Exit); } } -[MessagePackObject] +[CultDocument("aetheria.savedzone", "1"), MessagePackObject] public class SavedZone { [Key(0)] public string Name; - + [Key(1)] public float2 Position; - + [Key(2)] public int[] AdjacentZones; - + [Key(3)] public int[] Factions; - + [Key(4)] public int Owner; - + [Key(5)] public ZonePack Contents; } @@ -115,7 +118,7 @@ public abstract class SavedActionBarBinding [MessagePackObject] public class SavedActionBarConsumableBinding : SavedActionBarBinding { - [Key(0)] public DatabaseLink Target; + [Key(0)] public CultRecordRef Target; } [MessagePackObject] @@ -129,4 +132,4 @@ public class SavedActionBarGearBinding : SavedActionBarBinding public class SavedActionBarWeaponGroupBinding : SavedActionBarBinding { [Key(0)] public int Group; -} \ No newline at end of file +} diff --git a/Assets/Scripts/ServerShared/Zone.cs b/Assets/Scripts/ServerShared/Zone.cs index e9fefd78e..740529a1c 100644 --- a/Assets/Scripts/ServerShared/Zone.cs +++ b/Assets/Scripts/ServerShared/Zone.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using GameCult.Caching; using UniRx; using CultMath; using static CultMath.math; @@ -17,17 +18,15 @@ using Random = CultMath.Random; public class Zone { public Action Log; - //public HashSet Planets = new HashSet(); public ReactiveCollection Entities = new ReactiveCollection(); - //public Dictionary Orbits = new Dictionary(); - public Dictionary Planets = new Dictionary(); - public Dictionary PlanetInstances = new Dictionary(); + public Dictionary Planets = new Dictionary(); + public Dictionary PlanetInstances = new Dictionary(); - public Dictionary Orbits = new Dictionary(); - public Dictionary AsteroidBelts = new Dictionary(); + public Dictionary Orbits = new Dictionary(); + public Dictionary AsteroidBelts = new Dictionary(); public PlanetSettings Settings; - - private HashSet _updatedOrbits = new HashSet(); + + private HashSet _updatedOrbits = new HashSet(); private ItemManager _itemManager; private double _time; @@ -35,7 +34,7 @@ public class Zone public List Agents = new List(); private List BeltUpdates = new List(); - + public float Time { get => (float) _time; @@ -53,28 +52,30 @@ public class Zone _itemManager = itemManager; Settings = settings; _random = new Random(Convert.ToUInt32(abs(galaxyZone?.Name.GetHashCode() ?? 1337))); - + var cache = itemManager.ItemData; + foreach (var orbit in pack.Orbits) { - Orbits.Add(orbit.ID, new Orbit(Settings, orbit)); + Orbits.Add(orbit.Key, new Orbit(Settings, cache.Get(orbit))); } - - foreach (var planet in pack.Planets) + + foreach (var body in pack.Planets) { - Planets.Add(planet.ID, planet); + var planet = cache.Get(body); + Planets.Add(body.Key, planet); switch (planet) { case AsteroidBeltData belt: - AsteroidBelts[belt.ID] = new AsteroidBelt(belt); + AsteroidBelts[body.Key] = new AsteroidBelt(belt); break; case SunData sun: - PlanetInstances.Add(sun.ID, new Sun(settings, sun, Orbits[planet.Orbit])); + PlanetInstances.Add(body.Key, new Sun(settings, sun, Orbits[planet.Orbit.Key])); break; case GasGiantData gas: - PlanetInstances.Add(gas.ID, new GasGiant(settings, gas, Orbits[planet.Orbit])); + PlanetInstances.Add(body.Key, new GasGiant(settings, gas, Orbits[planet.Orbit.Key])); break; default: - PlanetInstances.Add(planet.ID, new Planet(settings, planet, Orbits[planet.Orbit])); + PlanetInstances.Add(body.Key, new Planet(settings, planet, Orbits[planet.Orbit.Key])); break; } } @@ -111,15 +112,15 @@ public class Zone Radius = Pack.Radius, Mass = Pack.Mass, Entities = Entities.Select(EntitySerializer.Pack).ToList(), - Orbits = Orbits.Values.Select(o=>o.Data).ToList(), - Planets = Planets.Values.ToList(), + Orbits = Orbits.Keys.Select(key => new CultRecordRef(key)).ToList(), + Planets = Planets.Keys.Select(key => new CultRecordRef(key)).ToList(), Time = _time }; } public void AddOrbit(OrbitData orbit) { - Orbits.Add(orbit.ID, new Orbit(Settings, orbit)); + Orbits.Add(_itemManager.ItemData.RefOf(orbit).Key, new Orbit(Settings, orbit)); } public void Update(float deltaTime) @@ -142,25 +143,25 @@ public class Zone belt.Value.OrbitPosition = belt.Value.NewOrbitPosition; BeltUpdates.Add(Task.Run(() => UpdateAsteroidTransforms(belt.Key))); } - + foreach(var agent in Agents) agent.Update(deltaTime); - + foreach (var entity in Entities.ToArray()) entity.Update(deltaTime); } - + // Determine orbital position recursively, caching parent positions to avoid repeated calculations - public float2 GetOrbitPosition(Guid orbitID) + public float2 GetOrbitPosition(CultRecordKey orbitID) { // Root orbit is fixed at origin - if(orbitID==Guid.Empty) + if(!orbitID.IsSet()) return float2.zero; if (!Orbits.ContainsKey(orbitID)) { Log?.Invoke("Requested orbit is not part of this zone!"); return float2.zero; } - + if (!_updatedOrbits.Contains(orbitID)) { var orbit = Orbits[orbitID]; @@ -169,7 +170,7 @@ public class Zone { var phase = (float) frac(_time / orbit.Period); pos = OrbitData.Evaluate(frac(phase + orbit.Data.Phase)) * orbit.Data.Distance; - + if (float.IsNaN(pos.x)) { //_context.Log("Orbit position is NaN, something went very wrong!"); @@ -177,9 +178,9 @@ public class Zone } } - var parentPosition = Orbits[orbitID].Data.Parent == Guid.Empty - ? Orbits[orbitID].Data.FixedPosition : - GetOrbitPosition(orbit.Data.Parent); + var parentPosition = !Orbits[orbitID].Data.Parent.IsSet() + ? Orbits[orbitID].Data.FixedPosition : + GetOrbitPosition(orbit.Data.Parent.Key); Orbits[orbitID].Position = parentPosition + pos; _updatedOrbits.Add(orbitID); } @@ -187,14 +188,14 @@ public class Zone return Orbits[orbitID].Position; } - public float2 GetOrbitVelocity(Guid orbit) + public float2 GetOrbitVelocity(CultRecordKey orbit) { if (Orbits.ContainsKey(orbit)) return Orbits[orbit].Velocity; return float2.zero; } - public int NearestAsteroid(Guid planetDataID, float2 position) + public int NearestAsteroid(CultRecordKey planetDataID, float2 position) { var beltData = Planets[planetDataID] as AsteroidBeltData; @@ -215,16 +216,16 @@ public class Zone return nearest; } - public bool AsteroidExists(Guid planetDataID, int asteroid) => ((AsteroidBeltData) Planets[planetDataID]).Asteroids.Length > asteroid && asteroid >= 0; + public bool AsteroidExists(CultRecordKey planetDataID, int asteroid) => ((AsteroidBeltData) Planets[planetDataID]).Asteroids.Length > asteroid && asteroid >= 0; - private void UpdateAsteroidTransforms(Guid planetDataID) + private void UpdateAsteroidTransforms(CultRecordKey planetDataID) { var beltData = Planets[planetDataID] as AsteroidBeltData; - + var belt = AsteroidBelts[planetDataID]; - var orbitData = Orbits[beltData.Orbit].Data; - belt.NewOrbitPosition = GetOrbitPosition(orbitData.Parent); + var orbitData = Orbits[beltData.Orbit.Key].Data; + belt.NewOrbitPosition = GetOrbitPosition(orbitData.Parent.Key); for (var i = 0; i < beltData.Asteroids.Length; i++) { float size; @@ -245,7 +246,7 @@ public class Zone } } - public OrbitData CreateOrbit(Guid parent, float2 position) + public OrbitData CreateOrbit(CultRecordKey parent, float2 position) { var parentPosition = GetOrbitPosition(parent); var delta = position - parentPosition; @@ -257,16 +258,15 @@ public class Zone var orbit = new OrbitData { - ID = Guid.NewGuid(), Distance = distance, - Parent = parent, + Parent = new CultRecordRef(parent), Phase = storedPhase }; - Orbits.Add(orbit.ID, new Orbit(Settings, orbit)); + Orbits.Add(_itemManager.ItemData.Upsert(orbit).Key, new Orbit(Settings, orbit)); return orbit; } - public void MineAsteroid(Entity miner, Guid asteroidBelt, int asteroid, float damage, float efficiency, float penetration) + public void MineAsteroid(Entity miner, CultRecordKey asteroidBelt, int asteroid, float damage, float efficiency, float penetration) { var beltData = Planets[asteroidBelt] as AsteroidBeltData; var belt = AsteroidBelts[asteroidBelt]; @@ -274,15 +274,15 @@ public class Zone var size = beltData.Asteroids[asteroid].Size; var asteroidHitpoints = Settings.AsteroidHitpoints.Evaluate(size); - + if (!belt.Damage.ContainsKey(asteroid)) belt.Damage[asteroid] = 0; belt.Damage[asteroid] = belt.Damage[asteroid] + damage; - + if (!belt.MiningAccumulator.ContainsKey((miner, asteroid))) belt.MiningAccumulator[(miner, asteroid)] = 0; belt.MiningAccumulator[(miner, asteroid)] = belt.MiningAccumulator[(miner, asteroid)] + damage; - + if (belt.Damage[asteroid] > asteroidHitpoints) { belt.RespawnTimers[asteroid] = Settings.AsteroidRespawnTime.Evaluate(size); @@ -309,11 +309,11 @@ public class Zone public SecurityLevel GetSecurityLevel(float2 pos) { if (GalaxyZone.Owner==null) return SecurityLevel.Open; - + var security = SecurityLevel.Open; foreach (var entity in Entities) { - if (entity is OrbitalEntity orbitalEntity && orbitalEntity.SecurityRadius > 1 && entity.Faction.ID == GalaxyZone.Owner.ID) + if (entity is OrbitalEntity orbitalEntity && orbitalEntity.SecurityRadius > 1 && entity.Faction == GalaxyZone.Owner) { if (orbitalEntity.SecurityLevel > security && length(orbitalEntity.Position.xz - pos) < orbitalEntity.SecurityRadius * Settings.SecureAreaRadiusMultiplier) security = orbitalEntity.SecurityLevel; @@ -322,7 +322,7 @@ public class Zone return security; } - + public float GetHeight(float2 position) { var result = -PowerPulse(length(position)/(Pack.Radius*2), Settings.ZoneDepthExponent) * Settings.ZoneDepth; diff --git a/Assets/Scripts/ServerShared/ZoneData.cs b/Assets/Scripts/ServerShared/ZoneData.cs index 72c623ac2..90158fdb4 100644 --- a/Assets/Scripts/ServerShared/ZoneData.cs +++ b/Assets/Scripts/ServerShared/ZoneData.cs @@ -1,10 +1,11 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; using System.Collections; using System.Collections.Generic; +using GameCult.Caching; using MessagePack; using Newtonsoft.Json; using UniRx; @@ -17,14 +18,14 @@ using float3 = CultMath.float3; public class ZonePack { [JsonProperty("planets"), Key(0)] - public List Planets = new List(); - + public List> Planets = new List>(); + [JsonProperty("orbits"), Key(1)] - public List Orbits = new List(); - + public List> Orbits = new List>(); + [JsonProperty("entities"), Key(2)] public List Entities = new List(); - + [JsonProperty("radius"), Key(3)] public float Radius = 2000; @@ -33,29 +34,24 @@ public class ZonePack [JsonProperty("time"), Key(5)] public double Time; - - + + } -[MessagePackObject, - JsonObject(MemberSerialization.OptIn), - Union(0, typeof(PlanetData)), - Union(1, typeof(AsteroidBeltData)), - Union(2, typeof(GasGiantData)), - Union(3, typeof(SunData))] -public abstract class BodyData : DatabaseEntry, INamedEntry +[JsonObject(MemberSerialization.OptIn)] +public abstract class BodyData { - [JsonProperty("name"), Key(1)] + [CultName, JsonProperty("name"), Key(1)] public string Name = ""; [JsonProperty("orbit"), Key(2)] - public Guid Orbit; + public CultRecordRef Orbit; [JsonProperty("mass"), Key(3)] public float Mass = 0; - [JsonProperty("resources"), Key(4)] - public Dictionary Resources = new Dictionary(); + [CultReference(typeof(SimpleCommodityData), many: true), JsonProperty("resources"), Key(4)] + public Dictionary, float> Resources = new Dictionary, float>(); [JsonProperty("bodyRadiusMul")] [Key(5)] public float BodyRadiusMultiplier = 1; @@ -68,42 +64,36 @@ public abstract class BodyData : DatabaseEntry, INamedEntry [JsonProperty("depthExp")] [Key(8)] public float GravityDepthExponent = 16; - - [IgnoreMember] public string EntryName - { - get => Name; - set => Name = value; - } } -[MessagePackObject, JsonObject(MemberSerialization.OptIn)] +[CultDocument("aetheria.planetdata", "1"), MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class PlanetData : BodyData { - + } -[MessagePackObject, JsonObject(MemberSerialization.OptIn)] +[CultDocument("aetheria.asteroidbeltdata", "1"), MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class AsteroidBeltData : BodyData { [JsonProperty("asteroids"), Key(9)] public Asteroid[] Asteroids; } -[MessagePackObject, JsonObject(MemberSerialization.OptIn)] +[CultDocument("aetheria.gasgiantdata", "1"), MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class GasGiantData : BodyData { [JsonProperty("firstOffsetDomainRotationSpeed"), Key(9)] public float FirstOffsetDomainRotationSpeed = 1; - + [JsonProperty("firstOffsetRotationSpeed"), Key(10)] public float FirstOffsetRotationSpeed = 1; - + [JsonProperty("secondOffsetDomainRotationSpeed"), Key(11)] public float SecondOffsetDomainRotationSpeed = 1; - + [JsonProperty("secondOffsetRotationSpeed"), Key(12)] public float SecondOffsetRotationSpeed = 1; - + [JsonProperty("albedoRotationSpeed"), Key(13)] public float AlbedoRotationSpeed = 1; @@ -118,19 +108,20 @@ public class GasGiantData : BodyData [JsonProperty("depthExp")] [Key(17)] public float WaveSpeedMultiplier = 8; - + [JsonProperty("materialOverrides"), Key(18)] public List MaterialOverrides = new List(); - + [JsonProperty("colors"), Key(19)] public float4[] Colors = new float4[0]; } +[CultDocument("aetheria.sundata", "1"), MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class SunData : GasGiantData { [JsonProperty("lightColor"), Key(20)] public float3 LightColor = float3.zero; - + [JsonProperty("fogTintColor"), Key(21)] public float3 FogTintColor = float3.zero; @@ -143,32 +134,32 @@ public class Asteroid { [JsonProperty("distance"), Key(0)] public float Distance; - + [JsonProperty("phase"), Key(1)] public float Phase; - + [JsonProperty("size"), Key(2)] public float Size; - + [JsonProperty("rotationSpeed"), Key(3)] public float RotationSpeed; } -[MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class OrbitData : DatabaseEntry +[CultDocument("aetheria.orbitdata", "1"), MessagePackObject, JsonObject(MemberSerialization.OptIn)] +public class OrbitData { [JsonProperty("parent"), Key(1)] - public Guid Parent; + public CultRecordRef Parent; [JsonProperty("distance"), Key(2)] public float Distance; [JsonProperty("phase"), Key(3)] public float Phase; - + [JsonProperty("phase"), Key(4)] public float2 FixedPosition = float2.zero; - + // [JsonProperty("period"), Key(4)] // public float Period; @@ -177,4 +168,4 @@ public class OrbitData : DatabaseEntry phase *= PI * 2; return new float2(cos(phase), sin(phase)); } -} \ No newline at end of file +} diff --git a/Assets/Scripts/ServerShared/ZoneGenerator.cs b/Assets/Scripts/ServerShared/ZoneGenerator.cs index f75526adc..533fe2ebb 100644 --- a/Assets/Scripts/ServerShared/ZoneGenerator.cs +++ b/Assets/Scripts/ServerShared/ZoneGenerator.cs @@ -1,4 +1,4 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public +/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ @@ -43,6 +43,7 @@ public static class ZoneGenerator bool isTutorial = false) { var pack = new ZonePack(); + var cache = itemManager.ItemData; var random = new Random(unchecked((uint) galaxyZone.Name.GetHashCode()) ^ (uint) pcg3d(galaxyZone.Position).x); @@ -50,7 +51,7 @@ public static class ZoneGenerator pack.Radius = zoneSettings.ZoneRadius.Evaluate(density); pack.Mass = zoneSettings.ZoneMass.Evaluate(density); var targetSubzoneCount = zoneSettings.SubZoneCount.Evaluate(density); - + //Debug.Log($"Generating zone at position {zone.Position} with radius {zoneRadius} and mass {zoneMass}"); var planets = new List(); @@ -58,10 +59,10 @@ public static class ZoneGenerator { var zoneBoundary = new Circle(float2.zero, pack.Radius * zoneSettings.ZoneBoundaryRadius); float boundaryTangentRadius(float2 point) => -zoneBoundary.DistanceTo(point); - + var occupiedAreas = new List(); float tangentRadius(float2 point) => min(boundaryTangentRadius(point), occupiedAreas.Min(circle => circle.DistanceTo(point))); - + var startPosition = random.NextFloat(pack.Radius * .25f, pack.Radius * .5f) * random.NextFloat2Direction(); occupiedAreas.Add(new Circle(startPosition, boundaryTangentRadius(startPosition))); @@ -91,52 +92,29 @@ public static class ZoneGenerator } else planets.AddRange(GenerateEntities(zoneSettings, ref random, pack.Mass, pack.Radius, float2.zero)); - - // Create collections to map between zone generator output and database entries + + // Every orbit is a record; parents link to records, so each orbit holds its key before any child names it var orbitMap = new Dictionary(); - var orbitInverseMap = new Dictionary(); - - // Create orbit database entries - pack.Orbits = planets.Select(planet => - { - var data = new OrbitData + foreach (var planet in planets) + cache.Upsert(orbitMap[planet] = new OrbitData { FixedPosition = planet.FixedPosition, Distance = planet.Distance, - //Period = planet.Period, Phase = planet.Phase - }; - orbitMap[planet] = data; - orbitInverseMap[data] = planet; - return data; - }).ToList(); + }); + foreach (var planet in planets.Where(p => p.Parent != null)) + { + orbitMap[planet].Parent = cache.RefOf(orbitMap[planet.Parent]); + cache.Upsert(orbitMap[planet]); + } + pack.Orbits = planets.Select(planet => cache.RefOf(orbitMap[planet])).ToList(); - // Link OrbitData parents to database GUIDs - foreach (var data in pack.Orbits) - data.Parent = orbitInverseMap[data].Parent != null - ? orbitMap[orbitInverseMap[data].Parent].ID - : Guid.Empty; - - // Cache resource densities - // var resourceMaps = mapLayers.Values - // .ToDictionary(m => m.ID, m => m.Evaluate(zone.Position, settings.ShapeSettings)); - pack.Planets = planets.Where(p=>!p.Empty).Select(planet => { - // Dictionary planetResources = new Dictionary(); BodyType bodyType = planet.Belt ? BodyType.Asteroid : planet.Mass > zoneSettings.SunMass ? BodyType.Sun : planet.Mass > zoneSettings.GasGiantMass ? BodyType.GasGiant : planet.Mass > zoneSettings.PlanetMass ? BodyType.Planet : BodyType.Planetoid; - - // foreach (var r in resources) - // { - // if ((bodyType & r.ResourceBodyType) != 0) - // { - // float quantity = ResourceValue(ref random, settings, r, r.ResourceDensity.Aggregate(1f, (m, rdm) => m * resourceMaps[rdm])); - // if (r.Floor < quantity) planetResources.Add(r.ID, quantity); - // } - // } BodyData planetData; switch (bodyType) @@ -159,12 +137,10 @@ public static class ZoneGenerator } planetData.Mass = planet.Mass; - planetData.Orbit = orbitMap[planet].ID; - // planetData.Resources = planetResources; - planetData.Name = planetData.ID.ToString().Substring(0, 8); + planetData.Orbit = cache.RefOf(orbitMap[planet]); if (planetData is AsteroidBeltData beltData) { - beltData.Asteroids = + beltData.Asteroids = Enumerable.Range(0, (int) zoneSettings.AsteroidCount.Evaluate(beltData.Mass * orbitMap[planet].Distance)) .Select(_ => new Asteroid { @@ -197,12 +173,12 @@ public static class ZoneGenerator float primary = random.NextFloat(); float right = frac(primary + zoneSettings.GasGiantBandColorSeparation); float left = frac(primary + 1 - zoneSettings.GasGiantBandColorSeparation); - + // Create n time keys from 0 to 1 var bandCount = (int) (zoneSettings.GasGiantBandCount.Evaluate(random.NextFloat()) + .5f); var times = Enumerable.Range(0, bandCount) .Select(i => (float) i / (bandCount-1)); - + // Each band has a chance of being either the primary or one of the adjacent hues // Saturation and Value are random with curves applied gas.Colors = times @@ -211,7 +187,7 @@ public static class ZoneGenerator zoneSettings.GasGiantBandSaturation.Evaluate(random.NextFloat()), zoneSettings.GasGiantBandSaturation.Evaluate(random.NextFloat()))),time)) .ToArray(); - + gas.FirstOffsetDomainRotationSpeed = 0; } gas.AlbedoRotationSpeed = -3; @@ -219,7 +195,10 @@ public static class ZoneGenerator gas.SecondOffsetRotationSpeed = 10; gas.SecondOffsetDomainRotationSpeed = -25; } - return planetData; + + // A body is named for the first eight characters of the key the cache mints for it + planetData.Name = cache.Upsert(planetData).Key.Value.Substring(0, 8); + return cache.Upsert(planetData); }).ToList(); var nearestFaction = galaxy.Factions.MinBy(f => galaxy.HomeZones[f].Distance[galaxyZone]); @@ -253,30 +232,28 @@ public static class ZoneGenerator { var lagrangeOrbit = new OrbitData { - ID = Guid.NewGuid(), Parent = baseOrbit.Parent, Distance = baseOrbit.Distance, Phase = baseOrbit.Phase + PI / 3 * sign(random.NextFloat() - .5f) }; - pack.Orbits.Add(lagrangeOrbit); + pack.Orbits.Add(cache.Upsert(lagrangeOrbit)); return lagrangeOrbit; } void PlaceTurret(OrbitData orbit, LoadoutGenerator loadoutGenerator, int distanceMultiplier) { var phase = 20f * distanceMultiplier / orbit.Distance; - + var turretOrbit = new OrbitData { - ID = Guid.NewGuid(), Parent = orbit.Parent, Distance = orbit.Distance, Phase = orbit.Phase + phase }; - pack.Orbits.Add(turretOrbit); + pack.Orbits.Add(cache.Upsert(turretOrbit)); var turret = loadoutGenerator.GenerateTurretLoadout(); if (turret == null) return; - turret.Orbit = turretOrbit.ID; + turret.Orbit = cache.RefOf(turretOrbit); pack.Entities.Add(turret); } @@ -301,7 +278,7 @@ public static class ZoneGenerator itemManager.Log($"Story station for {story.Faction?.Name} could not be generated; its story has nowhere to live!"); continue; } - station.Orbit = lagrangeOrbit.ID; + station.Orbit = cache.RefOf(lagrangeOrbit); station.SecurityLevel = story.Security; station.SecurityRadius = pack.Radius; station.Story = i; @@ -318,7 +295,7 @@ public static class ZoneGenerator var lagrangeOrbit = CreateLagrangeOrbit(orbit); var station = GetLoadoutGenerator(nearestFaction).GenerateStationLoadout(); if (station == null) continue; - station.Orbit = lagrangeOrbit.ID; + station.Orbit = cache.RefOf(lagrangeOrbit); station.SecurityLevel = security; station.SecurityRadius = pack.Radius; pack.Entities.Add(station); @@ -336,7 +313,7 @@ public static class ZoneGenerator return pack; } - + // static float ResourceValue(ref Random random, ZoneGenerationSettings settings, SimpleCommodityData resource, float density) // { // return random.NextPowerDistribution(resource.Minimum, resource.Maximum, resource.Exponent, @@ -357,20 +334,20 @@ public static class ZoneGenerator // There is some chance of generating a rosette or binary system // Probabilities which are fixed for the entire galaxy are in GlobalData, contained in the GameContext var rosette = random.NextFloat() < settings.RosetteProbability; - + if (rosette) { // Create a rosette with a number of vertices between 2 and 9 inclusive root.ExpandRosette(ref random, (int)(random.NextFloat(1, 5) + random.NextFloat(1, 5))); - + // Create a small number of less massive "captured" planets orbiting past the rosette root.ExpandSolar( ref random, - count: (int)(random.NextFloat(1, 3) * random.NextFloat(1, 2)), - massMulMin: .6f, - massMulMax: .8f, - distMulMin: 1.25f, - distMulMax: 1.75f, + count: (int)(random.NextFloat(1, 3) * random.NextFloat(1, 2)), + massMulMin: .6f, + massMulMax: .8f, + distMulMin: 1.25f, + distMulMax: 1.75f, jupiterJump: 1, massFraction: .1f); @@ -381,9 +358,9 @@ public static class ZoneGenerator // Give each child in the rosette its own mini solar system p.ExpandSolar( ref random, - count: (int) (random.NextFloat(1, 3 * m) + random.NextFloat(1, 3 * m)), - massMulMin: 0.75f, - massMulMax: 2.5f, + count: (int) (random.NextFloat(1, 3 * m) + random.NextFloat(1, 3 * m)), + massMulMin: 0.75f, + massMulMax: 2.5f, distMulMin: 1 + m * .25f, distMulMax: 1.05f + m * .5f, jupiterJump: random.NextFloat() * random.NextFloat() * 10 + 1, @@ -396,9 +373,9 @@ public static class ZoneGenerator // Create a regular old boring solar system root.ExpandSolar( ref random, - count: random.NextInt(5, 15), - massMulMin: 0.75f, - massMulMax: 2.5f, + count: random.NextInt(5, 15), + massMulMin: 0.75f, + massMulMax: 2.5f, distMulMin: 1.1f, distMulMax: 1.25f, jupiterJump: random.NextFloat() * random.NextFloat() * 10 + 1, @@ -412,13 +389,13 @@ public static class ZoneGenerator { // Get all children that are above the satellite creation mass floor and not rosette members var satelliteCandidates = rosette - ? root.AllPlanets().Where(p => - p != root && - p.Parent != root && + ? root.AllPlanets().Where(p => + p != root && + p.Parent != root && p.Mass > settings.SatelliteCreationMassFloor && !alreadyExpanded.Contains(p)) - : root.AllPlanets().Where(p => - p != root && + : root.AllPlanets().Where(p => + p != root && p.Mass > settings.SatelliteCreationMassFloor && !alreadyExpanded.Contains(p)); @@ -455,7 +432,7 @@ public static class ZoneGenerator var beltCandidates = rosette ? root.AllPlanets().Where(p => p != root && p.Parent != root && p.Mass < settings.BeltMassCeiling && !binaries.Contains(p) && p.Children.Count == 0) : root.AllPlanets().Where(p => p != root && p.Mass < settings.BeltMassCeiling && !binaries.Contains(p) && p.Children.Count == 0); - + foreach(var planet in beltCandidates.Reverse()) if (random.NextFloat() < settings.BeltProbability && !planet.Parent.Children.Any(p=>p.Belt)) planet.Belt = true; @@ -498,29 +475,29 @@ public class GeneratorPlanet public void ExpandRosette(ref Random random, int vertices) { //Debug.Log("Expanding Rosette"); - + // Rosette children replace the parent, parent orbital node is left empty Empty = true; - + // Masses in a rosette alternate, so every sequential pair has the same shared mass var sharedMass = Mass / vertices * 2; - + // Proportion of the masses of sequential pairs is random, but only for even vertex counts var proportion = vertices % 2 == 0 ? random.NextFloat(.5f,.95f) : .5f; - + // Place children at a fixed distance in the center of the range var dist = (ChildDistanceMinimum + ChildDistanceMaximum) / 2; - + // Position of first child var p0 = new float2(0, dist); - + // Position of second child var p1 = OrbitData.Evaluate(1.0f / vertices) * dist; - + // Maximum child distance is half the distance to the neighbor minus the neighbor's radius var p0ChildDist = (distance(p0, p1) * proportion - Settings.PlanetSafetyRadius.Evaluate(sharedMass * (1 - proportion))) * .75f; var p1ChildDist = (distance(p0, p1) * (1 - proportion) - Settings.PlanetSafetyRadius.Evaluate(sharedMass * proportion)) * .75f; - + for (int i = 0; i < vertices; i++) { var child = new GeneratorPlanet @@ -547,14 +524,14 @@ public class GeneratorPlanet // Expansion is impossible when child space is full if (count == 0 || ChildDistanceMaximum < ChildDistanceMinimum) return; - + var masses = new float[count]; var distances = new float[count]; - - // Accumulate total mass + + // Accumulate total mass // Initialize first mass and distance, actual number doesn't matter since total mass will be divided proportionally float massTotal = distances[0] = masses[0] = 1; - + // Masses and distances multiply from one planet to the next // Mass typically increases exponentially as you go further out // jupiterJump is an additional mass multiplier applied after half of the planets @@ -580,7 +557,7 @@ public class GeneratorPlanet distances[i] = lerp(ChildDistanceMinimum, ChildDistanceMaximum, (oldDistances[i] - oldDistances[0]) / (oldDistances[count - 1] - oldDistances[0])) + Settings.PlanetSafetyRadius.Evaluate(masses[i]); } - + for (var i = 0; i < count; i++) { // Only instantiate children above the mass floor @@ -606,4 +583,4 @@ public class GeneratorPlanet } } } -} \ No newline at end of file +} diff --git a/Directory.Build.targets b/Directory.Build.targets index 5bb98fe75..da7151646 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -4,6 +4,8 @@ Condition="'$(SkipCultLibRevisionCheck)' != 'true' and '@(ProjectReference->AnyHaveMetadataValue('Identity', '$(CultLibRoot)\packages\cultmath\src\CultMath\CultMath.csproj'))' == 'true'"> +