Entity Properties & Thermal Regulation

Entities such as colonies and ships can now be clicked on to reveal their properties or context menus
Orbital Colony loadout now has a new item (thermostatic heater) which itself has a new behavior type (Thermotoggle) allowing it to regulate its temperature for more agreeable living conditions
Fixed stat modifiers for hull stats (e.g. Hull Expansion)
Widened property label in DB inspector
This commit is contained in:
hyperion51 2020-05-26 01:12:06 +01:00
commit 698263ce63
15 changed files with 143 additions and 33 deletions

View file

@ -1273,6 +1273,7 @@
<e p="Shield.cs" t="Include" />
<e p="StatModifier.cs" t="Include" />
<e p="Switch.cs" t="Include" />
<e p="Thermotoggle.cs" t="Include" />
<e p="Thruster.cs" t="Include" />
<e p="TowingController.cs" t="Include" />
<e p="Trigger.cs" t="Include" />

View file

@ -29,7 +29,7 @@ Transform:
m_GameObject: {fileID: 7411673047664575939}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: -0.6599999, z: 0}
m_LocalScale: {x: 0.25000015, y: 0.25000015, z: 0}
m_LocalScale: {x: 0.25000015, y: 0.25000015, z: 0.25}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0

View file

@ -28,7 +28,7 @@ public class DatabaseInspector : EditorWindow
private static float2 _dragOffset;
private bool _ctrlDown;
private string[] _hardpointTypes;
private const int width = 100;
private const int width = 150;
private const int labelWidth = 20;
private Material _galaxyMat;
private Texture2D _white;
@ -985,7 +985,7 @@ public class DatabaseInspector : EditorWindow
}
// Only display heat, durability and quality effects if the stat actually varies
if (Math.Abs(value.Min - value.Max) > .01f)
if (Math.Abs(value.Min - value.Max) > .0001f)
{
using (new HorizontalScope())
{

View file

@ -87,6 +87,8 @@ public abstract class PersistentBehaviorData
Union(20, typeof(SwitchData)),
Union(21, typeof(TriggerData)),
Union(22, typeof(VisibilityData)),
Union(23, typeof(ThermotoggleData)),
Union(24, typeof(EnergyDrawData)),
JsonConverter(typeof(JsonKnownTypesConverter<BehaviorData>)), JsonObject(MemberSerialization.OptIn)]
public abstract class BehaviorData
{

View file

@ -22,6 +22,8 @@ public class Radiator : IBehavior
public GameContext Context { get; }
public BehaviorData Data => _data;
public float Emissivity;
private RadiatorData _data;
@ -35,7 +37,8 @@ public class Radiator : IBehavior
public bool Update(float delta)
{
var rad = pow(Entity.Temperature, Context.GlobalData.HeatRadiationPower) * Context.GlobalData.HeatRadiationMultiplier;
Emissivity = Context.Evaluate(_data.Emissivity, Item, Entity);
var rad = pow(Entity.Temperature, Context.GlobalData.HeatRadiationPower) * Context.GlobalData.HeatRadiationMultiplier * Emissivity;
Entity.Temperature -= rad * delta;
Entity.VisibilitySources[this] = rad;
return true;

View file

@ -34,6 +34,7 @@ public class Reactor : IBehavior
public GameContext Context { get; }
public BehaviorData Data => _data;
public float Capacitance;
public Reactor(GameContext context, ReactorData data, Entity entity, Gear item)
{
@ -45,17 +46,17 @@ public class Reactor : IBehavior
public bool Update(float delta)
{
var cap = Context.Evaluate(_data.Capacitance, Item, Entity);
Capacitance = Context.Evaluate(_data.Capacitance, Item, Entity);
var charge = Context.Evaluate(_data.Charge, Item, Entity) * delta;
var efficiency = Context.Evaluate(_data.Efficiency, Item, Entity);
Entity.AddHeat(charge / efficiency);
Entity.Energy += charge;
if (Entity.Energy > cap)
if (Entity.Energy > Capacitance)
{
Entity.AddHeat(-(Entity.Energy - cap) / efficiency * (1 - 1 / Context.Evaluate(_data.UnderloadRecovery, Item, Entity)));
Entity.Energy = cap;
Entity.AddHeat(-(Entity.Energy - Capacitance) / efficiency * (1 - 1 / Context.Evaluate(_data.UnderloadRecovery, Item, Entity)));
Entity.Energy = Capacitance;
}
if (Entity.Energy < 0)

View file

@ -54,14 +54,14 @@ public class StatModifier : IBehavior, IInitializableBehavior, IDisposableBehavi
if (statField != null)
{
if (typeof(EquippableItemData).IsAssignableFrom(targetType))
_stats = Entity.EquippedItems
_stats = Entity.EquippedItems.Append(Entity.Hull)
.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
_stats = Entity.EquippedItems.Append(Entity.Hull)
.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)

View file

@ -0,0 +1,43 @@
using System;
using System.Linq;
using MessagePack;
using Newtonsoft.Json;
[InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn), Order(-22)]
public class ThermotoggleData : BehaviorData
{
[TemperatureInspectable, JsonProperty("targetTemp"), Key(1)]
public float TargetTemperature;
[InspectableField, JsonProperty("perSecond"), Key(2)]
public bool HighPass;
public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item)
{
return new Thermotoggle(context, this, entity, item);
}
}
public class Thermotoggle : IBehavior
{
private ThermotoggleData _data;
private Entity Entity { get; }
private Gear Item { get; }
private GameContext Context { get; }
public BehaviorData Data => _data;
public Thermotoggle(GameContext context, ThermotoggleData data, Entity entity, Gear item)
{
_data = data;
Entity = entity;
Item = item;
Context = context;
}
public bool Update(float delta)
{
return Entity.Temperature < _data.TargetTemperature ^ _data.HighPass;
}
}

View file

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

View file

@ -42,6 +42,7 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
private Dictionary<Gear, List<IBehavior>> ItemBehaviors;
[IgnoreMember] public float Mass { get; private set; }
[IgnoreMember] public float OccupiedCapacity { get; private set; }
[IgnoreMember] public float SpecificHeat { get; private set; }
[IgnoreMember] public float Visibility => VisibilitySources.Values.Sum();
@ -128,6 +129,9 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
EquippedItems.Select(i => Context.Cache.Get<Gear>(i)).Sum(i => i.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);
OccupiedCapacity = EquippedItems.Select(i => Context.Cache.Get<Gear>(i)).Sum(i => i.ItemData.Size) +
Cargo.Select(i => Context.Cache.Get<ItemInstance>(i)).Sum(ii => Context.GetSize(ii));
}
public IEnumerable<T> GetBehaviors<T>() where T : class, IBehavior
@ -165,7 +169,14 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
public void AddHeat(float heat)
{
Temperature += heat / SpecificHeat;
if (Parent != Guid.Empty)
{
var parent = Context.Cache.Get<Entity>(Parent);
parent.AddHeat(heat);
}
else
Temperature += heat / SpecificHeat;
}
public virtual void Update(float delta)
@ -189,6 +200,7 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
var parent = Context.Cache.Get<Entity>(Parent);
Position = parent.Position;
Velocity = parent.Velocity;
Temperature = parent.Temperature;
}
// Processing stale item data properly was a pain in my ass, so the shortcut is just persisting and restoring everything

View file

@ -405,6 +405,20 @@ public class GameContext
return 0;
}
public float GetSize(ItemInstance item)
{
var data = GetData(item);
switch (item)
{
case CraftedItemInstance _:
return data.Size;
case SimpleCommodity commodity:
return data.Size * commodity.Quantity;
}
return 0;
}
public float GetHeatCapacity(ItemInstance item)
{
var data = GetData(item);
@ -659,7 +673,8 @@ public class GameContext
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}"
Name = $"{loadoutData.Name} {Random.NextInt(1,255):X}",
Temperature = 293
};
Cache.Add(entity);

View file

@ -232,7 +232,7 @@ public class StrategyGameManager : MonoBehaviour
foreach (var entry in zone.Contents) _cache.Add(entry);
if(_currentTab==GalaxyTabButton && _selectedZone == zone.Zone.ID)
PopulateZoneProperties(_selectedZone);
PopulatePropertiesPanel(_selectedZone);
if (_currentTab == ZoneTabButton && _populatedZone != zone.Zone.ID) PopulateZone();
});
@ -256,7 +256,7 @@ public class StrategyGameManager : MonoBehaviour
var zone = _cache.Get<ZoneData>(_selectedZone);
if (_populatedZone != _selectedZone && zone != null)
PopulateZone();
PopulateZoneProperties(_populatedZone);
PopulatePropertiesPanel(_populatedZone);
Camera.transform.position = -Vector3.forward;
if (zone != null)
Camera.orthographicSize = zone.Radius * ZoneSizeScale;
@ -280,10 +280,16 @@ public class StrategyGameManager : MonoBehaviour
_boundaryMaterial = ZoneBoundary.material;
_backgroundMaterial = ZoneBackground.material;
ClickRaycaster.OnClickMiss += () =>
ClickRaycaster.OnClickMiss += data =>
{
if (_currentTab == GalaxyTabButton) PopulateGalaxyProperties();
else if (_currentTab == ZoneTabButton) PopulateZoneProperties(_populatedZone);
else if (_currentTab == ZoneTabButton)
{
if (data.button == PointerEventData.InputButton.Left)
PopulatePropertiesPanel(_populatedZone);
else if (data.button == PointerEventData.InputButton.Right)
ShowContextMenu(_populatedZone);
}
else if (_currentTab == TechTabButton) PopulateTechProperties();
};
}
@ -296,15 +302,6 @@ public class StrategyGameManager : MonoBehaviour
PropertiesPanel.AddProperty("Sectors", () => $"{_context.GalaxyZones.Count}");
}
private void PopulateZoneProperties(Guid zone)
{
PropertiesPanel.Clear();
var zoneData = _cache.Get<ZoneData>(zone);
PropertiesPanel.Title.text = zoneData.Name;
PropertiesPanel.AddSection("Sector");
PropertiesPanel.AddProperty("Planets", () => $"{zoneData.Planets.Length}");
}
private void PopulateTechProperties()
{
PropertiesPanel.Clear();
@ -522,7 +519,8 @@ public class StrategyGameManager : MonoBehaviour
if(planet.Belt)
PropertiesPanel.AddSection("Asteroid Belt");
else
PropertiesPanel.AddSection(planet.Mass > _context.GlobalData.SunMass ? "Star" :
PropertiesPanel.AddSection(
planet.Mass > _context.GlobalData.SunMass ? "Star" :
planet.Mass > _context.GlobalData.GasGiantMass ? "Gas Giant" :
planet.Mass > _context.GlobalData.PlanetMass ? "Planet" :
"Planetoid");
@ -533,6 +531,31 @@ public class StrategyGameManager : MonoBehaviour
return new Tuple<string, string>(itemData.Name, $"{resource.Value:0}");
}));
}
if (targetObject is Entity entity)
{
PropertiesPanel.Clear();
PropertiesPanel.Title.text = entity.Name;
var hull = _context.Cache.Get<Gear>(entity.Hull);
var hullData = _context.Cache.Get<HullData>(hull.Data);
PropertiesPanel.AddSection(
hullData.HullType == HullType.Ship ? "Drone Ship" :
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("Mass", () => $"{entity.Mass}");
PropertiesPanel.AddProperty("Temperature", () => $"{entity.Temperature:0}°K");
PropertiesPanel.AddProperty("Energy", () => $"{entity.Energy:0}/{entity.GetBehaviors<Reactor>().First().Capacitance:0}");
}
if (targetObject is ZoneData zone)
{
PropertiesPanel.Clear();
PropertiesPanel.Title.text = zone.Name;
PropertiesPanel.AddSection("Sector");
PropertiesPanel.AddProperty("Planets", () => $"{zone.Planets.Length}");
}
}
void PopulateGalaxy()
@ -576,11 +599,7 @@ public class StrategyGameManager : MonoBehaviour
CultClient.Send(new ZoneRequestMessage{ZoneID = zone.ZoneID});
if (TestMode)
{
// if(!_context.Cache.Get<ZoneData>(zone.ZoneID).Visited)
// {
// GenerateZone(zone.ZoneID);
// }
PopulateZoneProperties(zone.ZoneID);
PopulatePropertiesPanel(zone.ZoneID);
}
_selectedZone = zone.ZoneID;
_selectedGalaxyZone = instanceZone;

View file

@ -2,10 +2,11 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class ClickRaycaster : MonoBehaviour
{
public event Action OnClickMiss;
public event Action<PointerEventData> OnClickMiss;
public Camera RayCamera;
private ClickCatcher _clickCatcher;
@ -22,7 +23,7 @@ public class ClickRaycaster : MonoBehaviour
if (clickable != null)
clickable.Click(pointer);
}
else OnClickMiss?.Invoke();
else OnClickMiss?.Invoke(pointer);
};
}
}

View file

@ -25,6 +25,7 @@ public class ReadOnlyPropertiesPanel : MonoBehaviour
{
var property = Instantiate(PropertyPrefab, transform);
property.Name.text = name;
property.Value.text = value();
property.ValueFunction = value;
_properties.Add(property.gameObject);
}

View file

@ -90,6 +90,7 @@
<Compile Include="Assets\Scripts\ServerShared\Behaviors\Shield.cs" />
<Compile Include="Assets\Scripts\ServerShared\Behaviors\StatModifier.cs" />
<Compile Include="Assets\Scripts\ServerShared\Behaviors\Switch.cs" />
<Compile Include="Assets\Scripts\ServerShared\Behaviors\Thermotoggle.cs" />
<Compile Include="Assets\Scripts\ServerShared\Behaviors\Thruster.cs" />
<Compile Include="Assets\Scripts\ServerShared\Behaviors\TowingController.cs" />
<Compile Include="Assets\Scripts\ServerShared\Behaviors\Trigger.cs" />