Massive Item Behavior Refactoring

Item behaviors are now separated into more granular units, allowing designers to create more interesting items by combining behaviors
This commit is contained in:
hyperion51 2020-05-12 01:42:13 +01:00
commit 8cd4ea3dc5
40 changed files with 822 additions and 445 deletions

View file

@ -1,54 +0,0 @@
using MessagePack;
using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class ActivatedItemUsageData : BehaviorData
{
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
return new ActivatedItemUsage(context, this, entity, item);
}
}
public class ActivatedItemUsage : IActivatedBehavior
{
private ActivatedItemUsageData _data;
private Entity Entity { get; }
private Gear Item { get; }
private GameContext Context { get; }
public BehaviorData Data => _data;
public ActivatedItemUsage(GameContext context, ActivatedItemUsageData data, Entity entity, Gear item)
{
_data = data;
Entity = entity;
Item = item;
Context = context;
}
public void Initialize()
{
}
public bool Activate()
{
throw new System.NotImplementedException();
}
public void Deactivate()
{
throw new System.NotImplementedException();
}
public bool Update(float delta)
{
return true;
}
public void Remove()
{
}
}

View file

@ -4,88 +4,88 @@ using System.Linq;
using MessagePack;
using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class AfterburnerData : BehaviorData
{
[InspectableField, JsonProperty("thrust"), Key(1)]
public PerformanceStat ThrustModifier = new PerformanceStat();
[InspectableField, JsonProperty("speed"), Key(2)]
public PerformanceStat SpeedModifier = new PerformanceStat();
[InspectableField, JsonProperty("torque"), Key(3)]
public PerformanceStat TorqueModifier = new PerformanceStat();
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
return new Afterburner(context, this, entity, item);
}
}
public class Afterburner : IActivatedBehavior
{
private List<Dictionary<IBehavior,float>> _modifiers = new List<Dictionary<IBehavior, float>>();
private AfterburnerData _data;
private Thruster _thruster;
private int _thrustAxis;
public Entity Entity { get; }
public Gear Item { get; }
public GameContext Context { get; }
public BehaviorData Data => _data;
public Afterburner(GameContext context, AfterburnerData data, Entity entity, Gear item)
{
Context = context;
_data = data;
Entity = entity;
Item = item;
}
public void Initialize()
{
_thruster = Entity.GetBehaviors<Thruster>().FirstOrDefault();
_thrustAxis = Entity.GetAxis<Thruster>();
}
public bool Update(float delta)
{
return true;
}
public bool Activate()
{
if (_thruster == null) return false;
var thrustMod = ((ThrusterData) _thruster.Data).Thrust.GetScaleModifiers(Entity);
thrustMod.Add(this,Context.Evaluate(_data.ThrustModifier,Item, Entity));
_modifiers.Add(thrustMod);
Entity.AxisOverrides[_thrustAxis] = 1;
return true;
// var speedMod = (Ship.Hull.ItemData as HullData).TopSpeed.GetScaleModifiers(Ship);
// _modifiers.Add(speedMod);
// speedMod.Add(this,Context.Evaluate(_data.SpeedModifier,Item, Ship));
//
// var torqueMod = (Ship.GetEquipped(HardpointType.Thruster).ItemData as ThrusterData).Torque.GetScaleModifiers(Ship);
// _modifiers.Add(torqueMod);
// torqueMod.Add(this,Context.Evaluate(_data.TorqueModifier,Item, Ship));
}
public void Deactivate()
{
Entity.AxisOverrides.Remove(_thrustAxis);
foreach (var mod in _modifiers)
{
mod.Remove(this);
}
_modifiers.Clear();
}
public void Remove()
{
}
}
// [InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
// public class AfterburnerData : BehaviorData
// {
// [InspectableField, JsonProperty("thrust"), Key(1)]
// public PerformanceStat ThrustModifier = new PerformanceStat();
//
// [InspectableField, JsonProperty("speed"), Key(2)]
// public PerformanceStat SpeedModifier = new PerformanceStat();
//
// [InspectableField, JsonProperty("torque"), Key(3)]
// public PerformanceStat TorqueModifier = new PerformanceStat();
//
// public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
// {
// return new Afterburner(context, this, entity, item);
// }
// }
//
// public class Afterburner : IActivatedBehavior
// {
// private List<Dictionary<IBehavior,float>> _modifiers = new List<Dictionary<IBehavior, float>>();
// private AfterburnerData _data;
// private Thruster _thruster;
// private int _thrustAxis;
//
// public Entity Entity { get; }
// public Gear Item { get; }
// public GameContext Context { get; }
//
// public BehaviorData Data => _data;
//
// public Afterburner(GameContext context, AfterburnerData data, Entity entity, Gear item)
// {
// Context = context;
// _data = data;
// Entity = entity;
// Item = item;
// }
//
// public void Initialize()
// {
// _thruster = Entity.GetBehaviors<Thruster>().FirstOrDefault();
// _thrustAxis = Entity.GetAxis<Thruster>();
// }
//
// public bool Update(float delta)
// {
// return true;
// }
//
// public bool Activate()
// {
// if (_thruster == null) return false;
//
// var thrustMod = ((ThrusterData) _thruster.Data).Thrust.GetScaleModifiers(Entity);
// thrustMod.Add(this,Context.Evaluate(_data.ThrustModifier,Item, Entity));
// _modifiers.Add(thrustMod);
//
// Entity.AxisOverrides[_thrustAxis] = 1;
//
// return true;
//
// // var speedMod = (Ship.Hull.ItemData as HullData).TopSpeed.GetScaleModifiers(Ship);
// // _modifiers.Add(speedMod);
// // speedMod.Add(this,Context.Evaluate(_data.SpeedModifier,Item, Ship));
// //
// // var torqueMod = (Ship.GetEquipped(HardpointType.Thruster).ItemData as ThrusterData).Torque.GetScaleModifiers(Ship);
// // _modifiers.Add(torqueMod);
// // torqueMod.Add(this,Context.Evaluate(_data.TorqueModifier,Item, Ship));
// }
//
// public void Deactivate()
// {
// Entity.AxisOverrides.Remove(_thrustAxis);
// foreach (var mod in _modifiers)
// {
// mod.Remove(this);
// }
// _modifiers.Clear();
// }
//
// public void Remove()
// {
// }
// }

View file

@ -11,23 +11,36 @@ using static Unity.Mathematics.noise;
public interface IBehavior
{
void Initialize();
bool Update(float delta);
void Remove();
BehaviorData Data { get; }
}
public interface IActivatedBehavior : IBehavior
{
bool Activate();
void Deactivate();
}
// public interface IActivatedBehavior : IBehavior
// {
// bool Activate();
// void Deactivate();
// }
public interface IAnalogBehavior : IBehavior
{
void SetAxis(float value);
}
public interface IDisposableBehavior
{
void Dispose();
}
public interface IInitializableBehavior
{
void Initialize();
}
public interface IAlwaysUpdatedBehavior
{
void AlwaysUpdate(float delta);
}
public interface IPersistentBehavior//<T> where T : IBehavior
{
PersistentBehaviorData Store();
@ -55,7 +68,7 @@ public abstract class PersistentBehaviorData
Union(1, typeof(LauncherData)),
Union(2, typeof(ReactorData)),
Union(3, typeof(RadiatorData)),
Union(4, typeof(AfterburnerData)),
Union(4, typeof(StatModifierData)),
Union(5, typeof(SensorData)),
Union(6, typeof(ReflectorData)),
Union(7, typeof(ShieldData)),
@ -66,6 +79,14 @@ public abstract class PersistentBehaviorData
Union(12, typeof(FactoryData)),
Union(13, typeof(PatrolControllerData)),
Union(14, typeof(TowingControllerData)),
Union(15, typeof(CooldownData)),
Union(16, typeof(HeatData)),
Union(17, typeof(HitscanData)),
Union(18, typeof(ItemUsageData)),
Union(19, typeof(RadianceData)),
Union(20, typeof(SwitchData)),
Union(21, typeof(TriggerData)),
Union(22, typeof(VisibilityData)),
JsonConverter(typeof(JsonKnownTypesConverter<BehaviorData>)), JsonObject(MemberSerialization.OptIn)]
public abstract class BehaviorData
{

View file

@ -0,0 +1,55 @@
using System;
using System.Linq;
using MessagePack;
using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class CooldownData : BehaviorData
{
[InspectableField, JsonProperty("cooldown"), Key(1)]
public PerformanceStat Cooldown = new PerformanceStat();
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
return new Cooldown(context, this, entity, item);
}
}
[UpdateOrder(-10)]
public class Cooldown : IBehavior, IAlwaysUpdatedBehavior
{
private CooldownData _data;
private Entity Entity { get; }
private Gear Item { get; }
private GameContext Context { get; }
public BehaviorData Data => _data;
private float _cooldown; // Normalized
public Cooldown(GameContext context, CooldownData data, Entity entity, Gear item)
{
_data = data;
Entity = entity;
Item = item;
Context = context;
}
public bool Update(float delta)
{
if (_cooldown < 0)
{
_cooldown = 1;
return true;
}
return false;
}
public void AlwaysUpdate(float delta)
{
_cooldown -= delta / Context.Evaluate(_data.Cooldown, Item, Entity);
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 9965ed11abd4e8c48b7b2bd8ab6e44e8
guid: d1782458ac454624dbab2872ebbff979
MonoImporter:
externalObjects: {}
serializedVersion: 2

View file

@ -22,7 +22,7 @@ public class FactoryData : BehaviorData
}
}
public class Factory : IBehavior, IPersistentBehavior//<Factory>
public class Factory : IBehavior, IPersistentBehavior
{
public Entity Entity { get; }
public Gear Item { get; }
@ -48,10 +48,6 @@ public class Factory : IBehavior, IPersistentBehavior//<Factory>
Item = item;
}
public void Initialize()
{
}
public bool Update(float delta)
{
var blueprint = Context.Cache.Get<BlueprintData>(_blueprint);
@ -227,10 +223,6 @@ public class Factory : IBehavior, IPersistentBehavior//<Factory>
_assignedPopulation = factoryPersistence.AssignedPopulation;
_productionQuality = factoryPersistence.ProductionQuality;
}
public void Remove()
{
}
}
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]

View file

@ -0,0 +1,42 @@
using System;
using System.Linq;
using MessagePack;
using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class HeatData : BehaviorData
{
[InspectableField, JsonProperty("heat"), Key(1)]
public PerformanceStat Heat = new PerformanceStat();
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
return new Heat(context, this, entity, item);
}
}
[UpdateOrder(10)]
public class Heat : IBehavior
{
private HeatData _data;
private Entity Entity { get; }
private Gear Item { get; }
private GameContext Context { get; }
public BehaviorData Data => _data;
public Heat(GameContext context, HeatData data, Entity entity, Gear item)
{
_data = data;
Entity = entity;
Item = item;
Context = context;
}
public bool Update(float delta)
{
Entity.AddHeat(Context.Evaluate(_data.Heat, Item, Entity));
return true;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a60f2300e35155940adf1f353388dcdd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -10,7 +10,7 @@ public class HitscanData : WeaponData
}
}
public class Hitscan : IActivatedBehavior
public class Hitscan : IBehavior
{
private bool _firing;
private float _cooldown; // normalized
@ -29,67 +29,10 @@ public class Hitscan : IActivatedBehavior
Entity = entity;
Item = item;
}
public bool Activate()
{
// Debug.Log("Activating ProjectileWeapon");
// _firing = true;
// Observable.EveryUpdate().TakeWhile(_ => _firing).Subscribe(_ =>
// {
// // Debug.Log($"Updating Observable {_cooldown}");
// if (_cooldown < 0)
// {
// _cooldown = 1;
// Fire(0);
// if(_projectileWeapon.BurstCount>1)
// Observable.Interval(TimeSpan.FromSeconds(_projectileWeapon.BurstTime.Evaluate(Hardpoint) / (_projectileWeapon.BurstCount-1))).Take(_projectileWeapon.BurstCount-1)
// .Subscribe(l => Fire(l+1));
// }
// });
return true;
}
private void Fire(long b)
{
// _firingVisibility += _projectileWeapon.Visibility.Evaluate(Hardpoint);
// Hardpoint.Temperature += _projectileWeapon.Heat.Evaluate(Hardpoint) / Hardpoint.HeatCapacity;
// var inst = GameObject.Instantiate(_projectileWeapon.BulletPrefab).transform;
// Physics.IgnoreCollision(Hardpoint.Ship.Ship.GetComponent<Collider>(), inst.GetComponent<Collider>());
// var bullet = inst.GetComponent<Bullet>();
// bullet.Target = Hardpoint.Ship.Ship.Target;
// bullet.Source = Hardpoint.Ship.Ship.Hitpoints;
// bullet.Lifetime = _projectileWeapon.Range.Evaluate(Hardpoint) / _projectileWeapon.Velocity.Evaluate(Hardpoint);
// bullet.Damage = _projectileWeapon.Damage.Evaluate(Hardpoint);
// inst.position = Hardpoint.Proxy.position;
// inst.rotation = Hardpoint.Proxy.rotation;
// inst.GetComponent<Rigidbody>().velocity = _projectileWeapon.Velocity.Evaluate(Hardpoint) * Vector3.RotateTowards(-inst.forward, Hardpoint.Ship.Ship.Direction, _projectileWeapon.Deflection * Mathf.Deg2Rad, 1);
// Hardpoint.Ship.Ship.AudioSource.PlayOneShot(_projectileWeapon.Sounds.RandomElement());
// Debug.Log($"Firing bullet {b}");
}
public void Deactivate()
{
_firing = false;
}
public void Initialize()
{
}
public bool Update(float delta)
{
_cooldown -= delta / Context.Evaluate(_data.Cooldown, Item, Entity);
_firingVisibility *= Context.Evaluate(_data.VisibilityDecay, Item, Entity);
if (_firingVisibility < 0.01f)
{
Entity.VisibilitySources.Remove(this);
}
return true;
}
public void Remove()
{
}
}

View file

@ -1,5 +1,6 @@

using System;
using System.Linq;
using MessagePack;
using Newtonsoft.Json;
@ -8,9 +9,6 @@ public class ItemUsageData : BehaviorData
{
[InspectableDatabaseLink(typeof(SimpleCommodityData)), JsonProperty("item"), Key(1)]
public Guid Item;
[InspectableField, JsonProperty("cooldown"), Key(2)]
public PerformanceStat Cooldown = new PerformanceStat();
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
@ -18,6 +16,7 @@ public class ItemUsageData : BehaviorData
}
}
[UpdateOrder(-5)]
public class ItemUsage : IBehavior
{
private ItemUsageData _data;
@ -36,16 +35,21 @@ public class ItemUsage : IBehavior
Context = context;
}
public void Initialize()
{
}
public bool Update(float delta)
{
return true;
}
var cargoInstances = Entity.Cargo.Select(c => Context.Cache.Get<ItemInstance>(c));
if (cargoInstances.FirstOrDefault(c => c.Data == _data.Item) is SimpleCommodity item)
{
if (item.Quantity > 1)
item.Quantity--;
else
{
Entity.Cargo.Remove(item.ID);
Context.Cache.Delete(item);
}
public void Remove()
{
return true;
}
return false;
}
}

View file

@ -7,34 +7,34 @@ using Unity.Mathematics;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class LauncherData : WeaponData
{
[InspectablePrefab, JsonProperty("missile"), Key(9)]
[InspectablePrefab, JsonProperty("missile"), Key(6)]
public string MissilePrefab;
[InspectableAnimationCurve, JsonProperty("guidance"), Key(10)]
[InspectableAnimationCurve, JsonProperty("guidance"), Key(7)]
public float4[] GuidanceCurve;
[InspectableAnimationCurve, JsonProperty("thrustCurve"), Key(11)]
[InspectableAnimationCurve, JsonProperty("thrustCurve"), Key(8)]
public float4[] ThrustCurve;
[InspectableAnimationCurve, JsonProperty("liftCurve"), Key(12)]
[InspectableAnimationCurve, JsonProperty("liftCurve"), Key(9)]
public float4[] LiftCurve;
[InspectableField, JsonProperty("thrust"), Key(13)]
[InspectableField, JsonProperty("thrust"), Key(10)]
public PerformanceStat Thrust = new PerformanceStat();
[InspectableField, JsonProperty("lockAngle"), Key(14)]
[InspectableField, JsonProperty("lockAngle"), Key(11)]
public float LockAngle;
[InspectableField, JsonProperty("frequency"), Key(15)]
[InspectableField, JsonProperty("frequency"), Key(12)]
public float DodgeFrequency;
[InspectableField, JsonProperty("launchSpeed"), Key(16)]
[InspectableField, JsonProperty("launchSpeed"), Key(13)]
public PerformanceStat LaunchSpeed = new PerformanceStat();
[InspectableField, JsonProperty("missileSpeed"), Key(17)]
[InspectableField, JsonProperty("missileSpeed"), Key(14)]
public PerformanceStat MissileSpeed = new PerformanceStat();
[InspectableField, JsonProperty("lockOnTime"), Key(18)]
[InspectableField, JsonProperty("lockOnTime"), Key(15)]
public PerformanceStat LockOnTime = new PerformanceStat();
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
@ -43,7 +43,7 @@ public class LauncherData : WeaponData
}
}
public class Launcher : IActivatedBehavior
public class Launcher : IBehavior, IAlwaysUpdatedBehavior
{
private bool _locking;
private float _lockingTimer;
@ -58,8 +58,6 @@ public class Launcher : IActivatedBehavior
public BehaviorData Data => _data;
public int Group => _data.Group;
public Launcher(GameContext context, LauncherData m, Entity entity, Gear item)
{
Context = context;
@ -81,9 +79,24 @@ public class Launcher : IActivatedBehavior
return true;
}
private void Fire(long b)
public void Deactivate()
{
// if (_lockingTimer < 0)
// {
// Fire(0);
// if(_launcher.BurstCount>1)
// Observable.Interval(TimeSpan.FromSeconds(_launcher.BurstTime.Evaluate(Hardpoint) / (_launcher.BurstCount-1))).Take(_launcher.BurstCount-1)
// .Subscribe(l => Fire(l+1));
// _lockingTimer = _cooldown = 1;
// _locking = _locked = false;
// _audio.Stop();
// }
// _locking = false;
// _lockingTimer = 1;
}
public bool Update(float delta)
{
// _firingVisibility += _launcher.Visibility.Evaluate(Hardpoint);
// Hardpoint.Temperature += _launcher.Heat.Evaluate(Hardpoint) / Hardpoint.HeatCapacity;
// var inst = GameObject.Instantiate(_launcher.MissilePrefab).transform;
@ -107,31 +120,12 @@ public class Launcher : IActivatedBehavior
// proj.Thrust = _launcher.Thrust.Evaluate(Hardpoint);
// _audio.PlayOneShot(_launcher.Sounds.RandomElement());
// Debug.Log($"Firing bullet {b}");
}
public void Deactivate()
{
// if (_lockingTimer < 0)
// {
// Fire(0);
// if(_launcher.BurstCount>1)
// Observable.Interval(TimeSpan.FromSeconds(_launcher.BurstTime.Evaluate(Hardpoint) / (_launcher.BurstCount-1))).Take(_launcher.BurstCount-1)
// .Subscribe(l => Fire(l+1));
// _lockingTimer = _cooldown = 1;
// _locking = _locked = false;
// _audio.Stop();
// }
// _locking = false;
// _lockingTimer = 1;
}
public void Initialize()
{
}
public bool Update(float delta)
{
return true;
}
public void AlwaysUpdate(float delta)
{
// if (Ship.Target == null)
// return;
//
@ -167,8 +161,4 @@ public class Launcher : IActivatedBehavior
// _firingVisibility = 0;
// }
}
public void Remove()
{
}
}

View file

@ -18,7 +18,8 @@ public class PatrolControllerData : ControllerData
}
}
public class PatrolController : IBehavior, IController
[UpdateOrder(-100)]
public class PatrolController : IBehavior, IController, IInitializableBehavior
{
public TaskType TaskType => TaskType.Tow;
public bool Available => false;
@ -68,8 +69,4 @@ public class PatrolController : IBehavior, IController
var entities = _context.ZonePlanets[_entity.Zone];
_targetOrbit = _context.Cache.Get<PlanetData>(entities[_context.Random.NextInt(entities.Length)]).Orbit;
}
public void Remove()
{
}
}

View file

@ -4,16 +4,16 @@ using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class ProjectileWeaponData : WeaponData
{
[InspectablePrefab, JsonProperty("bullet"), Key(9)]
[InspectablePrefab, JsonProperty("bullet"), Key(6)]
public string BulletPrefab;
[InspectableField, JsonProperty("spread"), Key(10)]
[InspectableField, JsonProperty("spread"), Key(7)]
public PerformanceStat Spread = new PerformanceStat();
[InspectableField, JsonProperty("bulletInherit"), Key(11)]
[InspectableField, JsonProperty("bulletInherit"), Key(8)]
public float Inherit;
[InspectableField, JsonProperty("bulletVelocity"), Key(12)]
[InspectableField, JsonProperty("bulletVelocity"), Key(9)]
public PerformanceStat Velocity = new PerformanceStat();
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
@ -22,18 +22,12 @@ public class ProjectileWeaponData : WeaponData
}
}
public class ProjectileWeapon : IActivatedBehavior
public class ProjectileWeapon : IBehavior
{
private ProjectileWeaponData _data;
private Entity Entity { get; }
private Gear Item { get; }
private GameContext Context { get; }
private float _firingVisibility;
private bool _firing;
private float _cooldown; // normalized
private float _burstCooldown;
private float _burstCooldownTime;
private int _burstRemaining;
public BehaviorData Data => _data;
@ -44,31 +38,9 @@ public class ProjectileWeapon : IActivatedBehavior
Entity = entity;
Item = item;
}
public bool Activate()
{
_firing = true;
return true;
// Debug.Log("Activating ProjectileWeapon");
// Observable.EveryUpdate().TakeWhile(_ => _firing).Subscribe(_ =>
// {
// // Debug.Log($"Updating Observable {_cooldown}");
// if (_cooldown < 0)
// {
// _cooldown = 1;
// Fire(0);
// if(_projectileWeapon.BurstCount>1)
// Observable.Interval(TimeSpan.FromSeconds(_projectileWeapon.BurstTime.Evaluate(Hardpoint) / (_projectileWeapon.BurstCount-1))).Take(_projectileWeapon.BurstCount-1)
// .Subscribe(l => Fire(l+1));
// }
// });
}
private void Fire()
{
_burstRemaining--;
_firingVisibility += Context.Evaluate(_data.Visibility, Item, Entity);
Entity.AddHeat(Context.Evaluate(_data.Heat, Item, Entity));
// private void Fire()
// {
// Hardpoint.Temperature += _projectileWeapon.Heat.Evaluate(Hardpoint) / Hardpoint.HeatCapacity;
// var inst = GameObject.Instantiate(_projectileWeapon.BulletPrefab).transform;
// Physics.IgnoreCollision(Hardpoint.Ship.Ship.GetComponent<Collider>(), inst.GetComponent<Collider>());
@ -82,49 +54,10 @@ public class ProjectileWeapon : IActivatedBehavior
// inst.GetComponent<Rigidbody>().velocity = _projectileWeapon.Velocity.Evaluate(Hardpoint) * Vector3.RotateTowards(-inst.forward, Hardpoint.Ship.Ship.Direction, _projectileWeapon.Deflection * Mathf.Deg2Rad, 1);
// Hardpoint.Ship.Ship.AudioSource.PlayOneShot(_projectileWeapon.Sounds.RandomElement());
// Debug.Log($"Firing bullet {b}");
}
public void Deactivate()
{
_firing = false;
}
public void Initialize()
{
}
// }
public bool Update(float delta)
{
_cooldown -= delta / Context.Evaluate(_data.Cooldown, Item, Entity);
if (_cooldown < 0)
{
_cooldown = 1;
_burstRemaining = _data.BurstCount;
_burstCooldownTime = Context.Evaluate(_data.BurstTime, Item, Entity) / _data.BurstCount;
_burstCooldown = -1;
Fire();
}
if (_burstRemaining > 0)
{
_burstCooldown -= delta / _burstCooldownTime;
if (_burstCooldown < 0)
{
_burstCooldown = 1;
Fire();
}
}
_firingVisibility *= Context.Evaluate(_data.VisibilityDecay, Item, Entity);
if (_firingVisibility < 0.01f)
{
Entity.VisibilitySources.Remove(this);
}
return true;
}
public void Remove()
{
}
}

View file

@ -0,0 +1,41 @@
using System;
using System.Linq;
using MessagePack;
using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class RadianceData : BehaviorData
{
[InspectableField, JsonProperty("radiance"), Key(1)]
public PerformanceStat Radiance = new PerformanceStat();
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
return new Radiance(context, this, entity, item);
}
}
public class Radiance : IBehavior
{
private RadianceData _data;
private Entity Entity { get; }
private Gear Item { get; }
private GameContext Context { get; }
public BehaviorData Data => _data;
public Radiance(GameContext context, RadianceData data, Entity entity, Gear item)
{
_data = data;
Entity = entity;
Item = item;
Context = context;
}
public bool Update(float delta)
{
// TODO: Light system!
return true;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1fbf8a3d31de89a4aa53d43e015536c7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -33,10 +33,6 @@ public class Radiator : IBehavior
Item = item;
}
public void Initialize()
{
}
public bool Update(float delta)
{
var rad = pow(Entity.Temperature, Context.GlobalData.HeatRadiationPower) * Context.GlobalData.HeatRadiationMultiplier;
@ -44,8 +40,4 @@ public class Radiator : IBehavior
Entity.VisibilitySources[this] = rad;
return true;
}
public void Remove()
{
}
}

View file

@ -43,10 +43,6 @@ public class Reactor : IBehavior
Item = item;
}
public void Initialize()
{
}
public bool Update(float delta)
{
var cap = Context.Evaluate(_data.Capacitance, Item, Entity);
@ -69,8 +65,4 @@ public class Reactor : IBehavior
}
return true;
}
public void Remove()
{
}
}

View file

@ -36,16 +36,9 @@ public class Reflector : IBehavior
Item = item;
}
public void Initialize()
{
}
public bool Update(float delta)
{
// TODO: Light system!
return true;
}
public void Remove()
{
}
}

View file

@ -5,17 +5,8 @@ using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class SensorData : BehaviorData
{
[InspectableField, JsonProperty("radiance"), Key(1)]
public PerformanceStat Radiance = new PerformanceStat();
[InspectableField, JsonProperty("masking"), Key(2)]
public PerformanceStat RadianceMasking = new PerformanceStat();
[InspectableField, JsonProperty("sensitivity"), Key(3)]
public PerformanceStat Sensitivity = new PerformanceStat();
[InspectableField, JsonProperty("range"), Key(4)]
public PerformanceStat Range = new PerformanceStat();
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
@ -41,12 +32,9 @@ public class Sensor : IBehavior
Context = context;
}
public void Initialize()
{
}
public bool Update(float delta)
{
// TODO: Handle Active Detection / Visibility From Reflected Radiance
return true;
// var ship = Hardpoint.Ship.Ship.transform;
// var contacts =
@ -64,10 +52,5 @@ public class Sensor : IBehavior
// }
//
// Hardpoint.Ship.VisibilitySources[this] = _data.Radiance.Evaluate(Hardpoint) / _data.RadianceMasking.Evaluate(Hardpoint);
// TODO: Handle Active Detection / Visibility From Reflected Radiance
}
public void Remove()
{
}
}

View file

@ -38,16 +38,8 @@ public class Shield : IBehavior
// TODO: Detect hits on Ship, keep a list of callbacks that modify the hit by reference
}
public void Initialize()
{
}
public bool Update(float delta)
{
return true;
}
public void Remove()
{
}
}

View file

@ -0,0 +1,95 @@
using System;
using System.Linq;
using MessagePack;
using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class StatModifierData : BehaviorData
{
[InspectableField, JsonProperty("stat"), Key(1)]
public StatReference Stat = new StatReference();
[InspectableField, JsonProperty("modifier"), Key(2)]
public PerformanceStat Modifier = new PerformanceStat();
[InspectableField, JsonProperty("type"), Key(3)]
public StatModifierType Type;
[InspectableType(typeof(BehaviorData)), JsonProperty("requireBehavior"), Key(4)]
public Type RequireBehavior;
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
return new StatModifier(context, this, entity, item);
}
}
[UpdateOrder(-4)]
public class StatModifier : IBehavior, IInitializableBehavior, IDisposableBehavior
{
private StatModifierData _data;
private Entity Entity { get; }
private Gear Item { get; }
private GameContext Context { get; }
public BehaviorData Data => _data;
private PerformanceStat[] _stats;
public StatModifier(GameContext context, StatModifierData data, Entity entity, Gear item)
{
_data = data;
Entity = entity;
Item = item;
Context = context;
}
public void Initialize()
{
var targetType = Context.StatObjects.FirstOrDefault(so => so.Name == _data.Stat.Target);
if (targetType != null)
{
var statField = targetType.GetFields()
.Where(f => f.FieldType == typeof(PerformanceStat)).FirstOrDefault(f => f.Name == _data.Stat.Stat);
if (statField != null)
{
if (typeof(EquippableItemData).IsAssignableFrom(targetType))
_stats = Entity.EquippedItems
.Select(id => Context.Cache.Get<Gear>(id))
.Where(gear => _data.RequireBehavior == null || gear.ItemData.Behaviors.Any(behavior => behavior.GetType() == _data.RequireBehavior))
.Where(gear => gear.ItemData.GetType() == targetType)
.Select(gear => statField.GetValue(gear.ItemData) as PerformanceStat)
.ToArray();
else
_stats = Entity.EquippedItems
.Select(id => Context.Cache.Get<Gear>(id))
.Where(gear => _data.RequireBehavior == null || gear.ItemData.Behaviors.Any(behavior => behavior.GetType() == _data.RequireBehavior))
.SelectMany(gear => gear.ItemData.Behaviors)
.Where(behaviorData => behaviorData.GetType() == targetType)
.Select(behaviorData => statField.GetValue(behaviorData) as PerformanceStat)
.ToArray();
}
}
}
public bool Update(float delta)
{
foreach (var stat in _stats)
(_data.Type == StatModifierType.Constant
? stat.GetConstantModifiers(Entity)
: stat.GetScaleModifiers(Entity))[this] = Context.Evaluate(_data.Modifier, Item, Entity);
return true;
}
public void Dispose()
{
foreach (var stat in _stats)
(_data.Type == StatModifierType.Constant ? stat.GetConstantModifiers(Entity) : stat.GetScaleModifiers(Entity)).Remove(this);
}
}
public enum StatModifierType
{
Constant,
Multiplier
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 839f7ac20a89cef46b2103058238d26e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,40 @@
using System;
using System.Linq;
using MessagePack;
using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class SwitchData : BehaviorData
{
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
return new Switch(context, this, entity, item);
}
}
[UpdateOrder(-25)]
public class Switch : IBehavior
{
private SwitchData _data;
private Entity Entity { get; }
private Gear Item { get; }
private GameContext Context { get; }
public BehaviorData Data => _data;
private bool Activated { get; set; }
public Switch(GameContext context, SwitchData data, Entity entity, Gear item)
{
_data = data;
Entity = entity;
Item = item;
Context = context;
}
public bool Update(float delta)
{
return Activated;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fabf8a72928044a4385e071218c6d7cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -48,10 +48,6 @@ public class Thruster : IAnalogBehavior
_input = saturate(value);
}
public void Initialize()
{
}
public bool Update(float delta)
{
Thrust = Context.Evaluate(_data.Thrust, Item, Entity);
@ -60,8 +56,4 @@ public class Thruster : IAnalogBehavior
Entity.VisibilitySources[this] = _input * Context.Evaluate(_data.Visibility, Item, Entity);
return true;
}
public void Remove()
{
}
}

View file

@ -16,7 +16,8 @@ public class TowingControllerData : ControllerData
}
}
public class TowingController : IBehavior, IPersistentBehavior, IController
[UpdateOrder(-100)]
public class TowingController : IBehavior, IPersistentBehavior, IController, IInitializableBehavior
{
public TaskType TaskType => TaskType.Tow;
public bool Available => _towingTask != Guid.Empty;
@ -149,10 +150,6 @@ public class TowingController : IBehavior, IPersistentBehavior, IController
{
_locomotion.Objective = _context.WormholePosition(_entity.Zone, _path[0].ZoneID);
}
public void Remove()
{
}
}
public class TowingControllerPersistence : PersistentBehaviorData

View file

@ -0,0 +1,55 @@
using System;
using System.Linq;
using MessagePack;
using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class TriggerData : BehaviorData
{
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
return new Trigger(context, this, entity, item);
}
}
[UpdateOrder(-20)]
public class Trigger : IBehavior
{
private TriggerData _data;
private Entity Entity { get; }
private Gear Item { get; }
private GameContext Context { get; }
public BehaviorData Data => _data;
public bool _pulled;
public void Pull()
{
_pulled = true;
}
public Trigger(GameContext context, TriggerData data, Entity entity, Gear item)
{
_data = data;
Entity = entity;
Item = item;
Context = context;
}
public void Initialize()
{
}
public bool Update(float delta)
{
if (_pulled)
{
_pulled = false;
return true;
}
return false;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1dcb2be1f50095d458088f381e5e98a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,54 @@
using System;
using System.Linq;
using MessagePack;
using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class VisibilityData : BehaviorData
{
[InspectableField, JsonProperty("visibility"), Key(1)]
public PerformanceStat Visibility = new PerformanceStat();
[InspectableField, JsonProperty("visibilityDecay"), Key(2)]
public PerformanceStat VisibilityDecay = new PerformanceStat();
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
return new Visibility(context, this, entity, item);
}
}
public class Visibility : IBehavior, IAlwaysUpdatedBehavior
{
private VisibilityData _data;
private Entity Entity { get; }
private Gear Item { get; }
private GameContext Context { get; }
public BehaviorData Data => _data;
private float _cooldown; // Normalized
public Visibility(GameContext context, VisibilityData data, Entity entity, Gear item)
{
_data = data;
Entity = entity;
Item = item;
Context = context;
}
public bool Update(float delta)
{
Entity.VisibilitySources[this] = Context.Evaluate(_data.Visibility, Item, Entity);
return true;
}
public void AlwaysUpdate(float delta)
{
// TODO: Time independent decay?
Entity.VisibilitySources[this] *= Context.Evaluate(_data.VisibilityDecay, Item, Entity);
if (Entity.VisibilitySources[this] < 0.01f) Entity.VisibilitySources.Remove(this);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6cd797c5c65ecf9438830c92ff4ded64
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -8,27 +8,15 @@ public abstract class WeaponData : BehaviorData
[InspectableField, JsonProperty("damageType"), Key(1)]
public DamageType DamageType;
[InspectableField, JsonProperty("damage"), Key(2)]
[InspectableField, JsonProperty("damage"), Key(2)]
public PerformanceStat Damage = new PerformanceStat();
[InspectableField, JsonProperty("range"), Key(3)]
[InspectableField, JsonProperty("range"), Key(3)]
public PerformanceStat Range = new PerformanceStat();
[InspectableField, JsonProperty("cooldown"), Key(4)]
public PerformanceStat Cooldown = new PerformanceStat();
[InspectableField, JsonProperty("heat"), Key(5)]
public PerformanceStat Heat = new PerformanceStat();
[InspectableField, JsonProperty("visibility"), Key(6)]
public PerformanceStat Visibility = new PerformanceStat();
[InspectableField, JsonProperty("visibilityDecay"), Key(7)]
public PerformanceStat VisibilityDecay = new PerformanceStat();
[InspectableField, JsonProperty("burstCount"), Key(8)]
[InspectableField, JsonProperty("burstCount"), Key(4)]
public int BurstCount;
[InspectableField, JsonProperty("burstTime"), Key(9)]
[InspectableField, JsonProperty("burstTime"), Key(5)]
public PerformanceStat BurstTime = new PerformanceStat();
}

View file

@ -78,7 +78,7 @@ public class BlueprintStatEffect
public class StatReference
{
[InspectableType(typeof(BehaviorData)), JsonProperty("behavior"), Key(1)]
public string Behavior;
public string Target;
[InspectableField, JsonProperty("stat"), Key(2)]
public string Stat;

View file

@ -31,7 +31,8 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
// [IgnoreMember] protected List<IBehavior> Behaviors;
[IgnoreMember] public Guid Zone;
[IgnoreMember] public Dictionary<int, List<IBehavior>> Behaviors;
[IgnoreMember] public Dictionary<int, List<IActivatedBehavior>> Bindings;
[IgnoreMember] public Dictionary<int, Switch> Switches;
[IgnoreMember] public Dictionary<int, Trigger> Triggers;
[IgnoreMember] public Dictionary<int, AxisSetting> Axes;
[IgnoreMember] public Dictionary<int, float> AxisOverrides = new Dictionary<int, float>();
[IgnoreMember] public readonly Dictionary<object, float> VisibilitySources = new Dictionary<object, float>();
@ -83,12 +84,15 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
.Select((grouping, i) => new {index = i, group = grouping})
.ToDictionary(ig => ig.index, ig => ig.group.Select(x => x.behavior).ToList());
Bindings = Behaviors
.Where(x => x.Value.Any(g => g is IActivatedBehavior))
.Select((x, i) => new {index = i, behaviors = x.Value
.Where(g => g is IActivatedBehavior)
.Cast<IActivatedBehavior>().ToList()})
.ToDictionary(x => x.index, x => x.behaviors);
Switches = Behaviors
.Where(x => x.Value.Any(g => g is Switch))
.Select((x, i) => new {index = i, s = x.Value.First(g => g is Switch) as Switch})
.ToDictionary(x => x.index, x => x.s);
Triggers = Behaviors
.Where(x => x.Value.Any(g => g is Trigger))
.Select((x, i) => new {index = i, s = x.Value.First(g => g is Trigger) as Trigger})
.ToDictionary(x => x.index, x => x.s);
Axes = Behaviors
.Where(x => x.Value.Any(g => g is IAnalogBehavior))
@ -103,7 +107,9 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
// .ToDictionary(b => b as IAnalogBehavior, b => 0f);
foreach (var behavior in Behaviors.Values
.SelectMany(behaviors=>behaviors)) behavior.Initialize();
.SelectMany(behaviors=>behaviors)
.Where(behavior => behavior is IInitializableBehavior)
.Cast<IInitializableBehavior>()) behavior.Initialize();
}
public void RecalculateMass()

View file

@ -31,10 +31,14 @@ public class GameContext
private Dictionary<Guid, float2> _orbitPositions = new Dictionary<Guid, float2>();
private Dictionary<Guid, float2> _previousOrbitPositions = new Dictionary<Guid, float2>();
private Guid _forceLoadZone;
private Type[] _statObjects;
public GlobalData GlobalData => _globalData ?? (_globalData = Cache.GetAll<GlobalData>().FirstOrDefault());
public DatabaseCache Cache { get; }
public Type[] StatObjects => _statObjects ?? (_statObjects = typeof(BehaviorData).GetAllChildClasses()
.Concat(typeof(EquippableItemData).GetAllChildClasses()).ToArray());
public Guid ForceLoadZone
{
get => _forceLoadZone;
@ -319,11 +323,11 @@ public class GameContext
}
// Get the first behavior of the type specified in the blueprint stat effect, return null if not found
var effectObject = effect.StatReference.Behavior == blueprintItem.Name ? (object) blueprintItem :
blueprintItem.Behaviors.FirstOrDefault(b => b.GetType().Name == effect.StatReference.Behavior);
var effectObject = effect.StatReference.Target == blueprintItem.Name ? (object) blueprintItem :
blueprintItem.Behaviors.FirstOrDefault(b => b.GetType().Name == effect.StatReference.Target);
if (effectObject == null)
{
_logger($"Attempted to get stat effect for Blueprint {blueprint.ID} but stat references missing behavior \"{effect.StatReference.Behavior}\"!");
_logger($"Attempted to get stat effect for Blueprint {blueprint.ID} but stat references missing behavior \"{effect.StatReference.Target}\"!");
return AffectedStats[effect] = null;
}
@ -332,7 +336,7 @@ public class GameContext
var field = type.GetField(effect.StatReference.Stat);
if (field == null)
{
_logger($"Attempted to get stat effect for Blueprint {blueprint.ID} but object {effect.StatReference.Behavior} does not have a stat named \"{effect.StatReference.Stat}\"!");
_logger($"Attempted to get stat effect for Blueprint {blueprint.ID} but object {effect.StatReference.Target} does not have a stat named \"{effect.StatReference.Stat}\"!");
return AffectedStats[effect] = null;
}

View file

@ -13,6 +13,7 @@ public static class RegisterResolver
// Set extensions to default resolver.
var resolver = CompositeResolver.Create(
MathResolver.Instance,
TypeResolver.Instance,
NativeGuidResolver.Instance,
StandardResolver.Instance
);

View file

@ -0,0 +1,65 @@
using System;
using System.Collections;
using System.Collections.Generic;
using MessagePack;
using MessagePack.Formatters;
public class TypeFormatter : MessagePack.Formatters.IMessagePackFormatter<Type>
{
public static readonly IMessagePackFormatter<Type> Instance = new TypeFormatter();
private TypeFormatter()
{
}
public void Serialize(ref MessagePackWriter writer, Type value, MessagePackSerializerOptions options)
{
writer.Write(value.AssemblyQualifiedName);
}
public Type Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
{
throw new InvalidOperationException("typecode is null, struct not supported");
}
var assemblyQualifiedName = reader.ReadString();
return Type.GetType(assemblyQualifiedName);
}
}
public class TypeResolver : IFormatterResolver
{
public static readonly TypeResolver Instance = new TypeResolver();
private TypeResolver()
{
}
public IMessagePackFormatter<T> GetFormatter<T>()
{
return FormatterCache<T>.Formatter;
}
private static object GetFormatterHelper(Type t)
{
if (t == typeof(Type))
{
return TypeFormatter.Instance;
}
return null;
}
private static class FormatterCache<T>
{
public static readonly IMessagePackFormatter<T> Formatter;
static FormatterCache()
{
Formatter = (IMessagePackFormatter<T>)GetFormatterHelper(typeof(T));
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ede4e7a24e20d134fb02868d010af83d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: