Refactor ExaminableDamage (#38978)

* Remove prototype caching in ExaminableDamageComponent

* Replace ExaminableDamagePrototype with LocalizedDatasetPrototype

* Allow null
This commit is contained in:
Tayrtahn
2025-07-14 00:35:47 -04:00
committed by GitHub
parent bd2212beff
commit 4f766f199c
4 changed files with 34 additions and 77 deletions

View File

@@ -1,5 +1,5 @@
using Content.Shared.Damage.Prototypes; using Content.Shared.Dataset;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Prototypes;
namespace Content.Server.Damage.Components; namespace Content.Server.Damage.Components;
@@ -9,8 +9,10 @@ namespace Content.Server.Damage.Components;
[RegisterComponent] [RegisterComponent]
public sealed partial class ExaminableDamageComponent : Component public sealed partial class ExaminableDamageComponent : Component
{ {
[DataField("messages", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<ExaminableDamagePrototype>))] /// <summary>
public string? MessagesProtoId; /// ID of the <see cref="LocalizedDatasetPrototype"/> containing messages to display a different damage levels.
/// The first message will be used at 0 damage with the others equally distributed across the range from undamaged to fully damaged.
public ExaminableDamagePrototype? MessagesProto; /// </summary>
[DataField]
public ProtoId<LocalizedDatasetPrototype>? Messages;
} }

View File

@@ -1,9 +1,6 @@
using System.Linq; using Content.Server.Damage.Components;
using Content.Server.Damage.Components;
using Content.Server.Destructible; using Content.Server.Destructible;
using Content.Server.Destructible.Thresholds.Triggers;
using Content.Shared.Damage; using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Rounding; using Content.Shared.Rounding;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -12,59 +9,42 @@ namespace Content.Server.Damage.Systems;
public sealed class ExaminableDamageSystem : EntitySystem public sealed class ExaminableDamageSystem : EntitySystem
{ {
[Dependency] private readonly DestructibleSystem _destructible = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IPrototypeManager _prototype = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<ExaminableDamageComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<ExaminableDamageComponent, ExaminedEvent>(OnExamine); SubscribeLocalEvent<ExaminableDamageComponent, ExaminedEvent>(OnExamine);
} }
private void OnInit(EntityUid uid, ExaminableDamageComponent component, ComponentInit args) private void OnExamine(Entity<ExaminableDamageComponent> ent, ref ExaminedEvent args)
{ {
if (component.MessagesProtoId == null) if (!_prototype.TryIndex(ent.Comp.Messages, out var proto) || proto.Values.Count == 0)
return;
component.MessagesProto = _prototype.Index<ExaminableDamagePrototype>(component.MessagesProtoId);
}
private void OnExamine(EntityUid uid, ExaminableDamageComponent component, ExaminedEvent args)
{
if (component.MessagesProto == null)
return; return;
var messages = component.MessagesProto.Messages; var percent = GetDamagePercent(ent);
if (messages.Length == 0) var level = ContentHelpers.RoundToNearestLevels(percent, 1, proto.Values.Count - 1);
return; var msg = Loc.GetString(proto.Values[level]);
var level = GetDamageLevel(uid, component);
var msg = Loc.GetString(messages[level]);
args.PushMarkup(msg, -99); args.PushMarkup(msg, -99);
} }
private int GetDamageLevel(EntityUid uid, ExaminableDamageComponent? component = null, /// <summary>
DamageableComponent? damageable = null, DestructibleComponent? destructible = null) /// Returns a value between 0 and 1 representing how damaged the entity is,
/// where 0 is undamaged and 1 is fully damaged.
/// </summary>
/// <returns>How damaged the entity is from 0 to 1</returns>
private float GetDamagePercent(Entity<ExaminableDamageComponent> ent)
{ {
if (!Resolve(uid, ref component, ref damageable, ref destructible)) if (!TryComp<DamageableComponent>(ent, out var damageable))
return 0;
if (component.MessagesProto == null)
return 0;
var maxLevels = component.MessagesProto.Messages.Length - 1;
if (maxLevels <= 0)
return 0;
var trigger = (DamageTrigger?) destructible.Thresholds
.LastOrDefault(threshold => threshold.Trigger is DamageTrigger)?.Trigger;
if (trigger == null)
return 0; return 0;
var damage = damageable.TotalDamage; var damage = damageable.TotalDamage;
var damageThreshold = trigger.Damage; var damageThreshold = _destructible.DestroyedAt(ent);
var fraction = damageThreshold == 0 ? 0f : (float) damage / damageThreshold;
var level = ContentHelpers.RoundToNearestLevels(fraction, 1, maxLevels); if (damageThreshold == 0)
return level; return 0;
return (damage / damageThreshold).Float();
} }
} }

View File

@@ -1,21 +0,0 @@
using Robust.Shared.Prototypes;
namespace Content.Shared.Damage.Prototypes;
/// <summary>
/// Prototype for examinable damage messages.
/// </summary>
[Prototype]
public sealed partial class ExaminableDamagePrototype : IPrototype
{
[IdDataField]
public string ID { get; private set; } = default!;
/// <summary>
/// List of damage messages IDs sorted by severity.
/// First one describes fully intact entity.
/// Last one describes almost destroyed.
/// </summary>
[DataField("messages")]
public string[] Messages = {};
}

View File

@@ -1,9 +1,5 @@
- type: examinableDamage - type: localizedDataset
id: WindowMessages id: WindowMessages
messages: values:
- comp-window-damaged-1 prefix: comp-window-damaged-
- comp-window-damaged-2 count: 6
- comp-window-damaged-3
- comp-window-damaged-4
- comp-window-damaged-5
- comp-window-damaged-6