using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager; using Robust.Shared.Serialization.Markdown.Mapping; using Robust.Shared.Serialization.Markdown.Validation; using Robust.Shared.Serialization.Markdown.Value; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; using Robust.Shared.Serialization.TypeSerializers.Interfaces; namespace Content.Shared.Damage; //todo writing public sealed class DamageSpecifierDictionarySerializer : ITypeReader, MappingDataNode> { private ITypeValidator, MappingDataNode> _damageTypeSerializer = new PrototypeIdDictionarySerializer(); private ITypeValidator, MappingDataNode> _damageGroupSerializer = new PrototypeIdDictionarySerializer(); public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node, IDependencyCollection dependencies, ISerializationContext? context = null) { var vals = new Dictionary(); if (node.TryGet("types", out var typesNode)) { vals.Add(new ValidatedValueNode(new ValueDataNode("types")), _damageTypeSerializer.Validate(serializationManager, typesNode, dependencies, context)); } if (node.TryGet("groups", out var groupsNode)) { vals.Add(new ValidatedValueNode(new ValueDataNode("groups")), _damageGroupSerializer.Validate(serializationManager, groupsNode, dependencies, context)); } return new ValidatedMappingNode(vals); } public Dictionary Read(ISerializationManager serializationManager, MappingDataNode node, IDependencyCollection dependencies, SerializationHookContext hookCtx, ISerializationContext? context = null, ISerializationManager.InstantiationDelegate>? instanceProvider = null) { var dict = instanceProvider != null ? instanceProvider() : new(); // Add all the damage types by just copying the type dictionary (if it is not null). if (node.TryGet("types", out var typesNode)) { serializationManager.Read(typesNode, instanceProvider: () => dict, notNullableOverride: true); } if (!node.TryGet("groups", out var groupsNode)) return dict; // Then resolve damage groups and add them var prototypeManager = dependencies.Resolve(); foreach (var entry in serializationManager.Read>(groupsNode, notNullableOverride: true)) { if (!prototypeManager.TryIndex(entry.Key, out var group)) { // This can happen if deserialized before prototypes are loaded. // i made this a warning bc it was failing tests -paul dependencies.Resolve().RootSawmill.Error($"Unknown damage group given to DamageSpecifier: {entry.Key}"); continue; } // Simply distribute evenly (except for rounding). // We do this by reducing remaining the # of types and damage every loop. var remainingTypes = group.DamageTypes.Count; var remainingDamage = entry.Value; foreach (var damageType in group.DamageTypes) { var damage = remainingDamage / FixedPoint2.New(remainingTypes); if (!dict.TryAdd(damageType, damage)) { // Key already exists, add values dict[damageType] += damage; } remainingDamage -= damage; remainingTypes -= 1; } } return dict; } }