Infrastructure and Production
Added the ability to directly install blueprints onto hardpoints in the colony tab Added the ability to customize production of factories This stuff is still kinda buggy
This commit is contained in:
parent
a99b4e82f3
commit
4eb83acb34
32 changed files with 2525 additions and 399 deletions
|
|
@ -24,21 +24,43 @@ public class FactoryData : BehaviorData
|
|||
|
||||
public class Factory : IBehavior, IPersistentBehavior
|
||||
{
|
||||
public float ProductionQuality;
|
||||
public double RetoolingTime;
|
||||
public string ItemName;
|
||||
public List<Guid> ItemsUnderConstruction = new List<Guid>();
|
||||
|
||||
public Entity Entity { get; }
|
||||
public Gear Item { get; }
|
||||
public GameContext Context { get; }
|
||||
|
||||
public BehaviorData Data => _data;
|
||||
|
||||
public float ToolingTime { get; private set; }
|
||||
|
||||
public Guid Blueprint
|
||||
{
|
||||
get => _blueprint;
|
||||
set
|
||||
{
|
||||
if (value != _blueprint)
|
||||
{
|
||||
_blueprint = value;
|
||||
RetoolingTime = ToolingTime;
|
||||
_retooling = true;
|
||||
OnToolingUpdate?.Invoke();
|
||||
OnToolingUpdate = null;
|
||||
ItemName = Context.Cache.Get<BlueprintData>(value).Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event Action OnToolingUpdate;
|
||||
|
||||
private FactoryData _data;
|
||||
|
||||
private Guid _blueprint;
|
||||
private float _remainingManHours;
|
||||
private bool _retooling;
|
||||
private bool _producing;
|
||||
private List<ItemInstance> _reservedStock = new List<ItemInstance>();
|
||||
private int _assignedPopulation;
|
||||
private float _productionQuality;
|
||||
private bool _retooling = false;
|
||||
|
||||
public Factory(GameContext context, FactoryData data, Entity entity, Gear item)
|
||||
{
|
||||
|
|
@ -50,148 +72,56 @@ public class Factory : IBehavior, IPersistentBehavior
|
|||
|
||||
public bool Update(float delta)
|
||||
{
|
||||
ToolingTime = Context.Evaluate(_data.ToolingTime, Item, Entity);
|
||||
var blueprint = Context.Cache.Get<BlueprintData>(_blueprint);
|
||||
if (_retooling || _producing)
|
||||
if (blueprint == null)
|
||||
return false;
|
||||
|
||||
if (RetoolingTime > 0)
|
||||
{
|
||||
_remainingManHours -= delta / 3600 * (_assignedPopulation + _data.AutomationPoints) /
|
||||
pow(lerp(blueprint.QualityFloor, 1, saturate(_productionQuality)),
|
||||
blueprint.ProductionExponent);
|
||||
RetoolingTime -= delta;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_remainingManHours < 0)
|
||||
if (_retooling)
|
||||
{
|
||||
if (_retooling)
|
||||
_retooling = false;
|
||||
else if (_producing)
|
||||
_retooling = false;
|
||||
OnToolingUpdate?.Invoke();
|
||||
OnToolingUpdate = null;
|
||||
}
|
||||
|
||||
if (ItemsUnderConstruction.Any())
|
||||
{
|
||||
var finishedConstruction = false;
|
||||
foreach (var item in ItemsUnderConstruction.ToArray())
|
||||
{
|
||||
var blueprintItemData = Context.Cache.Get(blueprint.Item);
|
||||
|
||||
if (blueprintItemData is CraftedItemData)
|
||||
Entity.IncompleteCargo[item] =
|
||||
Entity.IncompleteCargo[item] - delta * (_assignedPopulation + _data.AutomationPoints) /
|
||||
pow(lerp(blueprint.QualityFloor, 1, saturate(ProductionQuality)),
|
||||
blueprint.ProductionExponent);
|
||||
if(Entity.IncompleteCargo[item] < 0)
|
||||
{
|
||||
for (int i = 0; i < blueprint.Quantity; i++)
|
||||
{
|
||||
CraftedItemInstance newItem;
|
||||
|
||||
// Applying exponents to two random numbers and adding them produces a range of interesting probability distributions
|
||||
var quality = blueprint.Quality *
|
||||
pow(_productionQuality, blueprint.QualityExponent) *
|
||||
(pow(Context.Random.NextFloat(), blueprint.RandomExponent) +
|
||||
pow(Context.Random.NextFloat(), blueprint.RandomExponent)) / 2;
|
||||
|
||||
if (blueprintItemData is EquippableItemData equippableItemData)
|
||||
{
|
||||
var newGear = new Gear
|
||||
{
|
||||
Context = Context,
|
||||
Data = blueprintItemData.ID,
|
||||
Ingredients = _reservedStock.Select(ii=>ii.ID).ToList(),
|
||||
Quality = quality,
|
||||
Blueprint = _blueprint
|
||||
};
|
||||
newGear.Durability = Context.Evaluate(equippableItemData.Durability, newGear);
|
||||
newItem = newGear;
|
||||
}
|
||||
else
|
||||
{
|
||||
newItem = new CompoundCommodity
|
||||
{
|
||||
Context = Context,
|
||||
Data = blueprintItemData.ID,
|
||||
Ingredients = _reservedStock.Select(ii=>ii.ID).ToList(),
|
||||
Quality = quality,
|
||||
Blueprint = _blueprint
|
||||
};
|
||||
}
|
||||
Context.Cache.Add(newItem);
|
||||
Entity.Cargo.Add(newItem.ID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var simpleCommodityData = blueprintItemData as SimpleCommodityData;
|
||||
var simpleCommodityInstance = Entity.Cargo.FirstOrDefault(i => Context.Cache.Get<ItemInstance>(i).Data == simpleCommodityData.ID);
|
||||
if (simpleCommodityInstance == Guid.Empty)
|
||||
{
|
||||
var newSimpleCommodity = new SimpleCommodity
|
||||
{
|
||||
Context = Context,
|
||||
Data = simpleCommodityData.ID,
|
||||
Quantity = blueprint.Quantity
|
||||
};
|
||||
Context.Cache.Add(newSimpleCommodity);
|
||||
Entity.Cargo.Add(newSimpleCommodity.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.Cache.Get<SimpleCommodity>(simpleCommodityInstance).Quantity += blueprint.Quantity;
|
||||
}
|
||||
}
|
||||
Entity.RecalculateMass();
|
||||
|
||||
var simpleIngredients = new List<SimpleCommodity>();
|
||||
var compoundIngredients = new List<CompoundCommodity>();
|
||||
var hasAllIngredients = true;
|
||||
var cargoInstances = Entity.Cargo.Select(c => Context.Cache.Get<ItemInstance>(c));
|
||||
foreach (var kvp in blueprint.Ingredients)
|
||||
{
|
||||
var itemData = Context.Cache.Get(kvp.Key);
|
||||
if (itemData is SimpleCommodityData)
|
||||
{
|
||||
var matchingItem = cargoInstances.FirstOrDefault(ii =>
|
||||
{
|
||||
if (!(ii is SimpleCommodity simpleCommodity)) return false;
|
||||
return simpleCommodity.Data == itemData.ID && simpleCommodity.Quantity >= kvp.Value;
|
||||
}) as SimpleCommodity;
|
||||
hasAllIngredients = hasAllIngredients && matchingItem != null;
|
||||
if(matchingItem != null)
|
||||
simpleIngredients.Add(matchingItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
var matchingItems =
|
||||
cargoInstances.Where(ii => (ii as CompoundCommodity)?.Data == itemData.ID).Cast<CompoundCommodity>().ToArray();
|
||||
hasAllIngredients = hasAllIngredients && matchingItems.Length >= kvp.Value;
|
||||
if(matchingItems.Length >= kvp.Value)
|
||||
compoundIngredients.AddRange(matchingItems.Take(kvp.Value));
|
||||
}
|
||||
}
|
||||
|
||||
if (hasAllIngredients)
|
||||
{
|
||||
_reservedStock.AddRange(compoundIngredients);
|
||||
foreach (var compoundCommodity in compoundIngredients)
|
||||
{
|
||||
Entity.Cargo.Remove(compoundCommodity.ID);
|
||||
}
|
||||
foreach (var simpleCommodity in simpleIngredients)
|
||||
{
|
||||
var blueprintQuantity = blueprint.Ingredients
|
||||
.First(ingredient => ingredient.Key == simpleCommodity.ID).Value;
|
||||
if (simpleCommodity.Quantity == blueprintQuantity)
|
||||
{
|
||||
_reservedStock.Add(simpleCommodity);
|
||||
Entity.Cargo.Remove(simpleCommodity.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newSimpleCommodity = new SimpleCommodity
|
||||
{
|
||||
Context = Context,
|
||||
Data = simpleCommodity.Data,
|
||||
Quantity = blueprintQuantity
|
||||
};
|
||||
simpleCommodity.Quantity -= blueprintQuantity;
|
||||
_reservedStock.Add(newSimpleCommodity);
|
||||
}
|
||||
}
|
||||
Entity.RecalculateMass();
|
||||
_remainingManHours = blueprint.ProductionTime;
|
||||
_producing = true;
|
||||
Entity.Cargo.Add(item);
|
||||
Entity.IncompleteCargo.Remove(item);
|
||||
ItemsUnderConstruction.Remove(item);
|
||||
finishedConstruction = true;
|
||||
}
|
||||
}
|
||||
if(finishedConstruction)
|
||||
Entity.RecalculateMass();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Applying exponents to two random numbers and adding them produces a range of interesting probability distributions for quality
|
||||
ItemsUnderConstruction = Entity.Build(blueprint, blueprint.Quality *
|
||||
pow(ProductionQuality, blueprint.QualityExponent) *
|
||||
(pow(Context.Random.NextFloat(), blueprint.RandomExponent) +
|
||||
pow(Context.Random.NextFloat(), blueprint.RandomExponent)) / 2, ItemName);
|
||||
if(ItemsUnderConstruction.Any())
|
||||
Entity.RecalculateMass(); // TODO: FIX THIS UGLY HACK, needed to update UI
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public PersistentBehaviorData Store()
|
||||
|
|
@ -199,12 +129,9 @@ public class Factory : IBehavior, IPersistentBehavior
|
|||
return new FactoryPersistence
|
||||
{
|
||||
Blueprint = _blueprint,
|
||||
RemainingManHours = _remainingManHours,
|
||||
Retooling = _retooling,
|
||||
Producing = _producing,
|
||||
ReservedStock = _reservedStock.Select(i=>i.ID).ToArray(),
|
||||
RetoolingTime = RetoolingTime,
|
||||
AssignedPopulation = _assignedPopulation,
|
||||
ProductionQuality = _productionQuality
|
||||
ProductionQuality = ProductionQuality
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -212,12 +139,9 @@ public class Factory : IBehavior, IPersistentBehavior
|
|||
{
|
||||
var factoryPersistence = data as FactoryPersistence;
|
||||
_blueprint = factoryPersistence.Blueprint;
|
||||
_remainingManHours = factoryPersistence.RemainingManHours;
|
||||
_retooling = factoryPersistence.Retooling;
|
||||
_producing = factoryPersistence.Producing;
|
||||
_reservedStock = factoryPersistence.ReservedStock.Select(id => Context.Cache.Get<ItemInstance>(id)).ToList();
|
||||
RetoolingTime = factoryPersistence.RetoolingTime;
|
||||
_assignedPopulation = factoryPersistence.AssignedPopulation;
|
||||
_productionQuality = factoryPersistence.ProductionQuality;
|
||||
ProductionQuality = factoryPersistence.ProductionQuality;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -225,10 +149,7 @@ public class Factory : IBehavior, IPersistentBehavior
|
|||
public class FactoryPersistence : PersistentBehaviorData
|
||||
{
|
||||
[JsonProperty("blueprint"), Key(0)] public Guid Blueprint;
|
||||
[JsonProperty("remainingManHours"), Key(1)] public float RemainingManHours;
|
||||
[JsonProperty("retooling"), Key(2)] public bool Retooling;
|
||||
[JsonProperty("producing"), Key(3)] public bool Producing;
|
||||
[JsonProperty("reservedStock"), Key(4)] public Guid[] ReservedStock;
|
||||
[JsonProperty("retoolingTime"), Key(2)] public double RetoolingTime;
|
||||
[JsonProperty("assignedPopulation"), Key(5)] public int AssignedPopulation;
|
||||
[JsonProperty("productionQuality"), Key(6)] public float ProductionQuality;
|
||||
}
|
||||
66
Assets/Scripts/ServerShared/Corporations.cs
Normal file
66
Assets/Scripts/ServerShared/Corporations.cs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
[RethinkTable("Galaxy"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class Corporation : DatabaseEntry, INamedEntry
|
||||
{
|
||||
[JsonProperty("name"), Key(1)]
|
||||
public string Name;
|
||||
|
||||
[JsonProperty("parent"), Key(2)]
|
||||
public Guid Parent;
|
||||
|
||||
[JsonProperty("tasks"), Key(3)]
|
||||
public List<Guid> Tasks = new List<Guid>();
|
||||
|
||||
[JsonProperty("planetSurveyFloor"), Key(4)]
|
||||
public Dictionary<Guid, float> PlanetSurveyFloor = new Dictionary<Guid, float>();
|
||||
|
||||
[JsonProperty("unlockedBlueprints"), Key(5)]
|
||||
public List<Guid> UnlockedBlueprints = new List<Guid>();
|
||||
|
||||
[IgnoreMember] public string EntryName
|
||||
{
|
||||
get => Name;
|
||||
set => Name = value;
|
||||
}
|
||||
}
|
||||
|
||||
[RethinkTable("Galaxy"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class MegaCorporation : DatabaseEntry, INamedEntry
|
||||
{
|
||||
[InspectableField, JsonProperty("name"), Key(1)]
|
||||
public string Name;
|
||||
|
||||
[InspectableText, JsonProperty("description"), Key(2)]
|
||||
public string Description;
|
||||
|
||||
[InspectableTexture, JsonProperty("logo"), Key(3)]
|
||||
public string Logo;
|
||||
|
||||
[InspectableDatabaseLink(typeof(PersonalityAttribute)), JsonProperty("personality"), Key(4)]
|
||||
public Dictionary<Guid, float> Personality = new Dictionary<Guid, float>();
|
||||
|
||||
[InspectableDatabaseLink(typeof(LoadoutData)), JsonProperty("initialFleet"), Key(5)]
|
||||
public Dictionary<Guid, int> InitialFleet = new Dictionary<Guid, int>();
|
||||
|
||||
[InspectableDatabaseLink(typeof(BlueprintData)), JsonProperty("initialTechs"), Key(6)]
|
||||
public List<Guid> InitialTechnologies = new List<Guid>();
|
||||
|
||||
[JsonProperty("parent"), Key(7)]
|
||||
public Guid HomeZone;
|
||||
|
||||
[InspectableField, JsonProperty("placement"), Key(8)]
|
||||
public MegaPlacementType PlacementType;
|
||||
|
||||
[IgnoreMember] public string EntryName
|
||||
{
|
||||
get => Name;
|
||||
set => Name = value;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/ServerShared/Corporations.cs.meta
Normal file
11
Assets/Scripts/ServerShared/Corporations.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ce66dd66434e39f44bd4d4b9639aaeca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -74,62 +74,6 @@ public class Player : DatabaseEntry, INamedEntry
|
|||
}
|
||||
}
|
||||
|
||||
[RethinkTable("Galaxy"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class Corporation : DatabaseEntry, INamedEntry
|
||||
{
|
||||
[JsonProperty("name"), Key(1)]
|
||||
public string Name;
|
||||
|
||||
[JsonProperty("parent"), Key(2)]
|
||||
public Guid Parent;
|
||||
|
||||
[JsonProperty("tasks"), Key(3)]
|
||||
public List<Guid> Tasks = new List<Guid>();
|
||||
|
||||
[JsonProperty("planetSurveyFloor"), Key(4)]
|
||||
public Dictionary<Guid, float> PlanetSurveyFloor = new Dictionary<Guid, float>();
|
||||
|
||||
[IgnoreMember] public string EntryName
|
||||
{
|
||||
get => Name;
|
||||
set => Name = value;
|
||||
}
|
||||
}
|
||||
|
||||
[RethinkTable("Galaxy"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class MegaCorporation : DatabaseEntry, INamedEntry
|
||||
{
|
||||
[InspectableField, JsonProperty("name"), Key(1)]
|
||||
public string Name;
|
||||
|
||||
[InspectableText, JsonProperty("description"), Key(2)]
|
||||
public string Description;
|
||||
|
||||
[InspectableTexture, JsonProperty("logo"), Key(3)]
|
||||
public string Logo;
|
||||
|
||||
[InspectableDatabaseLink(typeof(PersonalityAttribute)), JsonProperty("personality"), Key(4)]
|
||||
public Dictionary<Guid, float> Personality = new Dictionary<Guid, float>();
|
||||
|
||||
[InspectableDatabaseLink(typeof(LoadoutData)), JsonProperty("initialFleet"), Key(5)]
|
||||
public Dictionary<Guid, int> InitialFleet = new Dictionary<Guid, int>();
|
||||
|
||||
[InspectableDatabaseLink(typeof(BlueprintData)), JsonProperty("initialTechs"), Key(6)]
|
||||
public List<Guid> InitialTechnologies = new List<Guid>();
|
||||
|
||||
[JsonProperty("parent"), Key(7)]
|
||||
public Guid HomeZone;
|
||||
|
||||
[InspectableField, JsonProperty("placement"), Key(8)]
|
||||
public MegaPlacementType PlacementType;
|
||||
|
||||
[IgnoreMember] public string EntryName
|
||||
{
|
||||
get => Name;
|
||||
set => Name = value;
|
||||
}
|
||||
}
|
||||
|
||||
[RethinkTable("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class LoadoutData : DatabaseEntry, INamedEntry
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,6 +60,14 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
|
|||
[JsonProperty("personality"), Key(15)]
|
||||
public Dictionary<Guid, float> Personality = new Dictionary<Guid, float>();
|
||||
|
||||
[JsonProperty("incompleteGear"), Key(16)]
|
||||
public Dictionary<Guid, double> IncompleteGear = new Dictionary<Guid, double>();
|
||||
//public List<IncompleteItem> IncompleteGear = new List<IncompleteItem>();
|
||||
|
||||
[JsonProperty("incompleteGear"), Key(17)]
|
||||
public Dictionary<Guid, double> IncompleteCargo = new Dictionary<Guid, double>();
|
||||
//public List<IncompleteItem> IncompleteCargo = new List<IncompleteItem>();
|
||||
|
||||
// [IgnoreMember] protected List<IBehavior> Behaviors;
|
||||
[IgnoreMember] public Guid Zone;
|
||||
[IgnoreMember] public Dictionary<int, List<IBehavior>> Behaviors;
|
||||
|
|
@ -69,14 +77,16 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
|
|||
[IgnoreMember] public Dictionary<int, float> AxisOverrides = new Dictionary<int, float>();
|
||||
[IgnoreMember] public readonly Dictionary<object, float> VisibilitySources = new Dictionary<object, float>();
|
||||
[IgnoreMember] public readonly Dictionary<string, float> Messages = new Dictionary<string, float>();
|
||||
|
||||
private Dictionary<Gear, EquippableItemData> GearData;
|
||||
private Dictionary<Gear, List<IBehavior>> ItemBehaviors;
|
||||
[IgnoreMember] public Dictionary<Gear, EquippableItemData> GearData;
|
||||
[IgnoreMember] public 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();
|
||||
|
||||
public event Action OnInventoryUpdate;
|
||||
|
||||
public float Capacity
|
||||
{
|
||||
get
|
||||
|
|
@ -111,16 +121,16 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
|
|||
|
||||
public void AddItemBehaviors()
|
||||
{
|
||||
var gear = EquippedItems.Append(Hull);
|
||||
var gearData = gear.ToDictionary(id => id, id => Context.Cache.Get<Gear>(id));
|
||||
GearData = gearData.Values.ToDictionary(g => g, g => g.ItemData);
|
||||
var gearIDs = EquippedItems.Append(Hull);
|
||||
var gear = gearIDs.ToDictionary(id => id, id => Context.Cache.Get<Gear>(id));
|
||||
GearData = gear.Values.ToDictionary(g => g, g => g.ItemData);
|
||||
|
||||
// Associate items with behavior list, used only for persistence
|
||||
ItemBehaviors = gear
|
||||
.Where(i=> gearData[i].ItemData.Behaviors?.Any()??false)
|
||||
.ToDictionary(i=> gearData[i], i => gearData[i].ItemData.Behaviors
|
||||
// Associate items with behavior list, used for persistence and convenience
|
||||
ItemBehaviors = gearIDs
|
||||
.Where(i=> gear[i].ItemData.Behaviors?.Any()??false)
|
||||
.ToDictionary(i=> gear[i], i => gear[i].ItemData.Behaviors
|
||||
.OrderBy(bd => bd.GetType().GetCustomAttribute<OrderAttribute>()?.Order ?? 0)
|
||||
.Select(bd => bd.CreateInstance(Context, this, gearData[i]))
|
||||
.Select(bd => bd.CreateInstance(Context, this, gear[i]))
|
||||
.ToList());
|
||||
|
||||
var behaviorGroups = ItemBehaviors
|
||||
|
|
@ -160,20 +170,207 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
|
|||
.Cast<IInitializableBehavior>()) behavior.Initialize();
|
||||
}
|
||||
|
||||
public void Equip(Gear gear)
|
||||
{
|
||||
if (Cargo.Contains(gear.ID)) Cargo.Remove(gear.ID);
|
||||
else if (IncompleteGear.Any(ig => ig.Key == gear.ID))
|
||||
IncompleteGear.Remove(IncompleteGear.First(ig => ig.Key == gear.ID).Key);
|
||||
else
|
||||
throw new ArgumentException("Attempted to equip gear which is not present in inventory!");
|
||||
|
||||
EquippedItems.Add(gear.ID);
|
||||
OnBeforeSerialize();
|
||||
OnAfterDeserialize();
|
||||
}
|
||||
|
||||
// public Guid Build(BlueprintData blueprint)
|
||||
// {
|
||||
// var gear = Context.CreateInstance(blueprint.Item, blueprint.Quality * .5f, blueprint.Quality);
|
||||
// IncompleteGear[gear.ID] = blueprint.ProductionTime;
|
||||
// RecalculateMass();
|
||||
// return gear.ID;
|
||||
// // IncompleteGear.Add(new IncompleteItem
|
||||
// // {
|
||||
// // Item = gear.ID,
|
||||
// // Blueprint = blueprint.ID,
|
||||
// // RemainingTime = blueprint.ProductionTime
|
||||
// // });
|
||||
// }
|
||||
|
||||
public List<Guid> Build(BlueprintData blueprint, float quality, string name, bool equip = false)
|
||||
{
|
||||
if (equip)
|
||||
{
|
||||
if(blueprint.FactoryItem!=Guid.Empty)
|
||||
throw new ArgumentException("Attempted to directly build a blueprint which requires a factory!");
|
||||
var blueprintItem = Context.Cache.Get<GearData>(blueprint.Item);
|
||||
if(blueprintItem == null)
|
||||
throw new ArgumentException("Attempted to directly build a blueprint for a missing or incompatible item!");
|
||||
}
|
||||
|
||||
var newItems = new List<Guid>();
|
||||
if (GetBlueprintIngredients(blueprint, out var simpleIngredients, out var compoundIngredients))
|
||||
{
|
||||
var ingredients = new List<ItemInstance>();
|
||||
ingredients.AddRange(compoundIngredients);
|
||||
foreach (var compoundCommodity in compoundIngredients)
|
||||
{
|
||||
Cargo.Remove(compoundCommodity.ID);
|
||||
}
|
||||
foreach (var simpleCommodity in simpleIngredients)
|
||||
{
|
||||
var blueprintQuantity = blueprint.Ingredients
|
||||
.First(ingredient => ingredient.Key == simpleCommodity.ItemData.ID).Value;
|
||||
if (simpleCommodity.Quantity == blueprintQuantity)
|
||||
{
|
||||
ingredients.Add(simpleCommodity);
|
||||
Cargo.Remove(simpleCommodity.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
var newSimpleCommodity = new SimpleCommodity
|
||||
{
|
||||
Context = Context,
|
||||
Data = simpleCommodity.Data,
|
||||
Quantity = blueprintQuantity
|
||||
};
|
||||
simpleCommodity.Quantity -= blueprintQuantity;
|
||||
ingredients.Add(newSimpleCommodity);
|
||||
}
|
||||
}
|
||||
|
||||
var blueprintItemData = Context.Cache.Get(blueprint.Item);
|
||||
|
||||
if (blueprintItemData is CraftedItemData)
|
||||
{
|
||||
for (int i = 0; i < blueprint.Quantity; i++)
|
||||
{
|
||||
CraftedItemInstance newItem;
|
||||
|
||||
if (blueprintItemData is EquippableItemData equippableItemData)
|
||||
{
|
||||
var newGear = new Gear
|
||||
{
|
||||
Context = Context,
|
||||
Data = blueprintItemData.ID,
|
||||
Ingredients = ingredients.Select(ii=>ii.ID).ToList(),
|
||||
Quality = quality,
|
||||
Blueprint = blueprint.ID,
|
||||
Name = name
|
||||
};
|
||||
newGear.Durability = Context.Evaluate(equippableItemData.Durability, newGear);
|
||||
newItem = newGear;
|
||||
}
|
||||
else
|
||||
{
|
||||
newItem = new CompoundCommodity
|
||||
{
|
||||
Context = Context,
|
||||
Data = blueprintItemData.ID,
|
||||
Ingredients = ingredients.Select(ii=>ii.ID).ToList(),
|
||||
Quality = quality,
|
||||
Blueprint = blueprint.ID,
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
Context.Cache.Add(newItem);
|
||||
if (equip)
|
||||
IncompleteGear[newItem.ID] = blueprint.ProductionTime;
|
||||
else
|
||||
IncompleteCargo[newItem.ID] = blueprint.ProductionTime;
|
||||
newItems.Add(newItem.ID);
|
||||
// IncompleteCargo.Add(new IncompleteItem
|
||||
// {
|
||||
// Item = newItem.ID,
|
||||
// Blueprint = blueprint.ID,
|
||||
// RemainingTime = blueprint.ProductionTime
|
||||
// });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var newSimpleCommodity = new SimpleCommodity
|
||||
{
|
||||
Context = Context,
|
||||
Data = blueprintItemData.ID,
|
||||
Quantity = blueprint.Quantity
|
||||
};
|
||||
Context.Cache.Add(newSimpleCommodity);
|
||||
IncompleteCargo[newSimpleCommodity.ID] = blueprint.ProductionTime;
|
||||
newItems.Add(newSimpleCommodity.ID);
|
||||
// IncompleteCargo.Add(new IncompleteItem
|
||||
// {
|
||||
// Item = newSimpleCommodity.ID,
|
||||
// Blueprint = blueprint.ID,
|
||||
// RemainingTime = blueprint.ProductionTime
|
||||
// });
|
||||
}
|
||||
|
||||
RecalculateMass();
|
||||
}
|
||||
|
||||
return newItems;
|
||||
}
|
||||
|
||||
public bool GetBlueprintIngredients(BlueprintData blueprint, out List<SimpleCommodity> simpleIngredients,
|
||||
out List<CompoundCommodity> compoundIngredients)
|
||||
{
|
||||
simpleIngredients = new List<SimpleCommodity>();
|
||||
compoundIngredients = new List<CompoundCommodity>();
|
||||
var hasAllIngredients = true;
|
||||
var cargoInstances = Cargo.Select(c => Context.Cache.Get<ItemInstance>(c));
|
||||
foreach (var kvp in blueprint.Ingredients)
|
||||
{
|
||||
var itemData = Context.Cache.Get(kvp.Key);
|
||||
if (itemData is SimpleCommodityData)
|
||||
{
|
||||
var matchingItem = cargoInstances.FirstOrDefault(ii =>
|
||||
{
|
||||
if (!(ii is SimpleCommodity simpleCommodity)) return false;
|
||||
return simpleCommodity.Data == itemData.ID && simpleCommodity.Quantity >= kvp.Value;
|
||||
}) as SimpleCommodity;
|
||||
hasAllIngredients = hasAllIngredients && matchingItem != null;
|
||||
if(matchingItem != null)
|
||||
simpleIngredients.Add(matchingItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
var matchingItems =
|
||||
cargoInstances.Where(ii => (ii as CompoundCommodity)?.Data == itemData.ID).Cast<CompoundCommodity>().ToArray();
|
||||
hasAllIngredients = hasAllIngredients && matchingItems.Length >= kvp.Value;
|
||||
if(matchingItems.Length >= kvp.Value)
|
||||
compoundIngredients.AddRange(matchingItems.Take(kvp.Value));
|
||||
}
|
||||
}
|
||||
|
||||
return hasAllIngredients;
|
||||
}
|
||||
|
||||
public void RecalculateMass()
|
||||
{
|
||||
Mass = Context.Cache.Get<Gear>(Hull).Mass +
|
||||
EquippedItems.Select(i => Context.Cache.Get<Gear>(i)).Sum(i => i.Mass) +
|
||||
IncompleteGear.Select(i => Context.Cache.Get<Gear>(i.Key)).Sum(i => i.Mass) +
|
||||
Cargo.Select(i => Context.Cache.Get<ItemInstance>(i)).Sum(ii => ii.Mass) +
|
||||
IncompleteCargo.Select(i => Context.Cache.Get<ItemInstance>(i.Key)).Sum(ii => ii.Mass) +
|
||||
Children.Select(i => Context.Cache.Get<Entity>(i)).Sum(c=>c.Mass);
|
||||
|
||||
SpecificHeat = Context.Cache.Get<Gear>(Hull).HeatCapacity +
|
||||
EquippedItems.Select(i => Context.Cache.Get<Gear>(i)).Sum(i => i.HeatCapacity) +
|
||||
IncompleteGear.Select(i => Context.Cache.Get<Gear>(i.Key)).Sum(i => i.HeatCapacity) +
|
||||
Cargo.Select(i => Context.Cache.Get<ItemInstance>(i)).Sum(ii => ii.HeatCapacity) +
|
||||
IncompleteCargo.Select(i => Context.Cache.Get<ItemInstance>(i.Key)).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));
|
||||
|
||||
OnInventoryUpdate?.Invoke();
|
||||
}
|
||||
|
||||
public void ClearInventoryListeners()
|
||||
{
|
||||
OnInventoryUpdate = null;
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetBehaviors<T>() where T : class, IBehavior
|
||||
|
|
@ -278,6 +475,15 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
|
|||
Messages.Remove(message);
|
||||
}
|
||||
|
||||
foreach (var incompleteGear in IncompleteGear.Keys.ToArray())
|
||||
{
|
||||
IncompleteGear[incompleteGear] = IncompleteGear[incompleteGear] - delta;
|
||||
if (IncompleteGear[incompleteGear] < 0)
|
||||
{
|
||||
Equip(Context.Cache.Get<Gear>(incompleteGear));
|
||||
}
|
||||
}
|
||||
|
||||
// Here's the PITA way
|
||||
// foreach (var staleItem in GearData
|
||||
// .Where(kvp=>kvp.Key.ItemData!=kvp.Value)
|
||||
|
|
@ -352,9 +558,9 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR
|
|||
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
RecalculateMass();
|
||||
|
||||
AddItemBehaviors();
|
||||
|
||||
RecalculateMass();
|
||||
|
||||
// Iterate only over the behaviors of items which contain persistent data
|
||||
// Filter the behaviors for each item to get the persistent ones, then cast them and combine with the persisted data array for that item
|
||||
|
|
@ -372,4 +578,12 @@ public class AxisSetting
|
|||
{
|
||||
public float Value;
|
||||
public List<IAnalogBehavior> Behaviors;
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public class IncompleteItem
|
||||
{
|
||||
[Key(0)] public Guid Item;
|
||||
[Key(1)] public Guid Blueprint;
|
||||
[Key(2)] public double RemainingTime;
|
||||
}
|
||||
|
|
@ -699,9 +699,6 @@ public class GameContext
|
|||
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)
|
||||
|
|
@ -764,11 +761,16 @@ public class GameContext
|
|||
{
|
||||
var item = Cache.Get<SimpleCommodityData>(data);
|
||||
if (item != null)
|
||||
return new SimpleCommodity
|
||||
{
|
||||
var newItem = new SimpleCommodity
|
||||
{
|
||||
Context = this,
|
||||
Data = data,
|
||||
Quantity = count
|
||||
};
|
||||
Cache.Add(newItem);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
_logger("Attempted to create Simple Commodity instance using missing or incorrect item id");
|
||||
return null;
|
||||
|
|
@ -809,7 +811,8 @@ public class GameContext
|
|||
Data = data,
|
||||
Ingredients = ingredients.Select(i=>i.ID).ToList(),
|
||||
Quality = Random.NextFloat(qualityMin, qualityMax),
|
||||
Blueprint = blueprint.ID
|
||||
Blueprint = blueprint.ID,
|
||||
Name = $"Generic {item.Name}"
|
||||
};
|
||||
newGear.Durability = Evaluate(equippableItemData.Durability, newGear);
|
||||
Cache.Add(newGear);
|
||||
|
|
@ -822,7 +825,8 @@ public class GameContext
|
|||
Data = data,
|
||||
Ingredients = ingredients.Select(i=>i.ID).ToList(),
|
||||
Quality = Random.NextFloat(qualityMin, qualityMax),
|
||||
Blueprint = blueprint.ID
|
||||
Blueprint = blueprint.ID,
|
||||
Name = $"Generic {item.Name}"
|
||||
};
|
||||
Cache.Add(newCommodity);
|
||||
return newCommodity;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ public abstract class CraftedItemInstance : ItemInstance
|
|||
[JsonProperty("ingredients"), Key(3)] public List<Guid> Ingredients = new List<Guid>();
|
||||
|
||||
[JsonProperty("blueprint"), Key(4)] public Guid Blueprint;
|
||||
|
||||
[JsonProperty("name"), Key(5)] public string Name;
|
||||
}
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
|
|
|
|||
Loading…
Reference in a new issue