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

@@ -37,7 +37,7 @@ namespace Content.Server.Chemistry.Components
internals.AreInternalsWorking()) internals.AreInternalsWorking())
return; return;
var chemistry = EntitySystem.Get<ChemistrySystem>(); var chemistry = EntitySystem.Get<ReactiveSystem>();
var cloneSolution = solution.Clone(); var cloneSolution = solution.Clone();
var transferAmount = FixedPoint2.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.EmptyVolume); var transferAmount = FixedPoint2.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.EmptyVolume);
var transferSolution = cloneSolution.SplitSolution(transferAmount); var transferSolution = cloneSolution.SplitSolution(transferAmount);

View File

@@ -126,7 +126,7 @@ namespace Content.Server.Chemistry.Components
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner.Uid, SolutionName, out var solution)) if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner.Uid, SolutionName, out var solution))
return; return;
var chemistry = EntitySystem.Get<ChemistrySystem>(); var chemistry = EntitySystem.Get<ReactiveSystem>();
var mapGrid = MapManager.GetGrid(Owner.Transform.GridID); var mapGrid = MapManager.GetGrid(Owner.Transform.GridID);
var tile = mapGrid.GetTileRef(Owner.Transform.Coordinates.ToVector2i(Owner.EntityManager, MapManager)); var tile = mapGrid.GetTileRef(Owner.Transform.Coordinates.ToVector2i(Owner.EntityManager, MapManager));

View File

@@ -17,7 +17,7 @@ namespace Content.Server.Nutrition.EntitySystems
{ {
public partial class SmokingSystem : EntitySystem public partial class SmokingSystem : EntitySystem
{ {
[Dependency] private readonly ChemistrySystem _chemistrySystem = default!; [Dependency] private readonly ReactiveSystem _reactiveSystem = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
private const float UpdateTimer = 3f; private const float UpdateTimer = 3f;
@@ -98,7 +98,7 @@ namespace Content.Server.Nutrition.EntitySystems
!containerManager.Owner.TryGetComponent(out BloodstreamComponent? bloodstream)) !containerManager.Owner.TryGetComponent(out BloodstreamComponent? bloodstream))
continue; continue;
_chemistrySystem.ReactionEntity(containerManager.Owner.Uid, ReactionMethod.Ingestion, inhaledSolution); _reactiveSystem.ReactionEntity(containerManager.Owner.Uid, ReactionMethod.Ingestion, inhaledSolution);
bloodstream.TryTransferSolution(inhaledSolution); bloodstream.TryTransferSolution(inhaledSolution);
} }

View File

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

View File

@@ -1,31 +1,45 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Shared.Chemistry.Reagent; using Content.Shared.Chemistry.Reagent;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; 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 override string Name => "Reactive";
public class ReactiveComponent : Component
{
public override string Name => "Reactive";
[DataField("reactions", required: true, readOnly: true, serverOnly: true)] /// <summary>
public List<ReactiveReagentEffectEntry> Reactions { get; } = default!; /// 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] /// <summary>
public class ReactiveReagentEffectEntry /// 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.
[DataField("methods")] /// </summary>
public HashSet<ReactionMethod> Methods = default!; [DataField("reactions", true, serverOnly: true)]
public List<ReactiveReagentEffectEntry>? Reactions;
[DataField("reagents", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<ReagentPrototype>))] }
public HashSet<string>? Reagents = null;
[DataDefinition]
[DataField("effects", required: true)] public class ReactiveReagentEffectEntry
public List<ReagentEffect> Effects = default!; {
} [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 namespace Content.Shared.Chemistry
{ {
[UsedImplicitly] [UsedImplicitly]
public partial class ChemistrySystem : EntitySystem public class ReactiveSystem : EntitySystem
{ {
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!;
@@ -40,20 +40,48 @@ namespace Content.Shared.Chemistry
var args = new ReagentEffectArgs(uid, null, source, reagent, var args = new ReagentEffectArgs(uid, null, source, reagent,
source?.GetReagentQuantity(reagent.ID) ?? reactVolume, EntityManager, method); 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)) foreach (var (key, val) in reagent.ReactiveEffects)
continue;
if (entry.Reagents != null && !entry.Reagents.Contains(reagent.ID))
continue;
foreach (var effect in entry.Effects)
{ {
if (!effect.ShouldApply(args, _robustRandom)) if (!val.Methods.Contains(method))
continue; 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] [DataDefinition]
public class ReagentPrototype : IPrototype, IInheritingPrototype 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] [ViewVariables]
[DataField("id", required: true)] [DataField("id", required: true)]
public string ID { get; } = default!; public string ID { get; } = default!;
@@ -64,9 +55,17 @@ namespace Content.Shared.Chemistry.Reagent
[DataField("spritePath")] [DataField("spritePath")]
public string SpriteReplacementPath { get; } = string.Empty; public string SpriteReplacementPath { get; } = string.Empty;
//List of metabolism effects this reagent has, should really only be used server-side. [DataField("metabolisms", serverOnly: true, customTypeSerializer: typeof(PrototypeIdDictionarySerializer<ReagentEffectsEntry, MetabolismGroupPrototype>))]
public IReadOnlyList<ITileReaction> TileReactions => _tileReactions; public Dictionary<string, ReagentEffectsEntry>? Metabolisms = null;
public IReadOnlyList<ReagentEffect> PlantMetabolism => _plantMetabolism;
[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> /// <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. /// 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) if (tile.Tile.IsEmpty)
return removed; return removed;
foreach (var reaction in _tileReactions) foreach (var reaction in TileReactions)
{ {
removed += reaction.TileReact(tile, this, reactVolume - removed); removed += reaction.TileReact(tile, this, reactVolume - removed);
@@ -115,7 +114,7 @@ namespace Content.Shared.Chemistry.Reagent
var entMan = IoCManager.Resolve<IEntityManager>(); var entMan = IoCManager.Resolve<IEntityManager>();
var random = IoCManager.Resolve<IRobustRandom>(); var random = IoCManager.Resolve<IRobustRandom>();
var args = new ReagentEffectArgs(plantHolder.Value, null, solution, this, amount.Quantity, entMan, null); 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)) if (!plantMetabolizable.ShouldApply(args, random))
continue; continue;
@@ -140,4 +139,14 @@ namespace Content.Shared.Chemistry.Reagent
[DataField("effects", required: true)] [DataField("effects", required: true)]
public ReagentEffect[] Effects = default!; 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!;
}
} }

View File

@@ -0,0 +1,5 @@
- type: reactiveGroup
id: Flammable
- type: reactiveGroup
id: Extinguish

View File

@@ -5,15 +5,9 @@
suffix: AI suffix: AI
components: components:
- type: Reactive - type: Reactive
reactions: groups:
- reagents: [Water] Flammable: [Touch]
methods: [Touch] Extinguish: [Touch]
effects:
- !type:ExtinguishReaction
- reagents: [WeldingFuel, Thermite, Plasma, Ethanol]
methods: [Touch]
effects:
- !type:FlammableReaction
- type: UtilityAI - type: UtilityAI
behaviorSets: behaviorSets:
# - Clothing # - Clothing

View File

@@ -11,15 +11,10 @@
- CanPilot - CanPilot
- FootstepSound - FootstepSound
- type: Reactive - type: Reactive
groups:
Flammable: [ Touch ]
Extinguish: [ Touch ]
reactions: reactions:
- reagents: [Water]
methods: [Touch]
effects:
- !type:ExtinguishReaction
- reagents: [WeldingFuel, Thermite, Plasma, Ethanol]
methods: [Touch]
effects:
- !type:FlammableReaction
- reagents: [Water, SpaceCleaner] - reagents: [Water, SpaceCleaner]
methods: [Touch] methods: [Touch]
effects: effects:

View File

@@ -60,14 +60,12 @@
- type: reagent - type: reagent
id: Ethanol id: Ethanol
name: ethanol name: ethanol
parent: BaseAlcohol
desc: A simple alcohol, makes you drunk if consumed, flammable. desc: A simple alcohol, makes you drunk if consumed, flammable.
physicalDesc: strong-smelling physicalDesc: strong-smelling
color: "#b05b3c" color: "#b05b3c"
boilingPoint: 78.2 boilingPoint: 78.2
meltingPoint: -114.1 meltingPoint: -114.1
tileReactions:
- !type:FlammableTileReaction
temperatureMultiplier: 1.35
metabolisms: metabolisms:
Poison: Poison:
effects: effects:

View File

@@ -6,6 +6,11 @@
effects: effects:
- !type:SatiateThirst - !type:SatiateThirst
factor: 3 factor: 3
reactiveEffects:
Extinguish:
methods: [ Touch ]
effects:
- !type:ExtinguishReaction
plantMetabolism: plantMetabolism:
- !type:PlantAdjustWater - !type:PlantAdjustWater
amount: 1 amount: 1
@@ -38,6 +43,11 @@
effects: effects:
- !type:SatiateThirst - !type:SatiateThirst
factor: 2 factor: 2
reactiveEffects:
Flammable:
methods: [ Touch ]
effects:
- !type:FlammableReaction
tileReactions: tileReactions:
- !type:FlammableTileReaction - !type:FlammableTileReaction
temperatureMultiplier: 1.35 temperatureMultiplier: 1.35

View File

@@ -1,6 +1,15 @@
- type: reagent - type: reagent
id: BasePyrotechnic
reactiveEffects:
Flammable:
methods: [ Touch ]
effects:
- !type:FlammableReaction
- type: reagent
id: Thermite id: Thermite
name: thermite name: thermite
parent: BasePyrotechnic
desc: A mixture that becomes extremely hot when ignited, and which can burn straight through walls when applied and ignited. It'll slowly inflict burn damage to anybody dumb enough to ingest it, but can't be ignited inside inside said dumb person. desc: A mixture that becomes extremely hot when ignited, and which can burn straight through walls when applied and ignited. It'll slowly inflict burn damage to anybody dumb enough to ingest it, but can't be ignited inside inside said dumb person.
physicalDesc: grainy physicalDesc: grainy
color: "#757245" color: "#757245"
@@ -20,6 +29,7 @@
- type: reagent - type: reagent
id: FoamingAgent id: FoamingAgent
name: foaming agent name: foaming agent
parent: BasePyrotechnic
desc: Makes foam such as that's required in metal foam grenades. desc: Makes foam such as that's required in metal foam grenades.
physicalDesc: foamy physicalDesc: foamy
color: "#215263" color: "#215263"
@@ -29,6 +39,7 @@
- type: reagent - type: reagent
id: WeldingFuel id: WeldingFuel
name: welding fuel name: welding fuel
parent: BasePyrotechnic
desc: Used by welders to weld. desc: Used by welders to weld.
physicalDesc: oily physicalDesc: oily
color: "#a76b1c" color: "#a76b1c"
@@ -40,6 +51,7 @@
- type: reagent - type: reagent
id: Fluorosurfactant id: Fluorosurfactant
name: fluorosurfactant name: fluorosurfactant
parent: BasePyrotechnic
desc: A perfluoronated sulfonic acid that forms a foam when mixed with water. desc: A perfluoronated sulfonic acid that forms a foam when mixed with water.
physicalDesc: opaque physicalDesc: opaque
color: "#9e6b38" color: "#9e6b38"

View File

@@ -115,6 +115,11 @@
- !type:RemoveReagent - !type:RemoveReagent
reagent: Inaprovaline reagent: Inaprovaline
amount: 2 amount: 2
reactiveEffects:
Flammable:
methods: [ Touch ]
effects:
- !type:FlammableReaction
- type: reagent - type: reagent
id: UnstableMutagen id: UnstableMutagen