NPCSystem.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. using System.Diagnostics.CodeAnalysis;
  2. using Content.Server.NPC.Components;
  3. using Content.Server.NPC.HTN;
  4. using Content.Shared.CCVar;
  5. using Content.Shared.Mind;
  6. using Content.Shared.Mind.Components;
  7. using Content.Shared.Mobs;
  8. using Content.Shared.Mobs.Systems;
  9. using Content.Shared.NPC;
  10. using Content.Shared.NPC.Systems;
  11. using Robust.Server.GameObjects;
  12. using Robust.Shared.Configuration;
  13. using Robust.Shared.Player;
  14. namespace Content.Server.NPC.Systems
  15. {
  16. /// <summary>
  17. /// Handles NPCs running every tick.
  18. /// </summary>
  19. public sealed partial class NPCSystem : EntitySystem
  20. {
  21. [Dependency] private readonly IConfigurationManager _configurationManager = default!;
  22. [Dependency] private readonly HTNSystem _htn = default!;
  23. [Dependency] private readonly MobStateSystem _mobState = default!;
  24. /// <summary>
  25. /// Whether any NPCs are allowed to run at all.
  26. /// </summary>
  27. public bool Enabled { get; set; } = true;
  28. private int _maxUpdates;
  29. private int _count;
  30. /// <inheritdoc />
  31. public override void Initialize()
  32. {
  33. base.Initialize();
  34. Subs.CVar(_configurationManager, CCVars.NPCEnabled, value => Enabled = value, true);
  35. Subs.CVar(_configurationManager, CCVars.NPCMaxUpdates, obj => _maxUpdates = obj, true);
  36. }
  37. public void OnPlayerNPCAttach(EntityUid uid, HTNComponent component, PlayerAttachedEvent args)
  38. {
  39. SleepNPC(uid, component);
  40. }
  41. public void OnPlayerNPCDetach(EntityUid uid, HTNComponent component, PlayerDetachedEvent args)
  42. {
  43. if (_mobState.IsIncapacitated(uid) || TerminatingOrDeleted(uid))
  44. return;
  45. // This NPC has an attached mind, so it should not wake up.
  46. if (TryComp<MindContainerComponent>(uid, out var mindContainer) && mindContainer.HasMind)
  47. return;
  48. WakeNPC(uid, component);
  49. }
  50. public void OnNPCMapInit(EntityUid uid, HTNComponent component, MapInitEvent args)
  51. {
  52. component.Blackboard.SetValue(NPCBlackboard.Owner, uid);
  53. WakeNPC(uid, component);
  54. }
  55. public void OnNPCShutdown(EntityUid uid, HTNComponent component, ComponentShutdown args)
  56. {
  57. SleepNPC(uid, component);
  58. }
  59. /// <summary>
  60. /// Is the NPC awake and updating?
  61. /// </summary>
  62. public bool IsAwake(EntityUid uid, HTNComponent component, ActiveNPCComponent? active = null)
  63. {
  64. return Resolve(uid, ref active, false);
  65. }
  66. public bool TryGetNpc(EntityUid uid, [NotNullWhen(true)] out NPCComponent? component)
  67. {
  68. // If you add your own NPC components then add them here.
  69. if (TryComp<HTNComponent>(uid, out var htn))
  70. {
  71. component = htn;
  72. return true;
  73. }
  74. component = null;
  75. return false;
  76. }
  77. /// <summary>
  78. /// Allows the NPC to actively be updated.
  79. /// </summary>
  80. public void WakeNPC(EntityUid uid, HTNComponent? component = null)
  81. {
  82. if (!Resolve(uid, ref component, false))
  83. {
  84. return;
  85. }
  86. Log.Debug($"Waking {ToPrettyString(uid)}");
  87. EnsureComp<ActiveNPCComponent>(uid);
  88. }
  89. public void SleepNPC(EntityUid uid, HTNComponent? component = null)
  90. {
  91. if (!Resolve(uid, ref component, false))
  92. {
  93. return;
  94. }
  95. // Don't bother with an event
  96. if (TryComp<HTNComponent>(uid, out var htn))
  97. {
  98. if (htn.Plan != null)
  99. {
  100. var currentOperator = htn.Plan.CurrentOperator;
  101. _htn.ShutdownTask(currentOperator, htn.Blackboard, HTNOperatorStatus.Failed);
  102. _htn.ShutdownPlan(htn);
  103. htn.Plan = null;
  104. }
  105. }
  106. Log.Debug($"Sleeping {ToPrettyString(uid)}");
  107. RemComp<ActiveNPCComponent>(uid);
  108. }
  109. /// <inheritdoc />
  110. public override void Update(float frameTime)
  111. {
  112. base.Update(frameTime);
  113. if (!Enabled)
  114. return;
  115. _count = 0;
  116. // Add your system here.
  117. _htn.UpdateNPC(ref _count, _maxUpdates, frameTime);
  118. }
  119. public void OnMobStateChange(EntityUid uid, HTNComponent component, MobStateChangedEvent args)
  120. {
  121. if (HasComp<ActorComponent>(uid))
  122. return;
  123. switch (args.NewMobState)
  124. {
  125. case MobState.Alive:
  126. WakeNPC(uid, component);
  127. break;
  128. case MobState.Critical:
  129. case MobState.Dead:
  130. SleepNPC(uid, component);
  131. break;
  132. }
  133. }
  134. }
  135. }