Reactive 3.0 (#5443)

* probably scrapping this

* reimpl old behavior

* misc fixes and initial yaml

* works basically first try
This commit is contained in:
mirrorcult
2021-11-22 02:17:35 -07:00
committed by GitHub
parent 8b47d0f43f
commit e40c9bc427
17 changed files with 152 additions and 71 deletions

View File

@@ -334,7 +334,7 @@ namespace Content.Shared.Chemistry.Components
public void DoEntityReaction(EntityUid uid, ReactionMethod method)
{
var chemistry = EntitySystem.Get<ChemistrySystem>();
var chemistry = EntitySystem.Get<ReactiveSystem>();
foreach (var (reagentId, quantity) in Contents.ToArray())
{

View File

@@ -1,31 +1,45 @@
using System;
using System.Collections.Generic;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
namespace Content.Shared.Chemistry.Reaction
namespace Content.Shared.Chemistry.Reaction;
[RegisterComponent]
public class ReactiveComponent : Component
{
[RegisterComponent]
public class ReactiveComponent : Component
{
public override string Name => "Reactive";
public override string Name => "Reactive";
[DataField("reactions", required: true, readOnly: true, serverOnly: true)]
public List<ReactiveReagentEffectEntry> Reactions { get; } = default!;
}
/// <summary>
/// A dictionary of reactive groups -> methods that work on them.
/// </summary>
[DataField("groups", readOnly: true, serverOnly: true,
customTypeSerializer:
typeof(PrototypeIdDictionarySerializer<HashSet<ReactionMethod>, ReactiveGroupPrototype>))]
public Dictionary<string, HashSet<ReactionMethod>>? ReactiveGroups;
[DataDefinition]
public class ReactiveReagentEffectEntry
{
[DataField("methods")]
public HashSet<ReactionMethod> Methods = default!;
[DataField("reagents", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<ReagentPrototype>))]
public HashSet<string>? Reagents = null;
[DataField("effects", required: true)]
public List<ReagentEffect> Effects = default!;
}
/// <summary>
/// Special reactions that this prototype can specify, outside of any that reagents already apply.
/// Useful for things like monkey cubes, which have a really prototype-specific effect.
/// </summary>
[DataField("reactions", true, serverOnly: true)]
public List<ReactiveReagentEffectEntry>? Reactions;
}
[DataDefinition]
public class ReactiveReagentEffectEntry
{
[DataField("methods")]
public HashSet<ReactionMethod> Methods = default!;
[DataField("reagents", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<ReagentPrototype>))]
public HashSet<string>? Reagents = null;
[DataField("effects", required: true)]
public List<ReagentEffect> Effects = default!;
[DataField("groups", required: true, readOnly: true, serverOnly: true,
customTypeSerializer:typeof(PrototypeIdDictionarySerializer<HashSet<ReactionMethod>, ReactiveGroupPrototype>))]
public Dictionary<string, HashSet<ReactionMethod>> ReactiveGroups { get; } = default!;
}

View File

@@ -0,0 +1,11 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Shared.Chemistry.Reaction;
[Prototype("reactiveGroup")]
public class ReactiveGroupPrototype : IPrototype
{
[DataField("id", required: true)]
public string ID { get; } = default!;
}

View File

@@ -11,7 +11,7 @@ using Robust.Shared.Random;
namespace Content.Shared.Chemistry
{
[UsedImplicitly]
public partial class ChemistrySystem : EntitySystem
public class ReactiveSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
@@ -40,20 +40,48 @@ namespace Content.Shared.Chemistry
var args = new ReagentEffectArgs(uid, null, source, reagent,
source?.GetReagentQuantity(reagent.ID) ?? reactVolume, EntityManager, method);
foreach (var entry in reactive.Reactions)
// First, check if the reagent wants to apply any effects.
if (reagent.ReactiveEffects != null && reactive.ReactiveGroups != null)
{
if (!entry.Methods.Contains(method))
continue;
if (entry.Reagents != null && !entry.Reagents.Contains(reagent.ID))
continue;
foreach (var effect in entry.Effects)
foreach (var (key, val) in reagent.ReactiveEffects)
{
if (!effect.ShouldApply(args, _robustRandom))
if (!val.Methods.Contains(method))
continue;
effect.Effect(args);
if (!reactive.ReactiveGroups.ContainsKey(key))
continue;
if (!reactive.ReactiveGroups[key].Contains(method))
continue;
foreach (var effect in val.Effects)
{
if (!effect.ShouldApply(args, _robustRandom))
continue;
effect.Effect(args);
}
}
}
// Then, check if the prototype has any effects it can apply as well.
if (reactive.Reactions != null)
{
foreach (var entry in reactive.Reactions)
{
if (!entry.Methods.Contains(method))
continue;
if (entry.Reagents != null && !entry.Reagents.Contains(reagent.ID))
continue;
foreach (var effect in entry.Effects)
{
if (!effect.ShouldApply(args, _robustRandom))
continue;
effect.Effect(args);
}
}
}
}

View File

@@ -23,15 +23,6 @@ namespace Content.Shared.Chemistry.Reagent
[DataDefinition]
public class ReagentPrototype : IPrototype, IInheritingPrototype
{
[DataField("metabolisms", serverOnly: true, customTypeSerializer: typeof(PrototypeIdDictionarySerializer<ReagentEffectsEntry, MetabolismGroupPrototype>))]
public Dictionary<string, ReagentEffectsEntry>? Metabolisms = null;
[DataField("tileReactions", serverOnly: true)]
private readonly List<ITileReaction> _tileReactions = new(0);
[DataField("plantMetabolism", serverOnly: true)]
private readonly List<ReagentEffect> _plantMetabolism = new(0);
[ViewVariables]
[DataField("id", required: true)]
public string ID { get; } = default!;
@@ -64,9 +55,17 @@ namespace Content.Shared.Chemistry.Reagent
[DataField("spritePath")]
public string SpriteReplacementPath { get; } = string.Empty;
//List of metabolism effects this reagent has, should really only be used server-side.
public IReadOnlyList<ITileReaction> TileReactions => _tileReactions;
public IReadOnlyList<ReagentEffect> PlantMetabolism => _plantMetabolism;
[DataField("metabolisms", serverOnly: true, customTypeSerializer: typeof(PrototypeIdDictionarySerializer<ReagentEffectsEntry, MetabolismGroupPrototype>))]
public Dictionary<string, ReagentEffectsEntry>? Metabolisms = null;
[DataField("reactiveEffects", serverOnly: true, customTypeSerializer:typeof(PrototypeIdDictionarySerializer<ReactiveReagentEffectEntry, ReactiveGroupPrototype>))]
public Dictionary<string, ReactiveReagentEffectEntry>? ReactiveEffects = null;
[DataField("tileReactions", serverOnly: true)]
public readonly List<ITileReaction> TileReactions = new(0);
[DataField("plantMetabolism", serverOnly: true)]
public readonly List<ReagentEffect> PlantMetabolisms = new(0);
/// <summary>
/// If the substance color is too dark we user a lighter version to make the text color readable when the user examines a solution.
@@ -93,7 +92,7 @@ namespace Content.Shared.Chemistry.Reagent
if (tile.Tile.IsEmpty)
return removed;
foreach (var reaction in _tileReactions)
foreach (var reaction in TileReactions)
{
removed += reaction.TileReact(tile, this, reactVolume - removed);
@@ -115,7 +114,7 @@ namespace Content.Shared.Chemistry.Reagent
var entMan = IoCManager.Resolve<IEntityManager>();
var random = IoCManager.Resolve<IRobustRandom>();
var args = new ReagentEffectArgs(plantHolder.Value, null, solution, this, amount.Quantity, entMan, null);
foreach (var plantMetabolizable in _plantMetabolism)
foreach (var plantMetabolizable in PlantMetabolisms)
{
if (!plantMetabolizable.ShouldApply(args, random))
continue;
@@ -140,4 +139,14 @@ namespace Content.Shared.Chemistry.Reagent
[DataField("effects", required: true)]
public ReagentEffect[] Effects = default!;
}
[DataDefinition]
public class ReactiveReagentEffectEntry
{
[DataField("methods", required: true)]
public HashSet<ReactionMethod> Methods = default!;
[DataField("effects", required: true)]
public ReagentEffect[] Effects = default!;
}
}