From 6aeb2ae280f3ad086625adc7bb0b4a69e28b15d0 Mon Sep 17 00:00:00 2001 From: hyperion51 Date: Wed, 6 May 2020 04:56:36 +0100 Subject: [PATCH] Entity Persistence Refactoring Entities refactored to enable robust persistence Entities detect stale data references and reload behaviors --- .../ServerShared/Agents/AgentController.cs | 13 +- .../Scripts/ServerShared/Agents/AgentTask.cs | 12 +- .../ServerShared/Agents/EntityAgent.cs | 21 +- .../Scripts/ServerShared/Agents/Locomotion.cs | 30 ++- .../ServerShared/Agents/StationTowing.cs | 7 +- .../ServerShared/Agents/VelocityMatch.cs | 35 +-- .../ServerShared/Behaviors/Afterburner.cs | 6 +- .../ServerShared/Behaviors/Behaviors.cs | 20 +- .../ServerShared/Behaviors/FactoryBehavior.cs | 48 ++-- .../ServerShared/Behaviors/Launcher.cs | 6 +- .../Behaviors/ProjectileWeapon.cs | 6 +- .../ServerShared/Behaviors/Radiator.cs | 6 +- .../Scripts/ServerShared/Behaviors/Reactor.cs | 6 +- .../ServerShared/Behaviors/Reflector.cs | 6 +- .../Scripts/ServerShared/Behaviors/Sensor.cs | 6 +- .../Scripts/ServerShared/Behaviors/Shield.cs | 6 +- .../ServerShared/Behaviors/Thruster.cs | 6 +- .../Scripts/ServerShared/Behaviors/Turning.cs | 6 +- .../Behaviors/VelocityConversion.cs | 6 +- .../ServerShared/Behaviors/VelocityLimit.cs | 6 +- .../Scripts/ServerShared/Behaviors/Weapon.cs | 2 +- Assets/Scripts/ServerShared/BlueprintData.cs | 2 +- Assets/Scripts/ServerShared/DatabaseItems.cs | 1 + Assets/Scripts/ServerShared/Entity.cs | 213 +++++++++++------- Assets/Scripts/ServerShared/ItemData.cs | 2 +- Assets/Scripts/ServerShared/OrbitalEntity.cs | 2 +- Assets/Scripts/ServerShared/Ship.cs | 2 +- Assets/Scripts/StrategyGameManager.cs | 4 +- Assets/Scripts/UI/DragHandler.cs | 15 +- 29 files changed, 299 insertions(+), 202 deletions(-) diff --git a/Assets/Scripts/ServerShared/Agents/AgentController.cs b/Assets/Scripts/ServerShared/Agents/AgentController.cs index 6c3c5864e..7d6ba5f52 100644 --- a/Assets/Scripts/ServerShared/Agents/AgentController.cs +++ b/Assets/Scripts/ServerShared/Agents/AgentController.cs @@ -7,25 +7,23 @@ using Random = Unity.Mathematics.Random; public class AgentController { - public Entity Entity { get; } + public Guid Entity { get; } public EntityAgent EntityAgent { get; } public GameContext Context { get; } public Guid Zone { get; set; } - public Guid HomeZone; - private Locomotion _locomotion; private VelocityMatch _velocityMatch; private Random _random = new Random((uint) (DateTime.Now.Ticks%uint.MaxValue)); private Guid _targetOrbit; - public AgentController(GameContext context, Guid zone, Entity entity) + public AgentController(GameContext context, Guid zone, Guid entity) { Entity = entity; Zone = zone; Context = context; - EntityAgent = new EntityAgent(context, zone, entity); - _locomotion = new Locomotion(entity); + EntityAgent = new EntityAgent(context, entity, zone, Guid.Empty); + _locomotion = new Locomotion(context, entity); _velocityMatch = new VelocityMatch(context, entity); _velocityMatch.OnMatch += () => { @@ -44,6 +42,7 @@ public class AgentController // $"Agent Distance: {distance} " + // $"Turnaround Distance: {_stoppingDistance + _turnaroundDistance} " + // $"Objective: {_objective.Key.ID.ToString().Substring(0, 8)}"); + var entity = Context.Cache.Get(Entity); if (EntityAgent.CurrentBehavior == _locomotion) { @@ -51,7 +50,7 @@ public class AgentController _velocityMatch.TargetOrbit = _targetOrbit; var matchDistanceTime = _velocityMatch.MatchDistanceTime; _locomotion.Objective = Context.GetOrbitPosition(_targetOrbit) + Context.GetOrbitVelocity(_targetOrbit) * matchDistanceTime.y; - var distance = length(_locomotion.Objective - Entity.Position); + var distance = length(_locomotion.Objective - entity.Position); if (distance < matchDistanceTime.x) EntityAgent.CurrentBehavior = _velocityMatch; } diff --git a/Assets/Scripts/ServerShared/Agents/AgentTask.cs b/Assets/Scripts/ServerShared/Agents/AgentTask.cs index 0fc930e53..2d2279af4 100644 --- a/Assets/Scripts/ServerShared/Agents/AgentTask.cs +++ b/Assets/Scripts/ServerShared/Agents/AgentTask.cs @@ -1,13 +1,19 @@ using System; using System.Collections; using System.Collections.Generic; +using JsonKnownTypes; +using MessagePack; +using Newtonsoft.Json; using UnityEngine; +[MessagePackObject, + Union(0, typeof(StationTowing)), + JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] public abstract class AgentTask { - public abstract AgentJob JobType { get; } - public int Priority; - public Guid Zone; + [IgnoreMember] public abstract AgentJob JobType { get; } + [JsonProperty("id"), Key(0)] public int Priority; + [JsonProperty("zone"), Key(1)] public Guid Zone; } public enum AgentJob diff --git a/Assets/Scripts/ServerShared/Agents/EntityAgent.cs b/Assets/Scripts/ServerShared/Agents/EntityAgent.cs index 5baf4d05c..22b5c2f53 100644 --- a/Assets/Scripts/ServerShared/Agents/EntityAgent.cs +++ b/Assets/Scripts/ServerShared/Agents/EntityAgent.cs @@ -1,24 +1,29 @@ using System; using System.Collections; using System.Collections.Generic; +using JsonKnownTypes; +using MessagePack; +using Newtonsoft.Json; +[MessagePackObject, + JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] public class EntityAgent { - public AgentBehavior CurrentBehavior; + [IgnoreMember] public AgentBehavior CurrentBehavior; + [IgnoreMember] public Guid Entity; + [IgnoreMember] public GameContext Context; + [JsonProperty("homeZone"), Key(0)] public Guid HomeZone; + [JsonProperty("homeColony"), Key(0)] public Guid HomeColony; - public Entity Entity { get; } - public GameContext Context { get; } - public Guid Zone { get; set; } - - public EntityAgent(GameContext context, Guid zone, Entity entity) + public EntityAgent(GameContext context, Guid entity, Guid homeZone, Guid homeColony) { Entity = entity; - Zone = zone; + HomeZone = homeZone; Context = context; } public void Update(float delta) { - CurrentBehavior.Update(delta); + CurrentBehavior?.Update(delta); } } diff --git a/Assets/Scripts/ServerShared/Agents/Locomotion.cs b/Assets/Scripts/ServerShared/Agents/Locomotion.cs index 6a2d72ab4..4475f604a 100644 --- a/Assets/Scripts/ServerShared/Agents/Locomotion.cs +++ b/Assets/Scripts/ServerShared/Agents/Locomotion.cs @@ -1,4 +1,5 @@ -using System.Collections; +using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using Unity.Mathematics; @@ -7,28 +8,33 @@ using static Unity.Mathematics.math; public class Locomotion : AgentBehavior { public float2 Objective; - private Entity _entity; - private IAnalogBehavior _thrust; - private IAnalogBehavior _turning; private const float Sensitivity = 1; private const float TangentSensitivity = 2; + + private GameContext _context; + private Guid _entity; + private IAnalogBehavior _thrust; + private IAnalogBehavior _turning; - public Locomotion(Entity entity) + public Locomotion(GameContext context, Guid entity) { + _context = context; _entity = entity; - _thrust = entity.Axes.Keys.FirstOrDefault(x => x is Thruster); - _turning = entity.Axes.Keys.FirstOrDefault(x => x is Turning); + var entityObject = _context.Cache.Get(_entity); + _thrust = entityObject.Axes.Keys.FirstOrDefault(x => x is Thruster); + _turning = entityObject.Axes.Keys.FirstOrDefault(x => x is Turning); } public override void Update(float delta) { + var entity = _context.Cache.Get(_entity); if (_thrust != null && _turning != null) { - float2 diff = Objective - _entity.Position; - float2 tangential = _entity.Velocity - dot(normalize(diff), normalize(_entity.Velocity)) * _entity.Velocity; - float angleDiff = _entity.Direction.AngleDiff(normalize(diff) - tangential * TangentSensitivity); - _entity.Axes[_turning] = clamp(-angleDiff * Sensitivity, -1, 1); - _entity.Axes[_thrust] = 1; + float2 diff = Objective - entity.Position; + float2 tangential = entity.Velocity - dot(normalize(diff), normalize(entity.Velocity)) * entity.Velocity; + float angleDiff = entity.Direction.AngleDiff(normalize(diff) - tangential * TangentSensitivity); + entity.Axes[_turning] = clamp(-angleDiff * Sensitivity, -1, 1); + entity.Axes[_thrust] = 1; } } } diff --git a/Assets/Scripts/ServerShared/Agents/StationTowing.cs b/Assets/Scripts/ServerShared/Agents/StationTowing.cs index d4fc5d707..012f5d871 100644 --- a/Assets/Scripts/ServerShared/Agents/StationTowing.cs +++ b/Assets/Scripts/ServerShared/Agents/StationTowing.cs @@ -1,11 +1,16 @@ using System; using System.Collections; using System.Collections.Generic; +using JsonKnownTypes; +using MessagePack; +using Newtonsoft.Json; using UnityEngine; +[MessagePackObject, + JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] public class StationTowing : AgentTask { - public override AgentJob JobType => AgentJob.Tow; + [IgnoreMember] public override AgentJob JobType => AgentJob.Tow; private Guid _entity; private Guid _targetOrbit; diff --git a/Assets/Scripts/ServerShared/Agents/VelocityMatch.cs b/Assets/Scripts/ServerShared/Agents/VelocityMatch.cs index 25ac1c631..7f29b0b9a 100644 --- a/Assets/Scripts/ServerShared/Agents/VelocityMatch.cs +++ b/Assets/Scripts/ServerShared/Agents/VelocityMatch.cs @@ -9,33 +9,35 @@ public class VelocityMatch : AgentBehavior { public event Action OnMatch; public Guid TargetOrbit; - private Entity _entity; + private Guid _entity; private IAnalogBehavior _thrust; private IAnalogBehavior _turning; private const float TurningSensitivity = 1; private const float ThrustSensitivity = 1; private const float TargetThreshold = .1f; - - public GameContext Context { get; } - public VelocityMatch(GameContext context, Entity entity) + private GameContext _context; + + public VelocityMatch(GameContext context, Guid entity) { - Context = context; + _context = context; _entity = entity; - _thrust = entity.Axes.Keys.FirstOrDefault(x => x is Thruster); - _turning = entity.Axes.Keys.FirstOrDefault(x => x is Turning); + var entityObject = _context.Cache.Get(_entity); + _thrust = entityObject.Axes.Keys.FirstOrDefault(x => x is Thruster); + _turning = entityObject.Axes.Keys.FirstOrDefault(x => x is Turning); } public override void Update(float delta) { + var entity = _context.Cache.Get(_entity); if (TargetOrbit != Guid.Empty && _thrust != null && _turning != null) { - var deltaV = Context.GetOrbitVelocity(TargetOrbit) - _entity.Velocity; + var deltaV = _context.GetOrbitVelocity(TargetOrbit) - entity.Velocity; if(length(deltaV) < TargetThreshold) OnMatch?.Invoke(); - var angleDiff = _entity.Direction.AngleDiff(deltaV); - _entity.Axes[_turning] = clamp(-angleDiff * TurningSensitivity, -1, 1); - _entity.Axes[_thrust] = saturate(length(pow(saturate(dot(normalize(_entity.Direction),normalize(deltaV))), 8)*length(deltaV))*ThrustSensitivity); + var angleDiff = entity.Direction.AngleDiff(deltaV); + entity.Axes[_turning] = clamp(-angleDiff * TurningSensitivity, -1, 1); + entity.Axes[_thrust] = saturate(length(pow(saturate(dot(normalize(entity.Direction),normalize(deltaV))), 8)*length(deltaV))*ThrustSensitivity); } } @@ -43,14 +45,15 @@ public class VelocityMatch : AgentBehavior { get { - var velocity = length(_entity.Velocity); - var deltaV = Context.GetOrbitVelocity(TargetOrbit) - _entity.Velocity; + var entity = _context.Cache.Get(_entity); + var velocity = length(entity.Velocity); + var deltaV = _context.GetOrbitVelocity(TargetOrbit) - entity.Velocity; - var stoppingTime = length(deltaV) / (_entity.Context.Evaluate((_thrust.Data as ThrusterData).Thrust, _thrust.Item, _entity) / _entity.Mass); + var stoppingTime = length(deltaV) / (_context.Evaluate((_thrust.Data as ThrusterData).Thrust, _thrust.Item, entity) / entity.Mass); var stoppingDistance = stoppingTime * (velocity / 2); - var angleDiff = _entity.Direction.AngleDiff(deltaV); - var turnaroundTime = angleDiff / (_entity.Context.Evaluate((_turning.Data as TurningData).Torque, _turning.Item, _entity) / _entity.Mass); + var angleDiff = entity.Direction.AngleDiff(deltaV); + var turnaroundTime = angleDiff / (_context.Evaluate((_turning.Data as TurningData).Torque, _turning.Item, entity) / entity.Mass); var turnaroundDistance = turnaroundTime * velocity; return float2(stoppingDistance + turnaroundDistance, stoppingTime + turnaroundTime); diff --git a/Assets/Scripts/ServerShared/Behaviors/Afterburner.cs b/Assets/Scripts/ServerShared/Behaviors/Afterburner.cs index 122e21409..19216cfd2 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Afterburner.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Afterburner.cs @@ -5,7 +5,7 @@ using MessagePack; using Newtonsoft.Json; [InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class AfterburnerData : IBehaviorData +public class AfterburnerData : BehaviorData { [InspectableField, JsonProperty("thrust"), Key(0)] public PerformanceStat ThrustModifier = new PerformanceStat(); @@ -16,7 +16,7 @@ public class AfterburnerData : IBehaviorData [InspectableField, JsonProperty("torque"), Key(2)] public PerformanceStat TorqueModifier = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new Afterburner(context, this, entity, item); } @@ -32,7 +32,7 @@ public class Afterburner : IActivatedBehavior public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; public Afterburner(GameContext context, AfterburnerData data, Entity entity, Gear item) { diff --git a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs index 4e78c1b7c..bf791783c 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs @@ -16,7 +16,7 @@ public interface IBehavior Entity Entity { get; } Gear Item { get; } GameContext Context { get; } - IBehaviorData Data { get; } + BehaviorData Data { get; } } public interface IActivatedBehavior : IBehavior @@ -35,9 +35,14 @@ public interface IPersistentBehavior// where T : IBehavior PersistentBehaviorData Store(); void Restore(PersistentBehaviorData data); } -[Union(0, typeof(FactoryPersistence)), + +[MessagePackObject, + Union(0, typeof(FactoryPersistence)), + JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] -public class PersistentBehaviorData { } +public abstract class PersistentBehaviorData +{ +} [InspectableField, Union(0, typeof(ProjectileWeaponData)), @@ -53,8 +58,11 @@ public class PersistentBehaviorData { } Union(10, typeof(VelocityConversionData)), Union(11, typeof(VelocityLimitData)), Union(12, typeof(FactoryData)), - JsonConverter(typeof(JsonKnownTypesConverter)), JsonObject(MemberSerialization.OptIn)] -public interface IBehaviorData + JsonConverter(typeof(JsonKnownTypesConverter)), JsonObject(MemberSerialization.OptIn)] +public abstract class BehaviorData { - IBehavior CreateInstance(GameContext context, Entity entity, Gear item); + // [InspectableField, JsonProperty("index"), Key(0)] + // public int Index; + + public abstract IBehavior CreateInstance(GameContext context, Entity entity, Gear item); } \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs b/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs index 53b7e608c..b0b567327 100644 --- a/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs +++ b/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs @@ -8,7 +8,7 @@ using static Unity.Mathematics.math; using Random = Unity.Mathematics.Random; [MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class FactoryData : IBehaviorData +public class FactoryData : BehaviorData { [InspectableField, JsonProperty("toolingTime"), Key(0)] public PerformanceStat ToolingTime = new PerformanceStat(); @@ -16,7 +16,7 @@ public class FactoryData : IBehaviorData [InspectableField, JsonProperty("automation"), Key(1)] public int AutomationPoints; - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new Factory(context, this, entity, item); } @@ -28,7 +28,7 @@ public class Factory : IBehavior, IPersistentBehavior// public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; private FactoryData _data; @@ -109,28 +109,28 @@ public class Factory : IBehavior, IPersistentBehavior// }; } Context.Cache.Add(newItem); - Entity.Cargo.Add(newItem); + Entity.Cargo.Add(newItem.ID); } } else { var simpleCommodityData = blueprintItemData as SimpleCommodityData; - var simpleCommodityInstance = Entity.Cargo.FirstOrDefault(i => i.Data == simpleCommodityData.ID) as SimpleCommodity; - if (simpleCommodityInstance == null) + var simpleCommodityInstance = Entity.Cargo.FirstOrDefault(i => i == simpleCommodityData.ID); + if (simpleCommodityInstance == Guid.Empty) { - simpleCommodityInstance = new SimpleCommodity + var newSimpleCommodity = new SimpleCommodity { Context = Context, Data = simpleCommodityData.ID, ID = Guid.NewGuid(), Quantity = blueprint.Quantity }; - Context.Cache.Add(simpleCommodityInstance); - Entity.Cargo.Add(simpleCommodityInstance); + Context.Cache.Add(newSimpleCommodity); + Entity.Cargo.Add(newSimpleCommodity.ID); } else { - simpleCommodityInstance.Quantity += blueprint.Quantity; + Context.Cache.Get(simpleCommodityInstance).Quantity += blueprint.Quantity; } } Entity.RecalculateMass(); @@ -138,15 +138,15 @@ public class Factory : IBehavior, IPersistentBehavior// var simpleIngredients = new List(); var compoundIngredients = new List(); var hasAllIngredients = true; + var cargoInstances = Entity.Cargo.Select(c => Context.Cache.Get(c)); foreach (var kvp in blueprint.Ingredients) { var itemData = Context.Cache.Get(kvp.Key); if (itemData is SimpleCommodityData) { - var matchingItem = Entity.Cargo.FirstOrDefault(ii => + var matchingItem = cargoInstances.FirstOrDefault(ii => { - var simpleCommodity = ii as SimpleCommodity; - if (simpleCommodity == null) return false; + if (!(ii is SimpleCommodity simpleCommodity)) return false; return simpleCommodity.Data == itemData.ID && simpleCommodity.Quantity >= kvp.Value; }) as SimpleCommodity; hasAllIngredients = hasAllIngredients && matchingItem != null; @@ -156,10 +156,10 @@ public class Factory : IBehavior, IPersistentBehavior// else { var matchingItems = - Entity.Cargo.Where(ii => (ii as CompoundCommodity)?.Data == itemData.ID).Cast().ToArray(); + cargoInstances.Where(ii => (ii as CompoundCommodity)?.Data == itemData.ID).Cast().ToArray(); hasAllIngredients = hasAllIngredients && matchingItems.Length >= kvp.Value; if(matchingItems.Length >= kvp.Value) - compoundIngredients.AddRange(matchingItems); + compoundIngredients.AddRange(matchingItems.Take(kvp.Value)); } } @@ -168,7 +168,7 @@ public class Factory : IBehavior, IPersistentBehavior// _reservedStock.AddRange(compoundIngredients); foreach (var compoundCommodity in compoundIngredients) { - Entity.Cargo.Remove(compoundCommodity); + Entity.Cargo.Remove(compoundCommodity.ID); } foreach (var simpleCommodity in simpleIngredients) { @@ -177,7 +177,7 @@ public class Factory : IBehavior, IPersistentBehavior// if (simpleCommodity.Quantity == blueprintQuantity) { _reservedStock.Add(simpleCommodity); - Entity.Cargo.Remove(simpleCommodity); + Entity.Cargo.Remove(simpleCommodity.ID); } else { @@ -230,11 +230,11 @@ public class Factory : IBehavior, IPersistentBehavior// [MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class FactoryPersistence : PersistentBehaviorData { - public Guid Blueprint; - public float RemainingManHours; - public bool Retooling; - public bool Producing; - public Guid[] ReservedStock; - public int AssignedPopulation; - public float ProductionQuality; + [JsonProperty("blueprint"), Key(0)] public Guid Blueprint; + [JsonProperty("remainingManHours"), Key(1)] public float RemainingManHours; + [JsonProperty("retooling"), Key(2)] public bool Retooling; + [JsonProperty("producing"), Key(3)] public bool Producing; + [JsonProperty("reservedStock"), Key(4)] public Guid[] ReservedStock; + [JsonProperty("assignedPopulation"), Key(5)] public int AssignedPopulation; + [JsonProperty("productionQuality"), Key(6)] public float ProductionQuality; } \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/Behaviors/Launcher.cs b/Assets/Scripts/ServerShared/Behaviors/Launcher.cs index e98f76b42..a831fd72f 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Launcher.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Launcher.cs @@ -5,7 +5,7 @@ using Newtonsoft.Json; using Unity.Mathematics; [InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class LauncherData : IBehaviorData +public class LauncherData : BehaviorData { [InspectablePrefab, JsonProperty("missile"), Key(9)] public string MissilePrefab; @@ -37,7 +37,7 @@ public class LauncherData : IBehaviorData [InspectableField, JsonProperty("lockOnTime"), Key(18)] public PerformanceStat LockOnTime = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new Launcher(context, this, entity, item); } @@ -162,5 +162,5 @@ public class Launcher : IActivatedBehavior // } } - public IBehaviorData Data => _launcher; + public BehaviorData Data => _launcher; } \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/Behaviors/ProjectileWeapon.cs b/Assets/Scripts/ServerShared/Behaviors/ProjectileWeapon.cs index c813f2e19..221a88d83 100644 --- a/Assets/Scripts/ServerShared/Behaviors/ProjectileWeapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/ProjectileWeapon.cs @@ -2,7 +2,7 @@ using MessagePack; using Newtonsoft.Json; [InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class ProjectileWeaponData : WeaponData, IBehaviorData +public class ProjectileWeaponData : WeaponData { [InspectablePrefab, JsonProperty("bullet"), Key(9)] public string BulletPrefab; @@ -16,7 +16,7 @@ public class ProjectileWeaponData : WeaponData, IBehaviorData [InspectableField, JsonProperty("bulletVelocity"), Key(12)] public PerformanceStat Velocity = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new ProjectileWeapon(context, this, entity, item); } @@ -97,5 +97,5 @@ public class ProjectileWeapon : IActivatedBehavior } } - public IBehaviorData Data => _projectileWeapon; + public BehaviorData Data => _projectileWeapon; } \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/Behaviors/Radiator.cs b/Assets/Scripts/ServerShared/Behaviors/Radiator.cs index 474468064..f2af749f1 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Radiator.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Radiator.cs @@ -4,12 +4,12 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class RadiatorData : IBehaviorData +public class RadiatorData : BehaviorData { [InspectableField, JsonProperty("emissivity"), Key(0)] public PerformanceStat Emissivity = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new Radiator(context, this, entity, item); } @@ -21,7 +21,7 @@ public class Radiator : IBehavior public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; private RadiatorData _data; diff --git a/Assets/Scripts/ServerShared/Behaviors/Reactor.cs b/Assets/Scripts/ServerShared/Behaviors/Reactor.cs index 5464dc8a1..f5db66cf4 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Reactor.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Reactor.cs @@ -2,7 +2,7 @@ using MessagePack; using Newtonsoft.Json; [MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class ReactorData : IBehaviorData +public class ReactorData : BehaviorData { [InspectableField, JsonProperty("charge"), Key(0)] public PerformanceStat Charge = new PerformanceStat(); @@ -19,7 +19,7 @@ public class ReactorData : IBehaviorData [InspectableField, JsonProperty("underload"), Key(4)] public PerformanceStat UnderloadRecovery = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new Reactor(context, this, entity, item); } @@ -33,7 +33,7 @@ public class Reactor : IBehavior public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; public Reactor(GameContext context, ReactorData data, Entity entity, Gear item) { diff --git a/Assets/Scripts/ServerShared/Behaviors/Reflector.cs b/Assets/Scripts/ServerShared/Behaviors/Reflector.cs index 508609e0c..c9b6d900b 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Reflector.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Reflector.cs @@ -4,7 +4,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class ReflectorData : IBehaviorData +public class ReflectorData : BehaviorData { [InspectableField, JsonProperty("crossSection"), Key(0)] public PerformanceStat CrossSection = new PerformanceStat(); @@ -12,7 +12,7 @@ public class ReflectorData : IBehaviorData // [InspectableAnimationCurve, JsonProperty("visibility"), Key(1)] // public float4[] VisibilityCurve; - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new Reflector(context, this, entity, item); } @@ -24,7 +24,7 @@ public class Reflector : IBehavior public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; private ReflectorData _data; diff --git a/Assets/Scripts/ServerShared/Behaviors/Sensor.cs b/Assets/Scripts/ServerShared/Behaviors/Sensor.cs index 729130540..06801bd62 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Sensor.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Sensor.cs @@ -3,7 +3,7 @@ using MessagePack; using Newtonsoft.Json; [InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class SensorData : IBehaviorData +public class SensorData : BehaviorData { [InspectableField, JsonProperty("radiance"), Key(0)] public PerformanceStat Radiance = new PerformanceStat(); @@ -17,7 +17,7 @@ public class SensorData : IBehaviorData [InspectableField, JsonProperty("range"), Key(3)] public PerformanceStat Range = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new Sensor(context, this, entity, item); } @@ -31,7 +31,7 @@ public class Sensor : IBehavior public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; public Sensor(GameContext context, SensorData data, Entity entity, Gear item) { diff --git a/Assets/Scripts/ServerShared/Behaviors/Shield.cs b/Assets/Scripts/ServerShared/Behaviors/Shield.cs index c9e61a423..600b8224e 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Shield.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Shield.cs @@ -4,7 +4,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class ShieldData : IBehaviorData +public class ShieldData : BehaviorData { [InspectableField, JsonProperty("efficiency"), Key(0)] public PerformanceStat Efficiency = new PerformanceStat(); @@ -12,7 +12,7 @@ public class ShieldData : IBehaviorData [InspectableField, JsonProperty("shielding"), Key(1)] public PerformanceStat Shielding = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new Shield(context, this, entity, item); } @@ -24,7 +24,7 @@ public class Shield : IBehavior public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; private ShieldData _data; diff --git a/Assets/Scripts/ServerShared/Behaviors/Thruster.cs b/Assets/Scripts/ServerShared/Behaviors/Thruster.cs index a4823c479..5241f1109 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Thruster.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Thruster.cs @@ -4,7 +4,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship)] -public class ThrusterData : IBehaviorData +public class ThrusterData : BehaviorData { [InspectableField, JsonProperty("thrust"), Key(0)] public PerformanceStat Thrust = new PerformanceStat(); @@ -15,7 +15,7 @@ public class ThrusterData : IBehaviorData [InspectableField, JsonProperty("heat"), Key(2)] public PerformanceStat Heat = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new Thruster(context, this, entity, item); } @@ -27,7 +27,7 @@ public class Thruster : IAnalogBehavior public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; private ThrusterData _data; diff --git a/Assets/Scripts/ServerShared/Behaviors/Turning.cs b/Assets/Scripts/ServerShared/Behaviors/Turning.cs index 8943d3f35..9c16f9761 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Turning.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Turning.cs @@ -4,7 +4,7 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class TurningData : IBehaviorData +public class TurningData : BehaviorData { [InspectableField, JsonProperty("torque"), Key(0)] public PerformanceStat Torque = new PerformanceStat(); @@ -15,7 +15,7 @@ public class TurningData : IBehaviorData [InspectableField, JsonProperty("heat"), Key(2)] public PerformanceStat Heat = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new Turning(context, this, entity, item); } @@ -27,7 +27,7 @@ public class Turning : IAnalogBehavior public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; private TurningData _data; diff --git a/Assets/Scripts/ServerShared/Behaviors/VelocityConversion.cs b/Assets/Scripts/ServerShared/Behaviors/VelocityConversion.cs index 283fd1494..4acda6667 100644 --- a/Assets/Scripts/ServerShared/Behaviors/VelocityConversion.cs +++ b/Assets/Scripts/ServerShared/Behaviors/VelocityConversion.cs @@ -4,12 +4,12 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class VelocityConversionData : IBehaviorData +public class VelocityConversionData : BehaviorData { [InspectableField, JsonProperty("traction"), Key(0)] public PerformanceStat Traction = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new VelocityConversion(context, this, entity, item); } @@ -21,7 +21,7 @@ public class VelocityConversion : IBehavior public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; private VelocityConversionData _data; diff --git a/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs b/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs index 4b83891cb..d22fc455d 100644 --- a/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs +++ b/Assets/Scripts/ServerShared/Behaviors/VelocityLimit.cs @@ -4,12 +4,12 @@ using Unity.Mathematics; using static Unity.Mathematics.math; [MessagePackObject, JsonObject(MemberSerialization.OptIn)] -public class VelocityLimitData : IBehaviorData +public class VelocityLimitData : BehaviorData { [InspectableField, JsonProperty("topSpeed"), Key(0)] public PerformanceStat TopSpeed = new PerformanceStat(); - public IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new VelocityLimit(context, this, entity, item); } @@ -22,7 +22,7 @@ public class VelocityLimit : IBehavior public Gear Item { get; } public GameContext Context { get; } - public IBehaviorData Data => _data; + public BehaviorData Data => _data; private VelocityLimitData _data; diff --git a/Assets/Scripts/ServerShared/Behaviors/Weapon.cs b/Assets/Scripts/ServerShared/Behaviors/Weapon.cs index 5ebe0525d..e80cdcedb 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Weapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Weapon.cs @@ -3,7 +3,7 @@ using Newtonsoft.Json; [Union(0, typeof(ProjectileWeaponData)), Union(1, typeof(LauncherData))] -public abstract class WeaponData +public abstract class WeaponData : BehaviorData { [InspectableField, JsonProperty("damageType"), Key(0)] public DamageType DamageType; diff --git a/Assets/Scripts/ServerShared/BlueprintData.cs b/Assets/Scripts/ServerShared/BlueprintData.cs index a2ed779bf..30707fe48 100644 --- a/Assets/Scripts/ServerShared/BlueprintData.cs +++ b/Assets/Scripts/ServerShared/BlueprintData.cs @@ -77,7 +77,7 @@ public class BlueprintStatEffect [InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class StatReference { - [InspectableType(typeof(IBehaviorData)), JsonProperty("behavior"), Key(1)] + [InspectableType(typeof(BehaviorData)), JsonProperty("behavior"), Key(1)] public string Behavior; [InspectableField, JsonProperty("stat"), Key(2)] diff --git a/Assets/Scripts/ServerShared/DatabaseItems.cs b/Assets/Scripts/ServerShared/DatabaseItems.cs index 5565f4784..e2996cafb 100644 --- a/Assets/Scripts/ServerShared/DatabaseItems.cs +++ b/Assets/Scripts/ServerShared/DatabaseItems.cs @@ -68,6 +68,7 @@ public class Player : DatabaseEntry, INamedEntry public class Corporation : DatabaseEntry, INamedEntry { [JsonProperty("name"), Key(1)] public string Name; + [JsonProperty("tasks"), Key(2)] public List Tasks = new List(); [IgnoreMember] public string EntryName { diff --git a/Assets/Scripts/ServerShared/Entity.cs b/Assets/Scripts/ServerShared/Entity.cs index 115808135..20d4d846e 100644 --- a/Assets/Scripts/ServerShared/Entity.cs +++ b/Assets/Scripts/ServerShared/Entity.cs @@ -15,32 +15,35 @@ using static Unity.Mathematics.math; JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackReceiver { + [JsonProperty("temperature"), Key(1)] public float Temperature; + [JsonProperty("energy"), Key(2)] public float Energy; + [JsonProperty("position"), Key(3)] public float2 Position; + [JsonProperty("direction"), Key(4)] public float2 Direction = float2(0,1); + [JsonProperty("velocity"), Key(5)] public float2 Velocity; + [JsonProperty("cargo"), Key(6)] public readonly List Cargo; // Type: ItemInstance + [JsonProperty("equipment"), Key(7)] public readonly List EquippedItems; // Type: Gear + [JsonProperty("parent"), Key(8)] public Guid Parent; // Type: Entity + [JsonProperty("children"), Key(9)] public List Children = new List(); // Type: Entity + [JsonProperty("hull"), Key(10)] public Guid Hull; // Type: Gear + [JsonProperty("persistedBehaviorData"), Key(11)] public Dictionary PersistedBehaviors; + [JsonProperty("agent"), Key(12)] public EntityAgent Agent; + + // [IgnoreMember] protected List Behaviors; + [IgnoreMember] public Guid Zone; + [IgnoreMember] public Dictionary> ItemBehaviors; + [IgnoreMember] public Dictionary> Bindings; + [IgnoreMember] public Dictionary Axes; [IgnoreMember] public Dictionary AxisOverrides = new Dictionary(); [IgnoreMember] public readonly Dictionary VisibilitySources = new Dictionary(); - public float Temperature; - public float Energy; - public float2 Position; - public float2 Direction = float2(0,1); - public float2 Velocity; - [IgnoreMember] public Dictionary> Bindings; - [IgnoreMember] public Dictionary Axes; - public readonly List Cargo; - public readonly List EquippedItems; - public Entity Parent; - public List Children = new List(); - public Guid Zone; - [IgnoreMember] protected List Behaviors; - - public Gear Hull { get; } + private Dictionary GearData; [IgnoreMember] public float Mass { get; private set; } [IgnoreMember] public float SpecificHeat { get; private set; } [IgnoreMember] public float Visibility => VisibilitySources.Values.Sum(); - public PersistentBehaviorData[] PersistedBehaviors; - public Entity(GameContext context, Gear hull, IEnumerable items, IEnumerable cargo) + public Entity(GameContext context, Guid hull, IEnumerable items, IEnumerable cargo) { ID = Guid.NewGuid(); Context = context; @@ -51,24 +54,35 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR RecalculateMass(); - var activeItems = Hull == null ? EquippedItems : EquippedItems.Append(Hull); + AddItemBehaviors(); + } + + public void AddItemBehaviors() + { + var gear = EquippedItems.Append(Hull); + var gearData = gear.ToDictionary(id => id, id => Context.Cache.Get(id)); + GearData = gearData.Values.ToDictionary(g => g, g => g.ItemData); - Behaviors = activeItems - .Where(i=>i.ItemData.Behaviors?.Any()??false) - .SelectMany(i => i.ItemData.Behaviors - .Select(bd => bd.CreateInstance(Context, this, i))) + var allbehaviors = gear + .Where(i=>gearData[i].ItemData.Behaviors?.Any()??false) + .SelectMany(i => gearData[i].ItemData.Behaviors + .Select(bd => bd.CreateInstance(Context, this, gearData[i]))) .OrderBy(b => b.GetType().GetCustomAttribute()?.Order ?? 0).ToList(); - Bindings = Behaviors + ItemBehaviors = allbehaviors + .GroupBy(b => b.Item.ID, (guid, behaviors) => new {guid, behaviors}) + .ToDictionary(g => gearData[g.guid], g => g.behaviors.ToList()); + + Bindings = allbehaviors .Where(b => b is IActivatedBehavior) .GroupBy(b => b.Item.ID, (guid, behaviors) => new {guid, behaviors}) - .ToDictionary(g => g.guid, g => g.behaviors.Cast().ToList()); + .ToDictionary(g => gearData[g.guid], g => g.behaviors.Cast().ToList()); - Axes = Behaviors + Axes = allbehaviors .Where(b => b is IAnalogBehavior) .ToDictionary(b => b as IAnalogBehavior, b => 0f); - foreach (var behavior in Behaviors) + foreach (var behavior in allbehaviors) { behavior.Initialize(); } @@ -76,28 +90,30 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR public void RecalculateMass() { - Mass = Hull?.Mass ?? 0 + - EquippedItems.Sum(i => i.Mass) + - Cargo.Sum(ii => ii.Mass) + - Children.Sum(c=>c.Mass); + Mass = Context.Cache.Get(Hull).Mass + + EquippedItems.Select(i => Context.Cache.Get(i)).Sum(i => i.Mass) + + Cargo.Select(i => Context.Cache.Get(i)).Sum(ii => ii.Mass) + + Children.Select(i => Context.Cache.Get(i)).Sum(c=>c.Mass); - SpecificHeat = (Hull?.HeatCapacity ?? 0) + - EquippedItems.Sum(i => i.HeatCapacity) + - Cargo.Sum(ii => ii.HeatCapacity); + SpecificHeat = Context.Cache.Get(Hull).HeatCapacity + + EquippedItems.Select(i => Context.Cache.Get(i)).Sum(i => i.HeatCapacity) + + Cargo.Select(i => Context.Cache.Get(i)).Sum(ii => ii.HeatCapacity); } public IEnumerable GetBehaviors() where T : class, IBehavior { - foreach (var behavior in Behaviors) - if (behavior is T b) - yield return b; + foreach (var behaviors in ItemBehaviors.Values) + foreach (var behavior in behaviors) + if (behavior is T b) + yield return b; } - public IEnumerable GetBehaviorData() where T : class, IBehaviorData + public IEnumerable GetBehaviorData() where T : BehaviorData { - foreach (var behavior in Behaviors) - if (behavior.Data is T b) - yield return b; + foreach (var behaviors in ItemBehaviors.Values) + foreach (var behavior in behaviors) + if (behavior.Data is T b) + yield return b; } public void AddHeat(float heat) @@ -109,60 +125,103 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR { foreach(var analogBehavior in Axes.Keys) analogBehavior.SetAxis(AxisOverrides.ContainsKey(analogBehavior) ? AxisOverrides[analogBehavior] : Axes[analogBehavior]); - - foreach(var behavior in Behaviors) + + foreach (var behavior in ItemBehaviors.SelectMany(item => item.Value)) behavior.Update(delta); - foreach (var item in EquippedItems.Where(item => item.ItemData.Performance(Temperature) < .01f)) + foreach (var staleItem in GearData + .Where(kvp=>kvp.Key.ItemData!=kvp.Value) + .Select(kvp=>kvp.Key)) + { + // Item is stale, there's an updated one in the database cache + //var actualItem = Context.Cache.Get(staleItem.ID); + var staleBehaviors = ItemBehaviors[staleItem]; + ItemBehaviors.Remove(staleItem); + + // We'll be reloading the item along with its behaviors, some data must be persisted + var persistentData = staleBehaviors + .Where(b => b is IPersistentBehavior) + .Cast() + .Select(b => b.Store()); + + // Regenerate the behavior list for the updated item + ItemBehaviors[staleItem] = staleItem.ItemData.Behaviors + .Select(bd => bd.CreateInstance(Context, this, staleItem)) + .OrderBy(b => b.GetType().GetCustomAttribute()?.Order ?? 0).ToList(); + + // Restore state for persisted behaviors + foreach(var persistentBehaviorData in ItemBehaviors[staleItem] + .Where(b => b is IPersistentBehavior) + .Cast() + .Zip(persistentData, (behavior, data) => new {behavior, data})) + persistentBehaviorData.behavior.Restore(persistentBehaviorData.data); + + // Regenerate activated behavior bindings + if (Bindings.ContainsKey(staleItem)) + { + Bindings.Remove(staleItem); + Bindings[staleItem] = ItemBehaviors[staleItem] + .Where(b => b is IActivatedBehavior) + .Cast().ToList(); + } + + // Remove axis bindings and overrides for analog behaviors + foreach (var axis in staleBehaviors.Where(b => b is IAnalogBehavior).Cast()) + { + Axes.Remove(axis); + if (AxisOverrides.ContainsKey(axis)) + AxisOverrides.Remove(axis); + } + + // Regenerate axis bindings for analog behaviors + foreach (var axis in ItemBehaviors[staleItem].Where(b => b is IAnalogBehavior).Cast()) + Axes[axis] = 0; + } + + foreach (var item in EquippedItems + .Select(item => Context.Cache.Get(item)) + .Where(item => item.ItemData.Performance(Temperature) < .01f)) item.Durability -= delta; - if (Parent != null) + if (Parent != Guid.Empty) { - Position = Parent.Position; - Velocity = Parent.Velocity; + var parent = Context.Cache.Get(Parent); + Position = parent.Position; + Velocity = parent.Velocity; } } public void OnBeforeSerialize() { - PersistedBehaviors = Behaviors - .Where(b => b is IPersistentBehavior) - .Cast() - .Select(b => b.Store()).ToArray(); + // Filter item behavior collections by those with any persistent behaviors + // For each item create an object containing the item ID and a list of persistent behaviors + // Then turn that into a dictionary mapping from item ID to an array of every behaviors persistent data + PersistedBehaviors = ItemBehaviors + .Where(x => x.Value.Any(b=>b is IPersistentBehavior)) + .Select(x => new {gear=x.Key, behaviors = x.Value + .Where(b=>b is IPersistentBehavior) + .Cast()}) + .ToDictionary(x=> x.gear.ID, x=>x.behaviors.Select(b => b.Store()).ToArray()); } public void OnAfterDeserialize() { RecalculateMass(); - - var activeItems = Hull == null ? EquippedItems : EquippedItems.Append(Hull); - Behaviors = activeItems - .Where(i=>i.ItemData.Behaviors?.Any()??false) - .SelectMany(i => i.ItemData.Behaviors - .Select(bd => bd.CreateInstance(Context, this, i))) - .OrderBy(b => b.GetType().GetCustomAttribute()?.Order ?? 0).ToList(); + AddItemBehaviors(); var index = 0; - foreach (var persistentBehavior in Behaviors - .Where(b => b is IPersistentBehavior) - .Cast()) - { - persistentBehavior.Restore(PersistedBehaviors[index++]); - } - - Bindings = Behaviors - .Where(b => b is IActivatedBehavior) - .GroupBy(b => b.Item.ID, (guid, behaviors) => new {guid, behaviors}) - .ToDictionary(g => g.guid, g => g.behaviors.Cast().ToList()); - - Axes = Behaviors - .Where(b => b is IAnalogBehavior) - .ToDictionary(b => b as IAnalogBehavior, b => 0f); - - foreach (var behavior in Behaviors) - { - behavior.Initialize(); - } + // Iterate only over the behaviors of items which contain persistent data + // Filter the behaviors for each item to get the persistent ones, then cast them and combine with the persisted data array for that item + foreach (var persistentBehaviorData in ItemBehaviors + .Where(itemBehaviors => PersistedBehaviors.ContainsKey(itemBehaviors.Key.ID)). + SelectMany(itemBehaviors => itemBehaviors.Value + .Where(b=> b is IPersistentBehavior) + .Cast() + .Zip(PersistedBehaviors[itemBehaviors.Key.ID], (behavior, data) => new{behavior, data}))) + persistentBehaviorData.behavior.Restore(persistentBehaviorData.data); + + Agent.Context = Context; + Agent.Entity = ID; } } \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/ItemData.cs b/Assets/Scripts/ServerShared/ItemData.cs index b9de99322..596f839af 100644 --- a/Assets/Scripts/ServerShared/ItemData.cs +++ b/Assets/Scripts/ServerShared/ItemData.cs @@ -105,7 +105,7 @@ public abstract class EquippableItemData : CraftedItemData public PerformanceStat HeatExponent = new PerformanceStat(); [InspectableField, JsonProperty("behaviors"), Key(13)] - public List Behaviors = new List(); + public List Behaviors = new List(); [IgnoreMember] public abstract HardpointType HardpointType { get; } diff --git a/Assets/Scripts/ServerShared/OrbitalEntity.cs b/Assets/Scripts/ServerShared/OrbitalEntity.cs index 1f8eaff90..b62dc99d2 100644 --- a/Assets/Scripts/ServerShared/OrbitalEntity.cs +++ b/Assets/Scripts/ServerShared/OrbitalEntity.cs @@ -9,7 +9,7 @@ public class OrbitalEntity : Entity { private Guid _orbitData; - public OrbitalEntity(GameContext context, Gear hull, IEnumerable items, IEnumerable cargo, Guid orbit) : base(context, hull, items, cargo) + public OrbitalEntity(GameContext context, Guid hull, IEnumerable items, IEnumerable cargo, Guid orbit) : base(context, hull, items, cargo) { _orbitData = orbit; } diff --git a/Assets/Scripts/ServerShared/Ship.cs b/Assets/Scripts/ServerShared/Ship.cs index 0a8656e8f..dbc5167bf 100644 --- a/Assets/Scripts/ServerShared/Ship.cs +++ b/Assets/Scripts/ServerShared/Ship.cs @@ -19,7 +19,7 @@ public class Ship : Entity // [IgnoreMember] public Dictionary Contacts = new Dictionary(); // [IgnoreMember] public Targetable Target; - public Ship(GameContext context, Gear hull, IEnumerable items, IEnumerable cargo) : base(context, hull, items, cargo) + public Ship(GameContext context, Guid hull, IEnumerable items, IEnumerable cargo) : base(context, hull, items, cargo) { } diff --git a/Assets/Scripts/StrategyGameManager.cs b/Assets/Scripts/StrategyGameManager.cs index f211ddf99..19a49f988 100644 --- a/Assets/Scripts/StrategyGameManager.cs +++ b/Assets/Scripts/StrategyGameManager.cs @@ -519,10 +519,10 @@ public class StrategyGameManager : MonoBehaviour if (args[0] == "ship") { - var entity = new Ship(_context, hull, gear, Enumerable.Empty()); + var entity = new Ship(_context, hull.ID, gear.Select(i=>i.ID), Enumerable.Empty()); _context.Cache.Add(entity); _context.ZoneEntities[_populatedZone][entity.ID] = entity; - _context.Agents.Add(new AgentController(_context, _populatedZone, entity)); + _context.Agents.Add(new AgentController(_context, _populatedZone, entity.ID)); var zoneShip = Instantiate(ZoneShipPrefab, ZoneRoot); zoneShip.Label.text = $"Ship {_zoneShips.Count}"; _zoneShips[entity] = zoneShip; diff --git a/Assets/Scripts/UI/DragHandler.cs b/Assets/Scripts/UI/DragHandler.cs index c8dba27e6..38507d0b5 100644 --- a/Assets/Scripts/UI/DragHandler.cs +++ b/Assets/Scripts/UI/DragHandler.cs @@ -9,17 +9,22 @@ public class DragHandler : MonoBehaviour public float Scaling; public ClickCatcher Background; private Vector2 _previousPosition; + private bool _isDragging; void Update() { + var newPosition = Camera.ScreenToWorldPoint(Input.mousePosition); + + if (!Input.GetMouseButton(0)) _isDragging = false; + + if (_isDragging) Camera.transform.position -= (Vector3) ((Vector2) newPosition - _previousPosition); + if (Background.PointerIsInside) { - var newPosition = Camera.ScreenToWorldPoint(Input.mousePosition); - if(Input.GetMouseButtonDown(0)) - _previousPosition = newPosition; - if (Input.GetMouseButton(0)) + if (Input.GetMouseButtonDown(0)) { - Camera.transform.position -= (Vector3)((Vector2) newPosition - _previousPosition); + _previousPosition = newPosition; + _isDragging = true; } if (abs(Input.mouseScrollDelta.y) > .01f)