Entity Spawning & Rendering

Entity rendering now fully supports dynamic entities from game context
Entity children now displayed underneath icon
GameContext can spawn entities by loadout
Selected corporation's initial fleet is spawned in parent corp's home sector
Properties panel API is now unified with context menu API
Properties panel labels now update dynamically
This commit is contained in:
hyperion51 2020-05-25 03:05:30 +01:00
commit 110ff883b8
25 changed files with 1019 additions and 165 deletions

View file

@ -84,7 +84,6 @@ public class Factory : IBehavior, IPersistentBehavior
{
Context = Context,
Data = blueprintItemData.ID,
ID = Guid.NewGuid(),
Ingredients = _reservedStock.Select(ii=>ii.ID).ToList(),
Quality = quality,
Blueprint = _blueprint
@ -98,7 +97,6 @@ public class Factory : IBehavior, IPersistentBehavior
{
Context = Context,
Data = blueprintItemData.ID,
ID = Guid.NewGuid(),
Ingredients = _reservedStock.Select(ii=>ii.ID).ToList(),
Quality = quality,
Blueprint = _blueprint
@ -118,7 +116,6 @@ public class Factory : IBehavior, IPersistentBehavior
{
Context = Context,
Data = simpleCommodityData.ID,
ID = Guid.NewGuid(),
Quantity = blueprint.Quantity
};
Context.Cache.Add(newSimpleCommodity);
@ -181,7 +178,6 @@ public class Factory : IBehavior, IPersistentBehavior
{
Context = Context,
Data = simpleCommodity.Data,
ID = Guid.NewGuid(),
Quantity = blueprintQuantity
};
simpleCommodity.Quantity -= blueprintQuantity;

View file

@ -50,6 +50,10 @@ public class TowingController : IBehavior, IPersistentBehavior, IController, IIn
public bool Update(float delta)
{
var towingTask = _context.Cache.Get<StationTowing>(_towingTask);
if (towingTask == null)
return false;
if (_path.Any())
{
_locomotion.Update(delta);
@ -64,7 +68,6 @@ public class TowingController : IBehavior, IPersistentBehavior, IController, IIn
}
else
{
var towingTask = _context.Cache.Get<StationTowing>(_towingTask);
var destination = float2(0);
var velocity = float2(0);
if (_towingPhase == TowingPhase.Pickup)
@ -97,19 +100,17 @@ public class TowingController : IBehavior, IPersistentBehavior, IController, IIn
_velocityMatch.OnMatch += () =>
{
var target = _context.ZoneEntities[_entity.Zone][towingTask.Station];
_entity.Children.Add(towingTask.Station);
target.Parent = _entity.ID;
_context.SetParent(target, _entity);
_towingPhase = TowingPhase.Delivery;
_movementPhase = MovementPhase.Locomotion;
};
else
_velocityMatch.OnMatch += () =>
{
var orbit = _context.CreateOrbit(towingTask.OrbitParent, _entity.Position);
var target = _context.ZoneEntities[_entity.Zone][towingTask.Station] as OrbitalEntity;
_entity.Children.Remove(towingTask.Station);
target.Parent = Guid.Empty;
_context.RemoveParent(target);
var orbit = _context.CreateOrbit(towingTask.OrbitParent, _entity.Position);
target.OrbitData = orbit.ID;
};
}

View file

@ -135,6 +135,9 @@ public class LoadoutData : DatabaseEntry, INamedEntry
[JsonProperty("items"), Key(3)]
public List<Guid> Items = new List<Guid>();
[InspectableDatabaseLink(typeof(SimpleCommodityData)), JsonProperty("resourceRequirements"), Key(4)]
public Dictionary<Guid, int> SimpleCargo = new Dictionary<Guid, int>();
[IgnoreMember] public string EntryName
{
get => Name;

View file

@ -13,7 +13,7 @@ using static Unity.Mathematics.math;
Union(0, typeof(Ship)),
Union(1, typeof(OrbitalEntity)),
JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter<Entity>))]
public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackReceiver
public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackReceiver, INamedEntry
{
[JsonProperty("temperature"), Key(1)] public float Temperature;
[JsonProperty("energy"), Key(2)] public float Energy;
@ -27,6 +27,7 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
[JsonProperty("hull"), Key(10)] public Guid Hull; // Type: Gear
[JsonProperty("persistedBehaviorData"), Key(11)] public Dictionary<Guid, PersistentBehaviorData[]> PersistedBehaviors;
[JsonProperty("corporation"), Key(12)] public Guid Corporation;
[JsonProperty("name"), Key(13)] public string Name;
// [IgnoreMember] protected List<IBehavior> Behaviors;
[IgnoreMember] public Guid Zone;
@ -44,10 +45,15 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
[IgnoreMember] public float SpecificHeat { get; private set; }
[IgnoreMember] public float Visibility => VisibilitySources.Values.Sum();
[IgnoreMember] public string EntryName
{
get => Name;
set => Name = value;
}
public Entity(GameContext context, Guid hull, IEnumerable<Guid> items, IEnumerable<Guid> cargo, Guid zone)
{
ID = Guid.NewGuid();
Context = context;
Zone = zone;
@ -120,7 +126,8 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
SpecificHeat = Context.Cache.Get<Gear>(Hull).HeatCapacity +
EquippedItems.Select(i => Context.Cache.Get<Gear>(i)).Sum(i => i.HeatCapacity) +
Cargo.Select(i => Context.Cache.Get<ItemInstance>(i)).Sum(ii => ii.HeatCapacity);
Cargo.Select(i => Context.Cache.Get<ItemInstance>(i)).Sum(ii => ii.HeatCapacity) +
Children.Select(i => Context.Cache.Get<Entity>(i)).Sum(c=>c.SpecificHeat);
}
public IEnumerable<T> GetBehaviors<T>() where T : class, IBehavior

View file

@ -30,6 +30,8 @@ public class GameContext
private Dictionary<Guid, float2> _orbitVelocities = new Dictionary<Guid, float2>();
private Dictionary<Guid, float2> _orbitPositions = new Dictionary<Guid, float2>();
private Dictionary<Guid, float2> _previousOrbitPositions = new Dictionary<Guid, float2>();
private Dictionary<Guid, float3[]> _asteroidPositions = new Dictionary<Guid, float3[]>();
private Dictionary<Guid, bool> _asteroidPositionsUpdated = new Dictionary<Guid, bool>();
private Guid _forceLoadZone;
private Type[] _statObjects;
@ -102,6 +104,9 @@ public class GameContext
: float2.zero;
}
foreach (var asteroids in _asteroidPositions.Keys)
_asteroidPositionsUpdated[asteroids] = false;
foreach (var corporation in Cache.GetAll<Corporation>())
{
foreach (var tasks in corporation.Tasks
@ -222,6 +227,28 @@ public class GameContext
return _orbitVelocities.ContainsKey(orbit) ? _orbitVelocities[orbit] : float2.zero;
}
public float3[] GetAsteroidTransforms(Guid planetDataID)
{
var planetData = Cache.Get<PlanetData>(planetDataID);
if (!_asteroidPositions.ContainsKey(planetDataID))
{
_asteroidPositions[planetDataID] = new float3[planetData.Asteroids.Length];
_asteroidPositionsUpdated[planetDataID] = false;
}
if (_asteroidPositionsUpdated[planetDataID])
return _asteroidPositions[planetDataID];
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));
}
return _asteroidPositions[planetDataID];
}
public OrbitData CreateOrbit(Guid parent, float2 position)
{
var parentOrbit = Cache.Get<OrbitData>(parent);
@ -236,7 +263,6 @@ public class GameContext
{
Context = this,
Distance = distance,
ID = Guid.NewGuid(),
Parent = parent,
Period = period,
Phase = storedPhase,
@ -511,6 +537,138 @@ public class GameContext
return stat.Min;
return result;
}
public Entity CreateEntity(Guid zone, Guid corporation, Guid loadout)
{
if (!(Cache.Get(loadout) is LoadoutData loadoutData))
{
_logger("Attempted to spawn invalid loadout ID");
return null;
}
if (!(Cache.Get(loadoutData.Hull) is HullData hullData))
{
_logger("Attempted to spawn loadout with invalid hull ID");
return null;
}
if (!(Cache.Get(zone) is ZoneData zoneData))
{
_logger("Attempted to spawn entity with invalid zone ID");
return null;
}
if (!(Cache.Get(corporation) is Corporation corpData))
{
_logger("Attempted to spawn entity with invalid corporation ID");
return null;
}
var gearData = loadoutData.Items
.Take(hullData.Hardpoints.Count)
.Where(id => id != Guid.Empty)
.Select(id => Cache.Get<GearData>(id))
.ToArray();
if (gearData.Any(g=>g==null))
{
_logger("Attempted to spawn loadout with invalid gear ID");
return null;
}
var cargoData = loadoutData.Items
.Skip(hullData.Hardpoints.Count)
.Where(id => id != Guid.Empty)
.Select(id => Cache.Get<CraftedItemData>(id))
.ToArray();
if (cargoData.Any(g=>g==null))
{
_logger("Attempted to spawn loadout with invalid cargo ID");
return null;
}
var gear = gearData
.Select(gd => CreateInstance(gd.ID, GlobalData.StartingGearQualityMin, GlobalData.StartingGearQualityMax))
.ToArray();
if (gear.Any(g=>g==null))
return null;
foreach(var g in gear)
Cache.Add(g);
var cargo = cargoData
.Select(gd => CreateInstance(gd.ID, GlobalData.StartingGearQualityMin, GlobalData.StartingGearQualityMax))
.ToArray();
if (cargo.Any(g=>g==null))
return null;
foreach(var c in cargo)
Cache.Add(c);
var simpleCargo = loadoutData.SimpleCargo?
.Select(x => CreateInstance(x.Key, x.Value))
.ToArray() ?? new SimpleCommodity[0];
if (simpleCargo.Any(g=>g==null))
return null;
foreach(var c in simpleCargo)
Cache.Add(c);
var hull = CreateInstance(loadoutData.Hull, GlobalData.StartingGearQualityMin, GlobalData.StartingGearQualityMax);
if(hull==null)
return null;
// Load target zone if not yet loaded
if (!_loadedZones.Contains(zone))
LoadZone(zone);
if (hullData.HullType == HullType.Ship)
{
var entity = new Ship(this, hull.ID, gear.Select(g => g.ID),
cargo.Select(c => c.ID).Concat(simpleCargo.Select(c => c.ID)), zone)
{
Name = $"{loadoutData.Name} {Random.NextInt(1,255):X}"
};
Cache.Add(entity);
ZoneEntities[zone][entity.ID] = entity;
return entity;
}
if (hullData.HullType == HullType.Station)
{
var distance = lerp(.2f, .8f, Random.NextFloat()) * zoneData.Radius;
var orbit = new OrbitData
{
Context = this,
Distance = distance,
Parent = _orbits
.Select(id => Cache.Get<OrbitData>(id))
.First(orbitData => orbitData.Zone == zone && orbitData.Parent == Guid.Empty).ID,
Period = OrbitalPeriod(distance),
Phase = Random.NextFloat(),
Zone = zone
};
Cache.Add(orbit);
var entity = new OrbitalEntity(this, hull.ID, gear.Select(g => g.ID),
cargo.Select(c => c.ID).Concat(simpleCargo.Select(c => c.ID)), orbit.ID, zone)
{
Name = $"{loadoutData.Name} {Random.NextInt(1,255):X}"
};
Cache.Add(entity);
ZoneEntities[zone][entity.ID] = entity;
return entity;
}
return null;
}
public SimpleCommodity CreateInstance(Guid data, int count)
{
@ -519,15 +677,14 @@ public class GameContext
return new SimpleCommodity
{
Data = data,
Quantity = count,
ID = Guid.NewGuid()
Quantity = count
};
_logger("Attempted to create Simple Commodity instance using missing or incorrect item id");
return null;
}
public CraftedItemInstance CreateInstance(Guid data, float quality)
public CraftedItemInstance CreateInstance(Guid data, float qualityMin, float qualityMax)
{
var item = Cache.Get<CraftedItemData>(data);
if (item == null)
@ -548,7 +705,7 @@ public class GameContext
var ingredient = Cache.Get(ci.Key);
return ingredient is SimpleCommodityData
? (IEnumerable<ItemInstance>) new[] {CreateInstance(ci.Key, ci.Value)}
: Enumerable.Range(0, ci.Value).Select(i => CreateInstance(ci.Key, quality));
: Enumerable.Range(0, ci.Value).Select(i => CreateInstance(ci.Key, qualityMin, qualityMax));
})
.ToList();
@ -560,9 +717,8 @@ public class GameContext
{
Context = this,
Data = data,
ID = Guid.NewGuid(),
Ingredients = ingredients.Select(i=>i.ID).ToList(),
Quality = quality,
Quality = Random.NextFloat(qualityMin, qualityMax),
Blueprint = blueprint.ID
};
newGear.Durability = Evaluate(equippableItemData.Durability, newGear);
@ -574,9 +730,8 @@ public class GameContext
{
Context = this,
Data = data,
ID = Guid.NewGuid(),
Ingredients = ingredients.Select(i=>i.ID).ToList(),
Quality = quality,
Quality = Random.NextFloat(qualityMin, qualityMax),
Blueprint = blueprint.ID
};
Cache.Add(newCommodity);
@ -615,4 +770,21 @@ public class GameContext
searched.Add(s);
}
}
public void SetParent(Entity child, Entity parent)
{
child.Parent = parent.ID;
parent.Children.Add(child.ID);
parent.RecalculateMass();
}
public void RemoveParent(Entity child)
{
if (child.Parent == Guid.Empty)
return;
var parent = Cache.Get<Entity>(child.Parent);
parent.Children.Remove(child.ID);
child.Parent = Guid.Empty;
}
}

View file

@ -133,6 +133,12 @@ public class GlobalData : DatabaseEntry
[InspectableField, JsonProperty("resourceDensityMaximum"), Key(41)]
public float ResourceDensityMaximum = 1.5f;
[InspectableField, JsonProperty("startingGearQualityMin"), Key(42)]
public float StartingGearQualityMin = .1f;
[InspectableField, JsonProperty("startingGearQualityMax"), Key(43)]
public float StartingGearQualityMax = .5f;
public float PlanetRadius(float mass)
{

View file

@ -54,9 +54,8 @@ public class ZoneGenerator
// Create orbit database entries
orbitData = planets.Select(planet =>
{
var data = new OrbitData()
var data = new OrbitData
{
ID = Guid.NewGuid(),
Distance = planet.Distance,
Period = planet.Period,
Phase = planet.Phase,
@ -95,7 +94,6 @@ public class ZoneGenerator
var planetData = new PlanetData
{
Mass = planet.Mass,
ID = Guid.NewGuid(),
Orbit = orbitMap[planet].ID,
Zone = zone.ID,
Belt = planet.Belt,