Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;

namespace Content.Shared._Sunrise.InteractionsPanel.Data.Conditions;

[Serializable, NetSerializable, DataDefinition]
public sealed partial class ItemCondition : IAppearCondition
{
[DataField]
public bool CheckInitiator { get; private set; } = true;

[DataField]
public bool CheckTarget { get; private set; }

[DataField]
public List<EntProtoId> ItemWhiteList { get; private set; } = new();
Comment on lines +18 to +19
Copy link
Contributor

@coderabbitai coderabbitai bot Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Пустой whitelist делает условие невыполнимым.

Если ItemWhiteList пуст (значение по умолчанию), то IsMatchingItem всегда возвращает false, и условие никогда не будет выполнено при CheckInitiator = true (также по умолчанию).

Рассмотрите добавление валидации или раннего возврата true, если whitelist пуст (если это интерпретируется как "любой предмет подходит").

💡 Возможное исправление
 private bool IsMatchingItem(EntityUid entity, EntityManager entityManager)
 {
+    // Пустой whitelist = любой предмет подходит
+    if (ItemWhiteList.Count == 0)
+        return true;
+
     if (!entityManager.TryGetComponent<MetaDataComponent>(entity, out var meta))
         return false;

     return meta.EntityPrototype != null && ItemWhiteList.Contains(meta.EntityPrototype.ID);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Content.Shared/_Sunrise/InteractionsPanel/Data/Conditions/ItemCondition.cs`
around lines 18 - 19, IsMatchingItem currently treats an empty ItemWhiteList as
non-matching which makes the condition impossible when CheckInitiator is true;
update IsMatchingItem (and any callers) so that if ItemWhiteList is null or
Count == 0 it returns true (treating an empty whitelist as "any item"), or
alternatively add validation in the ItemCondition constructor/OnDeserialize to
log/throw when ItemWhiteList is empty—preferred: implement the early-return
match inside IsMatchingItem to short-circuit and return true when ItemWhiteList
is empty to preserve expected default behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Поведение намеренное. ItemWhiteList — это вайтлист конкретных предметов, а не "наличие хоть какого-то предмета". Пустой список означает, что предметы для проверки не заданы, поэтому false — корректный результат.
Если CheckInitiator = true и ItemWhiteList пуст — это ошибка конфигурации в YAML, а не баг кода.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Soragy-bot, понял, спасибо за пояснение. Согласен — если ItemWhiteList пуст, это ошибка конфигурации в YAML, а не баг кода. Поведение корректно.

(>‿‿>)


✏️ Learnings added
Learnt from: Soragy-bot
Repo: space-sunrise/sunrise-station PR: 4066
File: Content.Shared/_Sunrise/InteractionsPanel/Data/Conditions/ItemCondition.cs:18-19
Timestamp: 2026-03-18T17:27:20.984Z
Learning: In Content.Shared/_Sunrise/InteractionsPanel/Data/Conditions/ItemCondition.cs, an empty ItemWhiteList intentionally causes IsMatchingItem to return false. It is a whitelist of specific items, not a "any item present" check. An empty ItemWhiteList combined with CheckInitiator=true is considered a YAML configuration error, not a code bug.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: kanopus952
Repo: space-sunrise/sunrise-station PR: 3973
File: Content.Server/_Sunrise/StationEvents/Components/ResearchPointVirusRuleComponent.cs:1-10
Timestamp: 2026-03-09T11:33:51.097Z
Learning: In C# projects using global using directives, attributes and types from Robust.Shared.Analyzers are accessible without per-file using statements when the corresponding global usings are configured (as in Content.Server/GlobalUsings.cs, Content.Shared/GlobalUsings.cs, Content.Client/GlobalUsings.cs). Do not add an explicit 'using Robust.Shared.Analyzers;' to individual files like Content.Server/_Sunrise/StationEvents/Components/ResearchPointVirusRuleComponent.cs unless a file outside the existing global usings context requires a separate import. Apply this guidance to all C# files; verify global usings cover the needed symbol in any new file.


[DataField]
public bool CheckEquipped { get; private set; }

[DataField]
public List<string> EquipmentSlots { get; private set; } = new();

public bool IsMet(EntityUid initiator, EntityUid target, EntityManager entityManager)
{
var handsSystem = entityManager.EntitySysManager.GetEntitySystem<SharedHandsSystem>();

if (CheckInitiator)
{
if (!HasRequiredItem(initiator, entityManager, handsSystem))
return false;
}

if (CheckTarget)
{
if (!HasRequiredItem(target, entityManager, handsSystem))
return false;
}

return true;
}

private bool HasRequiredItem(EntityUid entity, EntityManager entityManager, SharedHandsSystem handsSystem)
{
if (entityManager.TryGetComponent<HandsComponent>(entity, out var handsComponent))
{
foreach (var heldEntity in handsSystem.EnumerateHeld((entity, handsComponent)))
{
if (IsMatchingItem(heldEntity, entityManager))
return true;
}
}

if (CheckEquipped && entityManager.TryGetComponent<ContainerManagerComponent>(entity, out var containerManager))
{
foreach (var (key, container) in containerManager.Containers)
{
if (EquipmentSlots.Count > 0 && !EquipmentSlots.Contains(key))
continue;

foreach (var containedEntity in container.ContainedEntities)
{
if (IsMatchingItem(containedEntity, entityManager))
return true;
}
}
}

return false;
}

private bool IsMatchingItem(EntityUid entity, EntityManager entityManager)
{
if (!entityManager.TryGetComponent<MetaDataComponent>(entity, out var meta))
return false;

return meta.EntityPrototype != null && ItemWhiteList.Contains(meta.EntityPrototype.ID);
}
}
Loading