diff --git a/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml b/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml
index 595b40391..a7599e1d4 100644
--- a/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml
+++ b/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml
@@ -1245,6 +1245,7 @@
+
@@ -1260,6 +1261,8 @@
+
+
diff --git a/Assets/Scripts/ServerShared/Agents/AgentTask.cs b/Assets/Scripts/ServerShared/Agents/AgentTask.cs
index e6830122a..87518d9d7 100644
--- a/Assets/Scripts/ServerShared/Agents/AgentTask.cs
+++ b/Assets/Scripts/ServerShared/Agents/AgentTask.cs
@@ -8,6 +8,7 @@ using UnityEngine;
[MessagePackObject,
Union(0, typeof(StationTowing)),
+ Union(1, typeof(Mining)),
JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))]
public abstract class AgentTask : DatabaseEntry
{
@@ -25,6 +26,7 @@ public abstract class AgentTask : DatabaseEntry
public enum TaskType
{
+ None,
Mine,
Haul,
Tow,
diff --git a/Assets/Scripts/ServerShared/Agents/Mining.cs b/Assets/Scripts/ServerShared/Agents/Mining.cs
new file mode 100644
index 000000000..c5280d352
--- /dev/null
+++ b/Assets/Scripts/ServerShared/Agents/Mining.cs
@@ -0,0 +1,24 @@
+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 Mining : AgentTask
+{
+ [IgnoreMember] public override TaskType Type => TaskType.Mine;
+
+ [JsonProperty("asteroids"), Key(4)]
+ public Guid Asteroids;
+
+ // public StationTowing(Guid zone, Guid station, Guid orbitParent, float orbitDistance)
+ // {
+ // Zone = zone;
+ // Station = station;
+ // OrbitParent = orbitParent;
+ // OrbitDistance = orbitDistance;
+ // }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/ServerShared/Agents/Mining.cs.meta b/Assets/Scripts/ServerShared/Agents/Mining.cs.meta
new file mode 100644
index 000000000..1661dce42
--- /dev/null
+++ b/Assets/Scripts/ServerShared/Agents/Mining.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6e4409ff5e14e06468f205574cc67a3c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs
index d4c1bbcc3..db2967c21 100644
--- a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs
+++ b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs
@@ -89,6 +89,8 @@ public abstract class PersistentBehaviorData
Union(22, typeof(VisibilityData)),
Union(23, typeof(ThermotoggleData)),
Union(24, typeof(EnergyDrawData)),
+ Union(25, typeof(MiningControllerData)),
+ Union(26, typeof(MiningToolData)),
JsonConverter(typeof(JsonKnownTypesConverter)), JsonObject(MemberSerialization.OptIn)]
public abstract class BehaviorData
{
diff --git a/Assets/Scripts/ServerShared/Behaviors/Controller.cs b/Assets/Scripts/ServerShared/Behaviors/Controller.cs
index dd6e16d4a..e75b5e01f 100644
--- a/Assets/Scripts/ServerShared/Behaviors/Controller.cs
+++ b/Assets/Scripts/ServerShared/Behaviors/Controller.cs
@@ -41,12 +41,12 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh
protected bool MatchVelocity;
protected List Path;
protected Guid Task;
+ protected bool Moving;
private GameContext _context;
private Entity _entity;
private ControllerData _controllerData;
private MovementPhase _movementPhase;
- private bool _moving;
private Action _onFinishMoving;
public ControllerBase(GameContext context, ControllerData data, Entity entity)
@@ -67,7 +67,7 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh
public void AssignTask(Guid task)
{
Task = task;
- _moving = false;
+ Moving = false;
}
public bool Update(float delta)
@@ -79,18 +79,17 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh
return false;
// No task is assigned, but we're not home, go home!
- var homeEntity = _context.Cache.Get(HomeEntity);
- if (!_moving)
+ if (!Moving)
{
- if (Zone == homeEntity.Zone) MoveTo(homeEntity, true, () =>
- _context.SetParent(_entity, homeEntity));
- else MoveTo(homeEntity.Zone, () => MoveTo(homeEntity, true, () =>
- _context.SetParent(_entity, homeEntity)));
+ GoHome();
}
}
- if (_moving)
+ if (Moving)
{
+ if(_entity.Parent!=Guid.Empty)
+ _context.RemoveParent(_entity);
+
var distance = length(TargetPosition() - _entity.Position);
if (MatchVelocity)
{
@@ -108,8 +107,8 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh
VelocityMatch.Clear();
VelocityMatch.OnMatch += () =>
{
- _moving = false;
- _onFinishMoving();
+ Moving = false;
+ _onFinishMoving?.Invoke();
};
}
}
@@ -124,7 +123,7 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh
Locomotion.Update(delta);
if (distance < _controllerData.TargetDistance)
{
- _moving = false;
+ Moving = false;
_onFinishMoving();
}
}
@@ -133,13 +132,39 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh
return true;
}
+ public void FinishTask()
+ {
+ if (Task == Guid.Empty)
+ return;
+
+ var task = _context.Cache.Get(Task);
+ _context.Cache.Delete(task);
+ _context.Cache.Get(_entity.Corporation).Tasks.Remove(task.ID);
+ Task = Guid.Empty;
+ }
+
+ public void GoHome(Action onFinish = null)
+ {
+ var homeEntity = _context.Cache.Get(HomeEntity);
+ if (Zone == homeEntity.Zone) MoveTo(homeEntity, true, () =>
+ {
+ _context.SetParent(_entity, homeEntity);
+ onFinish?.Invoke();
+ });
+ else MoveTo(homeEntity.Zone, () => MoveTo(homeEntity, true, () =>
+ {
+ _context.SetParent(_entity, homeEntity);
+ onFinish?.Invoke();
+ }));
+ }
+
public void MoveTo(Entity entity, bool matchVelocity = true, Action onFinish = null)
{
TargetPosition = () => entity.Position;
TargetVelocity = () => entity.Velocity;
MatchVelocity = matchVelocity;
_movementPhase = MovementPhase.Locomotion;
- _moving = true;
+ Moving = true;
_onFinishMoving = onFinish;
}
@@ -149,7 +174,7 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh
TargetVelocity = () => float2.zero;
MatchVelocity = matchVelocity;
_movementPhase = MovementPhase.Locomotion;
- _moving = true;
+ Moving = true;
_onFinishMoving = onFinish;
}
@@ -159,7 +184,7 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh
TargetVelocity = velocity;
MatchVelocity = true;
_movementPhase = MovementPhase.Locomotion;
- _moving = true;
+ Moving = true;
_onFinishMoving = onFinish;
}
diff --git a/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs b/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs
index 6a5e06d89..8369525bc 100644
--- a/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs
+++ b/Assets/Scripts/ServerShared/Behaviors/FactoryBehavior.cs
@@ -109,7 +109,7 @@ public class Factory : IBehavior, IPersistentBehavior
else
{
var simpleCommodityData = blueprintItemData as SimpleCommodityData;
- var simpleCommodityInstance = Entity.Cargo.FirstOrDefault(i => i == simpleCommodityData.ID);
+ var simpleCommodityInstance = Entity.Cargo.FirstOrDefault(i => Context.Cache.Get(i).Data == simpleCommodityData.ID);
if (simpleCommodityInstance == Guid.Empty)
{
var newSimpleCommodity = new SimpleCommodity
diff --git a/Assets/Scripts/ServerShared/Behaviors/Hitscan.cs b/Assets/Scripts/ServerShared/Behaviors/Hitscan.cs
index e81c4ffc1..3bc66fd25 100644
--- a/Assets/Scripts/ServerShared/Behaviors/Hitscan.cs
+++ b/Assets/Scripts/ServerShared/Behaviors/Hitscan.cs
@@ -24,6 +24,7 @@ public class Hitscan : IBehavior
private float _firingVisibility;
public BehaviorData Data => _data;
+ public float Range { get; private set; }
public Hitscan(GameContext context, HitscanData c, Entity entity, Gear item)
{
@@ -36,6 +37,7 @@ public class Hitscan : IBehavior
public bool Update(float delta)
{
// TODO: Implement hitscan weapons!
+ Range = Context.Evaluate(_data.Range, Item, Entity);
return true;
}
diff --git a/Assets/Scripts/ServerShared/Behaviors/MiningController.cs b/Assets/Scripts/ServerShared/Behaviors/MiningController.cs
new file mode 100644
index 000000000..273765f5a
--- /dev/null
+++ b/Assets/Scripts/ServerShared/Behaviors/MiningController.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using MessagePack;
+using Newtonsoft.Json;
+using Unity.Mathematics;
+using static Unity.Mathematics.math;
+
+[MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)]
+public class MiningControllerData : ControllerData
+{
+ public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
+ {
+ return new MiningController(context, this, entity, item);
+ }
+}
+
+public class MiningController : ControllerBase, IBehavior, IPersistentBehavior, IInitializableBehavior
+{
+ public override TaskType TaskType => TaskType.Mine;
+ public BehaviorData Data => _data;
+
+ private MiningControllerData _data;
+ private GameContext _context;
+ private Entity _entity;
+ private Gear _item;
+ private bool _taskStarted;
+ private int _asteroid = -1;
+ private MiningTool _miningTool;
+ private Switch _toolSwitch;
+
+ public MiningController(GameContext context, MiningControllerData data, Entity entity, Gear item) : base(context, data, entity)
+ {
+ _context = context;
+ _data = data;
+ _entity = entity;
+ _item = item;
+ }
+
+ public new void Initialize()
+ {
+ _miningTool = _entity.GetBehaviors().First();
+ _toolSwitch = _entity.GetSwitch(_miningTool);
+ base.Initialize();
+ }
+
+ public new bool Update(float delta)
+ {
+ var miningTask = _context.Cache.Get(Task);
+ if (miningTask != null)
+ {
+ if (!_taskStarted)
+ {
+ NextAsteroid();
+ _taskStarted = true;
+ }
+ else
+ {
+ if (!Moving)
+ {
+ if (_entity.OccupiedCapacity < _entity.Capacity - 1)
+ {
+ var asteroidTransform = _context.GetAsteroidTransform(miningTask.Asteroids, _asteroid);
+ if (length(_entity.Position - asteroidTransform.xy) - asteroidTransform.w > _miningTool.Range)
+ {
+ _context.Log($"Mining Controller {_entity.Name} is out of range, moving to target asteroid.");
+ MoveTo(() => _context.GetAsteroidTransform(miningTask.Asteroids, _asteroid).xy,
+ () => _context.GetAsteroidVelocity(miningTask.Asteroids, _asteroid));
+ _toolSwitch.Activated = false;
+ }
+ else
+ {
+ if (_context.AsteroidExists(miningTask.Asteroids, _asteroid))
+ {
+ _miningTool.AsteroidBelt = miningTask.Asteroids;
+ _miningTool.Asteroid = _asteroid;
+ _toolSwitch.Activated = true;
+ }
+ else NextAsteroid();
+ }
+ }
+ else
+ {
+ _context.Log($"Mining Controller {_entity.Name} is out of cargo space. Returning home to offload cargo.");
+ GoHome(() =>
+ {
+ var homeEntity = _context.Cache.Get(HomeEntity);
+ if (!_entity.Cargo.ToArray().All(ii =>
+ _context.MoveCargo(_entity, homeEntity, _context.Cache.Get(ii))))
+ {
+ _context.Log($"Mining Controller {_entity.Name} has run out of cargo space in parent. Closing Task.");
+ FinishTask();
+ _taskStarted = false;
+ }
+ });
+ }
+ }
+ }
+ }
+ return base.Update(delta);
+ }
+
+ private void NextAsteroid()
+ {
+ var miningTask = _context.Cache.Get(Task);
+ _asteroid = _context.NearestAsteroid(miningTask.Asteroids, _entity.Position);
+ _context.Log($"Mining Controller {_entity.Name} selecting new asteroid.");
+ }
+
+ public PersistentBehaviorData Store()
+ {
+ return new MiningControllerPersistence
+ {
+ Task = Task
+ };
+ }
+
+ public void Restore(PersistentBehaviorData data)
+ {
+ var miningControllerPersistence = data as MiningControllerPersistence;
+ Task = miningControllerPersistence.Task;
+ }
+}
+
+public class MiningControllerPersistence : PersistentBehaviorData
+{
+ [JsonProperty("task"), Key(0)]
+ public Guid Task;
+}
\ No newline at end of file
diff --git a/Assets/Scripts/ServerShared/Behaviors/MiningController.cs.meta b/Assets/Scripts/ServerShared/Behaviors/MiningController.cs.meta
new file mode 100644
index 000000000..31d1d79bb
--- /dev/null
+++ b/Assets/Scripts/ServerShared/Behaviors/MiningController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b476455dca4333e4da76388aae46ac5e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs b/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs
new file mode 100644
index 000000000..cf3101d1e
--- /dev/null
+++ b/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Linq;
+using MessagePack;
+using Newtonsoft.Json;
+using Unity.Mathematics;
+using static Unity.Mathematics.math;
+
+[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(10)]
+public class MiningToolData : BehaviorData
+{
+ [InspectableField, JsonProperty("dps"), Key(1)]
+ public PerformanceStat DamagePerSecond = new PerformanceStat();
+
+ [InspectableField, JsonProperty("efficiency"), Key(2)]
+ public PerformanceStat Efficiency = new PerformanceStat();
+
+ [InspectableField, JsonProperty("penetration"), Key(3)]
+ public PerformanceStat Penetration = new PerformanceStat();
+
+ [InspectableField, JsonProperty("range"), Key(4)]
+ public PerformanceStat Range = new PerformanceStat();
+
+ public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
+ {
+ return new MiningTool(context, this, entity, item);
+ }
+}
+
+public class MiningTool : IBehavior
+{
+ public Guid AsteroidBelt;
+ public int Asteroid;
+
+ private MiningToolData _data;
+
+ private Entity Entity { get; }
+ private Gear Item { get; }
+ private GameContext Context { get; }
+
+ public BehaviorData Data => _data;
+ public float Range { get; private set; }
+
+ public MiningTool(GameContext context, MiningToolData data, Entity entity, Gear item)
+ {
+ _data = data;
+ Entity = entity;
+ Item = item;
+ Context = context;
+ }
+
+ public bool Update(float delta)
+ {
+ Range = Context.Evaluate(_data.Range, Item, Entity);
+ var asteroidTransform = Context.GetAsteroidTransform(AsteroidBelt, Asteroid);
+ if (AsteroidBelt != Guid.Empty &&
+ Context.AsteroidExists(AsteroidBelt, Asteroid) &&
+ length(Entity.Position - asteroidTransform.xy) - asteroidTransform.w < Range)
+ {
+ Context.MineAsteroid(
+ Entity,
+ AsteroidBelt,
+ Asteroid,
+ Context.Evaluate(_data.DamagePerSecond, Item, Entity) * delta,
+ Context.Evaluate(_data.Efficiency, Item, Entity),
+ Context.Evaluate(_data.Penetration, Item, Entity));
+ return true;
+ }
+
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs.meta b/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs.meta
new file mode 100644
index 000000000..9985f36a2
--- /dev/null
+++ b/Assets/Scripts/ServerShared/Behaviors/MiningTool.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a7eebfaae57b2304580ef7e4a2740993
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/ServerShared/Behaviors/PatrolController.cs b/Assets/Scripts/ServerShared/Behaviors/PatrolController.cs
index 1d834feae..3c7121d18 100644
--- a/Assets/Scripts/ServerShared/Behaviors/PatrolController.cs
+++ b/Assets/Scripts/ServerShared/Behaviors/PatrolController.cs
@@ -17,7 +17,7 @@ public class PatrolControllerData : ControllerData
public class PatrolController : IBehavior, IController, IInitializableBehavior
{
- public TaskType TaskType => TaskType.Tow;
+ public TaskType TaskType => TaskType.None;
public bool Available => false;
public Guid Zone => _entity.Zone;
public BehaviorData Data => _data;
@@ -26,7 +26,6 @@ public class PatrolController : IBehavior, IController, IInitializableBehavior
private GameContext _context;
private Entity _entity;
private Gear _item;
- private Guid _towingTask;
private Locomotion _locomotion;
private Guid _targetOrbit;
diff --git a/Assets/Scripts/ServerShared/Behaviors/Switch.cs b/Assets/Scripts/ServerShared/Behaviors/Switch.cs
index d52ed7502..88dee2a6a 100644
--- a/Assets/Scripts/ServerShared/Behaviors/Switch.cs
+++ b/Assets/Scripts/ServerShared/Behaviors/Switch.cs
@@ -22,7 +22,7 @@ public class Switch : IBehavior
public BehaviorData Data => _data;
- private bool Activated { get; set; }
+ public bool Activated { get; set; }
public Switch(GameContext context, SwitchData data, Entity entity, Gear item)
{
diff --git a/Assets/Scripts/ServerShared/Behaviors/TowingController.cs b/Assets/Scripts/ServerShared/Behaviors/TowingController.cs
index c7e5dfbcb..163ecf1c3 100644
--- a/Assets/Scripts/ServerShared/Behaviors/TowingController.cs
+++ b/Assets/Scripts/ServerShared/Behaviors/TowingController.cs
@@ -40,9 +40,6 @@ public class TowingController : ControllerBase, IBehavior, IPersistentBehavior
var towingTask = _context.Cache.Get(Task);
if (towingTask != null)
{
- if(_entity.Parent!=Guid.Empty)
- _context.RemoveParent(_entity);
-
if (!_taskStarted)
{
MoveTo(towingTask.Zone, () =>
@@ -66,7 +63,7 @@ public class TowingController : ControllerBase, IBehavior, IPersistentBehavior
var orbit = _context.CreateOrbit(towingTask.OrbitParent, _entity.Position);
target.OrbitData = orbit.ID;
- Task = Guid.Empty;
+ FinishTask();
_taskStarted = false;
});
});
diff --git a/Assets/Scripts/ServerShared/Entity.cs b/Assets/Scripts/ServerShared/Entity.cs
index cab53fb2d..55bc9bd8b 100644
--- a/Assets/Scripts/ServerShared/Entity.cs
+++ b/Assets/Scripts/ServerShared/Entity.cs
@@ -45,6 +45,15 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
[IgnoreMember] public float OccupiedCapacity { get; private set; }
[IgnoreMember] public float SpecificHeat { get; private set; }
[IgnoreMember] public float Visibility => VisibilitySources.Values.Sum();
+ public float Capacity
+ {
+ get
+ {
+ var hull = Context.Cache.Get(Hull);
+ var hullData = Context.Cache.Get(hull.Data);
+ return Context.Evaluate(hullData.Capacity, hull, this);
+ }
+ }
[IgnoreMember] public string EntryName
{
@@ -168,6 +177,21 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
return -1;
}
+ public int GetSwitch() where T : class, IBehavior
+ {
+ var s = Behaviors
+ .FirstOrDefault(x => x.Value.Any(g => g is Switch) && x.Value.Any(g => g is T))
+ .Value.First(g => g is Switch) as Switch;
+ return Switches.FirstOrDefault(kvp => kvp.Value == s).Key;
+ }
+
+ public Switch GetSwitch(IBehavior behavior)
+ {
+ return Behaviors
+ .FirstOrDefault(x => x.Value.Any(g => g == behavior))
+ .Value.First(g => g is Switch) as Switch;
+ }
+
public void AddHeat(float heat)
{
if (Parent != Guid.Empty)
diff --git a/Assets/Scripts/ServerShared/GameContext.cs b/Assets/Scripts/ServerShared/GameContext.cs
index 3c507e90e..9fba85edf 100644
--- a/Assets/Scripts/ServerShared/GameContext.cs
+++ b/Assets/Scripts/ServerShared/GameContext.cs
@@ -30,7 +30,10 @@ public class GameContext
private Dictionary _orbitVelocities = new Dictionary();
private Dictionary _orbitPositions = new Dictionary();
private Dictionary _previousOrbitPositions = new Dictionary();
- private Dictionary _asteroidPositions = new Dictionary();
+ private Dictionary _asteroidTransforms = new Dictionary(); // x, y, rotation, scale
+ private Dictionary _previousAsteroidTransforms = new Dictionary(); // x, y, rotation, scale
+ private Dictionary<(Guid, int), float> _asteroidRespawnTimers = new Dictionary<(Guid, int), float>();
+ private Dictionary<(Guid, int), float> _asteroidDamage = new Dictionary<(Guid, int), float>();
private Dictionary _asteroidPositionsUpdated = new Dictionary();
private Guid _forceLoadZone;
private Type[] _statObjects;
@@ -104,7 +107,7 @@ public class GameContext
: float2.zero;
}
- foreach (var asteroids in _asteroidPositions.Keys)
+ foreach (var asteroids in _asteroidTransforms.Keys)
_asteroidPositionsUpdated[asteroids] = false;
foreach (var corporation in Cache.GetAll())
@@ -232,26 +235,82 @@ public class GameContext
return _orbitVelocities.ContainsKey(orbit) ? _orbitVelocities[orbit] : float2.zero;
}
- public float3[] GetAsteroidTransforms(Guid planetDataID)
+ public int NearestAsteroid(Guid planetDataID, float2 position)
{
var planetData = Cache.Get(planetDataID);
- if (!_asteroidPositions.ContainsKey(planetDataID))
+
+ var asteroidPositions = GetAsteroidTransforms(planetDataID);
+
+ int nearest = 0;
+ float nearestDistance = Single.MaxValue;
+ for (int i = 0; i < planetData.Asteroids.Length; i++)
{
- _asteroidPositions[planetDataID] = new float3[planetData.Asteroids.Length];
+ var dist = lengthsq(asteroidPositions[i].xy - position);
+ if (AsteroidExists(planetDataID, i) && dist < nearestDistance)
+ {
+ nearest = i;
+ nearestDistance = dist;
+ }
+ }
+
+ return nearest;
+ }
+
+ public bool AsteroidExists(Guid planetDataID, int asteroid) =>
+ !_asteroidRespawnTimers.ContainsKey((planetDataID, asteroid));
+
+ public float2 GetAsteroidVelocity(Guid planetDataID, int asteroid)
+ {
+ UpdateAsteroidTransforms(planetDataID);
+
+ if (!_previousAsteroidTransforms.ContainsKey(planetDataID))
+ return float2.zero;
+
+ return (_asteroidTransforms[planetDataID][asteroid].xy - _previousAsteroidTransforms[planetDataID][asteroid].xy) / _deltaTime;
+ }
+
+ public float4 GetAsteroidTransform(Guid planetDataID, int asteroid)
+ {
+ UpdateAsteroidTransforms(planetDataID);
+ return _asteroidTransforms[planetDataID][asteroid];
+ }
+
+ public float4[] GetAsteroidTransforms(Guid planetDataID)
+ {
+ UpdateAsteroidTransforms(planetDataID);
+
+ return _asteroidTransforms[planetDataID];
+ }
+
+ private void UpdateAsteroidTransforms(Guid planetDataID)
+ {
+ var planetData = Cache.Get(planetDataID);
+
+ if (!_asteroidTransforms.ContainsKey(planetDataID))
+ {
+ _asteroidTransforms[planetDataID] = new float4[planetData.Asteroids.Length];
_asteroidPositionsUpdated[planetDataID] = false;
}
if (_asteroidPositionsUpdated[planetDataID])
- return _asteroidPositions[planetDataID];
+ return;
+
+ if (!_previousAsteroidTransforms.ContainsKey(planetDataID))
+ _previousAsteroidTransforms[planetDataID] = new float4[planetData.Asteroids.Length];
+ Array.Copy(_asteroidTransforms[planetDataID], _previousAsteroidTransforms[planetDataID], planetData.Asteroids.Length);
+
+ var orbitData = Cache.Get(planetData.Orbit);
+ var orbitPosition = GetOrbitPosition(orbitData.Parent);
for (var i = 0; i < planetData.Asteroids.Length; i++)
{
- _asteroidPositions[planetDataID][i] = float3(
- OrbitData.Evaluate((float) frac(Time / OrbitalPeriod(planetData.Asteroids[i].x) * GlobalData.OrbitSpeedMultiplier +
- planetData.Asteroids[i].y)) * planetData.Asteroids[i].x,
- (float) (Time * planetData.Asteroids[i].w % 360.0));
+ _asteroidTransforms[planetDataID][i] = float4(
+ OrbitData.Evaluate((float) frac(Time / OrbitalPeriod(planetData.Asteroids[i].Distance) * GlobalData.OrbitSpeedMultiplier +
+ planetData.Asteroids[i].Phase)) * planetData.Asteroids[i].Distance + orbitPosition,
+ (float) (Time * planetData.Asteroids[i].RotationSpeed % 360.0),
+ _asteroidRespawnTimers.ContainsKey((planetDataID, i)) ? 0 : planetData.Asteroids[i].Size);
}
- return _asteroidPositions[planetDataID];
+ _asteroidPositionsUpdated[planetDataID] = true;
}
public OrbitData CreateOrbit(Guid parent, float2 position)
@@ -274,11 +333,9 @@ public class GameContext
Phase = storedPhase,
Zone = parentOrbit.Zone
};
- _lastCreatedOrbit = orbit;
Cache.Add(orbit);
return orbit;
}
- private OrbitData _lastCreatedOrbit;
public float OrbitalPeriod(float distance)
{
@@ -812,4 +869,133 @@ public class GameContext
parent.RecalculateMass();
child.Parent = Guid.Empty;
}
+
+ public void MineAsteroid(Entity miner, Guid asteroidBelt, int asteroid, float damage, float efficiency, float penetration)
+ {
+ var planetData = Cache.Get(asteroidBelt);
+ var asteroidTransform = GetAsteroidTransform(asteroidBelt, asteroid);
+ var hpLerp = unlerp(GlobalData.AsteroidSizeMin, GlobalData.AsteroidSizeMax, asteroidTransform.w);
+ var asteroidHitpoints = lerp(GlobalData.AsteroidHitpointsMin, GlobalData.AsteroidHitpointsMax, pow(hpLerp, GlobalData.AsteroidHitpointsPower));
+ if (!_asteroidDamage.ContainsKey((asteroidBelt, asteroid)))
+ _asteroidDamage[(asteroidBelt, asteroid)] = 0;
+ _asteroidDamage[(asteroidBelt, asteroid)] = _asteroidDamage[(asteroidBelt, asteroid)] + damage;
+ if (_asteroidDamage[(asteroidBelt, asteroid)] > asteroidHitpoints)
+ _asteroidRespawnTimers[(asteroidBelt, asteroid)] =
+ lerp(GlobalData.AsteroidRespawnMin, GlobalData.AsteroidRespawnMax, hpLerp);
+ var resource = planetData.Resources.MaxBy(x => pow(x.Value, 1f / penetration) * Random.NextFloat());
+ if (resource.Value * efficiency * Random.NextFloat() > 1 && miner.OccupiedCapacity < miner.Capacity - 1)
+ {
+ var simpleCommodityTarget = miner.Cargo
+ .Select(i => Cache.Get(i))
+ .FirstOrDefault(i => i.Data == resource.Key) as SimpleCommodity;
+ if (simpleCommodityTarget == null)
+ {
+ var newSimpleCommodity = new SimpleCommodity
+ {
+ Context = this,
+ Data = resource.Key,
+ Quantity = 1
+ };
+ Cache.Add(newSimpleCommodity);
+ miner.Cargo.Add(newSimpleCommodity.ID);
+ miner.RecalculateMass();
+ }
+ else
+ {
+ simpleCommodityTarget.Quantity++;
+ miner.RecalculateMass();
+ }
+ }
+ }
+
+ public bool MoveCargo(Entity source, Entity target, ItemInstance item, int quantity = int.MaxValue)
+ {
+ if (item is CraftedItemInstance craftedItemInstance)
+ {
+ var craftedItemData = Cache.Get(craftedItemInstance.Data);
+ if (target.Capacity - target.OccupiedCapacity > craftedItemData.Size)
+ {
+ // Target has the cargo capacity for the item, simply move the instance
+ source.Cargo.Remove(item.ID);
+ target.Cargo.Add(item.ID);
+ source.RecalculateMass();
+ target.RecalculateMass();
+ return true;
+ }
+ return false;
+ }
+
+ if (item is SimpleCommodity simpleCommoditySource)
+ {
+ quantity = min(quantity, simpleCommoditySource.Quantity);
+ var simpleCommodityData = Cache.Get(simpleCommoditySource.Data);
+ var spareCapacity = (int) (target.Capacity - target.OccupiedCapacity);
+ var simpleCommodityTarget = target.Cargo
+ .Select(i => Cache.Get(i))
+ .FirstOrDefault(i => i.Data == simpleCommodityData.ID) as SimpleCommodity;
+ var success = spareCapacity >= quantity;
+ quantity = min(quantity, spareCapacity);
+ if (simpleCommodityTarget == null)
+ {
+ if (quantity == simpleCommoditySource.Quantity)
+ {
+ // Target has the cargo capacity to hold the full quantity,
+ // and the target has no matching item instance;
+ // simply move the existing item instance to the target
+ source.Cargo.Remove(simpleCommoditySource.ID);
+ target.Cargo.Add(simpleCommoditySource.ID);
+ source.RecalculateMass();
+ target.RecalculateMass();
+ return success;
+ }
+ else
+ {
+ // Target has the cargo capacity to hold the desired quantity
+ // and the target has no matching item instance;
+ // Create a new item instance on the target and decrement the quantity of the source instance
+ var newSimpleCommodity = new SimpleCommodity
+ {
+ Context = this,
+ Data = simpleCommodityData.ID,
+ Quantity = simpleCommoditySource.Quantity
+ };
+ Cache.Add(newSimpleCommodity);
+ target.Cargo.Add(newSimpleCommodity.ID);
+ simpleCommoditySource.Quantity -= quantity;
+ source.RecalculateMass();
+ target.RecalculateMass();
+ return success;
+ }
+ }
+ else
+ {
+ if (quantity == simpleCommoditySource.Quantity)
+ {
+ // Target has the cargo capacity to hold the full quantity,
+ // and there is already a matching item instance;
+ // delete the source entity's item instance and increment the target's quantity
+ source.Cargo.Remove(simpleCommoditySource.ID);
+ Cache.Delete(simpleCommoditySource);
+ simpleCommodityTarget.Quantity += quantity;
+ source.RecalculateMass();
+ target.RecalculateMass();
+ return success;
+ }
+ else
+ {
+ // Target has the cargo capacity to hold the desired quantity,
+ // and there is already a matching item instance;
+ // decrement the source's quantity and increment the target's quantity
+ simpleCommoditySource.Quantity -= quantity;
+ simpleCommodityTarget.Quantity += quantity;
+ source.RecalculateMass();
+ target.RecalculateMass();
+ return success;
+ }
+ }
+
+ }
+
+ return false;
+ }
}
\ No newline at end of file
diff --git a/Assets/Scripts/ServerShared/GlobalData.cs b/Assets/Scripts/ServerShared/GlobalData.cs
index 21589ec8e..257e31be9 100644
--- a/Assets/Scripts/ServerShared/GlobalData.cs
+++ b/Assets/Scripts/ServerShared/GlobalData.cs
@@ -139,6 +139,21 @@ public class GlobalData : DatabaseEntry
[InspectableField, JsonProperty("startingGearQualityMax"), Key(43)]
public float StartingGearQualityMax = .5f;
+
+ [InspectableField, JsonProperty("asteroidHitpointsMin"), Key(44)]
+ public float AsteroidHitpointsMin = 10f;
+
+ [InspectableField, JsonProperty("asteroidHitpointsMax"), Key(45)]
+ public float AsteroidHitpointsMax = 200f;
+
+ [InspectableField, JsonProperty("asteroidHitpointsPower"), Key(46)]
+ public float AsteroidHitpointsPower = 2f;
+
+ [InspectableField, JsonProperty("asteroidRespawnMin"), Key(47)]
+ public float AsteroidRespawnMin = 10f;
+
+ [InspectableField, JsonProperty("asteroidRespawnMax"), Key(48)]
+ public float AsteroidRespawnMax = 100f;
public float PlanetRadius(float mass)
{
diff --git a/Assets/Scripts/ServerShared/ZoneData.cs b/Assets/Scripts/ServerShared/ZoneData.cs
index aade3105a..f80ab95dd 100644
--- a/Assets/Scripts/ServerShared/ZoneData.cs
+++ b/Assets/Scripts/ServerShared/ZoneData.cs
@@ -94,7 +94,7 @@ public class PlanetData : DatabaseEntry, INamedEntry
public Dictionary Resources = new Dictionary();
[JsonProperty("asteroids"), Key(7)]
- public float4[] Asteroids; // Distance, Phase, Size, RotationSpeed
+ public Asteroid[] Asteroids; // Distance, Phase, Size, RotationSpeed
// [JsonProperty("radius")] [Key(5)]
// public float GravityRadius;
@@ -106,6 +106,15 @@ public class PlanetData : DatabaseEntry, INamedEntry
}
}
+[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
+public class Asteroid
+{
+ public float Distance;
+ public float Phase;
+ public float Size;
+ public float RotationSpeed;
+}
+
[RethinkTable("Galaxy"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class OrbitData : DatabaseEntry
{
diff --git a/Assets/Scripts/ServerShared/ZoneGenerator.cs b/Assets/Scripts/ServerShared/ZoneGenerator.cs
index 665fba7fe..225226c48 100644
--- a/Assets/Scripts/ServerShared/ZoneGenerator.cs
+++ b/Assets/Scripts/ServerShared/ZoneGenerator.cs
@@ -104,11 +104,15 @@ public class ZoneGenerator
{
planetData.Asteroids =
Enumerable.Range(0, (int) (pow(planetData.Mass, context.GlobalData.BeltMassExponent) / context.GlobalData.BeltMassRatio * orbitMap[planet].Distance))
- .Select(_ => float4(context.Random.NextFloat(orbitMap[planet].Distance * .5f, orbitMap[planet].Distance * 1.5f),
- context.Random.NextFloat(),
- pow(context.Random.NextFloat(), context.GlobalData.AsteroidSizeExponent) * (context.GlobalData.AsteroidSizeMax - context.GlobalData.AsteroidSizeMin) + context.GlobalData.AsteroidSizeMin,
- context.Random.NextFloat() * context.GlobalData.AsteroidRotationSpeed))
- .ToArray();
+ .Select(_ => new Asteroid
+ {
+ Distance = context.Random.NextFloat(orbitMap[planet].Distance * .5f, orbitMap[planet].Distance * 1.5f),
+ Phase = context.Random.NextFloat(),
+ Size = pow(context.Random.NextFloat(), context.GlobalData.AsteroidSizeExponent) *
+ (context.GlobalData.AsteroidSizeMax - context.GlobalData.AsteroidSizeMin) +
+ context.GlobalData.AsteroidSizeMin,
+ RotationSpeed = context.Random.NextFloat() * context.GlobalData.AsteroidRotationSpeed
+ }).ToArray();
}
return planetData;
}).ToArray();
diff --git a/Assets/Scripts/StrategyGameManager.cs b/Assets/Scripts/StrategyGameManager.cs
index a963ae0b7..f3af07be1 100644
--- a/Assets/Scripts/StrategyGameManager.cs
+++ b/Assets/Scripts/StrategyGameManager.cs
@@ -371,7 +371,7 @@ public class StrategyGameManager : MonoBehaviour
foreach (var belt in _zoneBelts)
{
- belt.Value.Transform.position = float3(_context.GetOrbitPosition(belt.Key) * ZoneSizeScale, .15f);
+ //belt.Value.Transform.position = float3(_context.GetOrbitPosition(belt.Key) * ZoneSizeScale, .15f);
belt.Value.Update();
}
@@ -543,15 +543,31 @@ public class StrategyGameManager : MonoBehaviour
ContextMenu.Clear();
if (targetObject is PlanetData planet)
{
- ContextMenu.AddOption("Test Option 1", () => Debug.Log("Test Option 1 Selected"));
- ContextMenu.AddOption("Test Option 2", () => Debug.Log("Test Option 2 Selected"));
- ContextMenu.AddDropdown("Test Dropdown", new []
+ if (planet.Belt)
{
- ("Dropdown Option 1", (Action) (() => Debug.Log("Dropdown Option 1 Selected"))),
- ("Dropdown Option 2", (Action) (() => Debug.Log("Dropdown Option 2 Selected"))),
- ("Dropdown Option 3", (Action) (() => Debug.Log("Dropdown Option 3 Selected")))
- });
- ContextMenu.AddOption("Test Option 3", () => Debug.Log("Test Option 3 Selected"));
+ ContextMenu.AddOption("Create Mining Task", () =>
+ {
+ var task = new Mining
+ {
+ Asteroids = clickTarget,
+ Context = _context,
+ Priority = 0,
+ Reserved = false,
+ Zone = _populatedZone
+ };
+ _cache.Add(task);
+ _cache.Get(_playerCorporation).Tasks.Add(task.ID);
+ });
+ }
+ // ContextMenu.AddOption("Test Option 1", () => Debug.Log("Test Option 1 Selected"));
+ // ContextMenu.AddOption("Test Option 2", () => Debug.Log("Test Option 2 Selected"));
+ // ContextMenu.AddDropdown("Test Dropdown", new []
+ // {
+ // ("Dropdown Option 1", (Action) (() => Debug.Log("Dropdown Option 1 Selected"))),
+ // ("Dropdown Option 2", (Action) (() => Debug.Log("Dropdown Option 2 Selected"))),
+ // ("Dropdown Option 3", (Action) (() => Debug.Log("Dropdown Option 3 Selected")))
+ // });
+ // ContextMenu.AddOption("Test Option 3", () => Debug.Log("Test Option 3 Selected"));
}
else if (targetObject is Ship ship)
{
@@ -617,7 +633,7 @@ public class StrategyGameManager : MonoBehaviour
hullData.HullType == HullType.Station ? "Colony" :
"Weapons Platform");
PropertiesPanel.AddProperty("Hull", () => $"{hullData.Name}");
- PropertiesPanel.AddProperty("Capacity", () => $"{entity.OccupiedCapacity}/{_context.Evaluate(hullData.Capacity, hull, entity)}");
+ PropertiesPanel.AddProperty("Capacity", () => $"{entity.OccupiedCapacity}/{entity.Capacity}");
PropertiesPanel.AddProperty("Mass", () => $"{entity.Mass}");
PropertiesPanel.AddProperty("Temperature", () => $"{entity.Temperature:0}°K");
PropertiesPanel.AddProperty("Energy", () => $"{entity.Energy:0}/{entity.GetBehaviors().First().Capacitance:0}");
@@ -986,9 +1002,11 @@ public class AsteroidBelt
private Vector2[] _uvs;
private int[] _indices;
private Guid _data;
+ private Guid _orbit;
private GameContext _context;
private Mesh _mesh;
private float _zoneScale;
+ private float _size;
public AsteroidBelt(GameContext context, MeshFilter meshFilter, MeshCollider collider, Guid data, int spritesheetWidth, int spritesheetHeight, float zoneScale)
{
@@ -999,6 +1017,8 @@ public class AsteroidBelt
_collider = collider;
_zoneScale = zoneScale;
var planetData = context.Cache.Get(data);
+ var orbitData = context.Cache.Get(planetData.Orbit);
+ _orbit = orbitData.Parent;
_vertices = new Vector3[planetData.Asteroids.Length*4];
_normals = new Vector3[planetData.Asteroids.Length*4];
_uvs = new Vector2[planetData.Asteroids.Length*4];
@@ -1009,8 +1029,8 @@ public class AsteroidBelt
// vertex order: bottom left, top left, top right, bottom right
for (var i = 0; i < planetData.Asteroids.Length; i++)
{
- if (planetData.Asteroids[i].x > maxDist)
- maxDist = planetData.Asteroids[i].x;
+ if (planetData.Asteroids[i].Distance > maxDist)
+ maxDist = planetData.Asteroids[i].Distance;
var spriteX = Random.Range(0, spritesheetWidth);
var spriteY = Random.Range(0, spritesheetHeight);
@@ -1038,6 +1058,7 @@ public class AsteroidBelt
_mesh.triangles = _indices;
_mesh.normals = _normals;
_mesh.bounds = new Bounds(Vector3.zero, Vector3.one * maxDist);
+ _size = maxDist;
_filter.mesh = _mesh;
//_collider.sharedMesh = _mesh;
@@ -1051,12 +1072,13 @@ public class AsteroidBelt
{
var rotation = Quaternion.Euler(0, 0, asteroidTransforms[i].z);
var position = (Vector3) (Vector2) asteroidTransforms[i].xy * _zoneScale;
- _vertices[i * 4] = rotation * new Vector3(-planetData.Asteroids[i].z,-planetData.Asteroids[i].z,0) + position;
- _vertices[i * 4 + 1] = rotation * new Vector3(-planetData.Asteroids[i].z,planetData.Asteroids[i].z,0) + position;
- _vertices[i * 4 + 2] = rotation * new Vector3(planetData.Asteroids[i].z,planetData.Asteroids[i].z,0) + position;
- _vertices[i * 4 + 3] = rotation * new Vector3(planetData.Asteroids[i].z,-planetData.Asteroids[i].z,0) + position;
+ _vertices[i * 4] = rotation * new Vector3(-asteroidTransforms[i].w * _zoneScale,-asteroidTransforms[i].w * _zoneScale,0) + position;
+ _vertices[i * 4 + 1] = rotation * new Vector3(-asteroidTransforms[i].w * _zoneScale,asteroidTransforms[i].w * _zoneScale,0) + position;
+ _vertices[i * 4 + 2] = rotation * new Vector3(asteroidTransforms[i].w * _zoneScale,asteroidTransforms[i].w * _zoneScale,0) + position;
+ _vertices[i * 4 + 3] = rotation * new Vector3(asteroidTransforms[i].w * _zoneScale,-asteroidTransforms[i].w * _zoneScale,0) + position;
}
+ _mesh.bounds = new Bounds((Vector2) _context.GetOrbitPosition(_orbit) * _zoneScale, Vector3.one * (_size * _zoneScale * 2));
_mesh.vertices = _vertices;
_collider.sharedMesh = _mesh;
}
diff --git a/Economy.Shared.Unity.csproj b/Economy.Shared.Unity.csproj
index dcf068551..b5f806f24 100644
--- a/Economy.Shared.Unity.csproj
+++ b/Economy.Shared.Unity.csproj
@@ -64,6 +64,7 @@
+
@@ -77,6 +78,8 @@
+
+