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.<type>", "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<T> members become CultRecordRef<T>;
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 <noreply@anthropic.com>
This commit is contained in:
parent
b4c06b50cb
commit
a2b54889b4
50 changed files with 537 additions and 542 deletions
|
|
@ -25,6 +25,8 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="$(CultLibRoot)\packages\cultmath\src\CultMath\CultMath.csproj" />
|
||||
<ProjectReference Include="$(CultLibRoot)\src\GameCult.Caching\GameCult.Caching.csproj" />
|
||||
<ProjectReference Include="$(CultLibRoot)\src\GameCult.Caching.MessagePack\GameCult.Caching.MessagePack.csproj" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
57
Assets/Scripts/ServerShared/AetheriaStores.cs
Normal file
57
Assets/Scripts/ServerShared/AetheriaStores.cs
Normal file
|
|
@ -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<T>(this CultRecordRef<T> 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<T>(this CultCache cache, CultRecordRef<T> reference) where T : class =>
|
||||
reference.IsSet() ? cache.Get<T>(reference.Key) : null;
|
||||
|
||||
// A reference to a document this cache holds. The key comes from the cache, never from the document.
|
||||
public static CultRecordRef<T> RefOf<T>(this CultCache cache, T document) where T : class =>
|
||||
new CultRecordRef<T>(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<T> Upsert<T>(this CultCache cache, T document) where T : class =>
|
||||
new CultRecordRef<T>(cache.UpsertAsync(document).Result.Key);
|
||||
}
|
||||
11
Assets/Scripts/ServerShared/AetheriaStores.cs.meta
Normal file
11
Assets/Scripts/ServerShared/AetheriaStores.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a37c91e4d05b4f8e82c6b1d9e4f0a2c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<DatabaseEntry>))]
|
||||
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; }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<DatabaseEntry>))]
|
||||
JsonObject(MemberSerialization.OptIn)]
|
||||
public class Mining : AgentTask
|
||||
{
|
||||
[IgnoreMember] public override TaskType Type => TaskType.Mine;
|
||||
|
||||
[JsonProperty("asteroids"), Key(4)]
|
||||
public Guid Asteroids;
|
||||
public CultRecordKey Asteroids;
|
||||
}
|
||||
|
|
@ -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];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<DatabaseEntry>))]
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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<DatabaseEntry>))]
|
||||
JsonObject(MemberSerialization.OptIn)]
|
||||
public class Survey : AgentTask
|
||||
{
|
||||
[IgnoreMember] public override TaskType Type => TaskType.Explore;
|
||||
|
||||
[JsonProperty("station"), Key(4)]
|
||||
public List<Guid> Planets;
|
||||
public List<CultRecordKey> Planets;
|
||||
}
|
||||
4
Assets/Scripts/ServerShared/AssemblyInfo.cs
Normal file
4
Assets/Scripts/ServerShared/AssemblyInfo.cs
Normal file
|
|
@ -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))]
|
||||
11
Assets/Scripts/ServerShared/AssemblyInfo.cs.meta
Normal file
11
Assets/Scripts/ServerShared/AssemblyInfo.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5d8e2b7a1c4f4e3a9b6d0f2c8a1e7b43
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<PersistentBehaviorData>))]
|
||||
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<BehaviorData>)), JsonObject(MemberSerialization.OptIn)]
|
||||
JsonObject(MemberSerialization.OptIn)]
|
||||
public abstract class BehaviorData
|
||||
{
|
||||
[Inspectable, JsonProperty("group"), Key(0)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<SimpleCommodityData> 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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ public class VelocityLimitData : BehaviorData
|
|||
}
|
||||
}
|
||||
|
||||
[Order(100)]
|
||||
public class VelocityLimit : Behavior
|
||||
{
|
||||
public float Limit { get; private set; }
|
||||
|
|
|
|||
|
|
@ -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<SimpleCommodityData> 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)]
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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<Guid, float> Personality = new Dictionary<Guid, float>();
|
||||
|
||||
[Inspectable, CultReference(typeof(PersonalityAttribute), many: true), JsonProperty("personality"), Key(5)]
|
||||
public Dictionary<CultRecordRef<PersonalityAttribute>, float> Personality = new Dictionary<CultRecordRef<PersonalityAttribute>, 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<NameFile> GeonameFile;
|
||||
|
||||
[InspectableDatabaseLink(typeof(HullData)), JsonProperty("bossHull"), Key(10)]
|
||||
public Guid BossHull;
|
||||
[Inspectable, JsonProperty("bossHull"), Key(10)]
|
||||
public CultRecordRef<HullData> BossHull;
|
||||
|
||||
[Inspectable, JsonProperty("influence"), Key(11)]
|
||||
public int InfluenceDistance = 4;
|
||||
|
||||
[InspectableDatabaseLink(typeof(Faction)), RangedFloat(0, 1), JsonProperty("allegiance"), Key(12)]
|
||||
public Dictionary<Guid, float> Allegiance = new Dictionary<Guid, float>();
|
||||
|
||||
[InspectableSoundBank, JsonProperty("overworldMusic"), Key(13)]
|
||||
[Inspectable, CultReference(typeof(Faction), many: true), CultInspectorRange(0, 1), JsonProperty("allegiance"), Key(12)]
|
||||
public Dictionary<CultRecordRef<Faction>, float> Allegiance = new Dictionary<CultRecordRef<Faction>, 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ItemData>(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<Guid, List<ItemInstance>> ItemsOfType = new Dictionary<Guid, List<ItemInstance>>();
|
||||
public readonly Dictionary<CultRecordKey, List<ItemInstance>> ItemsOfType = new Dictionary<CultRecordKey, List<ItemInstance>>();
|
||||
|
||||
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<ItemInstance>();
|
||||
ItemsOfType[item.Data.LinkID].Add(item);
|
||||
if(!ItemsOfType.ContainsKey(item.Data.Key))
|
||||
ItemsOfType[item.Data.Key] = new List<ItemInstance>();
|
||||
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<ItemInstance>();
|
||||
ItemsOfType[item.Data.LinkID].Add(item);
|
||||
if(!ItemsOfType.ContainsKey(item.Data.Key))
|
||||
ItemsOfType[item.Data.Key] = new List<ItemInstance>();
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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<OrbitData>(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<Faction>(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<OrbitData> 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> 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
|
||||
|
|
|
|||
|
|
@ -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<T>(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);
|
||||
|
|
|
|||
|
|
@ -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<CraftedItemData> Design;
|
||||
|
||||
[InspectableDatabaseLink(typeof(Faction)), JsonProperty("manufacturer"), Key(4)]
|
||||
public Guid Manufacturer;
|
||||
[Inspectable, JsonProperty("manufacturer"), Key(4)]
|
||||
public CultRecordRef<Faction> Manufacturer;
|
||||
|
||||
[Inspectable, JsonProperty("roles"), Key(5)]
|
||||
public List<ProductRole> Roles = new List<ProductRole>();
|
||||
|
||||
[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
|
||||
|
|
|
|||
|
|
@ -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<string> Log { get; }
|
||||
public bool IsPrelude { get; }
|
||||
|
||||
private HashSet<Guid> _containedFactions;
|
||||
private HashSet<CultRecordKey> _containedFactions;
|
||||
private GalaxyZone[] _exitPath;
|
||||
private Dictionary<Faction, MarkovNameGenerator> _nameGenerators = new Dictionary<Faction, MarkovNameGenerator>();
|
||||
private readonly CultCache _cache;
|
||||
|
|
@ -51,13 +52,14 @@ public class Galaxy
|
|||
Log = log;
|
||||
Background = savedGame.Background;
|
||||
|
||||
Factions = savedGame.Factions.Select(cultCache.Get<Faction>).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<NameFile>(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> faction)
|
||||
{
|
||||
_containedFactions ??= new HashSet<Guid>(Factions.Select(f => f.ID));
|
||||
return _containedFactions.Contains(factionID);
|
||||
_containedFactions ??= new HashSet<CultRecordKey>(Factions.Select(f => _cache.RefOf(f).Key));
|
||||
return _containedFactions.Contains(faction.Key);
|
||||
}
|
||||
|
||||
class DijkstraVertex
|
||||
|
|
|
|||
|
|
@ -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<InputLayoutRow>)),
|
||||
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<InputLayoutColumn>)),
|
||||
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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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<ItemData>))]
|
||||
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<Faction> 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<CraftedItemData>))]
|
||||
[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<Guid, float> DemandProfile = new Dictionary<Guid, float>();
|
||||
[Inspectable, CultReference(typeof(PersonalityAttribute), many: true), JsonProperty("demandProfile"), Key(10)]
|
||||
public Dictionary<CultRecordRef<PersonalityAttribute>, float> DemandProfile = new Dictionary<CultRecordRef<PersonalityAttribute>, 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<HardpointData> Hardpoints = new List<HardpointData>();
|
||||
|
||||
[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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<ItemInstance>))]
|
||||
JsonObject(MemberSerialization.OptIn)]
|
||||
public abstract class ItemInstance
|
||||
{
|
||||
[JsonProperty("data"), Key(0)] public DatabaseLink<ItemData> Data;
|
||||
[JsonProperty("data"), Key(0)] public CultRecordRef<ItemData> 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<CraftedItemInstance>))]
|
||||
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<RoleFill> Ingredients = new List<RoleFill>();
|
||||
|
||||
// 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<FactionProductData> 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.
|
||||
|
|
|
|||
|
|
@ -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<string, GalaxyMapLayerData> MapLayers = new Dictionary<string, GalaxyMapLayerData>();
|
||||
// public SimpleCommodityData[] Resources;
|
||||
// public Dictionary<Guid, List<IController>> CorporationControllers = new Dictionary<Guid, List<IController>>();
|
||||
// public Dictionary<Guid, ZoneDefinition> GalaxyZones;
|
||||
|
||||
|
||||
private Action<string> _logger;
|
||||
|
||||
private double _time;
|
||||
private float _deltaTime;
|
||||
private Dictionary<Guid, Zone> _zones = new Dictionary<Guid, Zone>();
|
||||
|
||||
// private Guid _forceLoadZone;
|
||||
|
||||
// public GlobalData GlobalData => _globalData ?? (_globalData = ItemData.GetAll<GlobalData>().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<CraftedItemData, int> Tier = new Dictionary<CraftedItemData, int>();
|
||||
|
||||
public ItemManager(CultCache itemData, GameplaySettings settings, Action<string> 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<ItemData>{LinkID = item.ID},
|
||||
Data = ItemData.RefOf<ItemData>(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<ItemData> {LinkID = item.ID}, Quality = quality, Durability = equippableItemData.Durability
|
||||
Data = ItemData.RefOf<ItemData>(item), Quality = quality, Durability = equippableItemData.Durability
|
||||
};
|
||||
}
|
||||
|
||||
var newCommodity = new CompoundCommodity
|
||||
{
|
||||
Data = new DatabaseLink<ItemData>{LinkID = item.ID},
|
||||
Data = ItemData.RefOf<ItemData>(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<CraftedItemData>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<T>(int count, float sizeExponent, Predicate<T> filter = null, bool required = false) where T : EquippableItemData
|
||||
{
|
||||
var candidates = ItemManager.ItemData.GetAll<FactionProductData>()
|
||||
.Select(product => (product, design: ItemManager.ItemData.Get<CraftedItemData>(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<Faction> 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<int> _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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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<SavedZone>[] Zones;
|
||||
|
||||
[Key(1)]
|
||||
public Guid[] Factions;
|
||||
|
||||
public CultRecordRef<Faction>[] Factions;
|
||||
|
||||
[Key(2)]
|
||||
public Dictionary<int, int> HomeZones;
|
||||
|
||||
|
||||
[Key(3)]
|
||||
public Dictionary<int, int> 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<ConsumableItemData> Target;
|
||||
[Key(0)] public CultRecordRef<ConsumableItemData> Target;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
|
|
@ -129,4 +132,4 @@ public class SavedActionBarGearBinding : SavedActionBarBinding
|
|||
public class SavedActionBarWeaponGroupBinding : SavedActionBarBinding
|
||||
{
|
||||
[Key(0)] public int Group;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string> Log;
|
||||
//public HashSet<Guid> Planets = new HashSet<Guid>();
|
||||
public ReactiveCollection<Entity> Entities = new ReactiveCollection<Entity>();
|
||||
//public Dictionary<Guid, OrbitData> Orbits = new Dictionary<Guid, OrbitData>();
|
||||
public Dictionary<Guid, BodyData> Planets = new Dictionary<Guid, BodyData>();
|
||||
public Dictionary<Guid, Planet> PlanetInstances = new Dictionary<Guid, Planet>();
|
||||
public Dictionary<CultRecordKey, BodyData> Planets = new Dictionary<CultRecordKey, BodyData>();
|
||||
public Dictionary<CultRecordKey, Planet> PlanetInstances = new Dictionary<CultRecordKey, Planet>();
|
||||
|
||||
public Dictionary<Guid, Orbit> Orbits = new Dictionary<Guid, Orbit>();
|
||||
public Dictionary<Guid, AsteroidBelt> AsteroidBelts = new Dictionary<Guid, AsteroidBelt>();
|
||||
public Dictionary<CultRecordKey, Orbit> Orbits = new Dictionary<CultRecordKey, Orbit>();
|
||||
public Dictionary<CultRecordKey, AsteroidBelt> AsteroidBelts = new Dictionary<CultRecordKey, AsteroidBelt>();
|
||||
public PlanetSettings Settings;
|
||||
|
||||
private HashSet<Guid> _updatedOrbits = new HashSet<Guid>();
|
||||
|
||||
private HashSet<CultRecordKey> _updatedOrbits = new HashSet<CultRecordKey>();
|
||||
|
||||
private ItemManager _itemManager;
|
||||
private double _time;
|
||||
|
|
@ -35,7 +34,7 @@ public class Zone
|
|||
public List<Agent> Agents = new List<Agent>();
|
||||
|
||||
private List<Task> BeltUpdates = new List<Task>();
|
||||
|
||||
|
||||
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<OrbitData>(key)).ToList(),
|
||||
Planets = Planets.Keys.Select(key => new CultRecordRef<BodyData>(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<OrbitData>(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;
|
||||
|
|
|
|||
|
|
@ -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<BodyData> Planets = new List<BodyData>();
|
||||
|
||||
public List<CultRecordRef<BodyData>> Planets = new List<CultRecordRef<BodyData>>();
|
||||
|
||||
[JsonProperty("orbits"), Key(1)]
|
||||
public List<OrbitData> Orbits = new List<OrbitData>();
|
||||
|
||||
public List<CultRecordRef<OrbitData>> Orbits = new List<CultRecordRef<OrbitData>>();
|
||||
|
||||
[JsonProperty("entities"), Key(2)]
|
||||
public List<EntityPack> Entities = new List<EntityPack>();
|
||||
|
||||
|
||||
[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<OrbitData> Orbit;
|
||||
|
||||
[JsonProperty("mass"), Key(3)]
|
||||
public float Mass = 0;
|
||||
|
||||
[JsonProperty("resources"), Key(4)]
|
||||
public Dictionary<Guid, float> Resources = new Dictionary<Guid, float>();
|
||||
[CultReference(typeof(SimpleCommodityData), many: true), JsonProperty("resources"), Key(4)]
|
||||
public Dictionary<CultRecordRef<SimpleCommodityData>, float> Resources = new Dictionary<CultRecordRef<SimpleCommodityData>, 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<string> MaterialOverrides = new List<string>();
|
||||
|
||||
|
||||
[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<OrbitData> 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<GeneratorPlanet>();
|
||||
|
|
@ -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<Circle>();
|
||||
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<GeneratorPlanet, OrbitData>();
|
||||
var orbitInverseMap = new Dictionary<OrbitData, GeneratorPlanet>();
|
||||
|
||||
// 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<Guid, float> planetResources = new Dictionary<Guid, float>();
|
||||
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
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
Condition="'$(SkipCultLibRevisionCheck)' != 'true' and '@(ProjectReference->AnyHaveMetadataValue('Identity', '$(CultLibRoot)\packages\cultmath\src\CultMath\CultMath.csproj'))' == 'true'">
|
||||
<Error Condition="!Exists('$(CultLibRoot)\packages\cultmath\src\CultMath\CultMath.csproj')"
|
||||
Text="CultLibRoot '$(CultLibRoot)' does not contain the required CultMath project." />
|
||||
<Error Condition="!Exists('$(CultLibRoot)\src\GameCult.Caching\GameCult.Caching.csproj')"
|
||||
Text="CultLibRoot '$(CultLibRoot)' does not contain the required GameCult.Caching project." />
|
||||
<Exec Command=""$(GitExecutable)" -C "$(CultLibRoot)" rev-parse HEAD"
|
||||
ConsoleToMSBuild="true"
|
||||
StandardOutputImportance="Low">
|
||||
|
|
|
|||
Loading…
Reference in a new issue