json generator alternator and vibrator (#718)
* json generator alternator and vibrator * каким хуем ты не закоммитился уебан
This commit is contained in:
@@ -30,6 +30,7 @@ using Robust.Shared.Prototypes;
|
|||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Content.Server._White;
|
using Content.Server._White;
|
||||||
|
using Content.Server._White.GuideGenerator;
|
||||||
using Content.Server._White.JoinQueue;
|
using Content.Server._White.JoinQueue;
|
||||||
using Content.Server._White.Jukebox;
|
using Content.Server._White.Jukebox;
|
||||||
using Content.Server._White.PandaSocket.Main;
|
using Content.Server._White.PandaSocket.Main;
|
||||||
@@ -145,6 +146,15 @@ namespace Content.Server.Entry
|
|||||||
file = resourceManager.UserData.OpenWriteText(resPath.WithName("react_" + dest));
|
file = resourceManager.UserData.OpenWriteText(resPath.WithName("react_" + dest));
|
||||||
ReactionJsonGenerator.PublishJson(file);
|
ReactionJsonGenerator.PublishJson(file);
|
||||||
file.Flush();
|
file.Flush();
|
||||||
|
file = resourceManager.UserData.OpenWriteText(resPath.WithName("entity_" + dest));
|
||||||
|
EntityJsonGenerator.PublishJson(file);
|
||||||
|
file.Flush();
|
||||||
|
file = resourceManager.UserData.OpenWriteText(resPath.WithName("mealrecipes_" + dest));
|
||||||
|
MealsRecipesJsonGenerator.PublishJson(file);
|
||||||
|
file.Flush();
|
||||||
|
file = resourceManager.UserData.OpenWriteText(resPath.WithName("healthchangereagents_" + dest));
|
||||||
|
HealthChangeReagentsJsonGenerator.PublishJson(file);
|
||||||
|
file.Flush();
|
||||||
IoCManager.Resolve<IBaseServer>().Shutdown("Data generation done");
|
IoCManager.Resolve<IBaseServer>().Shutdown("Data generation done");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using Robust.Shared.Prototypes;
|
|||||||
|
|
||||||
namespace Content.Server.GuideGenerator;
|
namespace Content.Server.GuideGenerator;
|
||||||
|
|
||||||
public sealed class ReactionJsonGenerator
|
public sealed partial class ReactionJsonGenerator
|
||||||
{
|
{
|
||||||
public static void PublishJson(StreamWriter file)
|
public static void PublishJson(StreamWriter file)
|
||||||
{
|
{
|
||||||
@@ -19,13 +19,16 @@ public sealed class ReactionJsonGenerator
|
|||||||
.Select(x => new ReactionEntry(x))
|
.Select(x => new ReactionEntry(x))
|
||||||
.ToDictionary(x => x.Id, x => x);
|
.ToDictionary(x => x.Id, x => x);
|
||||||
|
|
||||||
|
if (reactions is not null) AddMixingCategories(reactions, prototype);
|
||||||
|
|
||||||
var serializeOptions = new JsonSerializerOptions
|
var serializeOptions = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
WriteIndented = true,
|
WriteIndented = true,
|
||||||
Converters =
|
Converters =
|
||||||
{
|
{
|
||||||
new UniversalJsonConverter<ReagentEffect>(),
|
new UniversalJsonConverter<ReagentEffect>(),
|
||||||
}
|
},
|
||||||
|
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals
|
||||||
};
|
};
|
||||||
|
|
||||||
file.Write(JsonSerializer.Serialize(reactions, serializeOptions));
|
file.Write(JsonSerializer.Serialize(reactions, serializeOptions));
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Content.Server.Body.Components;
|
using Content.Server._White.GuideGenerator;
|
||||||
using Content.Shared.Body.Prototypes;
|
|
||||||
using Content.Shared.Chemistry.Reaction;
|
using Content.Shared.Chemistry.Reaction;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Server.GuideGenerator;
|
namespace Content.Server.GuideGenerator;
|
||||||
|
|
||||||
@@ -31,8 +29,11 @@ public sealed class ReagentEntry
|
|||||||
[JsonPropertyName("recipes")]
|
[JsonPropertyName("recipes")]
|
||||||
public List<string> Recipes { get; } = new();
|
public List<string> Recipes { get; } = new();
|
||||||
|
|
||||||
|
[JsonPropertyName("textColor")]
|
||||||
|
public string TextColor { get; }
|
||||||
|
|
||||||
[JsonPropertyName("metabolisms")]
|
[JsonPropertyName("metabolisms")]
|
||||||
public Dictionary<string, ReagentEffectsEntry>? Metabolisms { get; }
|
public Dictionary<string, _White.GuideGenerator.ReagentEffectsEntry>? Metabolisms { get; }
|
||||||
|
|
||||||
public ReagentEntry(ReagentPrototype proto)
|
public ReagentEntry(ReagentPrototype proto)
|
||||||
{
|
{
|
||||||
@@ -42,7 +43,13 @@ public sealed class ReagentEntry
|
|||||||
Description = proto.LocalizedDescription;
|
Description = proto.LocalizedDescription;
|
||||||
PhysicalDescription = proto.LocalizedPhysicalDescription;
|
PhysicalDescription = proto.LocalizedPhysicalDescription;
|
||||||
SubstanceColor = proto.SubstanceColor.ToHex();
|
SubstanceColor = proto.SubstanceColor.ToHex();
|
||||||
Metabolisms = proto.Metabolisms?.ToDictionary(x => x.Key.Id, x => x.Value);
|
var r = proto.SubstanceColor.R;
|
||||||
|
var g = proto.SubstanceColor.G;
|
||||||
|
var b = proto.SubstanceColor.B;
|
||||||
|
TextColor = (0.2126f * r + 0.7152f * g + 0.0722f * b > 0.5
|
||||||
|
? Color.Black
|
||||||
|
: Color.White).ToHex();
|
||||||
|
Metabolisms = proto.Metabolisms?.ToDictionary(x => x.Key.Id, x => new _White.GuideGenerator.ReagentEffectsEntry(x.Value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +67,18 @@ public sealed class ReactionEntry
|
|||||||
[JsonPropertyName("products")]
|
[JsonPropertyName("products")]
|
||||||
public Dictionary<string, float> Products { get; }
|
public Dictionary<string, float> Products { get; }
|
||||||
|
|
||||||
|
[JsonPropertyName("mixingCategories")]
|
||||||
|
public List<MixingCategoryEntry> MixingCategories { get; } = new();
|
||||||
|
[JsonPropertyName("minTemp")]
|
||||||
|
public float MinTemp { get; }
|
||||||
|
[JsonPropertyName("maxTemp")]
|
||||||
|
public float MaxTemp { get; }
|
||||||
|
[JsonPropertyName("hasMax")]
|
||||||
|
public bool HasMax { get; }
|
||||||
|
|
||||||
[JsonPropertyName("effects")]
|
[JsonPropertyName("effects")]
|
||||||
|
public List<ReagentEffectEntry> ExportEffects { get; } = new();
|
||||||
|
[JsonIgnore]
|
||||||
public List<ReagentEffect> Effects { get; }
|
public List<ReagentEffect> Effects { get; }
|
||||||
|
|
||||||
public ReactionEntry(ReactionPrototype proto)
|
public ReactionEntry(ReactionPrototype proto)
|
||||||
@@ -76,6 +94,11 @@ public sealed class ReactionEntry
|
|||||||
.Select(x => KeyValuePair.Create(x.Key, x.Value.Float()))
|
.Select(x => KeyValuePair.Create(x.Key, x.Value.Float()))
|
||||||
.ToDictionary(x => x.Key, x => x.Value);
|
.ToDictionary(x => x.Key, x => x.Value);
|
||||||
Effects = proto.Effects;
|
Effects = proto.Effects;
|
||||||
|
|
||||||
|
ExportEffects = proto.Effects.Select(x => new ReagentEffectEntry(x)).ToList();
|
||||||
|
MinTemp = proto.MinimumTemperature;
|
||||||
|
MaxTemp = proto.MaximumTemperature;
|
||||||
|
HasMax = !float.IsPositiveInfinity(MaxTemp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
Content.Server/_White/GuideGenerator/EntityEntry.cs
Normal file
23
Content.Server/_White/GuideGenerator/EntityEntry.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Server.GuideGenerator;
|
||||||
|
|
||||||
|
public sealed class EntityEntry
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
[JsonPropertyName("desc")]
|
||||||
|
public string Description { get; }
|
||||||
|
|
||||||
|
public EntityEntry(EntityPrototype proto)
|
||||||
|
{
|
||||||
|
Id = proto.ID;
|
||||||
|
Name = TextTools.TextTools.CapitalizeString(proto.Name);
|
||||||
|
Description = proto.Description;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
Content.Server/_White/GuideGenerator/EntityJsonGenerator.cs
Normal file
27
Content.Server/_White/GuideGenerator/EntityJsonGenerator.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Server.GuideGenerator;
|
||||||
|
|
||||||
|
public sealed class EntityJsonGenerator
|
||||||
|
{
|
||||||
|
public static void PublishJson(StreamWriter file)
|
||||||
|
{
|
||||||
|
var prototype = IoCManager.Resolve<IPrototypeManager>();
|
||||||
|
var prototypes =
|
||||||
|
prototype
|
||||||
|
.EnumeratePrototypes<EntityPrototype>()
|
||||||
|
.Where(x => !x.Abstract)
|
||||||
|
.Select(x => new EntityEntry(x))
|
||||||
|
.ToDictionary(x => x.Id, x => x);
|
||||||
|
|
||||||
|
var serializeOptions = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
file.Write(JsonSerializer.Serialize(prototypes, serializeOptions));
|
||||||
|
}
|
||||||
|
}
|
||||||
74
Content.Server/_White/GuideGenerator/GrindRecipeEntry.cs
Normal file
74
Content.Server/_White/GuideGenerator/GrindRecipeEntry.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||||
|
using Content.Shared.Kitchen.Components;
|
||||||
|
|
||||||
|
namespace Content.Server.GuideGenerator;
|
||||||
|
|
||||||
|
public sealed class GrindRecipeEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id of grindable item
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Human-readable name of recipe.
|
||||||
|
/// Should automatically be localized by default
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of recipe
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public string Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Item that will be grinded into something
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("input")]
|
||||||
|
public string Input { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dictionary of reagents that entity contains; aka "Recipe Result"
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("result")]
|
||||||
|
public Dictionary<string, int>? Result { get; } = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
|
||||||
|
public GrindRecipeEntry(EntityPrototype proto)
|
||||||
|
{
|
||||||
|
Id = proto.ID;
|
||||||
|
Name = TextTools.TextTools.CapitalizeString(proto.Name);
|
||||||
|
Type = "grindableRecipes";
|
||||||
|
Input = proto.ID;
|
||||||
|
var foodSolutionName = "food"; // default to food because everything in prototypes defaults to "food"
|
||||||
|
|
||||||
|
// Now, to become a recipe, entity must:
|
||||||
|
// A) Have "Extractable" component on it.
|
||||||
|
// B) Have "SolutionContainerManager" component on it.
|
||||||
|
// C) Have "GrindableSolution" declared in "SolutionContainerManager" component.
|
||||||
|
// D) Have solution with name declared in "SolutionContainerManager.GrindableSolution" inside its "SolutionContainerManager" component.
|
||||||
|
// F) Have "Food" in its name (see Content.Server/_White/GuideGenerator/MealsRecipesJsonGenerator.cs)
|
||||||
|
if (proto.Components.TryGetComponent("Extractable", out var extractableComp) && proto.Components.TryGetComponent("SolutionContainerManager", out var solutionCompRaw))
|
||||||
|
{
|
||||||
|
var extractable = (ExtractableComponent) extractableComp;
|
||||||
|
var solutionComp = (SolutionContainerManagerComponent) solutionCompRaw;
|
||||||
|
foodSolutionName = extractable.GrindableSolution;
|
||||||
|
|
||||||
|
if (solutionComp.Solutions != null && foodSolutionName != null)
|
||||||
|
{
|
||||||
|
foreach (ReagentQuantity reagent in solutionComp.Solutions[(string) foodSolutionName].Contents)
|
||||||
|
{
|
||||||
|
Result[reagent.Reagent.Prototype] = reagent.Quantity.Int();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Result = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
using Content.Server.Chemistry.ReagentEffects;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
using static Content.Server.GuideGenerator.ChemistryJsonGenerator;
|
||||||
|
|
||||||
|
namespace Content.Server._White.GuideGenerator;
|
||||||
|
public sealed class HealthChangeReagentsJsonGenerator
|
||||||
|
{
|
||||||
|
public static void PublishJson(StreamWriter file)
|
||||||
|
{
|
||||||
|
var prototype = IoCManager.Resolve<IPrototypeManager>();
|
||||||
|
|
||||||
|
Dictionary<string, Dictionary<string, Dictionary<string, float>>> healthChangeReagents = new();
|
||||||
|
|
||||||
|
// Сбор данных
|
||||||
|
foreach (var reagent in prototype.EnumeratePrototypes<ReagentPrototype>())
|
||||||
|
{
|
||||||
|
if (reagent.Metabolisms is null) continue;
|
||||||
|
|
||||||
|
foreach (var metabolism in reagent.Metabolisms)
|
||||||
|
{
|
||||||
|
foreach (HealthChange effect in metabolism.Value.Effects.Where(x => x is HealthChange))
|
||||||
|
{
|
||||||
|
foreach (var damage in effect.Damage.DamageDict)
|
||||||
|
{
|
||||||
|
var damageType = damage.Key;
|
||||||
|
var damageChangeType = damage.Value.Float() < 0 ? "health" : "damage";
|
||||||
|
|
||||||
|
if (!healthChangeReagents.ContainsKey(damageType))
|
||||||
|
{
|
||||||
|
healthChangeReagents.Add(damageType, new());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!healthChangeReagents[damageType].ContainsKey(damageChangeType))
|
||||||
|
{
|
||||||
|
healthChangeReagents[damageType].Add(damageChangeType, new());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Берем максимальный показатель (один реагент может наносить разный урон при разных условиях)
|
||||||
|
var damageChangeValueAbs = Math.Abs(damage.Value.Float() / metabolism.Value.MetabolismRate.Float()); // вычисляем показатель за 1 ед. вещества, а не 1 сек. нахождения я в организме.
|
||||||
|
if (healthChangeReagents[damageType][damageChangeType].TryGetValue(reagent.ID, out var previousValue))
|
||||||
|
{
|
||||||
|
healthChangeReagents[damageType][damageChangeType][reagent.ID] = Math.Max(previousValue, damageChangeValueAbs);
|
||||||
|
}
|
||||||
|
else healthChangeReagents[damageType][damageChangeType].Add(reagent.ID, damageChangeValueAbs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сортировка
|
||||||
|
Dictionary<string, Dictionary<string, List<string>>> healthChangeReagentsSorted = new();
|
||||||
|
|
||||||
|
foreach (var damageType in healthChangeReagents)
|
||||||
|
{
|
||||||
|
foreach (var damageChangeType in damageType.Value)
|
||||||
|
{
|
||||||
|
foreach (var reagent in damageChangeType.Value)
|
||||||
|
{
|
||||||
|
if (!healthChangeReagentsSorted.ContainsKey(damageType.Key))
|
||||||
|
{
|
||||||
|
healthChangeReagentsSorted.Add(damageType.Key, new());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!healthChangeReagentsSorted[damageType.Key].ContainsKey(damageChangeType.Key))
|
||||||
|
{
|
||||||
|
healthChangeReagentsSorted[damageType.Key].Add(damageChangeType.Key, new());
|
||||||
|
}
|
||||||
|
|
||||||
|
healthChangeReagentsSorted[damageType.Key][damageChangeType.Key].Add(reagent.Key);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
healthChangeReagentsSorted[damageType.Key][damageChangeType.Key].Sort(Comparer<string>.Create((s1, s2) =>
|
||||||
|
-healthChangeReagents[damageType.Key][damageChangeType.Key][s1].CompareTo(healthChangeReagents[damageType.Key][damageChangeType.Key][s2])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var serializeOptions = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals
|
||||||
|
};
|
||||||
|
|
||||||
|
file.Write(JsonSerializer.Serialize(healthChangeReagentsSorted, serializeOptions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
93
Content.Server/_White/GuideGenerator/HeatableRecipeEntry.cs
Normal file
93
Content.Server/_White/GuideGenerator/HeatableRecipeEntry.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Shared.Construction;
|
||||||
|
using Content.Shared.Construction.Prototypes;
|
||||||
|
using Content.Shared.Construction.Steps;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.GuideGenerator;
|
||||||
|
|
||||||
|
public sealed class HeatableRecipeEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id of recipe
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Human-readable name of recipe.
|
||||||
|
/// Should automatically be localized by default
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of recipe
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public string Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Temp, required for "input" thing to become "result" thing
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("minTemp")]
|
||||||
|
public float MinTemp { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Item that will be transformed into something with enough temp
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("input")]
|
||||||
|
public string Input { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Result of a recipe.
|
||||||
|
/// If it is null then recipe does not exist or we could not get recipe info.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("result")]
|
||||||
|
public string? Result { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public HeatableRecipeEntry(
|
||||||
|
ConstructionGraphPrototype constructionProto, // to get data from construction prototype (minTemp, result)
|
||||||
|
EntityPrototype entityPrototype // to get entity data (name, input entity id)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var graphID = "";
|
||||||
|
var startNode = constructionProto.Nodes[constructionProto.Start!];
|
||||||
|
if (entityPrototype.Components.TryGetComponent("Construction", out var constructionCompRaw)) // does entity actually has Construction component?
|
||||||
|
{
|
||||||
|
foreach (var nodeEdgeRaw in startNode.Edges) // because we don't know what node contains heating step (in case if it is not constructionProto.Start) let's check every node and see if we will get anything
|
||||||
|
{
|
||||||
|
var nodeEdge = (ConstructionGraphEdge)nodeEdgeRaw;
|
||||||
|
foreach (var nodeStepRaw in nodeEdge.Steps)
|
||||||
|
{
|
||||||
|
if (nodeStepRaw.GetType().Equals(typeof(TemperatureConstructionGraphStep))) // TemperatureConstructionGraphStep is used only in steaks recipes, so for now we can afford it
|
||||||
|
{
|
||||||
|
var nodeStep = (TemperatureConstructionGraphStep)nodeStepRaw;
|
||||||
|
graphID = nodeEdge.Target; // required to check when we need to leave second loop; this is the best solution, because nodeEdge.Target is marked as required datafield and cannot be null
|
||||||
|
ServerEntityManager em = new();
|
||||||
|
MinTemp = nodeStep.MinTemperature.HasValue ? nodeStep.MinTemperature.Value : 0;
|
||||||
|
Result = nodeStep.MinTemperature.HasValue ? constructionProto.Nodes[nodeEdge.Target].Entity.GetId(null, null, new GraphNodeEntityArgs(em)) : null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (graphID != "") break; // we're done! let's leave!
|
||||||
|
}
|
||||||
|
if (graphID == "") // we've failed to get anything :(
|
||||||
|
{
|
||||||
|
MinTemp = 0;
|
||||||
|
Result = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // if entity does not have construction component then it cannot be constructed - (c) Jason Statham
|
||||||
|
{
|
||||||
|
MinTemp = 0;
|
||||||
|
Result = null;
|
||||||
|
}
|
||||||
|
Input = entityPrototype.ID;
|
||||||
|
Name = TextTools.TextTools.CapitalizeString(entityPrototype.Name);
|
||||||
|
Id = entityPrototype.ID;
|
||||||
|
Type = "heatableRecipes";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Content.Shared.Chemistry.Reaction;
|
||||||
|
using Content.Shared.Kitchen;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Shared.Construction.Prototypes;
|
||||||
|
using Content.Server.Construction.Components;
|
||||||
|
using Content.Server.Chemistry.ReactionEffects;
|
||||||
|
|
||||||
|
namespace Content.Server.GuideGenerator;
|
||||||
|
|
||||||
|
public sealed class MealsRecipesJsonGenerator
|
||||||
|
{
|
||||||
|
public static void PublishJson(StreamWriter file)
|
||||||
|
{
|
||||||
|
var prototype = IoCManager.Resolve<IPrototypeManager>();
|
||||||
|
var entities = prototype.EnumeratePrototypes<EntityPrototype>();
|
||||||
|
var constructable = prototype.EnumeratePrototypes<ConstructionGraphPrototype>();
|
||||||
|
var output = new Dictionary<string, dynamic>();
|
||||||
|
|
||||||
|
var microwaveRecipes =
|
||||||
|
prototype
|
||||||
|
.EnumeratePrototypes<FoodRecipePrototype>()
|
||||||
|
.Select(x => new MicrowaveRecipeEntry(x))
|
||||||
|
.ToDictionary(x => x.Id, x => x);
|
||||||
|
|
||||||
|
|
||||||
|
var sliceableRecipes =
|
||||||
|
entities
|
||||||
|
.Where(x => x.Components.TryGetComponent("SliceableFood", out var _))
|
||||||
|
.Select(x => new SliceRecipeEntry(x))
|
||||||
|
.Where(x => x.Result != "") // SOMEONE THOUGHT THAT IT WOULD BE A GREAT IDEA TO PUT COMPONENT ON AN ITEM WITHOUT SPECIFYING THE OUTPUT THING.
|
||||||
|
.Where(x => x.Count > 0) // Just in case.
|
||||||
|
.ToDictionary(x => x.Id, x => x);
|
||||||
|
|
||||||
|
|
||||||
|
var grindableRecipes =
|
||||||
|
entities
|
||||||
|
.Where(x => x.Components.TryGetComponent("Extractable", out var _))
|
||||||
|
.Where(x => x.Components.TryGetComponent("SolutionContainerManager", out var _))
|
||||||
|
.Where(x => (Regex.Match(x.ID.ToLower().Trim(), @".*[Ff]ood*").Success)) // we dont need some "organ" or "pills" prototypes.
|
||||||
|
.Select(x => new GrindRecipeEntry(x))
|
||||||
|
.Where(x => x.Result != null)
|
||||||
|
.ToDictionary(x => x.Id, x => x);
|
||||||
|
|
||||||
|
|
||||||
|
// construction-related items start
|
||||||
|
var constructionGraphs =
|
||||||
|
constructable
|
||||||
|
.Where(x => (Regex.Match(x.ID.ToLower().Trim(), @".*.*[Bb]acon*|.*[Ss]teak*|[Pp]izza*|[Tt]ortilla*|[Ee]gg*").Success)) // we only need recipes that has "bacon", "steak", "pizza" "tortilla" and "egg" in it, since they are the only "constructable" recipes
|
||||||
|
.ToDictionary(x => x.ID, x => x);
|
||||||
|
|
||||||
|
var constructableEntities = // list of entities which names match regex and has Construction component
|
||||||
|
entities
|
||||||
|
.Where(x => (Regex.Match(x.ID.ToLower().Trim(), @"(?<![Cc]rate)[Ff]ood*").Success))
|
||||||
|
.Where(x => x.Components.ContainsKey("Construction"))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var entityGraphs = new Dictionary<string, string>(); // BFH. Since we cannot get component from another .Where call (because of CS0103), let's keep everything in one temp dictionary.
|
||||||
|
|
||||||
|
foreach (var ent in constructableEntities)
|
||||||
|
{
|
||||||
|
if (ent.Components.TryGetComponent("Construction", out var constructionCompRaw))
|
||||||
|
{
|
||||||
|
var constructionComp = (ConstructionComponent)constructionCompRaw;
|
||||||
|
entityGraphs[ent.ID] = constructionComp.Graph;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var constructableHeatableEntities = constructableEntities // let's finally create our heatable recipes list
|
||||||
|
.Where(x => constructionGraphs.ContainsKey(entityGraphs[x.ID]))
|
||||||
|
.Select(x => new HeatableRecipeEntry(constructionGraphs[entityGraphs[x.ID]], x))
|
||||||
|
.Where(x => (x.Result != null))
|
||||||
|
.Where(x => x.Id != x.Result) // sometimes things dupe (for example if someone puts construction component on both inout and output things)
|
||||||
|
.ToDictionary(x => x.Id, x => x);
|
||||||
|
|
||||||
|
|
||||||
|
var constructableToolableEntities = constructableEntities // let's finally create our toolmade recipes list
|
||||||
|
.Where(x => constructionGraphs.ContainsKey(entityGraphs[x.ID]))
|
||||||
|
.Select(x => new ToolRecipeEntry(constructionGraphs[entityGraphs[x.ID]], x))
|
||||||
|
.Where(x => (x.Result != null))
|
||||||
|
.Where(x => x.Id != x.Result) // the same here, things sometimes dupe
|
||||||
|
.ToDictionary(x => x.Id, x => x);
|
||||||
|
// construction-related items end
|
||||||
|
|
||||||
|
// reaction-related items start
|
||||||
|
var reactionPrototypes =
|
||||||
|
prototype
|
||||||
|
.EnumeratePrototypes<ReactionPrototype>()
|
||||||
|
.Select(x => new ReactionEntry(x))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
|
||||||
|
var mixableRecipes = new Dictionary<string, Dictionary<string, string>>(); // this is a list because we have https://station14.ru/wiki/Модуль:Chemistry_Lookup that already has everything we need and does everything for us.
|
||||||
|
|
||||||
|
foreach (var react in reactionPrototypes)
|
||||||
|
{
|
||||||
|
foreach (var effect in react.Effects)
|
||||||
|
if (effect.GetType().Equals(typeof(CreateEntityReactionEffect)))
|
||||||
|
{
|
||||||
|
var trueEffect = (CreateEntityReactionEffect)effect;
|
||||||
|
if (Regex.Match(trueEffect.Entity.ToLower().Trim(), @".*[Ff]ood*").Success) if (!mixableRecipes.ContainsKey(react.Id))
|
||||||
|
{
|
||||||
|
mixableRecipes[react.Id] = new Dictionary<string, string>();
|
||||||
|
mixableRecipes[react.Id]["id"] = react.Id;
|
||||||
|
mixableRecipes[react.Id]["type"] = "mixableRecipes";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// reaction-related items end
|
||||||
|
|
||||||
|
output["microwaveRecipes"] = microwaveRecipes;
|
||||||
|
output["sliceableRecipes"] = sliceableRecipes;
|
||||||
|
output["grindableRecipes"] = grindableRecipes;
|
||||||
|
output["heatableRecipes"] = constructableHeatableEntities;
|
||||||
|
output["toolmadeRecipes"] = constructableToolableEntities;
|
||||||
|
output["mixableRecipes"] = mixableRecipes;
|
||||||
|
|
||||||
|
var serializeOptions = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true
|
||||||
|
};
|
||||||
|
|
||||||
|
file.Write(JsonSerializer.Serialize(output, serializeOptions));
|
||||||
|
}
|
||||||
|
}
|
||||||
71
Content.Server/_White/GuideGenerator/MicrowaveRecipeEntry.cs
Normal file
71
Content.Server/_White/GuideGenerator/MicrowaveRecipeEntry.cs
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Content.Shared.Kitchen;
|
||||||
|
|
||||||
|
namespace Content.Server.GuideGenerator;
|
||||||
|
|
||||||
|
public sealed class MicrowaveRecipeEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id of recipe
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Human-readable name of recipe.
|
||||||
|
/// Should automatically be localized by default
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of recipe
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public string Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time to cook something (for microwave recipes)
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("time")]
|
||||||
|
public uint Time { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Solids required to cook something
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("solids")]
|
||||||
|
public Dictionary<string, uint> Solids { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reagents required to cook something
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("reagents")]
|
||||||
|
public Dictionary<string, uint> Reagents { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Result of a recipe
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("result")]
|
||||||
|
public string Result { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public MicrowaveRecipeEntry(FoodRecipePrototype proto)
|
||||||
|
{
|
||||||
|
Id = proto.ID;
|
||||||
|
Name = TextTools.TextTools.CapitalizeString(proto.Name);
|
||||||
|
Type = "microwaveRecipes";
|
||||||
|
Time = proto.CookTime;
|
||||||
|
Solids = proto.IngredientsSolids
|
||||||
|
.ToDictionary(
|
||||||
|
sol => sol.Key,
|
||||||
|
sol => (uint)(int)sol.Value.Int()
|
||||||
|
);
|
||||||
|
Reagents = proto.IngredientsReagents
|
||||||
|
.ToDictionary(
|
||||||
|
rea => rea.Key,
|
||||||
|
rea => (uint)(int)rea.Value.Int()
|
||||||
|
);
|
||||||
|
Result = proto.Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Content.Server/_White/GuideGenerator/MixingCategoryEntry.cs
Normal file
19
Content.Server/_White/GuideGenerator/MixingCategoryEntry.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Content.Shared.Chemistry.Reaction;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server._White.GuideGenerator;
|
||||||
|
|
||||||
|
public sealed class MixingCategoryEntry
|
||||||
|
{
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
public MixingCategoryEntry(MixingCategoryPrototype proto)
|
||||||
|
{
|
||||||
|
Name = Loc.GetString(proto.VerbText);
|
||||||
|
Id = proto.ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using Content.Server._White.GuideGenerator;
|
||||||
|
using Content.Shared.Chemistry.Reaction;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Server.GuideGenerator;
|
||||||
|
public sealed partial class ReactionJsonGenerator
|
||||||
|
{
|
||||||
|
[ValidatePrototypeId<MixingCategoryPrototype>]
|
||||||
|
private const string DefaultMixingCategory = "DummyMix";
|
||||||
|
|
||||||
|
private static void AddMixingCategories(Dictionary<String, ReactionEntry> reactions, IPrototypeManager prototype)
|
||||||
|
{
|
||||||
|
foreach (var reaction in reactions)
|
||||||
|
{
|
||||||
|
var reactionPrototype = prototype.Index<ReactionPrototype>(reaction.Key);
|
||||||
|
var mixingCategories = new List<MixingCategoryPrototype>();
|
||||||
|
if (reactionPrototype.MixingCategories != null)
|
||||||
|
{
|
||||||
|
foreach (var category in reactionPrototype.MixingCategories)
|
||||||
|
{
|
||||||
|
mixingCategories.Add(prototype.Index(category));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mixingCategories.Add(prototype.Index<MixingCategoryPrototype>(DefaultMixingCategory));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var mixingCategory in mixingCategories)
|
||||||
|
{
|
||||||
|
reactions[reaction.Key].MixingCategories.Add(new MixingCategoryEntry(mixingCategory));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
Content.Server/_White/GuideGenerator/ReagentEffectEntry.cs
Normal file
40
Content.Server/_White/GuideGenerator/ReagentEffectEntry.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server._White.GuideGenerator;
|
||||||
|
public sealed class ReagentEffectEntry
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
[JsonPropertyName("description")]
|
||||||
|
public string Description { get; }
|
||||||
|
|
||||||
|
public ReagentEffectEntry(ReagentEffect proto)
|
||||||
|
{
|
||||||
|
var prototype = IoCManager.Resolve<IPrototypeManager>();
|
||||||
|
var entSys = IoCManager.Resolve<IEntitySystemManager>();
|
||||||
|
|
||||||
|
Id = proto.GetType().Name;
|
||||||
|
Description = GuidebookEffectDescriptionToWeb(proto.GuidebookEffectDescription(prototype, entSys) ?? "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GuidebookEffectDescriptionToWeb(string guideBookText)
|
||||||
|
{
|
||||||
|
guideBookText = guideBookText.Replace("[", "<");
|
||||||
|
guideBookText = guideBookText.Replace("]", ">");
|
||||||
|
guideBookText = guideBookText.Replace("color", "span");
|
||||||
|
|
||||||
|
while (guideBookText.IndexOf("<span=") != -1)
|
||||||
|
{
|
||||||
|
var first = guideBookText.IndexOf("<span=") + "<span=".Length - 1;
|
||||||
|
var last = guideBookText.IndexOf(">", first);
|
||||||
|
var replacementString = guideBookText.Substring(first, last - first);
|
||||||
|
var color = replacementString.Substring(1);
|
||||||
|
guideBookText = guideBookText.Replace(replacementString, string.Format(" style=\"color: {0};\"", color));
|
||||||
|
}
|
||||||
|
|
||||||
|
return guideBookText;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Content.Server/_White/GuideGenerator/ReagentEffectsEntry.cs
Normal file
20
Content.Server/_White/GuideGenerator/ReagentEffectsEntry.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Server._White.GuideGenerator;
|
||||||
|
public sealed class ReagentEffectsEntry
|
||||||
|
{
|
||||||
|
[JsonPropertyName("rate")]
|
||||||
|
public FixedPoint2 MetabolismRate { get; } = FixedPoint2.New(0.5f);
|
||||||
|
|
||||||
|
[JsonPropertyName("effects")]
|
||||||
|
public List<ReagentEffectEntry> Effects { get; } = new();
|
||||||
|
|
||||||
|
public ReagentEffectsEntry(Shared.Chemistry.Reagent.ReagentEffectsEntry proto)
|
||||||
|
{
|
||||||
|
MetabolismRate = proto.MetabolismRate;
|
||||||
|
Effects = proto.Effects.Select(x => new ReagentEffectEntry(x)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
65
Content.Server/_White/GuideGenerator/SliceRecipeEntry.cs
Normal file
65
Content.Server/_White/GuideGenerator/SliceRecipeEntry.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Server.Nutrition.Components;
|
||||||
|
|
||||||
|
namespace Content.Server.GuideGenerator;
|
||||||
|
|
||||||
|
public sealed class SliceRecipeEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id of sliceable item
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Human-readable name of recipe.
|
||||||
|
/// Should automatically be localized by default
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of recipe
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public string Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Item that will be sliced into something
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("input")]
|
||||||
|
public string Input { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Result of a recipe
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("result")]
|
||||||
|
public string Result { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Count of result item
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("count")]
|
||||||
|
public int Count { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public SliceRecipeEntry(EntityPrototype proto)
|
||||||
|
{
|
||||||
|
Id = proto.ID;
|
||||||
|
Name = TextTools.TextTools.CapitalizeString(proto.Name);
|
||||||
|
Type = "sliceableRecipes";
|
||||||
|
Input = proto.ID;
|
||||||
|
if (proto.Components.TryGetComponent("SliceableFood", out var comp))
|
||||||
|
{
|
||||||
|
var sliceable = (SliceableFoodComponent) comp;
|
||||||
|
Result = sliceable.Slice ?? "";
|
||||||
|
Count = sliceable.TotalCount;
|
||||||
|
}
|
||||||
|
else // just in case something will go wrong and we somehow will not get our component
|
||||||
|
{
|
||||||
|
Result = "";
|
||||||
|
Count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
Content.Server/_White/GuideGenerator/TextTools.cs
Normal file
25
Content.Server/_White/GuideGenerator/TextTools.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
namespace Content.Server.GuideGenerator.TextTools;
|
||||||
|
|
||||||
|
public sealed class TextTools
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Capitalizes first letter of given string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">String to capitalize</param>
|
||||||
|
/// <returns>String with capitalized first letter</returns>
|
||||||
|
public static string CapitalizeString(string str)
|
||||||
|
{
|
||||||
|
if (str.Length > 1)
|
||||||
|
{
|
||||||
|
return char.ToUpper(str[0]) + str.Remove(0, 1);
|
||||||
|
}
|
||||||
|
else if (str.Length == 1)
|
||||||
|
{
|
||||||
|
return char.ToUpper(str[0]).ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
96
Content.Server/_White/GuideGenerator/ToolRecipeEntry.cs
Normal file
96
Content.Server/_White/GuideGenerator/ToolRecipeEntry.cs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Shared.Construction;
|
||||||
|
using Content.Shared.Construction.Prototypes;
|
||||||
|
using Content.Shared.Construction.Steps;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.GuideGenerator;
|
||||||
|
|
||||||
|
public sealed class ToolRecipeEntry // because of https://github.com/space-wizards/space-station-14/pull/20624, some recipes can now be cooked using tools
|
||||||
|
// actually, the code is pretty similar with HeatableRecipeEntry. The only difference is that we need ToolConstructionGraphStep instead of TemperatureConstructionGraphStep
|
||||||
|
// comments are left untouched :)
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id of recipe
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Human-readable name of recipe.
|
||||||
|
/// Should automatically be localized by default
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of recipe
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public string Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of tool that is used to convert input into result
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("tool")]
|
||||||
|
public string? Tool { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Item that will be transformed into something with enough temp
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("input")]
|
||||||
|
public string Input { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Result of a recipe.
|
||||||
|
/// If it is null then recipe does not exist or we could not get recipe info.
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("result")]
|
||||||
|
public string? Result { get; }
|
||||||
|
|
||||||
|
|
||||||
|
public ToolRecipeEntry(
|
||||||
|
ConstructionGraphPrototype constructionProto, // to get data from construction prototype (Tool, result)
|
||||||
|
EntityPrototype entityPrototype // to get entity data (name, input entity id)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var graphID = "";
|
||||||
|
var startNode = constructionProto.Nodes[constructionProto.Start!];
|
||||||
|
if (entityPrototype.Components.TryGetComponent("Construction", out var constructionCompRaw)) // does entity actually has Construction component?
|
||||||
|
{
|
||||||
|
foreach (var nodeEdgeRaw in startNode.Edges) // because we don't know what node contains heating step (in case if it is not constructionProto.Start) let's check every node and see if we will get anything
|
||||||
|
{
|
||||||
|
var nodeEdge = (ConstructionGraphEdge)nodeEdgeRaw;
|
||||||
|
foreach (var nodeStepRaw in nodeEdge.Steps)
|
||||||
|
{
|
||||||
|
if (nodeStepRaw.GetType().Equals(typeof(ToolConstructionGraphStep))) // ToolConstructionGraphStep is used only in steaks recipes, so for now we can afford it
|
||||||
|
{
|
||||||
|
var nodeStep = (ToolConstructionGraphStep)nodeStepRaw;
|
||||||
|
graphID = nodeEdge.Target; // required to check when we need to leave second loop; this is the best solution, because nodeEdge.Target is marked as required datafield and cannot be null
|
||||||
|
ServerEntityManager em = new();
|
||||||
|
Tool = nodeStep.Tool;
|
||||||
|
Result = constructionProto.Nodes[nodeEdge.Target].Entity.GetId(null, null, new GraphNodeEntityArgs(em));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (graphID != "") break; // we're done! let's leave!
|
||||||
|
}
|
||||||
|
if (graphID == "") // we've failed to get anything :(
|
||||||
|
{
|
||||||
|
Tool = null;
|
||||||
|
Result = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // if entity does not have construction component then it cannot be constructed - (c) Jason Statham
|
||||||
|
{
|
||||||
|
Tool = null;
|
||||||
|
Result = null;
|
||||||
|
}
|
||||||
|
Input = entityPrototype.ID;
|
||||||
|
Name = TextTools.TextTools.CapitalizeString(entityPrototype.Name);
|
||||||
|
Id = entityPrototype.ID;
|
||||||
|
Type = "toolmadeRecipes";
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user