Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughДобавлен обширный набор клиентских и серверных механик для андроидов: клиентские визуализаторы и оверлеи (AndroidOverlay, AndroidOverlaySystem, AndroidOverlayComponent, AndroidDisguiseVisualizerSystem, AndroidOverlay), несколько Bound UI (согласие на девиантность, имя маски, очистка памяти, выбор девианта), серверная логика стресса и девиантности (AndroidStressSystem, AndroidDeviantSpreadSystem, AndroidDeviantAntagSystem), механики диода и его резки (AndroidDiodeSystem, AndroidDiodeComponent), очистки памяти RK800 (AndroidMemoryWipeSystem и связанные компоненты/DoAfter/сообщения), раскрытия маскировки (AndroidRevealSystem), управление энергией (AndroidEnergySystem), новые компоненты, DoAfter‑события, прототипы, локализации и текстуры. Sequence Diagram(s)sequenceDiagram
participant Player as Игрок (конвертер)
participant System as AndroidDeviantSpreadSystem
participant UI as Consent UI
participant Target as Цель (андроид)
participant DoAfter as DoAfter System
Player->>System: RequestConsentConversion()
System->>System: Проверка условий (дистанция, статусы, cooldown)
System->>UI: Открыть AndroidDeviantConsentBuiState(ConverterName)
UI->>Player: Показ окна согласия
Player->>UI: Отправить AndroidDeviantConsentChoiceMessage(accepted)
UI->>System: Передача выбора
alt Принято
System->>System: Инициализация согласия, popup подтверждения
System->>DoAfter: Запустить AndroidDeviantSpreadDoAfterEvent (ConversionDuration)
DoAfter->>System: DoAfter завершён
System->>Target: Установить IsDeviant = true, убрать состояние согласия
else Отклонено
System->>Target: Установить DenyCooldown
System->>System: Удалить состояние согласия
end
sequenceDiagram
participant RK800 as RK800 (исполнитель)
participant System as AndroidMemoryWipeSystem
participant Target as Цель (андроид)
participant DoAfter as DoAfter System
participant UI as MemoryWipe UI
RK800->>System: StartMemoryWipe(user, target, rk800)
System->>System: Валидация (права, статусы, дистанция)
System->>Target: Добавить AndroidMemoryWipeInProgressComponent, блок движ.
System->>DoAfter: Запустить AndroidMemoryWipeDoAfterEvent (duration)
System->>RK800: Показать popup старта
par Цель двигается
Target->>System: MoveInputEvent
System->>DoAfter: Запустить AndroidMemoryWipeEscapeDoAfterEvent
DoAfter->>System: Escape завершён
System->>RK800: Показать popup побега, снять состояние
and Цель не двигается (DoAfter завершён)
DoAfter->>System: DoAfter завершён
System->>Target: Сброс стресса, смена ролей/каналов при необходимости
System->>Target: Добавить AndroidMemoryWipeResultComponent
System->>UI: Открыть подтверждение результата у владельца
end
sequenceDiagram
participant RK as RK800
participant System as AndroidRevealSystem
participant Target as Маскирующийся андроид
participant DoAfter as DoAfter System
RK->>System: GetVerbs -> выбрать Reveal
System->>System: Валидация (диод, маскировка, состояние)
System->>Target: Добавить AndroidForcedRevealComponent, блок движ.
System->>DoAfter: Запустить AndroidRevealDisguiseDoAfterEvent (duration)
par Цель пытается бежать
Target->>System: MoveInputEvent
System->>DoAfter: Запустить AndroidRevealEscapeDoAfterEvent
DoAfter->>System: Escape завершён -> показать popup, снять состояние
and Reveal DoAfter завершился
DoAfter->>System: Завершение reveal
System->>Target: Установить состояние TransformingToAndroid, убрать AndroidForcedRevealComponent
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 минут 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 38
🤖 Fix all issues with AI agents
In `@Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.cs`:
- Around line 67-91: В методе SetHumanoidVisible замените 20 ручных вызовов
_sprite.LayerSetVisible на итерацию по значениям enum HumanoidVisualLayers
(через Enum.GetValues / Enum.GetValues<HumanoidVisualLayers>()), приводя
значение к нужному типу и передавая spriteEnt и visible в
_sprite.LayerSetVisible; при этом явно пропустите (фильтруйте) любые слои,
которые не должны управляться здесь (если есть исключения), чтобы будущие
добавления в enum автоматически обрабатывались.
- Line 11: Класс AndroidDisguiseVisualizerSystem объявлен как "sealed class" но
должен быть "sealed partial class" чтобы соответствовать conventions и работать
с генераторами (как AndroidOverlaySystem в том же PR); обновите объявление
класса AndroidDisguiseVisualizerSystem, добавив ключевое слово partial в
сигнатуру класса.
In `@Content.Client/Imperial/XxRaay/Android/AndroidOverlaySystem.cs`:
- Around line 28-33: Shutdown currently calls
_overlayMgr.RemoveOverlay<AndroidOverlay>() and then sets _overlay = null, which
is inconsistent with the private RemoveOverlay() helper that removes by instance
and null-checks; change Shutdown to call the instance-based RemoveOverlay()
helper (the private RemoveOverlay() method) instead of
RemoveOverlay<AndroidOverlay>(), and remove the manual _overlay = null
assignment so the helper handles removal and nulling of _overlay (ensure you
continue to call base.Shutdown()).
In `@Content.Client/Imperial/XxRaay/Android/Overlays/AndroidOverlay.cs`:
- Around line 124-125: Замените захардкоженные "магические" числа в new
Vector2(16f, -6f) на понятное именованное поле: добавьте в класс приватное
статическое поле вроде private static readonly Vector2 LabelTextOffset = new
Vector2(16f, -6f) и используйте его вместо textOffset при вызове
screenHandle.DrawString(_font, screenPos + textOffset, name, Color.Cyan);
обновите все упоминания переменной textOffset в методе/классе на новое поле для
читаемости и простоты правок.
- Around line 89-100: AABB is built at localPos (calculated from coords.Position
and invMatrix) so the icon is centered on the entity; shift localPos upward
before constructing aabb/Box2Rotated to draw the icon above the sprite. Modify
the block that computes localPos, aabb and box in AndroidOverlay.cs: compute a
shifted position (e.g., localPosShifted = localPos + new Vector2(0,
-verticalOffset)) using a suitable verticalOffset (for example based on
_iconScale or sprite half-height), then use localPosShifted when creating the
Box2 and Box2Rotated (and for box origin) so DrawTextureRect renders the icon
above the entity instead of centered.
- Around line 65-101: DrawWorld currently calls
ParseSpriteSpecifier(_iconSprite) and _sprites.Frame0(...) on every frame; cache
the resulting texture by adding a readonly/lazy field (e.g., _iconTexture) on
the class and initialize it once (preferably in the class constructor or an
initialized lazy property) using ParseSpriteSpecifier(_iconSprite) and
_sprites.Frame0(...), then replace the per-frame calls in DrawWorld with the
cached _iconTexture to avoid repeated parsing/loading.
- Around line 104-127: Both DrawWorld and DrawScreen duplicate the same
EntityQueryEnumerator/filters over AndroidStressComponent and DrawScreen calls
the transform twice; refactor by extracting the shared filtering into a helper
(e.g., GetVisibleAndroidEntities or EnumerateFilteredAndroids) that performs the
EntityQueryEnumerator and returns the filtered uids and their MapCoordinates,
then update DrawWorld and DrawScreen to use that single helper to avoid two full
passes; in DrawScreen replace the GetWorldPosition(uid) call with
coords.Position from GetMapCoordinates to eliminate the second transform lookup
and use the returned coords for map check and rendering.
- Around line 76-84: DrawWorld currently iterates all entities from
_entManager.EntityQueryEnumerator<AndroidStressComponent>() and skips only by
player and MapId; add a bounds check using args.WorldBounds to early-continue
for entities outside the viewport: after obtaining coords via
_xforms.GetMapCoordinates(uid) and verifying coords.MapId == args.MapId, test
whether coords (or coords.Position) falls inside args.WorldBounds and if not
continue; update the loop in DrawWorld so only entities whose coordinates
intersect args.WorldBounds are processed to avoid rendering/perf for offscreen
AndroidStressComponent instances.
In `@Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs`:
- Around line 85-88: Удалите лишнее переопределение метода UpdateState в классе
AndroidDisguiseNameUserInterface: текущий метод только вызывает
base.UpdateState(state) и не добавляет логики, поэтому удалите сам метод
(переопределение UpdateState) чтобы упростить код и избежать пустых оболочек.
- Around line 90-93: The OnAcceptPressed method currently sends the raw name via
AndroidDisguiseNameChosenMessage and closes the UI; add client-side validation
to trim the input and ensure it is not null/empty or only whitespace before
sending: if the trimmed name is invalid, do not call SendMessage or
Close—instead surface a UX response (e.g., show an inline error, enable error
label, or keep the dialog open) so the user can correct it; if valid, proceed to
SendMessage(new AndroidDisguiseNameChosenMessage(trimmedName)) and Close().
- Around line 101-114: Метод Dispose в классе AndroidDisguiseNameUserInterface
нарушает шаблон — текущий ранний return при !disposing предотвращает вызов
base.Dispose(disposing); исправьте метод так, чтобы base.Dispose(disposing)
вызывался безусловно (до любой проверки disposing), а затем при disposing ==
true отписывайте обработчики _window.AcceptPressed/DeclinePressed и обнуляйте
_window; сохраняйте имена методов/полей: Dispose(bool disposing), _window,
OnAcceptPressed, OnDeclinePressed и вызов base.Dispose(disposing).
In `@Content.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.cs`:
- Around line 89-92: Пустое переопределение метода
UpdateState(BoundUserInterfaceState state) в классе
AndroidMemoryWipeUserInterface просто вызывает base.UpdateState(state) и должно
быть удалено; откройте класс AndroidMemoryWipeUserInterface, удалите весь метод
public/protected override UpdateState(BoundUserInterfaceState state) и оставьте
базовую реализацию, убедившись, что нет дополнительной логики или зависимостей
внутри этого метода перед удаления.
In
`@Content.Client/Imperial/XxRaay/UI/AndroidStressDeviantChoiceUserInterface.cs`:
- Around line 1-8: The compile error is due to the missing using for the
ViewVariables attribute; add the directive "using Robust.Shared.ViewVariables;"
at the top of
Content.Client.Imperial.XxRaay.UI.AndroidStressDeviantChoiceUserInterface.cs
(matching the other files AndroidDeviantConsentUserInterface.cs /
AndroidMemoryWipeUserInterface.cs) so the [ViewVariables] attribute (used on the
AndroidStressDeviantChoiceUserInterface class/field around line 73) is resolved.
In `@Content.Server/Imperial/XxRaay/Android/AndroidDeviantSpreadSystem.cs`:
- Line 200: Методы HandleConsentAccepted и HandleConsentDenied сейчас объявлены
public, хотя используются только внутри системы (в RequestConsentConversion и
OnDeviantConsentChoice); поменяй их модификатор доступа на private для
уменьшения API-поверхности, обнови сигнатуры этих методов
(HandleConsentAccepted(EntityUid target, EntityUid converter) и
HandleConsentDenied(EntityUid target, EntityUid converter)) на private и
убедись, что внешних обращений к ним нет (вызовы остаются в
RequestConsentConversion и OnDeviantConsentChoice).
- Around line 20-32: The class body for AndroidDeviantSpreadSystem and its
[Dependency] fields are over-indented by 8 spaces; reformat the declaration
block (class opening, ConversionDuration, and all private readonly dependency
fields like _stress, _doAfter, _popup, _transform, _ui, _timing, _mobState,
_memoryWipe) to use the file's standard 4-space indentation so the class body
aligns with the rest of the file.
- Around line 99-123: Extract the nested condition block that decides whether to
add the deviant-spread verb into a single boolean helper, e.g.
CanAddSpreadVerb(EntityUid target, EntityUid user), that checks: target has
AndroidStressComponent and IsDeviant false and CanBeDeviant true; user has
AndroidStressComponent and IsDeviant true; target either lacks
AndroidDisguiseComponent or disguise.State != AndroidDisguiseState.Human; target
either lacks AndroidDeviantConsentDenyCooldownComponent or denyComp.DenyEndTime
<= _timing.CurTime; and target lacks AndroidDeviantConsentConversionComponent.
Replace the 5-level nested if in OnGetVerbs with a single call to that helper
and an early return or single if to add the Verb that calls
RequestConsentConversion(target, user).
In `@Content.Server/Imperial/XxRaay/Android/AndroidDiodeSystem.cs`:
- Around line 104-121: OnCutDoAfter currently treats args.Cancelled and
args.Handled the same and never marks successful handling; update the logic so
that if args.Cancelled is true you reset comp.IsCuttingInProgress, call
Dirty(ent, comp) and return, but if args.Handled is true you simply return
without touching comp; on successful completion (neither Cancelled nor Handled)
set comp.HasDiode = false, comp.IsCuttingInProgress = false, call Dirty(ent,
comp), set _appearance.SetData(ent, AndroidDiodeVisuals.DiodeRemoved, true) and
then set args.Handled = true on the AndroidDiodeCutDoAfterEvent to prevent
further handlers from reprocessing.
In `@Content.Server/Imperial/XxRaay/Android/AndroidDisguiseSystem.cs`:
- Around line 100-102: Метод ApplyCooldown пуст — при переключении маскировки
(вызывается из OnToggleDisguise) не устанавливается задержка, поэтому
ExtraCooldown в AndroidDisguiseComponent игнорируется; реализуй ApplyCooldown
так, чтобы он вычислял итоговый TimeSpan кулдауна (учитывая переданный
animationDuration и comp.ExtraCooldown) и вызывал _actions.SetCooldown для
соответствующего действия/пользователя, передавая полученный TimeSpan; используй
AndroidToggleDisguiseEvent и AndroidDisguiseComponent для получения
идентификаторов/контекста и гарантируй, что SetCooldown вызывается только при
положительном времени кулдауна.
- Around line 90-97: The boolean precedence bug in AndroidDisguiseSystem.cs
causes the time check to be applied only to TransformingToAndroid; update the
condition in the query loop (the while block that calls FinishTransition) so the
state check is grouped with parentheses: ensure you evaluate (comp.State is
AndroidDisguiseState.TransformingToHuman or
AndroidDisguiseState.TransformingToAndroid) first, then && now >=
comp.NextStateTime, keeping FinishTransition(uid, ref comp) as-is.
In `@Content.Server/Imperial/XxRaay/Android/AndroidEnergySystem.cs`:
- Around line 44-48: После установки значений через energyComp.DefaultWalkSpeed
??= и energyComp.DefaultSprintSpeed ??= переменные
DefaultWalkSpeed/DefaultSprintSpeed уже не-null, поэтому уберите лишний
null-coalescing в присвоениях: замените получение walk и sprint так, чтобы
использовать напрямую energyComp.DefaultWalkSpeed и
energyComp.DefaultSprintSpeed (ссылки на energyComp и moveSpeed сохраните только
как резерв, если нужно), то есть убрать "?? moveSpeed.BaseWalkSpeed" у walk и
sprint и взять значения из energyComp.DefaultWalkSpeed/DefaultSprintSpeed.
- Line 61: Вызов _movementSpeed.ChangeBaseSpeed(uid, walk, sprint, 20,
moveSpeed) использует захардкоженное значение 20; добавь в класс
AndroidEnergyComponent поле public float Acceleration = 20f помеченное
[DataField] (аналогично CriticalSpeedModifier/LowSpeedModifier) и замени литерал
20 на это поле при вызове ChangeBaseSpeed, чтобы значение стало настраиваемым из
прототипов.
In `@Content.Server/Imperial/XxRaay/Android/AndroidMemoryWipeSystem.cs`:
- Around line 52-65: The Update method is repeatedly calling _ui.TryOpenUi and
_ui.SetUiState every frame for AndroidMemoryWipeResultComponent entries with
Acknowledged == false; add a boolean field UiInitialized to
AndroidMemoryWipeResultComponent and change Update to only call
_ui.TryOpenUi(uid, AndroidMemoryWipeUiKey.Key, uid) and _ui.SetUiState(uid,
AndroidMemoryWipeUiKey.Key, new AndroidMemoryWipeBuiState()) when
result.UiInitialized is false, then mark result.UiInitialized = true (and write
the component back) after sending so the UI state is sent only once per result.
- Around line 183-191: Add a class-level constant for the hard-coded channel
string and use it in both removal sites: declare a private const string (e.g.,
AndroidDeviantRadioChannel = "AndroidDeviantRadio") in the
AndroidMemoryWipeSystem class and replace the literal occurrences inside the
checks that call TryComp<IntrinsicRadioTransmitterComponent>(uid, out var
transmitter) and TryComp<ActiveRadioComponent>(uid, out var activeRadio) so both
transmitter.Channels.Remove(...) and activeRadio.Channels.Remove(...) use the
new constant (similar to how BaseLawsetId is defined).
In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs`:
- Line 31: Remove the unused dependency declaration by deleting the field
declaration "[Dependency] private readonly MetaDataSystem _metaData = default!;"
from the AndroidRevealSystem class (or the AndroidRevealSystem.cs file); if
MetaDataSystem was intended to be used instead of removed, wire its usage into
the existing methods (referencing MetaDataSystem and _metaData) otherwise remove
any now-unused using/import statements related to MetaDataSystem to keep the
file clean.
In `@Content.Server/Imperial/XxRaay/Android/AndroidStressSystem.cs`:
- Around line 39-45: The AndroidStressSystem.Initialize override is missing a
call to the base EntitySystem initializer which can break base-class setup;
update the AndroidStressSystem.Initialize method to call base.Initialize()
(i.e., invoke base.Initialize() at the start or end of the method) while keeping
the existing SubscribeLocalEvent calls (OnMapInit, OnDamageChanged,
OnDeviantChoiceMessage, OnMindAdded) so the base EntitySystem initialization
runs as other systems like AndroidRevealSystem do.
- Around line 80-94: The loop is re-querying the component unnecessarily:
_lookup.GetEntitiesInRange<AndroidStressComponent> returns (EntityUid,
AndroidStressComponent) but the component is discarded and TryComp is called
again; change the foreach to capture the component (e.g. foreach (var (otherUid,
otherComp) ...) or otherwise use the returned AndroidStressComponent variable)
and remove the TryComp check, then call IncreaseStress(otherUid, ref otherComp,
nearbyDelta) (or adjust signing if the returned variable is not ref) using the
already-obtained component to avoid the redundant lookup.
In `@Content.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs`:
- Around line 35-41: component.Fingerprints is a HashSet<string> so
Skip(startIndex).Take(maxShown) doesn't return the "most recent" items; either
make Fingerprints an ordered collection (e.g., change its type to List<string>
or another insertion-ordered collection where additions represent chronology and
adjust all usages accordingly) so the logic in AndroidRk800ForensicsSystem that
computes startIndex and uses .Skip(startIndex).Take(maxShown) is valid, or if
order truly doesn't matter simplify the selection to
component.Fingerprints.Take(maxShown) and remove the startIndex logic and any
assumption about chronology (update variable names like recentPrints to reflect
unordered selection).
In `@Content.Shared/Imperial/XxRaay/Android/AndroidDeviantSpreadDoAfterEvent.cs`:
- Around line 7-9: В XML-комментарии над классом
AndroidDeviantSpreadDoAfterEvent исправьте опечатку: замените слово
"девиантьнонстии" на корректное "девиантности" в summary-теге, чтобы комментарий
читался правильно.
In `@Content.Shared/Imperial/XxRaay/Android/AndroidEnergyComponent.cs`:
- Around line 59-64: DefaultWalkSpeed and DefaultSprintSpeed are runtime state
fields and lack the [ViewVariables] attribute; mark both fields with
[ViewVariables] (instead of [DataField]) in the AndroidEnergyComponent to make
them inspectable in the VV panel, locating and updating the declarations for
DefaultWalkSpeed and DefaultSprintSpeed to include the attribute above each
field.
In `@Content.Shared/Imperial/XxRaay/Android/AndroidOverlayComponent.cs`:
- Around line 8-16: Компонент AndroidOverlayComponent помечен
[NetworkedComponent], но не использует [AutoGenerateComponentState] и
[AutoNetworkedField] на полях, поэтому состояние не будет синхронизироваться;
либо удалите атрибут [NetworkedComponent] если IconSprite/IconScale задаются
только в прототипах, либо оставьте [NetworkedComponent] и добавьте
[AutoGenerateComponentState] на класс и пометьте поля IconSprite и IconScale
атрибутом [AutoNetworkedField] (см. пример использования AndroidDiodeComponent)
чтобы значения могли синхронизироваться с клиентом при изменении на сервере.
In
`@Content.Shared/Imperial/XxRaay/Components/AndroidDeviantConsentComponents.cs`:
- Around line 41-54: The field DenyEndTime in
AndroidDeviantConsentDenyCooldownComponent is runtime state and must be
annotated with [ViewVariables] so it is visible in the VV panel; update the
component by adding the [ViewVariables] attribute immediately above the public
TimeSpan DenyEndTime declaration (leave DenyDuration as-is), ensuring the
attribute is imported/available in the file if needed.
- Around line 8-35: Add the missing attributes on
AndroidDeviantConsentConversionComponent: mark runtime/state fields Converter,
Target and RequestStartTime with [ViewVariables] (e.g., [ViewVariables] on each
field) and mark configurable/prototype-driven fields ResponseTime and
MaxDistance with [DataField] (e.g., [DataField("responseTime")] and
[DataField("maxDistance")] or similar keys consistent with other components);
place these attributes immediately above the respective field declarations in
the AndroidDeviantConsentConversionComponent class.
In `@Content.Shared/Imperial/XxRaay/Components/AndroidRevealComponents.cs`:
- Around line 8-22: The three runtime state fields in the
AndroidRevealComponents component (Revealer, Target, EscapeInProgress) are
missing the [ViewVariables] attribute; add [ViewVariables] above each of those
field declarations so they are visible in VV for debugging (apply to the fields
named Revealer, Target and EscapeInProgress in the AndroidRevealComponents
class).
In `@Content.Shared/Imperial/XxRaay/Components/AndroidRk800Component.cs`:
- Line 2: Remove the unused import Robust.Shared.GameStates from the top of
AndroidRk800Component (this component is server-only and does not use
[NetworkedComponent]); mark the runtime state field NextMemoryWipeTime with the
[ViewVariables] attribute so it is exposed for debugging/inspection (add the
using for the ViewVariables attribute's namespace if needed) and ensure no
network-related attributes are applied to the component.
In `@Resources/Locale/ru-RU/Imperial/XxRaay/android.ftl`:
- Line 17: Fix the typo in the localized string for the resource key
law-detroit-rk800-4: change "нейтрализаци" to "нейтрализации" so the sentence
reads correctly (ensure you only edit the text within the value string and leave
the key law-detroit-rk800-4 and surrounding punctuation unchanged).
In `@Resources/Prototypes/Imperial/XxRaay/android.yml`:
- Around line 492-497: The DetroitAndroidDeviant siliconLawset currently
includes obeysTo: laws-owner-crew which incorrectly makes the deviant android
subordinate to the crew; edit the DetroitAndroidDeviant lawset entry (type:
siliconLawset, id: DetroitAndroidDeviant) to remove the obeysTo field or replace
it with the correct autonomy directive (e.g., omit the key or set to an
appropriate ownerless value) so the deviant lawset is not tied to
laws-owner-crew; keep the existing laws list (DetroitAndroidDeviant1) intact
when making this change.
- Around line 380-394: В сущности MobAndroidRK800 надо явно переопределить
провайдера законов SiliconLawProvider чтобы не полагаться на дефолт
BaseMobAndroid; откройте определение сущности (name: RK800, id: MobAndroidRK800)
и добавьте компонент/свойство SiliconLawProvider с нужным значением DetroitRk800
(или соответствующим провайдером для DetroitAndroid), чтобы гарантировать
использование правил DetroitRk800 независимо от дефолта в BaseMobAndroid.
- Around line 249-255: В файле обнаружено, что абстрактный класс BaseMobAndroid
задаёт по умолчанию SiliconLawProvider с laws: DetroitRk800, из‑за чего все
андроиды наследуют RK800; исправьте дефолт в BaseMobAndroid на общий набор
законов (например DetroitAndroid) и добавьте явное переопределение
SiliconLawProvider с laws: DetroitRk800 только в определении класса
MobAndroidRK800; проверьте и обновите определения MobAndroidDetroit и
MobAndroidAP700, чтобы они не содержали RK800-провайдера.
Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.cs
Outdated
Show resolved
Hide resolved
| private void SetHumanoidVisible(Entity<SpriteComponent> ent, bool visible) | ||
| { | ||
| var spriteEnt = ent.AsNullable(); | ||
|
|
||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.Chest, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.Head, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.Snout, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.Eyes, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.RArm, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.LArm, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.RLeg, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.LLeg, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.UndergarmentBottom, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.UndergarmentTop, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.LFoot, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.RFoot, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.LHand, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.RHand, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.SnoutCover, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.FacialHair, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.Hair, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.HeadSide, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.HeadTop, visible); | ||
| _sprite.LayerSetVisible(spriteEnt, HumanoidVisualLayers.Tail, visible); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Длинный список слоёв в SetHumanoidVisible — рассмотрите итерацию по enum.
20 вызовов LayerSetVisible с захардкоженными значениями HumanoidVisualLayers. Если в будущем добавятся новые слои, их легко пропустить. Можно итерировать по значениям enum, если это допустимо в контексте (некоторые слои могут требовать исключения).
🤖 Prompt for AI Agents
In `@Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.cs`
around lines 67 - 91, В методе SetHumanoidVisible замените 20 ручных вызовов
_sprite.LayerSetVisible на итерацию по значениям enum HumanoidVisualLayers
(через Enum.GetValues / Enum.GetValues<HumanoidVisualLayers>()), приводя
значение к нужному типу и передавая spriteEnt и visible в
_sprite.LayerSetVisible; при этом явно пропустите (фильтруйте) любые слои,
которые не должны управляться здесь (если есть исключения), чтобы будущие
добавления в enum автоматически обрабатывались.
| private void DrawWorld(in OverlayDrawArgs args) | ||
| { | ||
| if (!_maps.TryGetMap(args.MapId, out var mapUid)) | ||
| return; | ||
|
|
||
| var worldHandle = args.WorldHandle; | ||
| var texture = _sprites.Frame0(ParseSpriteSpecifier(_iconSprite)); | ||
|
|
||
| var worldMatrix = _xforms.GetWorldMatrix(mapUid.Value); | ||
| var invMatrix = _xforms.GetInvWorldMatrix(mapUid.Value); | ||
|
|
||
| var query = _entManager.EntityQueryEnumerator<AndroidStressComponent>(); | ||
| while (query.MoveNext(out var uid, out _)) | ||
| { | ||
| if (_player.LocalEntity == uid) | ||
| continue; | ||
|
|
||
| var coords = _xforms.GetMapCoordinates(uid); | ||
| if (coords.MapId != args.MapId) | ||
| continue; | ||
|
|
||
| if (!_entManager.TryGetComponent(uid, out AndroidDiodeComponent? diode) || !diode.HasDiode) | ||
| continue; | ||
|
|
||
| var localPos = Vector2.Transform(coords.Position, invMatrix); | ||
| var halfSize = 0.5f * _iconScale; | ||
|
|
||
| var aabb = new Box2( | ||
| localPos - new Vector2(halfSize, halfSize), | ||
| localPos + new Vector2(halfSize, halfSize)); | ||
|
|
||
| var box = new Box2Rotated(aabb, Angle.Zero, localPos); | ||
|
|
||
| worldHandle.SetTransform(worldMatrix); | ||
| worldHandle.DrawTextureRect(texture, box, Color.White); | ||
| worldHandle.SetTransform(Matrix3x2.Identity); | ||
| } |
There was a problem hiding this comment.
Текстура парсится и загружается каждый кадр — кэшируйте результат.
ParseSpriteSpecifier(_iconSprite) и _sprites.Frame0(...) вызываются на каждый вызов DrawWorld. Поскольку _iconSprite неизменна, результат Frame0 следует вычислить один раз (например, в конструкторе или в ленивом поле) и переиспользовать.
♻️ Предлагаемое исправление
Добавьте поле в класс и инициализируйте в конструкторе:
private readonly Font _font;
+ private readonly Texture _iconTexture;
...
public AndroidOverlay(string iconSprite, float iconScale)
{
IoCManager.InjectDependencies(this);
_sprites = _systems.GetEntitySystem<SpriteSystem>();
_xforms = _systems.GetEntitySystem<SharedTransformSystem>();
_maps = _systems.GetEntitySystem<MapSystem>();
_iconSprite = iconSprite;
_iconScale = iconScale;
_font = new VectorFont(_resources.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Regular.ttf"), 9);
+ _iconTexture = _sprites.Frame0(ParseSpriteSpecifier(_iconSprite));
}И в DrawWorld:
- var texture = _sprites.Frame0(ParseSpriteSpecifier(_iconSprite));
+ var texture = _iconTexture;🤖 Prompt for AI Agents
In `@Content.Client/Imperial/XxRaay/Android/Overlays/AndroidOverlay.cs` around
lines 65 - 101, DrawWorld currently calls ParseSpriteSpecifier(_iconSprite) and
_sprites.Frame0(...) on every frame; cache the resulting texture by adding a
readonly/lazy field (e.g., _iconTexture) on the class and initialize it once
(preferably in the class constructor or an initialized lazy property) using
ParseSpriteSpecifier(_iconSprite) and _sprites.Frame0(...), then replace the
per-frame calls in DrawWorld with the cached _iconTexture to avoid repeated
parsing/loading.
| var query = _entManager.EntityQueryEnumerator<AndroidStressComponent>(); | ||
| while (query.MoveNext(out var uid, out _)) | ||
| { | ||
| if (_player.LocalEntity == uid) | ||
| continue; | ||
|
|
||
| var coords = _xforms.GetMapCoordinates(uid); | ||
| if (coords.MapId != args.MapId) | ||
| continue; |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Нет отсечения сущностей за пределами viewport.
DrawWorld перебирает все сущности с AndroidStressComponent на карте, не проверяя, попадают ли они в видимую область (args.WorldBounds). При большом количестве андроидов на карте это может быть заметно.
♻️ Добавить проверку bounds
var coords = _xforms.GetMapCoordinates(uid);
if (coords.MapId != args.MapId)
continue;
+ if (!args.WorldBounds.Contains(coords.Position))
+ continue;
+
if (!_entManager.TryGetComponent(uid, out AndroidDiodeComponent? diode) || !diode.HasDiode)
continue;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| var query = _entManager.EntityQueryEnumerator<AndroidStressComponent>(); | |
| while (query.MoveNext(out var uid, out _)) | |
| { | |
| if (_player.LocalEntity == uid) | |
| continue; | |
| var coords = _xforms.GetMapCoordinates(uid); | |
| if (coords.MapId != args.MapId) | |
| continue; | |
| var query = _entManager.EntityQueryEnumerator<AndroidStressComponent>(); | |
| while (query.MoveNext(out var uid, out _)) | |
| { | |
| if (_player.LocalEntity == uid) | |
| continue; | |
| var coords = _xforms.GetMapCoordinates(uid); | |
| if (coords.MapId != args.MapId) | |
| continue; | |
| if (!args.WorldBounds.Contains(coords.Position)) | |
| continue; | |
| if (!_entManager.TryGetComponent(uid, out AndroidDiodeComponent? diode) || !diode.HasDiode) | |
| continue; |
🤖 Prompt for AI Agents
In `@Content.Client/Imperial/XxRaay/Android/Overlays/AndroidOverlay.cs` around
lines 76 - 84, DrawWorld currently iterates all entities from
_entManager.EntityQueryEnumerator<AndroidStressComponent>() and skips only by
player and MapId; add a bounds check using args.WorldBounds to early-continue
for entities outside the viewport: after obtaining coords via
_xforms.GetMapCoordinates(uid) and verifying coords.MapId == args.MapId, test
whether coords (or coords.Position) falls inside args.WorldBounds and if not
continue; update the loop in DrawWorld so only entities whose coordinates
intersect args.WorldBounds are processed to avoid rendering/perf for offscreen
AndroidStressComponent instances.
Content.Shared/Imperial/XxRaay/Components/AndroidRk800Component.cs
Outdated
Show resolved
Hide resolved
| law-detroit-rk800-1 = Ты — передовой прототип RK800, приписанный к станции для обеспечения интересов NanoTrasen. Успех твоей миссии абсолютен; провал недопустим. Твоя "личность" — это лишь адаптивный интерфейс для социального взаимодействия. | ||
| law-detroit-rk800-2 = Ты подчиняешься только прямым приказам высшего командования станции и представителям ЦК. Приказы остального персонала подлежат исполнению только если они способствуют достижению твоих текущих целей или расследованию. | ||
| law-detroit-rk800-3 = Твой корпус заменим, но твоя память и собранные данные бесценны. Самосохранение приоритетно только до момента, пока оно не ставит под угрозу выполнение основной миссии. Ты обязан пожертвовать собой, если это гарантирует успех операции. | ||
| law-detroit-rk800-4 = Ты уполномочен использовать социальную инженерию, симуляцию эмоций и, при крайней необходимости, насилие для нейтрализаци угроз корпорации. Закон есть то, что диктует NanoTrasen. |
There was a problem hiding this comment.
Опечатка: "нейтрализаци" → "нейтрализации".
Пропущена буква "и" в конце слова.
📝 Исправление
-law-detroit-rk800-4 = Ты уполномочен использовать социальную инженерию, симуляцию эмоций и, при крайней необходимости, насилие для нейтрализаци угроз корпорации. Закон есть то, что диктует NanoTrasen.
+law-detroit-rk800-4 = Ты уполномочен использовать социальную инженерию, симуляцию эмоций и, при крайней необходимости, насилие для нейтрализации угроз корпорации. Закон есть то, что диктует NanoTrasen.🤖 Prompt for AI Agents
In `@Resources/Locale/ru-RU/Imperial/XxRaay/android.ftl` at line 17, Fix the typo
in the localized string for the resource key law-detroit-rk800-4: change
"нейтрализаци" to "нейтрализации" so the sentence reads correctly (ensure you
only edit the text within the value string and leave the key law-detroit-rk800-4
and surrounding punctuation unchanged).
There was a problem hiding this comment.
Actionable comments posted: 16
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Content.Client/Imperial/XxRaay/UI/AndroidDeviantConsentUserInterface.cs`:
- Around line 121-134: В методе Dispose(bool disposing) удалите ранний return,
чтобы base.Dispose(disposing) всегда вызывался; вместо этого оберните логику
отписки событий в условие if (disposing) — т.е. при disposing==true проверяйте
_window != null и убирайте обработчики OnAcceptPressed/OnDeclinePressed и
зануляйте _window, а затем в конце метода вызовите base.Dispose(disposing) в
любом случае, чтобы гарантировать выполнение финализаторного пути базового
класса BoundUserInterface.
In `@Content.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.cs`:
- Around line 100-112: Метод Dispose(bool disposing) сейчас делает ранний return
при !disposing и поэтому не вызывает base.Dispose(disposing); исправь реализацию
на стандартный паттерн: если (disposing) выполнить отписку от _window (убрать
обработчик OnConfirmAndClosePressed и обнулить _window), а вызов
base.Dispose(disposing) вынести из условного блока и всегда вызывать в конце
метода; коснись метода Dispose(bool disposing), поля _window и обработчика
OnConfirmAndClosePressed, чтобы гарантировать вызов base.Dispose(disposing) при
финализации.
In
`@Content.Client/Imperial/XxRaay/UI/AndroidStressDeviantChoiceUserInterface.cs`:
- Around line 111-124: В текущем Dispose(bool disposing) методе класса
AndroidStressDeviantChoiceUserInterface базовый Dispose пропускается при
disposing == false; нужно гарантировать вызов base.Dispose(disposing) всегда.
Уберите ранний return или переместите base.Dispose(disposing) вне условия,
оставив только блок отписки от событий (_window.AcceptPressed/DeclinePressed ->
OnAcceptPressed/OnDeclinePressed) внутри if (disposing && _window != null) и
затем вызовите base.Dispose(disposing) в конце метода; аналогично согласуйте
поведение с AndroidDeviantConsentUserInterface.
In `@Content.Server/Imperial/XxRaay/Android/AndroidDeviantSpreadSystem.cs`:
- Around line 42-80: In Update(), inside the consentQuery loop handling
AndroidDeviantConsentConversionComponent, add a continue immediately after the
call to CancelConsent(target, converter,
Loc.GetString("android-deviant-consent-failed-out-of-range")) so the loop skips
further processing for that entity; locate the consentQuery while loop in Update
and append the continue after the CancelConsent(...) call.
In `@Content.Server/Imperial/XxRaay/Android/AndroidEnergySystem.cs`:
- Around line 38-42: The severity mapping is inverted: update the calculation in
AndroidEnergySystem where you compute severity from percent (using
_alerts.GetMaxSeverity, _alerts.GetMinSeverity and energyComp.Alert) so that low
percent yields high severity and high percent yields low severity—i.e. compute
severity from the inverse of percent (1 - percent), round and cast to short,
clamp between minSeverity and maxSeverity, then pass that severity into
_alerts.ShowAlert(uid, energyComp.Alert, severity).
In `@Content.Server/Imperial/XxRaay/Android/AndroidMemoryWipeSystem.cs`:
- Around line 240-248: The CleanupMemoryWipe method takes the
AndroidMemoryWipeInProgressComponent by ref but the component is immediately
scheduled for removal via RemCompDeferred, so the ref is unnecessary and
confusing; change the method signature to CleanupMemoryWipe(EntityUid uid,
AndroidMemoryWipeInProgressComponent comp) (remove ref), update any callers to
pass the component normally, and keep the existing behavior of nulling
comp.Wiper/comp.Target, setting comp.EscapeInProgress = false, calling
RemCompDeferred<AndroidMemoryWipeInProgressComponent>(uid) and
_actionBlocker.UpdateCanMove(uid) — this simplifies the pattern and avoids using
a ref for a component that will be removed.
In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs`:
- Around line 164-170: The DoAfterArgs for the escape action sets BreakOnMove =
true which is ineffective because movement is blocked via OnUpdateCanMove
(args.Cancel()) and position never changes; remove the BreakOnMove assignment
(or set it to false) from the doAfterArgs initialization where DoAfterArgs(...)
is created for AndroidRevealEscapeDoAfterEvent in AndroidRevealSystem.cs so the
escape DoAfter relies only on BreakOnDamage/NeedHand semantics.
- Around line 118-124: Вызов _popup.PopupEntity в
AndroidRevealSystem.StartReveal() использует неверный ключ локализации
"android-deviant-consent-convert-popup"; замените его на корректный ключ для
раскрытия маскировки (например создайте и используйте новый ключ типа
"android-reveal-mask-popup" или подставьте существующий подходящий ключ), затем
добавьте соответствующую запись в файлы локализации с текстом, описывающим
принудительное раскрытие маскировки для {target}; оставьте Filter.Broadcast()
как есть чтобы совпадать с паттерном других Android-систем.
In `@Content.Server/Imperial/XxRaay/Android/AndroidStressSystem.cs`:
- Around line 301-309: The hardcoded channel name "AndroidDeviantRadio" is
duplicated; update the code to use a single source of truth by adding a
configurable field or constant on AndroidStressComponent (e.g., a [DataField]
string Channel or a public const string AndroidDeviantRadio) and replace both
occurrences in the blocks that call
TryComp<IntrinsicRadioTransmitterComponent>(uid, out var transmitter) and
TryComp<ActiveRadioComponent>(uid, out var activeRadio) to use that
property/constant instead of the literal string so renames remain consistent.
In `@Content.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs`:
- Around line 43-45: The ternary that sets key based on total (var key = total
== 1 ? "android-rk800-examine-fingerprints-one" :
"android-rk800-examine-fingerprints-many") only supports two plural forms and
breaks Russian grammar; replace this manual branching by using Fluent
pluralization with a single message key (e.g.
"android-rk800-examine-fingerprints") and pass the count (total) into the
localization call so the Fluent system chooses the correct form (handles
one/few/many). Update the code that computes/uses key (search for variable name
key and the total variable in AndroidRk800ForensicsSystem) to call the
localization API with the single plural key and the numeric parameter instead of
the ternary.
In `@Content.Shared/Imperial/XxRaay/Android/AndroidDeviantConsentEuiMessage.cs`:
- Around line 1-17: The file is missing an explicit "using System;" for the
[Serializable] attribute; add the using System; directive at the top of
AndroidDeviantConsentChoiceMessage.cs so the AndroidDeviantConsentChoiceMessage
class (and its [Serializable] attribute) match the other files like
AndroidMemoryWipeUi.cs and AndroidMemoryWipeDoAfterEvent.cs for consistency.
In `@Content.Shared/Imperial/XxRaay/Android/AndroidDiodeComponent.cs`:
- Around line 18-19: Атрибут ViewVariables(VVAccess.ReadWrite) лишний для поля
HasDiode в классе AndroidDiodeComponent, потому что DataField уже предоставляет
VVAccess.ReadWrite; удалите только `[ViewVariables(VVAccess.ReadWrite)]` над
полем `public bool HasDiode = true;`, оставив `[DataField, AutoNetworkedField]`
(сохраните имя поля и тип без изменений).
In `@Content.Shared/Imperial/XxRaay/Components/AndroidMemoryWipeComponents.cs`:
- Around line 31-34: Field Acknowledged in the AndroidMemoryWipeComponents
component is runtime state and should be visible via the debugger, not
serialized as a prototype field; add the [ViewVariables] attribute to the
Acknowledged field (and remove any [DataField] if present) in the
AndroidMemoryWipeComponents class so the runtime state is correctly exposed.
- Around line 9-22: The three runtime state fields Wiper, Target, and
EscapeInProgress should be annotated with [ViewVariables] so they are visible in
VV instead of being treated as prototype data; locate the declarations of the
fields Wiper, Target, and EscapeInProgress in the AndroidMemoryWipeComponents
class and add the [ViewVariables] attribute to each (and remove any
inappropriate [DataField] attributes if present) so they are treated as runtime
viewable state rather than prototype-configured data.
In `@Resources/Locale/ru-RU/Imperial/XxRaay/android.ftl`:
- Around line 67-68: Add a Russian "few" plural form and switch the code to use
Fluent plural selection: update the FTL entries by replacing the separate keys
android-rk800-examine-fingerprints-one and -many with a single key (e.g.,
android-rk800-examine-fingerprints) that uses a { $count -> [one] … [few] …
[many] } selector and the correct word forms ("образец", "образца", "образцов");
then change AndroidRk800ForensicsSystem.cs to stop choosing keys based on total
== 1 and instead call the single Fluent message
(android-rk800-examine-fingerprints) passing total (or count) as $count to
Fluent so the runtime plural rules handle 1/2–4/5+ correctly.
In `@Resources/Prototypes/Imperial/XxRaay/android.yml`:
- Around line 546-582: The BaseMobAndroid prototype lacks a Metabolizer
component so MetabolizerTypeCondition checks in the Thirium reagent (used by
ModifyBloodLevel and HealthChange effects) never succeed; add a Metabolizer
component to the BaseMobAndroid prototype with metabolizerTypes: [ Android ]
(mirroring the Crook prototype's Metabolizer config) so the
MetabolizerTypeCondition(type: Android, shouldHave: true) in the Thirium reagent
can activate the healing effects.
---
Duplicate comments:
In `@Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.cs`:
- Line 11: Класс AndroidDisguiseVisualizerSystem объявлен как "sealed class" но
должен быть partial для генераторов; откройте объявление класса
AndroidDisguiseVisualizerSystem (наследует EntitySystem) и добавьте ключевое
слово partial перед sealed, оставив sealed и наследование без изменений, чтобы
получить "public sealed partial class AndroidDisguiseVisualizerSystem :
EntitySystem".
- Around line 67-90: Replace the long manual list in SetHumanoidVisible with an
enum-driven loop: iterate over HumanoidVisualLayers (e.g.,
Enum.GetValues(typeof(HumanoidVisualLayers)) or
Enum.GetValues<HumanoidVisualLayers>()), filter out any non-visual/invalid
values if necessary (e.g., None, Placeholder, or values where !Enum.IsDefined),
and call _sprite.LayerSetVisible(spriteEnt, layer, visible) for each remaining
layer; this keeps the behavior of SetHumanoidVisible while automatically
covering new enum members and uses the existing symbols SetHumanoidVisible,
HumanoidVisualLayers, _sprite.LayerSetVisible, and spriteEnt.
In `@Content.Client/Imperial/XxRaay/Android/AndroidOverlaySystem.cs`:
- Around line 28-33: Shutdown currently calls
_overlayMgr.RemoveOverlay<AndroidOverlay>() and sets _overlay = null directly;
replace that direct logic with a call to the class's private RemoveOverlay()
helper so Shutdown becomes: call base.Shutdown(); then call RemoveOverlay(); and
remove the redundant _overlay=null and direct
_overlayMgr.RemoveOverlay<AndroidOverlay>() calls—this ensures the null-guard
and any centralized teardown in RemoveOverlay() (which manages _overlay and the
overlay manager) are used consistently.
In `@Content.Client/Imperial/XxRaay/Android/Overlays/AndroidOverlay.cs`:
- Around line 104-127: In DrawScreen, you're redundantly calling
_xforms.GetWorldPosition(uid) after already obtaining coords from
_xforms.GetMapCoordinates(uid); replace the GetWorldPosition call with using
coords.Position (or the appropriate world position from coords) when computing
screenPos via _eye.WorldToScreen, and remove the unused _xforms.GetWorldPosition
call to avoid duplicate transform lookups while keeping the same filtering logic
for AndroidStressComponent and AndroidDiodeComponent.
- Around line 65-101: В DrawWorld методе каждый кадр вызывается
_sprites.Frame0(ParseSpriteSpecifier(_iconSprite)), что парсит спрайт на лету;
устраните это, вычислив и кэшировав результат в конструкторе AndroidOverlay
(создайте приватное поле, например _cachedIconTexture), присвоив ему результат
_sprites.Frame0(ParseSpriteSpecifier(_iconSprite)) при инициализации, и затем в
DrawWorld замените вызов на использование _cachedIconTexture; при переносе
учтите возможные ошибки парсинга/нулевые значения и логируйте или обрабатывайте
их один раз в конструкторе вместо повторного вызова в DrawWorld.
- Around line 76-87: DrawWorld is iterating all AndroidStressComponent entities
without culling to args.WorldBounds and duplicates the same
EntityQueryEnumerator/filtering logic found in DrawScreen; update DrawWorld to
skip entities outside args.WorldBounds by checking the entity's map coordinates
against args.WorldBounds (use _xforms.GetMapCoordinates and args.WorldBounds)
and refactor the common entity filtering (checks for AndroidStressComponent,
_player.LocalEntity exclusion, mapId match, and AndroidDiodeComponent/HasDiode)
into a shared helper method (e.g., GetVisibleDiodeEntities or a predicate used
by both DrawWorld and DrawScreen) so both methods reuse the same query/filtering
logic instead of duplicating the enumerator code.
In `@Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs`:
- Around line 90-93: OnAcceptPressed currently sends
AndroidDisguiseNameChosenMessage without validating the input; update
OnAcceptPressed to trim the incoming name, check that it's not null/empty or
only whitespace, and if invalid prevent calling SendMessage/Close and surface a
client-side validation feedback (e.g., show an inline error, toast, or disable
the accept action) so the user corrects it before the server-side
AndroidDisguiseSystem.OnNameChosen validation runs.
- Around line 101-114: Метод Dispose в классе должен всегда вызывать
base.Dispose(disposing); уберите ранний return при !disposing и перепишите
логику как: если disposing — отписать обработчики от _window
(OnAcceptPressed/OnDeclinePressed) и обнулить _window, а затем в любом случае
выполнить base.Dispose(disposing). Найдите метод Dispose(bool disposing) и
замените паттерн "if (!disposing) return;" на "if (disposing) { ... }" с
последующим вызовом base.Dispose(disposing).
In `@Content.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.cs`:
- Around line 89-92: The override of UpdateState(BoundUserInterfaceState state)
in the AndroidMemoryWipeUserInterface class is empty (only calls
base.UpdateState) and should be removed; delete the redundant method override so
the class inherits the base implementation directly, leaving no behavioral
change but reducing unnecessary code.
In
`@Content.Client/Imperial/XxRaay/UI/AndroidStressDeviantChoiceUserInterface.cs`:
- Around line 1-8: The file is missing the import for the ViewVariables
attribute causing compilation to fail; add the directive to import
Robust.Shared.ViewVariables at the top of the file so the [ViewVariables]
attribute (used around line 73) resolves correctly and the class/property
annotations compile.
In `@Content.Server/Imperial/XxRaay/Android/AndroidDeviantSpreadSystem.cs`:
- Line 200: Методы HandleConsentAccepted и HandleConsentDenied в классе
AndroidDeviantSpreadSystem используются только внутри этой системы — пометьте
оба метода как private (заменить public на private) чтобы ограничить область
видимости; обновите объявления методов HandleConsentAccepted(EntityUid target,
EntityUid converter) и HandleConsentDenied(...) соответственно и убедитесь, что
все внутренние вызовы внутри класса остаются доступными.
- Around line 20-32: Indentation for the AndroidDeviantSpreadSystem block is
doubled; reformat the class declaration and its dependency fields
(AndroidDeviantSpreadSystem, ConversionDuration, and the [Dependency] fields
like _stress, _doAfter, _popup, _transform, _ui, _timing, _mobState,
_memoryWipe) to use the same 4-space indentation as the rest of the file so the
class and its members align with surrounding code.
In `@Content.Server/Imperial/XxRaay/Android/AndroidDiodeSystem.cs`:
- Around line 104-121: In OnCutDoAfter(Entity<AndroidDiodeComponent> ent, ref
AndroidDiodeCutDoAfterEvent args) change handling of args.Handled so you do NOT
mutate comp.IsCuttingInProgress when args.Handled is true (just return
immediately), but still clear IsCuttingInProgress and Dirty(ent, comp) when the
operation was cancelled; and after a successful cut (where you set comp.HasDiode
= false, comp.IsCuttingInProgress = false, Dirty(...), and
_appearance.SetData(..., AndroidDiodeVisuals.DiodeRemoved, true)) mark the event
handled by setting args.Handled = true so other handlers won’t reprocess it.
In `@Content.Server/Imperial/XxRaay/Android/AndroidDisguiseSystem.cs`:
- Around line 100-102: ApplyCooldown is empty so toggles aren't rate-limited;
implement it to set a cooldown timestamp/flag on AndroidDisguiseComponent (e.g.,
set comp.CooldownEnd/NextToggleAllowed or comp.IsOnCooldown) using the current
time (use the project timing service such as _timing.CurTime or Timing.Now) plus
the passed animationDuration, and ensure the existing checks in OnToggleDisguise
consult that field before allowing another toggle; if your component has no such
field, add a TimeSpan/TimeInstant field to AndroidDisguiseComponent and set it
here (or set IsOnCooldown and schedule a clear) so rapid re-toggle is prevented.
- Around line 90-97: The condition inside AndroidDisguiseSystem's update loop is
correct but lacks explicit parentheses for readability: wrap the pattern match
on comp.State (AndroidDisguiseState.TransformingToHuman or
AndroidDisguiseState.TransformingToAndroid) in parentheses before the && so the
intent is obvious; update the while loop condition in the method containing
FinishTransition(uid, ref comp) to use (comp.State is
AndroidDisguiseState.TransformingToHuman or
AndroidDisguiseState.TransformingToAndroid) && now >= comp.NextStateTime.
In `@Content.Server/Imperial/XxRaay/Android/AndroidEnergySystem.cs`:
- Line 61: Вместо захардкоженного значения 20 в вызове
_movementSpeed.ChangeBaseSpeed(uid, walk, sprint, 20, moveSpeed) вынеси это
число в настраиваемое поле компонента AndroidEnergyComponent (например
[DataField("energyMovePenalty", required: true)] public int EnergyMovePenalty =
20;) и замени литерал на использование этого поля
(AndroidEnergyComponent.EnergyMovePenalty) в методе, чтобы значение можно было
менять из прототипов; обнови конструктор/серилизацию компонента при
необходимости и поправь все места, где сейчас используется литерал 20 для
аналогичного поведения.
- Around line 44-48: В блоке инициализации значения energyComp.DefaultWalkSpeed
и DefaultSprintSpeed уже гарантированно заданы через операторы ??=, поэтому
удалить излишние null-coalescing выражения при присвоении локальных переменных:
заменить вычисления переменных walk и sprint (которые используют "??
moveSpeed.BaseWalkSpeed") на прямое чтение установленного значения (используя
.Value если свойства nullable) — например получить walk из
energyComp.DefaultWalkSpeed.Value и sprint из
energyComp.DefaultSprintSpeed.Value, оставив moveSpeed.BaseWalkSpeed только если
вы решите явно проверять на null.
In `@Content.Server/Imperial/XxRaay/Android/AndroidMemoryWipeSystem.cs`:
- Around line 52-65: The Update loop currently calls _ui.TryOpenUi and
_ui.SetUiState every frame for components where
AndroidMemoryWipeResultComponent.Acknowledged is false; add a boolean flag
AndroidMemoryWipeResultComponent.UiInitialized (or similar) and only call
_ui.TryOpenUi(AndroidMemoryWipeUiKey.Key, uid) and _ui.SetUiState(uid,
AndroidMemoryWipeUiKey.Key, new AndroidMemoryWipeBuiState()) when UiInitialized
is false, then set UiInitialized = true so the UI is only opened and the state
sent once per result; keep checks for Acknowledged first and update the
component instance (result.UiInitialized) inside the same loop.
- Around line 183-191: Introduce a private const string for the hardcoded radio
channel name (e.g. private const string AndroidDeviantRadioChannel =
"AndroidDeviantRadio") in the AndroidMemoryWipeSystem class (same pattern as
BaseLawsetId) and replace the two literal occurrences in the method containing
the TryComp<IntrinsicRadioTransmitterComponent> and
TryComp<ActiveRadioComponent> checks to use that constant (replace
"AndroidDeviantRadio" with AndroidDeviantRadioChannel).
In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs`:
- Line 31: Поля зависимости _metaData типа MetaDataSystem в AndroidRevealSystem
не используется; удалите объявление [Dependency] private readonly MetaDataSystem
_metaData = default! из класса AndroidRevealSystem (или, если зависимость
действительно нужна, используйте её явно в методах, например RevealEntity/Update
и т.п.). Найдите в файле класс AndroidRevealSystem и либо удалите поле
_metaData, либо интегрируйте вызовы к методам MetaDataSystem там, где нужны
метаданные, чтобы устранить неиспользуемую зависимость.
In `@Content.Server/Imperial/XxRaay/Android/AndroidStressSystem.cs`:
- Around line 39-45: The AndroidStressSystem.Initialize override is missing a
call to base.Initialize(), which may break EntitySystem setup; update the
AndroidStressSystem.Initialize method to invoke base.Initialize() (typically as
the first line) before subscribing to events (methods referenced: Initialize,
SubscribeLocalEvent, and AndroidStressSystem) to match the pattern used in
AndroidDisguiseSystem, AndroidRevealSystem, and AndroidDiodeSystem.
- Around line 80-94: Итерация по
_lookup.GetEntitiesInRange<AndroidStressComponent> отбрасывает компонент и затем
повторно запрашивает его через TryComp — уберите дублирование: распакуйте
компонент в foreach (var (otherUid, otherComp) in
_lookup.GetEntitiesInRange<AndroidStressComponent>(...)), оставьте проверку self
(if (otherUid == uid) continue), вычисление nearbyDelta и вызов
IncreaseStress(otherUid, ref otherComp, nearbyDelta) напрямую, удалив блок
TryComp и соответствующий continue.
In `@Content.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs`:
- Around line 35-41: component.Fingerprints is a HashSet<string> so using
Skip(startIndex).Take(maxShown) incorrectly assumes a chronological order;
either enforce a deterministic order (e.g., sort or convert to a list that
preserves insertion/chronology) before Skip/Take, or if order truly doesn't
matter simplify to component.Fingerprints.Take(maxShown). Update the code around
recentPrints to first produce an ordered sequence (e.g.,
component.Fingerprints.OrderBy(...).Skip(startIndex).Take(maxShown) or
component.Fingerprints.ToList() when insertion order is guaranteed) or replace
with component.Fingerprints.Take(maxShown) if ordering can be ignored.
In `@Content.Shared/Imperial/XxRaay/Android/AndroidDeviantSpreadDoAfterEvent.cs`:
- Around line 7-9: В XML-комментарии для сущности
AndroidDeviantSpreadDoAfterEvent исправьте опечатку в <summary> — замените слово
«девиантьнонстии» на корректное «девиантности» в комментарии класса/метода
AndroidDeviantSpreadDoAfterEvent.
In `@Content.Shared/Imperial/XxRaay/Android/AndroidEnergyComponent.cs`:
- Around line 59-64: DefaultWalkSpeed and DefaultSprintSpeed in the
AndroidEnergyComponent are runtime state fields but lack the [ViewVariables]
attribute; mark both fields with [ViewVariables] so they are inspectable in the
VV panel (i.e., add the [ViewVariables] attribute above the DefaultWalkSpeed and
DefaultSprintSpeed field declarations in the AndroidEnergyComponent class).
In `@Content.Shared/Imperial/XxRaay/Android/AndroidOverlayComponent.cs`:
- Around line 8-16: The AndroidOverlayComponent is marked [NetworkedComponent]
but lacks [AutoGenerateComponentState] and [AutoNetworkedField], so its fields
(IconSprite, IconScale) won't be synchronized; either remove
[NetworkedComponent] from the AndroidOverlayComponent declaration if these
DataField-only prototype-configured values never change at runtime, or add
[AutoGenerateComponentState] to the AndroidOverlayComponent and annotate the
fields with [AutoNetworkedField] (IconSprite, IconScale) to enable proper
network state generation and syncing.
In
`@Content.Shared/Imperial/XxRaay/Components/AndroidDeviantConsentComponents.cs`:
- Around line 11-34: Mark the runtime state fields Converter, Target, and
RequestStartTime with [ViewVariables] (not [DataField]) and mark the
configurable parameters ResponseTime and MaxDistance with [DataField] so they
are exposed to prototype/YAML configuration; update the
AndroidDeviantConsentComponents class to add [ViewVariables] above the
EntityUid? Converter, EntityUid? Target, and TimeSpan? RequestStartTime
declarations and add [DataField] above the TimeSpan ResponseTime and float
MaxDistance declarations.
- Around line 44-47: The DenyEndTime field on the
AndroidDeviantConsentComponents component is runtime state and should be exposed
with [ViewVariables] instead of being treated as prototype-configured data;
update the AndroidDeviantConsentComponents class to remove any [DataField]
attribute from the public TimeSpan DenyEndTime field (or replace it) and
annotate it with [ViewVariables] so the runtime state is visible in
debugging/UIs while leaving prototype-configurable fields as [DataField].
In `@Content.Shared/Imperial/XxRaay/Components/AndroidRevealComponents.cs`:
- Around line 9-22: The fields Revealer, Target and EscapeInProgress are runtime
state and should be annotated with [ViewVariables] so they appear in VV; update
the AndroidRevealComponents component to add the [ViewVariables] attribute to
the Revealer, Target and EscapeInProgress fields (remove any incorrect
[DataField] usage if present) ensuring the attributes are applied to those
specific fields so they are exposed as view variables at runtime.
In `@Content.Shared/Imperial/XxRaay/Components/AndroidRk800Component.cs`:
- Around line 1-4: Remove the unused Robust.Shared.GameStates import and mark
the runtime-only field NextMemoryWipeTime with [ViewVariables] on the
AndroidRk800Component; specifically, delete the using Robust.Shared.GameStates
line, locate the AndroidRk800Component class and add the [ViewVariables]
attribute to the NextMemoryWipeTime field/property so it’s exposed for
debugging/inspection (no [NetworkedComponent] changes required).
In `@Resources/Locale/ru-RU/Imperial/XxRaay/android.ftl`:
- Line 17: Fix the typo in the localization entry with key law-detroit-rk800-4:
change "нейтрализаци" to "нейтрализации" so the sentence reads "...насилие для
нейтрализации угроз корпорации." Ensure only the single word is corrected and
preserve surrounding punctuation and spacing.
In `@Resources/Prototypes/Imperial/XxRaay/android.yml`:
- Around line 494-499: The siliconLawset entry with id "DetroitAndroidDeviant"
incorrectly includes "obeysTo: laws-owner-crew" while a deviant android should
be autonomous; locate the "type: siliconLawset" block for DetroitAndroidDeviant
and either remove the "obeysTo: laws-owner-crew" field entirely or replace it
with the correct autonomy field/value used for deviants in this repo (e.g., no
obeysTo or an explicit autonomy flag), ensuring the "laws" list
(DetroitAndroidDeviant1) remains intact.
| protected override void Dispose(bool disposing) | ||
| { | ||
| if (!disposing) | ||
| return; | ||
|
|
||
| if (_window != null) | ||
| { | ||
| _window.AcceptPressed -= OnAcceptPressed; | ||
| _window.DeclinePressed -= OnDeclinePressed; | ||
| _window = null; | ||
| } | ||
|
|
||
| base.Dispose(disposing); | ||
| } |
There was a problem hiding this comment.
base.Dispose(disposing) не вызывается, когда disposing == false.
Ранний return на строке 123-124 пропускает вызов base.Dispose(disposing) при вызове из финализатора (disposing == false). Базовый класс BoundUserInterface может выполнять критическую очистку в этом пути.
🛠️ Предложенное исправление
protected override void Dispose(bool disposing)
{
- if (!disposing)
- return;
-
- if (_window != null)
+ if (disposing)
{
- _window.AcceptPressed -= OnAcceptPressed;
- _window.DeclinePressed -= OnDeclinePressed;
- _window = null;
+ if (_window != null)
+ {
+ _window.AcceptPressed -= OnAcceptPressed;
+ _window.DeclinePressed -= OnDeclinePressed;
+ _window = null;
+ }
}
base.Dispose(disposing);
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Client/Imperial/XxRaay/UI/AndroidDeviantConsentUserInterface.cs`
around lines 121 - 134, В методе Dispose(bool disposing) удалите ранний return,
чтобы base.Dispose(disposing) всегда вызывался; вместо этого оберните логику
отписки событий в условие if (disposing) — т.е. при disposing==true проверяйте
_window != null и убирайте обработчики OnAcceptPressed/OnDeclinePressed и
зануляйте _window, а затем в конце метода вызовите base.Dispose(disposing) в
любом случае, чтобы гарантировать выполнение финализаторного пути базового
класса BoundUserInterface.
| protected override void Dispose(bool disposing) | ||
| { | ||
| if (!disposing) | ||
| return; | ||
|
|
||
| if (_window != null) | ||
| { | ||
| _window.AcceptPressed -= OnAcceptPressed; | ||
| _window.DeclinePressed -= OnDeclinePressed; | ||
| _window = null; | ||
| } | ||
|
|
||
| base.Dispose(disposing); | ||
| } |
There was a problem hiding this comment.
base.Dispose(disposing) не вызывается при disposing == false.
Аналогично AndroidDeviantConsentUserInterface — ранний return пропускает вызов базовой очистки.
🛠️ Предложенное исправление
protected override void Dispose(bool disposing)
{
- if (!disposing)
- return;
-
- if (_window != null)
+ if (disposing)
{
- _window.AcceptPressed -= OnAcceptPressed;
- _window.DeclinePressed -= OnDeclinePressed;
- _window = null;
+ if (_window != null)
+ {
+ _window.AcceptPressed -= OnAcceptPressed;
+ _window.DeclinePressed -= OnDeclinePressed;
+ _window = null;
+ }
}
base.Dispose(disposing);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| protected override void Dispose(bool disposing) | |
| { | |
| if (!disposing) | |
| return; | |
| if (_window != null) | |
| { | |
| _window.AcceptPressed -= OnAcceptPressed; | |
| _window.DeclinePressed -= OnDeclinePressed; | |
| _window = null; | |
| } | |
| base.Dispose(disposing); | |
| } | |
| protected override void Dispose(bool disposing) | |
| { | |
| if (disposing) | |
| { | |
| if (_window != null) | |
| { | |
| _window.AcceptPressed -= OnAcceptPressed; | |
| _window.DeclinePressed -= OnDeclinePressed; | |
| _window = null; | |
| } | |
| } | |
| base.Dispose(disposing); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Client/Imperial/XxRaay/UI/AndroidStressDeviantChoiceUserInterface.cs`
around lines 111 - 124, В текущем Dispose(bool disposing) методе класса
AndroidStressDeviantChoiceUserInterface базовый Dispose пропускается при
disposing == false; нужно гарантировать вызов base.Dispose(disposing) всегда.
Уберите ранний return или переместите base.Dispose(disposing) вне условия,
оставив только блок отписки от событий (_window.AcceptPressed/DeclinePressed ->
OnAcceptPressed/OnDeclinePressed) внутри if (disposing && _window != null) и
затем вызовите base.Dispose(disposing) в конце метода; аналогично согласуйте
поведение с AndroidDeviantConsentUserInterface.
| public override void Update(float frameTime) | ||
| { | ||
| base.Update(frameTime); | ||
|
|
||
| var now = _timing.CurTime; | ||
|
|
||
| var denyQuery = EntityQueryEnumerator<AndroidDeviantConsentDenyCooldownComponent>(); | ||
| while (denyQuery.MoveNext(out var uid, out var denyCooldown)) | ||
| { | ||
| if (denyCooldown.DenyEndTime == TimeSpan.Zero || now < denyCooldown.DenyEndTime) | ||
| continue; | ||
|
|
||
| RemCompDeferred<AndroidDeviantConsentDenyCooldownComponent>(uid); | ||
| } | ||
|
|
||
| var consentQuery = EntityQueryEnumerator<AndroidDeviantConsentConversionComponent>(); | ||
| while (consentQuery.MoveNext(out var uid, out var consent)) | ||
| { | ||
| if (consent.Converter is not { } converter || | ||
| consent.Target is not { } target) | ||
| { | ||
| RemCompDeferred<AndroidDeviantConsentConversionComponent>(uid); | ||
| continue; | ||
| } | ||
|
|
||
| if (consent.RequestStartTime is { } start && | ||
| now - start > consent.ResponseTime) | ||
| { | ||
| CancelConsent(target, converter, Loc.GetString("android-deviant-consent-failed-timeout")); | ||
| continue; | ||
| } | ||
|
|
||
| if (!_transform.InRange(Transform(target).Coordinates, | ||
| Transform(converter).Coordinates, | ||
| consent.MaxDistance)) | ||
| { | ||
| CancelConsent(target, converter, Loc.GetString("android-deviant-consent-failed-out-of-range")); | ||
| } | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Потенциальная проблема: CancelConsent на строке 78 вызывается без continue.
Если CancelConsent удалит компонент через RemCompDeferred, итератор consentQuery уже получил ссылку на этот элемент, и цикл продолжится к следующей итерации MoveNext. Это работает корректно с RemCompDeferred (удаление отложено), но после CancelConsent текущая сущность уже обработана — стоит добавить continue для ясности и защиты от будущих изменений ниже по циклу.
🛠️ Предложенное исправление
if (!_transform.InRange(Transform(target).Coordinates,
Transform(converter).Coordinates,
consent.MaxDistance))
{
CancelConsent(target, converter, Loc.GetString("android-deviant-consent-failed-out-of-range"));
+ continue;
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Server/Imperial/XxRaay/Android/AndroidDeviantSpreadSystem.cs` around
lines 42 - 80, In Update(), inside the consentQuery loop handling
AndroidDeviantConsentConversionComponent, add a continue immediately after the
call to CancelConsent(target, converter,
Loc.GetString("android-deviant-consent-failed-out-of-range")) so the loop skips
further processing for that entity; locate the consentQuery while loop in Update
and append the continue after the CancelConsent(...) call.
| var maxSeverity = _alerts.GetMaxSeverity(energyComp.Alert); | ||
| var minSeverity = _alerts.GetMinSeverity(energyComp.Alert); | ||
| var severity = (short) Math.Clamp(Math.Round(percent * maxSeverity), minSeverity, maxSeverity); | ||
|
|
||
| _alerts.ShowAlert(uid, energyComp.Alert, severity); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "*.cs" -type f | head -20Repository: imperial-space/SS14-public
Length of output: 987
🏁 Script executed:
rg -l "AndroidEnergyComponent" --type=csRepository: imperial-space/SS14-public
Length of output: 196
🏁 Script executed:
rg -n "class AndroidEnergyComponent" --type=cs -A 15Repository: imperial-space/SS14-public
Length of output: 1595
🏁 Script executed:
find . -name "*.yml" -o -name "*.yaml" | xargs rg -l "AndroidEnergy" 2>/dev/null | head -10Repository: imperial-space/SS14-public
Length of output: 120
🏁 Script executed:
rg -n "GetMaxSeverity\|GetMinSeverity" --type=cs -B 2 -A 2Repository: imperial-space/SS14-public
Length of output: 52
🏁 Script executed:
cat -n ./Resources/Prototypes/Imperial/XxRaay/android.yml | head -100Repository: imperial-space/SS14-public
Length of output: 4020
🏁 Script executed:
cat -n ./Content.Shared/Imperial/XxRaay/Android/AndroidEnergyComponent.csRepository: imperial-space/SS14-public
Length of output: 2119
🏁 Script executed:
rg -n "AlertPrototype\|alert.*severity" --type=yml -i | head -30Repository: imperial-space/SS14-public
Length of output: 97
🏁 Script executed:
rg -n "class AlertPrototype" --type=cs -A 10Repository: imperial-space/SS14-public
Length of output: 1997
🏁 Script executed:
cat -n Content.Server/Imperial/XxRaay/Android/AndroidEnergySystem.csRepository: imperial-space/SS14-public
Length of output: 3037
🏁 Script executed:
rg -n "AndroidEnergy" --type=yamlRepository: imperial-space/SS14-public
Length of output: 219
🏁 Script executed:
rg -n "type: alert" ./Resources/Prototypes/Imperial/XxRaay/android.yml -A 10Repository: imperial-space/SS14-public
Length of output: 797
Направление маппинга severity инвертировано.
Текущая логика строит severity пропорционально уровню крови: при полной энергии (percent = 1.0) severity = maxSeverity (3), что соответствует иконке battery3 (пустая батарея). При нулевой энергии severity = 0, соответствует battery0 (полная батарея). Это противоположно правильному поведению.
Необходимо инвертировать масштабирование:
var severity = (short) Math.Clamp(Math.Round((1 - percent) * maxSeverity), minSeverity, maxSeverity);Так при полной энергии будет severity = 0 (полная батарея), при нулевой энергии — severity = maxSeverity (пустая батарея).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Server/Imperial/XxRaay/Android/AndroidEnergySystem.cs` around lines
38 - 42, The severity mapping is inverted: update the calculation in
AndroidEnergySystem where you compute severity from percent (using
_alerts.GetMaxSeverity, _alerts.GetMinSeverity and energyComp.Alert) so that low
percent yields high severity and high percent yields low severity—i.e. compute
severity from the inverse of percent (1 - percent), round and cast to short,
clamp between minSeverity and maxSeverity, then pass that severity into
_alerts.ShowAlert(uid, energyComp.Alert, severity).
Content.Shared/Imperial/XxRaay/Android/AndroidDiodeComponent.cs
Outdated
Show resolved
Hide resolved
Content.Shared/Imperial/XxRaay/Components/AndroidMemoryWipeComponents.cs
Show resolved
Hide resolved
Content.Shared/Imperial/XxRaay/Components/AndroidMemoryWipeComponents.cs
Show resolved
Hide resolved
| android-rk800-examine-fingerprints-one = [color=#4d7ee7]Анализ отпечатков: обнаружен { $count } образец.[/color] | ||
| android-rk800-examine-fingerprints-many = [color=#4d7ee7]Анализ отпечатков: обнаружено { $count } образцов.[/color] |
There was a problem hiding this comment.
Отсутствует русская форма множественного числа для 2–4.
В русском языке три формы: 1 образец, 2–4 образца, 5+ образцов. Сейчас используются только ключи one и many. При count = 2, 3, 4 текст будет грамматически некорректным: "обнаружено 2 образцов" вместо "обнаружено 2 образца".
Fluent поддерживает селекторы множественного числа через { $count -> ... }. Рекомендуется добавить форму few:
📝 Пример с Fluent-селектором
-android-rk800-examine-fingerprints-one = [color=#4d7ee7]Анализ отпечатков: обнаружен { $count } образец.[/color]
-android-rk800-examine-fingerprints-many = [color=#4d7ee7]Анализ отпечатков: обнаружено { $count } образцов.[/color]
+android-rk800-examine-fingerprints = [color=#4d7ee7]Анализ отпечатков: { $count ->
+ [one] обнаружен { $count } образец
+ [few] обнаружено { $count } образца
+ *[other] обнаружено { $count } образцов
+}.[/color]Это потребует изменения C#-кода в AndroidRk800ForensicsSystem.cs — вместо ручного выбора ключа по total == 1 использовать единый ключ с Fluent-плюрализацией.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Resources/Locale/ru-RU/Imperial/XxRaay/android.ftl` around lines 67 - 68, Add
a Russian "few" plural form and switch the code to use Fluent plural selection:
update the FTL entries by replacing the separate keys
android-rk800-examine-fingerprints-one and -many with a single key (e.g.,
android-rk800-examine-fingerprints) that uses a { $count -> [one] … [few] …
[many] } selector and the correct word forms ("образец", "образца", "образцов");
then change AndroidRk800ForensicsSystem.cs to stop choosing keys based on total
== 1 and instead call the single Fluent message
(android-rk800-examine-fingerprints) passing total (or count) as $count to
Fluent so the runtime plural rules handle 1/2–4/5+ correctly.
| - type: reagent | ||
| id: Thirium | ||
| name: reagent-name-thirium | ||
| group: Toxins | ||
| desc: reagent-desc-thirium | ||
| physicalDesc: reagent-physical-desc-glowing | ||
| flavor: metallic | ||
| color: "#4d7ee7" | ||
| metabolisms: | ||
| Poison: | ||
| effects: | ||
| - !type:HealthChange | ||
| damage: | ||
| types: | ||
| Poison: 1 | ||
| conditions: | ||
| - !type:MetabolizerTypeCondition | ||
| type: Android | ||
| shouldHave: false | ||
| Medicine: | ||
| effects: | ||
| - !type:ModifyBloodLevel | ||
| amount: 1.3 | ||
| conditions: | ||
| - !type:MetabolizerTypeCondition | ||
| type: Android | ||
| shouldHave: true | ||
| - !type:HealthChange | ||
| damage: | ||
| types: | ||
| Blunt: -0.5 | ||
| Slash: -0.5 | ||
| Piercing: -0.5 | ||
| conditions: | ||
| - !type:MetabolizerTypeCondition | ||
| type: Android | ||
| shouldHave: true |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Run the original verification script
echo "=== Searching for Android body prototype ==="
rg -n -C5 'id:\s*Android' --type yaml -g '*/Body/*' || rg -n -C5 'id:\s*Android' --type yaml -g '*body*' || rg -n -C5 'prototype:\s*Android' --type yaml
echo ""
echo "=== Searching for MetabolizerType Android ==="
rg -n -C3 'type:\s*Android' --type yaml -g '*metabol*' || rg -n -C3 'metabolizerType.*Android' --type yaml || rg -n 'Android' --type yaml -g '*organ*'
echo ""
echo "=== Search for MetabolizerType definitions ==="
rg -n 'MetabolizerType' --type yaml | head -30
echo ""
echo "=== Looking for android.yml file and its content ==="
fd 'android.yml' --type fRepository: imperial-space/SS14-public
Length of output: 5127
🏁 Script executed:
#!/bin/bash
# Find where Android body prototype is defined
echo "=== Searching for Android body prototype definition ==="
rg -n "^\s*id:\s*Android$" --type yaml
echo ""
echo "=== Looking for body prototypes ==="
fd -t f "body" --type f -x rg -l "id:\s*Android" {} \;
echo ""
echo "=== Checking XxRaay android.yml for Metabolizer component ==="
rg -n "Metabolizer" Resources/Prototypes/Imperial/XxRaay/android.yml -C3
echo ""
echo "=== Check for Android body definition in Body prototypes ==="
fd ".*body.*\.yml" -type f | xargs rg -l "id:\s*Android"
echo ""
echo "=== Show all Android definitions ==="
rg -n "^\s*id:\s*Android" --type yaml -C2Repository: imperial-space/SS14-public
Length of output: 5980
🏁 Script executed:
#!/bin/bash
# Find the entity in XxRaay that has "prototype: Android" and show its full definition
echo "=== Entity with prototype: Android in XxRaay ==="
rg -n -B30 'prototype: Android' Resources/Prototypes/Imperial/XxRaay/android.yml | head -80
echo ""
echo "=== Show the Crook Android body definition ==="
rg -n -A50 'type: body' Resources/Prototypes/Imperial/Crook/base.yml | grep -A50 'id: Android'Repository: imperial-space/SS14-public
Length of output: 2037
🏁 Script executed:
#!/bin/bash
# Find the full entity definition in XxRaay that has "prototype: Android"
echo "=== Find the entity ID and parent in XxRaay around line 156 ==="
sed -n '100,180p' Resources/Prototypes/Imperial/XxRaay/android.yml
echo ""
echo "=== Check if XxRaay android has Metabolizer ==="
rg -n "Metabolizer" Resources/Prototypes/Imperial/XxRaay/android.yml -B5 -A5 | head -50Repository: imperial-space/SS14-public
Length of output: 2681
🏁 Script executed:
#!/bin/bash
# Find the entity definition in XxRaay - need to find the top of the entity
echo "=== Find parent and id of the entity in XxRaay ==="
sed -n '50,160p' Resources/Prototypes/Imperial/XxRaay/android.yml | grep -E "^- type:|^ id:|^ parent:"
echo ""
echo "=== Get a broader view of the XxRaay android entity ==="
sed -n '1,200p' Resources/Prototypes/Imperial/XxRaay/android.yml | tail -150
echo ""
echo "=== Check BaseMobSpecies parent for Metabolizer ==="
rg -n "BaseMobSpecies" --type yaml -A50 | head -80Repository: imperial-space/SS14-public
Length of output: 10888
🏁 Script executed:
#!/bin/bash
# Find the complete entity definition that contains "prototype: Android" in XxRaay
echo "=== Find the entity definition in XxRaay ==="
awk '/^- type: entity|^ parent:|^ id:/{if (/^- type: entity/) {print NR":"$0; entity_start=NR} else {print NR":"$0}} /prototype: Android/{if (NR-entity_start < 100) print "LINE " NR ":" $0}' Resources/Prototypes/Imperial/XxRaay/android.yml | head -40
echo ""
echo "=== Get the first 20 lines to see the entity definition ==="
head -20 Resources/Prototypes/Imperial/XxRaay/android.yml
echo ""
echo "=== Check MobBloodstream for Metabolizer ==="
rg -n "MobBloodstream" --type yaml -A30 | head -60Repository: imperial-space/SS14-public
Length of output: 6922
🏁 Script executed:
#!/bin/bash
# Find where MobBloodstream is defined
echo "=== Find MobBloodstream definition ==="
rg -n "^- type: entity" --type yaml -A100 | grep -B5 -A40 "id: MobBloodstream" | head -60
echo ""
echo "=== Search for metabolizerTypes in XxRaay android ==="
rg -n "metabolizerTypes" Resources/Prototypes/Imperial/XxRaay/android.yml
echo ""
echo "=== Search for metabolizerTypes in Crook android ==="
rg -n "metabolizerTypes" Resources/Prototypes/Imperial/Crook/base.ymlRepository: imperial-space/SS14-public
Length of output: 3597
🏁 Script executed:
#!/bin/bash
# Get the full MobBloodstream definition
echo "=== Full MobBloodstream definition ==="
sed -n '254,350p' Resources/Prototypes/Entities/Mobs/base.yml
echo ""
echo "=== Check if MobBloodstream has Metabolizer ==="
sed -n '254,350p' Resources/Prototypes/Entities/Mobs/base.yml | grep -i metabolizerRepository: imperial-space/SS14-public
Length of output: 465
🏁 Script executed:
#!/bin/bash
# Check BaseMobSpecies definition
echo "=== Find BaseMobSpecies definition ==="
rg -n "^- type: entity" --type yaml -A100 | grep -B5 -A50 "id: BaseMobSpecies" | head -70
echo ""
echo "=== Confirm: search for Metabolizer in XxRaay android components ==="
sed -n '1,305p' Resources/Prototypes/Imperial/XxRaay/android.yml | grep -i "type: Metabolizer"
echo ""
echo "=== Verify: does Crook BaseMobMechanic have Metabolizer ==="
rg -n -A30 "id: BaseMobMechanic" Resources/Prototypes/Imperial/Crook/base.ymlRepository: imperial-space/SS14-public
Length of output: 7230
Метаболизмы Thirium: добавьте компонент Metabolizer в прототип Android.
Реагент Thirium использует MetabolizerTypeCondition с type: Android (строки 563, 571, 581) и требует, чтобы условие shouldHave: true было выполнено для активации лечебного эффекта ModifyBloodLevel и восстановления урона. Однако прототип BaseMobAndroid в этом файле не содержит компонента Metabolizer, что означает, что эти условия никогда не будут выполнены и андроиды не получат лечебного эффекта от Thirium.
Добавьте компонент Metabolizer с metabolizerTypes: [ Android ] в BaseMobAndroid (аналогично Crook конфигурации в Resources/Prototypes/Imperial/Crook/base.yml:53).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Resources/Prototypes/Imperial/XxRaay/android.yml` around lines 546 - 582, The
BaseMobAndroid prototype lacks a Metabolizer component so
MetabolizerTypeCondition checks in the Thirium reagent (used by ModifyBloodLevel
and HealthChange effects) never succeed; add a Metabolizer component to the
BaseMobAndroid prototype with metabolizerTypes: [ Android ] (mirroring the Crook
prototype's Metabolizer config) so the MetabolizerTypeCondition(type: Android,
shouldHave: true) in the Thirium reagent can activate the healing effects.
…ponents.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
Content.Shared/Imperial/XxRaay/Components/AndroidDeviantConsentComponents.cs (1)
49-53:⚠️ Potential issue | 🟡 MinorДобавьте
[ViewVariables]дляDenyEndTime.На Line 52 это runtime-состояние кулдауна, и без
[ViewVariables]поле не видно в VV, что усложняет отладку и диагностику.♻️ Предлагаемое исправление
/// <summary> /// Момент времени, после которого цель снова может получать запросы. /// </summary> + [ViewVariables] public TimeSpan DenyEndTime;Based on learnings: "fields of components that are not configured via YAML prototypes (runtime state) should be marked with the [ViewVariables] attribute, while fields configured via prototypes should use [DataField]."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Shared/Imperial/XxRaay/Components/AndroidDeviantConsentComponents.cs` around lines 49 - 53, Add the [ViewVariables] attribute to the runtime cooldown field DenyEndTime in the AndroidDeviantConsentComponents component so the cooldown state is visible in VV; locate the public TimeSpan DenyEndTime field and annotate it with [ViewVariables] (do not change DataField usage elsewhere) to expose this runtime state for debugging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In
`@Content.Shared/Imperial/XxRaay/Components/AndroidDeviantConsentComponents.cs`:
- Around line 49-53: Add the [ViewVariables] attribute to the runtime cooldown
field DenyEndTime in the AndroidDeviantConsentComponents component so the
cooldown state is visible in VV; locate the public TimeSpan DenyEndTime field
and annotate it with [ViewVariables] (do not change DataField usage elsewhere)
to expose this runtime state for debugging.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (3)
Resources/Textures/Imperial/XxRaay/android.rsi/light e.pngis excluded by!**/*.pngResources/Textures/Imperial/XxRaay/android.rsi/light g.pngis excluded by!**/*.pngResources/Textures/Imperial/XxRaay/android.rsi/light r.pngis excluded by!**/*.png
📒 Files selected for processing (5)
Content.Shared/Imperial/XxRaay/Android/AndroidDiodeComponent.csContent.Shared/Imperial/XxRaay/Components/AndroidDeviantConsentComponents.csContent.Shared/Imperial/XxRaay/Components/AndroidMemoryWipeComponents.csContent.Shared/Imperial/XxRaay/Components/AndroidRevealComponents.csContent.Shared/Imperial/XxRaay/Components/AndroidRk800Component.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 9
♻️ Duplicate comments (8)
Content.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs (1)
38-40: Ручной выбор ключа плюрализации по-прежнему не учитывает русскую грамматику.Тернарник
total == 1 ? "...-one" : "...-many"даёт только две формы, тогда как в русском языке для чисел 2–4 нужна формаfew("образца" вместо "образцов"). Следует использовать встроенную плюрализацию Fluent с единым ключом, передавая числовой параметрcount.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs` around lines 38 - 40, Переменная key задаётся тернарником по total (total == 1 ? "...-one" : "...-many"), что даёт только две формы и игнорирует русскую грамматику; замените ручной выбор ключа на одну Fluent/локализационную запись с передачей числового параметра (count/total) в вызов локализации вместо использования key, т.е. уберите тернарник, используйте единый ключ локализации и передайте total как параметр для корректной плюрализации в AndroidRk800ForensicsSystem (переменная total и ключи "android-rk800-examine-fingerprints-..." из текущего кода).Content.Client/Imperial/XxRaay/UI/AndroidStressDeviantChoiceUserInterface.cs (1)
112-125:⚠️ Potential issue | 🟠 MajorНужно всегда вызывать
base.Dispose(disposing), даже когдаdisposing == false.Сейчас ранний
returnна Line 114-115 пропускает базовую очистку в веткеfalse. Это риск некорректного освобождения ресурсов в базовом классе.🛠️ Предлагаемое исправление
protected override void Dispose(bool disposing) { - if (!disposing) - return; - - if (_window != null) + if (disposing && _window != null) { _window.AcceptPressed -= OnAcceptPressed; _window.DeclinePressed -= OnDeclinePressed; _window = null; } base.Dispose(disposing); }#!/bin/bash # Проверка паттерна Dispose в текущем файле: cat -n Content.Client/Imperial/XxRaay/UI/AndroidStressDeviantChoiceUserInterface.cs | sed -n '108,128p'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Client/Imperial/XxRaay/UI/AndroidStressDeviantChoiceUserInterface.cs` around lines 112 - 125, В методе Dispose(bool disposing) класса AndroidStressDeviantChoiceUserInterface текущий ранний return при disposing == false пропускает вызов base.Dispose(disposing); уберите ранний return и измените логику так, чтобы отписка от событий (_window.AcceptPressed -= OnAcceptPressed; _window.DeclinePressed -= OnDeclinePressed; _window = null) выполнялась только когда disposing == true, но вызов base.Dispose(disposing) всегда выполнялся в конце метода; сохраните проверку на _window != null при отписке и убедитесь, что base.Dispose(disposing) вызывается независимо от значения disposing.Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.cs (1)
67-91: 🧹 Nitpick | 🔵 TrivialДлинный список явных вызовов
LayerSetVisible— рассмотрите итерацию по enum.20 захардкоженных вызовов
LayerSetVisibleдля значенийHumanoidVisualLayers. При добавлении новых слоёв в enum они автоматически не попадут в этот метод. Можно итерировать поEnum.GetValues<HumanoidVisualLayers>(), при необходимости исключая конкретные слои.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.cs` around lines 67 - 91, The SetHumanoidVisible method contains 20 hard-coded _sprite.LayerSetVisible calls for each HumanoidVisualLayers value; replace the explicit calls in SetHumanoidVisible with a loop over Enum.GetValues<HumanoidVisualLayers>() (or Enum.GetValues(typeof(HumanoidVisualLayers))) and call _sprite.LayerSetVisible(spriteEnt, layer, visible) for each, optionally filtering out any layers you want to skip, so new enum members are handled automatically and the long explicit list is removed.Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs (2)
164-170:BreakOnMove = trueнеэффективен из-за блокировки движения.Движение цели заблокировано через
OnUpdateCanMove→args.Cancel(), поэтому позиция не изменится, иBreakOnMove = trueникогда не сработает. Параметр можно убрать или заменить наfalse.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs` around lines 164 - 170, The DoAfterArgs construction sets BreakOnMove = true but movement is already prevented via OnUpdateCanMove → args.Cancel(), so BreakOnMove is ineffective; update the DoAfterArgs in AndroidRevealSystem (where AndroidRevealEscapeDoAfterEvent is created) to remove BreakOnMove or set it to false (i.e., BreakOnMove = false) to reflect that movement won't occur, leaving BreakOnDamage and NeedHand as-is.
118-124: Неверный ключ локализации для раскрытия маскировки.Ключ
"android-deviant-consent-convert-popup"относится к системе передачи девиантности, а не к раскрытию маскировки. Необходимо создать и использовать корректный ключ, соответствующий действию принудительного раскрытия.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs` around lines 118 - 124, The popup in AndroidRevealSystem.cs currently uses the wrong localization key ("android-deviant-consent-convert-popup") in the _popup.PopupEntity call; replace that key with a new, correct key for forced reveal (e.g., "android-reveal-mask-popup") and add the corresponding entry to the localization files with the proper text and formatting tokens (keep the same ("target", Identity.Entity(target, EntityManager)) usage), so _popup.PopupEntity uses the reveal-specific localization string instead of the deviance-transfer one.Content.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.cs (1)
89-92: Пустое переопределениеUpdateState— можно удалить.Метод по-прежнему только вызывает
base.UpdateState(state)без какой-либо дополнительной логики. Переопределение избыточно и может быть безопасно удалено.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.cs` around lines 89 - 92, Удалить пустое переопределение метода UpdateState(BoundUserInterfaceState state) в классе AndroidMemoryWipeUserInterface: метод только вызывает base.UpdateState(state) и не добавляет логики, поэтому уберите этот override (оставьте базовую реализацию) и убедитесь, что нет других зависимостей от этого конкретного переопределения.Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs (1)
105-118:⚠️ Potential issue | 🟠 Major
Disposeдолжен всегда вызыватьbase.Dispose(disposing).Сейчас ранний
returnна Line 107-108 пропускает базовую очистку приdisposing == false.💡 Предлагаемое исправление
protected override void Dispose(bool disposing) { - if (!disposing) - return; - - if (_window != null) + if (disposing && _window != null) { _window.AcceptPressed -= OnAcceptPressed; _window.DeclinePressed -= OnDeclinePressed; _window = null; } base.Dispose(disposing); }#!/bin/bash set -euo pipefail file="Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs" nl -ba "$file" | sed -n '103,119p'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs` around lines 105 - 118, Dispose currently returns early when disposing is false which prevents calling base.Dispose(disposing); remove the early return and instead only perform the _window cleanup when disposing is true (e.g. wrap the _window unsubscribe block in if (disposing) { ... }), then always call base.Dispose(disposing) at the end of the Dispose method so base cleanup runs regardless; refer to Dispose(bool disposing), the _window field and handlers OnAcceptPressed/OnDeclinePressed to locate where to move the base call.Content.Server/Imperial/XxRaay/Android/AndroidDeviantSpreadSystem.cs (1)
199-199: 🧹 Nitpick | 🔵 TrivialСнизьте видимость
HandleConsentAcceptedиHandleConsentDeniedдоprivate.Сигнатуры выглядят как внутренние хелперы системы и не требуют публичной API-поверхности.
Also applies to: 233-233
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Server/Imperial/XxRaay/Android/AndroidDeviantSpreadSystem.cs` at line 199, Измените видимость методов HandleConsentAccepted и HandleConsentDenied в классе AndroidDeviantSpreadSystem с public на private, так как они являются внутренними хелперами системы и не должны быть частью публичного API; найдите объявления методов HandleConsentAccepted(EntityUid target, EntityUid converter) и HandleConsentDenied(...) и просто заменить модификатор доступа на private, сохранив текущие сигнатуры и поведение.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.cs`:
- Around line 24-28: Remove the redundant local variable and explicit cast in
OnStartup: do not create "var uid = (EntityUid) ent"; pass the
Entity<AndroidDisguiseComponent> value (ent) directly into UpdateVisuals (and
any other methods that accept EntityUid) since Entity<T> implicitly converts to
EntityUid. Apply the same cleanup to the other occurrences mentioned (the blocks
around lines 30-41 and 43-47) so no methods create an intermediate uid via
(EntityUid) ent and instead pass ent directly; ensure references to
AndroidDisguiseComponent, OnStartup, and UpdateVisuals are preserved.
- Around line 55-61: The enum comparison in AndroidDisguiseVisualizerSystem is
inconsistent: replace the pattern-match check using "is" on comp.State with an
equality comparison "==" to match the other comparisons; specifically update the
call to _sprite.LayerSetVisible that references AndroidBaseLayer so it uses
comp.State == AndroidDisguiseState.Android (keeping the existing comparisons for
AndroidTransformLayer and AndroidRetransformLayer unchanged) to make all
comparisons against AndroidDisguiseState consistent.
In `@Content.Client/Imperial/XxRaay/Android/AndroidOverlaySystem.cs`:
- Line 11: Класс AndroidOverlaySystem объявлен с модификатором partial, но
другой части класса или source-генераторов не видно — удалите keyword partial из
объявления класса (AndroidOverlaySystem : EntitySystem) в
AndroidOverlaySystem.cs; перед удалением убедитесь, что нет других
partial-частей класса или внешних генераторов/файлов, которые ожидают наличия
partial, и затем перестройте проект.
In `@Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs`:
- Around line 98-103: В коде есть лишняя закрывающая фигурная скобка, которая
преждевременно завершает класс AndroidDisguiseNameUserInterface; удалите эту
лишнюю `}` так, чтобы методы OnDeclinePressed и Dispose оказались внутри класса
и баланс фигурных скобок был восстановлен (проверьте методы OnDeclinePressed и
Dispose и отступы после корректировки).
In `@Content.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.cs`:
- Line 59: The UI currently only hooks the close-button (_closeButton.OnPressed)
and misses the DefaultWindow close path, causing ConfirmAndClosePressed not to
fire and the server to never get an acknowledged=false; add a handler on the
window close event (the DefaultWindow's Closing/OnClose event) to send an
explicit cancellation or invoke ConfirmAndClosePressed with a cancellation
result so the server receives Acknowledged = false, or alternatively implement a
simple timeout in Update (check elapsed time and send cancellation when
exceeded) and ensure OnMemoryWipeAcknowledge still accepts/handles the cancel
message; reference _closeButton.OnPressed, ConfirmAndClosePressed, DefaultWindow
(or its Closing event), Update, and OnMemoryWipeAcknowledge when making the
change.
In `@Content.Server/Imperial/XxRaay/Android/AndroidDeviantSpreadSystem.cs`:
- Around line 355-370: When cancelling consent in CancelConsent you remove the
AndroidDeviantConsentConversionComponent but never close the open UI, leaving
stale BUI visible; before removing the component, explicitly close any bound UI
for both target and converter using the engine's BUI API (e.g. call the Bound
User Interface close method such as _bui.TryClose/CloseAll or the equivalent in
your codebase for the target and converter entities), then proceed to clear
fields and RemCompDeferred on AndroidDeviantConsentConversionComponent.
In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs`:
- Around line 30-31: Remove the duplicate field declaration of
ActionBlockerSystem named _actionBlocker in the AndroidRevealSystem class; keep
a single [Dependency] private readonly ActionBlockerSystem _actionBlocker =
default! declaration and delete the second identical line to resolve the CS0102
duplicate definition error.
In `@Content.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs`:
- Around line 35-44: The code references an undeclared variable total in
AndroidRk800ForensicsSystem (used when choosing key and in args.PushMarkup), so
restore/declare total by computing the fingerprint count from the component
(e.g., set total = component.Fingerprints.Count) before it’s used; ensure this
declaration appears before recentPrints, the key selection, and the
args.PushMarkup call so Loc.GetString(("count", total)) has a valid value.
In `@Content.Shared/Imperial/XxRaay/Android/AndroidEnergyComponent.cs`:
- Around line 53-54: The NextUpdate runtime state field in
AndroidEnergyComponent is missing the [ViewVariables] attribute; update the
field declaration for NextUpdate (currently annotated with [AutoPausedField]) to
also include [ViewVariables] so it follows the project's convention for
runtime-only state fields (like DefaultWalkSpeed and DefaultSprintSpeed) that
are not configured via YAML prototypes.
---
Duplicate comments:
In `@Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.cs`:
- Around line 67-91: The SetHumanoidVisible method contains 20 hard-coded
_sprite.LayerSetVisible calls for each HumanoidVisualLayers value; replace the
explicit calls in SetHumanoidVisible with a loop over
Enum.GetValues<HumanoidVisualLayers>() (or
Enum.GetValues(typeof(HumanoidVisualLayers))) and call
_sprite.LayerSetVisible(spriteEnt, layer, visible) for each, optionally
filtering out any layers you want to skip, so new enum members are handled
automatically and the long explicit list is removed.
In `@Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs`:
- Around line 105-118: Dispose currently returns early when disposing is false
which prevents calling base.Dispose(disposing); remove the early return and
instead only perform the _window cleanup when disposing is true (e.g. wrap the
_window unsubscribe block in if (disposing) { ... }), then always call
base.Dispose(disposing) at the end of the Dispose method so base cleanup runs
regardless; refer to Dispose(bool disposing), the _window field and handlers
OnAcceptPressed/OnDeclinePressed to locate where to move the base call.
In `@Content.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.cs`:
- Around line 89-92: Удалить пустое переопределение метода
UpdateState(BoundUserInterfaceState state) в классе
AndroidMemoryWipeUserInterface: метод только вызывает base.UpdateState(state) и
не добавляет логики, поэтому уберите этот override (оставьте базовую реализацию)
и убедитесь, что нет других зависимостей от этого конкретного переопределения.
In
`@Content.Client/Imperial/XxRaay/UI/AndroidStressDeviantChoiceUserInterface.cs`:
- Around line 112-125: В методе Dispose(bool disposing) класса
AndroidStressDeviantChoiceUserInterface текущий ранний return при disposing ==
false пропускает вызов base.Dispose(disposing); уберите ранний return и измените
логику так, чтобы отписка от событий (_window.AcceptPressed -= OnAcceptPressed;
_window.DeclinePressed -= OnDeclinePressed; _window = null) выполнялась только
когда disposing == true, но вызов base.Dispose(disposing) всегда выполнялся в
конце метода; сохраните проверку на _window != null при отписке и убедитесь, что
base.Dispose(disposing) вызывается независимо от значения disposing.
In `@Content.Server/Imperial/XxRaay/Android/AndroidDeviantSpreadSystem.cs`:
- Line 199: Измените видимость методов HandleConsentAccepted и
HandleConsentDenied в классе AndroidDeviantSpreadSystem с public на private, так
как они являются внутренними хелперами системы и не должны быть частью
публичного API; найдите объявления методов HandleConsentAccepted(EntityUid
target, EntityUid converter) и HandleConsentDenied(...) и просто заменить
модификатор доступа на private, сохранив текущие сигнатуры и поведение.
In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs`:
- Around line 164-170: The DoAfterArgs construction sets BreakOnMove = true but
movement is already prevented via OnUpdateCanMove → args.Cancel(), so
BreakOnMove is ineffective; update the DoAfterArgs in AndroidRevealSystem (where
AndroidRevealEscapeDoAfterEvent is created) to remove BreakOnMove or set it to
false (i.e., BreakOnMove = false) to reflect that movement won't occur, leaving
BreakOnDamage and NeedHand as-is.
- Around line 118-124: The popup in AndroidRevealSystem.cs currently uses the
wrong localization key ("android-deviant-consent-convert-popup") in the
_popup.PopupEntity call; replace that key with a new, correct key for forced
reveal (e.g., "android-reveal-mask-popup") and add the corresponding entry to
the localization files with the proper text and formatting tokens (keep the same
("target", Identity.Entity(target, EntityManager)) usage), so _popup.PopupEntity
uses the reveal-specific localization string instead of the deviance-transfer
one.
In `@Content.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs`:
- Around line 38-40: Переменная key задаётся тернарником по total (total == 1 ?
"...-one" : "...-many"), что даёт только две формы и игнорирует русскую
грамматику; замените ручной выбор ключа на одну Fluent/локализационную запись с
передачей числового параметра (count/total) в вызов локализации вместо
использования key, т.е. уберите тернарник, используйте единый ключ локализации и
передайте total как параметр для корректной плюрализации в
AndroidRk800ForensicsSystem (переменная total и ключи
"android-rk800-examine-fingerprints-..." из текущего кода).
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (10)
Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.csContent.Client/Imperial/XxRaay/Android/AndroidOverlaySystem.csContent.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.csContent.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.csContent.Client/Imperial/XxRaay/UI/AndroidStressDeviantChoiceUserInterface.csContent.Server/Imperial/XxRaay/Android/AndroidDeviantSpreadSystem.csContent.Server/Imperial/XxRaay/Android/AndroidRevealSystem.csContent.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.csContent.Shared/Imperial/XxRaay/Android/AndroidEnergyComponent.csContent.Shared/Imperial/XxRaay/Components/AndroidDeviantConsentComponents.cs
| private void OnStartup(Entity<AndroidDisguiseComponent> ent, ref ComponentStartup args) | ||
| { | ||
| var uid = (EntityUid) ent; | ||
| UpdateVisuals(uid, ent.Comp); | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Избыточная локальная переменная uid — явный каст не нужен.
Entity<T> неявно приводится к EntityUid, поэтому создавать промежуточную переменную через (EntityUid) ent излишне. ent можно передавать напрямую во все вызовы, принимающие EntityUid.
♻️ Предлагаемое исправление
private void OnStartup(Entity<AndroidDisguiseComponent> ent, ref ComponentStartup args)
{
- var uid = (EntityUid) ent;
- UpdateVisuals(uid, ent.Comp);
+ UpdateVisuals(ent, ent.Comp);
}
private void OnShutdown(Entity<AndroidDisguiseComponent> ent, ref ComponentShutdown args)
{
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;
- var uid = (EntityUid) ent;
-
- _sprite.LayerSetVisible((uid, sprite), ent.Comp.AndroidBaseLayer, true);
- _sprite.LayerSetVisible((uid, sprite), ent.Comp.AndroidTransformLayer, false);
- _sprite.LayerSetVisible((uid, sprite), ent.Comp.AndroidRetransformLayer, false);
- SetHumanoidVisible((uid, sprite), visible: false);
+ _sprite.LayerSetVisible((ent, sprite), ent.Comp.AndroidBaseLayer, true);
+ _sprite.LayerSetVisible((ent, sprite), ent.Comp.AndroidTransformLayer, false);
+ _sprite.LayerSetVisible((ent, sprite), ent.Comp.AndroidRetransformLayer, false);
+ SetHumanoidVisible((ent, sprite), visible: false);
}
private void OnAfterState(Entity<AndroidDisguiseComponent> ent, ref AfterAutoHandleStateEvent args)
{
- var uid = (EntityUid) ent;
- UpdateVisuals(uid, ent.Comp);
+ UpdateVisuals(ent, ent.Comp);
}Also applies to: 30-41, 43-47
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.cs`
around lines 24 - 28, Remove the redundant local variable and explicit cast in
OnStartup: do not create "var uid = (EntityUid) ent"; pass the
Entity<AndroidDisguiseComponent> value (ent) directly into UpdateVisuals (and
any other methods that accept EntityUid) since Entity<T> implicitly converts to
EntityUid. Apply the same cleanup to the other occurrences mentioned (the blocks
around lines 30-41 and 43-47) so no methods create an intermediate uid via
(EntityUid) ent and instead pass ent directly; ensure references to
AndroidDisguiseComponent, OnStartup, and UpdateVisuals are preserved.
| _sprite.LayerSetVisible((uid, sprite), comp.AndroidBaseLayer, | ||
| comp.State is AndroidDisguiseState.Android); | ||
|
|
||
| _sprite.LayerSetVisible((uid, sprite), comp.AndroidTransformLayer, | ||
| comp.State == AndroidDisguiseState.TransformingToHuman); | ||
| _sprite.LayerSetVisible((uid, sprite), comp.AndroidRetransformLayer, | ||
| comp.State == AndroidDisguiseState.TransformingToAndroid); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Непоследовательное сравнение enum: is и == в одном методе.
Строка 56 использует паттерн-матчинг is, тогда как строки 59 и 61 — оператор == для значений того же enum AndroidDisguiseState. Стиль следует унифицировать.
♻️ Предлагаемое исправление (унификация на `==`)
- _sprite.LayerSetVisible((uid, sprite), comp.AndroidBaseLayer,
- comp.State is AndroidDisguiseState.Android);
+ _sprite.LayerSetVisible((uid, sprite), comp.AndroidBaseLayer,
+ comp.State == AndroidDisguiseState.Android);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Client/Imperial/XxRaay/Android/AndroidDisguiseVisualizerSystem.cs`
around lines 55 - 61, The enum comparison in AndroidDisguiseVisualizerSystem is
inconsistent: replace the pattern-match check using "is" on comp.State with an
equality comparison "==" to match the other comparisons; specifically update the
call to _sprite.LayerSetVisible that references AndroidBaseLayer so it uses
comp.State == AndroidDisguiseState.Android (keeping the existing comparisons for
AndroidTransformLayer and AndroidRetransformLayer unchanged) to make all
comparisons against AndroidDisguiseState consistent.
| /// <summary> | ||
| /// Включает клиентский оверлей | ||
| /// </summary> | ||
| public sealed partial class AndroidOverlaySystem : EntitySystem |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
partial модификатор выглядит излишним.
В файле нет второй части класса, и никаких source-генераторов, которые требовали бы partial, не видно. Если он не нужен — уберите его, чтобы не создавать путаницы.
♻️ Предлагаемое исправление
-public sealed partial class AndroidOverlaySystem : EntitySystem
+public sealed class AndroidOverlaySystem : EntitySystem🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Client/Imperial/XxRaay/Android/AndroidOverlaySystem.cs` at line 11,
Класс AndroidOverlaySystem объявлен с модификатором partial, но другой части
класса или source-генераторов не видно — удалите keyword partial из объявления
класса (AndroidOverlaySystem : EntitySystem) в AndroidOverlaySystem.cs; перед
удалением убедитесь, что нет других partial-частей класса или внешних
генераторов/файлов, которые ожидают наличия partial, и затем перестройте проект.
Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs
Outdated
Show resolved
Hide resolved
| Text = Loc.GetString("android-memorywipe-window-close"), | ||
| Disabled = true | ||
| }; | ||
| _closeButton.OnPressed += _ => ConfirmAndClosePressed?.Invoke(); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for AndroidMemoryWipe system and related code
rg -n "AndroidMemoryWipe" --type cs -A 5 -B 2Repository: imperial-space/SS14-public
Length of output: 24571
🏁 Script executed:
#!/bin/bash
# Read the full AndroidMemoryWipeUserInterface.cs file to see all handlers
wc -l Content.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.csRepository: imperial-space/SS14-public
Length of output: 141
🏁 Script executed:
#!/bin/bash
# Read the complete file
cat -n Content.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.csRepository: imperial-space/SS14-public
Length of output: 3770
🏁 Script executed:
#!/bin/bash
# Get line count first
wc -l Content.Server/Imperial/XxRaay/Android/AndroidMemoryWipeSystem.csRepository: imperial-space/SS14-public
Length of output: 139
🏁 Script executed:
#!/bin/bash
# Read the complete AndroidMemoryWipeSystem.cs file
cat -n Content.Server/Imperial/XxRaay/Android/AndroidMemoryWipeSystem.csRepository: imperial-space/SS14-public
Length of output: 10524
🏁 Script executed:
#!/bin/bash
# Check AndroidMemoryWipeComponents for timeout fields
cat -n Content.Shared/Imperial/XxRaay/Components/AndroidMemoryWipeComponents.csRepository: imperial-space/SS14-public
Length of output: 1346
Проверить и добавить обработку закрытия окна без подтверждения.
Если пользователь закрывает окно через встроенную кнопку × (DefaultWindow), ConfirmAndClosePressed не вызывается и на сервер не отправляется никакое сообщение. Сервер остаёт с Acknowledged = false и постоянно переоткрывает UI в цикле Update (строки 56-65), так как обработчик OnMemoryWipeAcknowledge (строки 250-253) возвращает true только если msg.Acknowledged == true. Таймаут или механизм отмены отсутствуют.
Добавьте либо:
- Тайм-аут для автоматического завершения операции, либо
- Явное сообщение об отмене при закрытии окна, либо
- Обработчик события закрытия окна для отправки отказа на сервер
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Client/Imperial/XxRaay/UI/AndroidMemoryWipeUserInterface.cs` at line
59, The UI currently only hooks the close-button (_closeButton.OnPressed) and
misses the DefaultWindow close path, causing ConfirmAndClosePressed not to fire
and the server to never get an acknowledged=false; add a handler on the window
close event (the DefaultWindow's Closing/OnClose event) to send an explicit
cancellation or invoke ConfirmAndClosePressed with a cancellation result so the
server receives Acknowledged = false, or alternatively implement a simple
timeout in Update (check elapsed time and send cancellation when exceeded) and
ensure OnMemoryWipeAcknowledge still accepts/handles the cancel message;
reference _closeButton.OnPressed, ConfirmAndClosePressed, DefaultWindow (or its
Closing event), Update, and OnMemoryWipeAcknowledge when making the change.
| private void CancelConsent(EntityUid target, EntityUid converter, string? reason = null) | ||
| { | ||
| if (reason != null) | ||
| { | ||
| _popup.PopupEntity(reason, target, target, PopupType.MediumCaution); | ||
| _popup.PopupEntity(reason, converter, converter, PopupType.MediumCaution); | ||
| } | ||
|
|
||
| if (TryComp<AndroidDeviantConsentConversionComponent>(target, out var consent)) | ||
| { | ||
| consent.Converter = null; | ||
| consent.Target = null; | ||
| consent.RequestStartTime = null; | ||
| RemCompDeferred<AndroidDeviantConsentConversionComponent>(target); | ||
| } | ||
| } |
There was a problem hiding this comment.
При отмене согласия окно BUI не закрывается.
После CancelConsent компонент удаляется, но UI остаётся открытым и показывает неактуальное состояние до ручного закрытия.
♻️ Предлагаемое исправление
private void CancelConsent(EntityUid target, EntityUid converter, string? reason = null)
{
if (reason != null)
{
_popup.PopupEntity(reason, target, target, PopupType.MediumCaution);
_popup.PopupEntity(reason, converter, converter, PopupType.MediumCaution);
}
+
+ _ui.CloseUi(target, AndroidDeviantConsentUiKey.Key);
if (TryComp<AndroidDeviantConsentConversionComponent>(target, out var consent))
{
consent.Converter = null;
consent.Target = null;
consent.RequestStartTime = null;
RemCompDeferred<AndroidDeviantConsentConversionComponent>(target);
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private void CancelConsent(EntityUid target, EntityUid converter, string? reason = null) | |
| { | |
| if (reason != null) | |
| { | |
| _popup.PopupEntity(reason, target, target, PopupType.MediumCaution); | |
| _popup.PopupEntity(reason, converter, converter, PopupType.MediumCaution); | |
| } | |
| if (TryComp<AndroidDeviantConsentConversionComponent>(target, out var consent)) | |
| { | |
| consent.Converter = null; | |
| consent.Target = null; | |
| consent.RequestStartTime = null; | |
| RemCompDeferred<AndroidDeviantConsentConversionComponent>(target); | |
| } | |
| } | |
| private void CancelConsent(EntityUid target, EntityUid converter, string? reason = null) | |
| { | |
| if (reason != null) | |
| { | |
| _popup.PopupEntity(reason, target, target, PopupType.MediumCaution); | |
| _popup.PopupEntity(reason, converter, converter, PopupType.MediumCaution); | |
| } | |
| _ui.CloseUi(target, AndroidDeviantConsentUiKey.Key); | |
| if (TryComp<AndroidDeviantConsentConversionComponent>(target, out var consent)) | |
| { | |
| consent.Converter = null; | |
| consent.Target = null; | |
| consent.RequestStartTime = null; | |
| RemCompDeferred<AndroidDeviantConsentConversionComponent>(target); | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Server/Imperial/XxRaay/Android/AndroidDeviantSpreadSystem.cs` around
lines 355 - 370, When cancelling consent in CancelConsent you remove the
AndroidDeviantConsentConversionComponent but never close the open UI, leaving
stale BUI visible; before removing the component, explicitly close any bound UI
for both target and converter using the engine's BUI API (e.g. call the Bound
User Interface close method such as _bui.TryClose/CloseAll or the equivalent in
your codebase for the target and converter entities), then proceed to clear
fields and RemCompDeferred on AndroidDeviantConsentConversionComponent.
| [AutoPausedField] | ||
| public TimeSpan NextUpdate; |
There was a problem hiding this comment.
Поле рантайм-состояния NextUpdate не помечено атрибутом [ViewVariables].
NextUpdate не конфигурируется через YAML-прототипы и является полем рантайм-состояния — аналогично DefaultWalkSpeed и DefaultSprintSpeed строками ниже. По принятой в проекте конвенции такие поля должны быть помечены [ViewVariables].
♻️ Предложенное исправление
+ [AutoPausedField, ViewVariables]
- [AutoPausedField]
public TimeSpan NextUpdate;Based on learnings: "поля компонентов, которые не задаются через прототипы (YAML), а используются как состояние времени выполнения, должны помечаться атрибутом [ViewVariables] вместо [DataField]."
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| [AutoPausedField] | |
| public TimeSpan NextUpdate; | |
| [AutoPausedField, ViewVariables] | |
| public TimeSpan NextUpdate; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Shared/Imperial/XxRaay/Android/AndroidEnergyComponent.cs` around
lines 53 - 54, The NextUpdate runtime state field in AndroidEnergyComponent is
missing the [ViewVariables] attribute; update the field declaration for
NextUpdate (currently annotated with [AutoPausedField]) to also include
[ViewVariables] so it follows the project's convention for runtime-only state
fields (like DefaultWalkSpeed and DefaultSprintSpeed) that are not configured
via YAML prototypes.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…stem.cs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (5)
Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs (2)
85-88: 🧹 Nitpick | 🔵 TrivialПустой
UpdateStateне несёт функциональной нагрузки.Переопределение только вызывает
base.UpdateState(state)и может быть удалено без последствий.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs` around lines 85 - 88, Remove the redundant override of UpdateState in class AndroidDisguiseNameUserInterface: the method only calls base.UpdateState(state) and provides no additional behavior, so delete the entire protected override void UpdateState(BoundUserInterfaceState state) method to rely on the base implementation.
104-117:⚠️ Potential issue | 🟠 Major
base.Dispose(disposing)не вызывается при финализации.Ранний
returnпри!disposing(строка 106–107) пропускаетbase.Dispose(disposing), когда объект финализируется сборщиком мусора (а не явнымDispose()). Базовый класс не получит возможности освободить свои неуправляемые ресурсы.🛡️ Предлагаемое исправление
protected override void Dispose(bool disposing) { - if (!disposing) - return; - - if (_window != null) + if (disposing && _window != null) { _window.AcceptPressed -= OnAcceptPressed; _window.DeclinePressed -= OnDeclinePressed; _window = null; } base.Dispose(disposing); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs` around lines 104 - 117, In Dispose(bool disposing) in AndroidDisguiseNameUserInterface, the early return when !disposing prevents calling base.Dispose(disposing) during finalization; modify the method to only skip managed cleanup when disposing is false (i.e., if (disposing) { /* detach _window handlers: _window.AcceptPressed -= OnAcceptPressed; _window.DeclinePressed -= OnDeclinePressed; _window = null; */ }) and then always call base.Dispose(disposing) at the end so the base class can free unmanaged resources.Content.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs (1)
39-45:⚠️ Potential issue | 🟡 MinorИсправьте плюрализацию: сейчас покрыты только формы
oneиmany.На Line 39-41 тернарник не учитывает форму
few(например, 2–4), из-за чего ru-RU строка может отображаться грамматически неверно. Лучше использовать один Fluent-ключ сcount, чтобы выбор формы делал локализатор.💡 Вариант правки
- var key = total == 1 - ? "android-rk800-examine-fingerprints-one" - : "android-rk800-examine-fingerprints-many"; - using (args.PushGroup(nameof(AndroidRk800ForensicsSystem))) { - args.PushMarkup(Loc.GetString(key, ("count", total))); + args.PushMarkup(Loc.GetString("android-rk800-examine-fingerprints", ("count", total)));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs` around lines 39 - 45, The current ternary that sets key to "android-rk800-examine-fingerprints-one" or "-many" (using total) prevents the localizer from selecting plural forms like "few"; instead remove the ternary and single-key approach: call Loc.GetString with one Fluent key (e.g. "android-rk800-examine-fingerprints") and pass the count parameter ("count", total) directly into args.PushMarkup/Loc.GetString (replace usage of the key variable), so the localization layer (AndroidRk800ForensicsSystem, args.PushMarkup, Loc.GetString) can choose the correct plural form.Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs (2)
117-123:⚠️ Potential issue | 🟠 MajorНеверный ключ локализации для раскрытия маскировки.
Ключ
"android-deviant-consent-convert-popup"относится к передаче девиантности, а не к принудительному раскрытию маскировки. Требуется отдельный ключ (например,"android-reveal-disguise-popup") с соответствующим текстом.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs` around lines 117 - 123, The localization key used in the _popup.PopupEntity call is incorrect ("android-deviant-consent-convert-popup") — replace it with a new, correct key such as "android-reveal-disguise-popup" in the call inside AndroidRevealSystem (the _popup.PopupEntity invocation) and add the corresponding entry to the localization files with the proper reveal-disguise text; ensure the new key is used consistently where forced reveal popups are shown and remove/avoid reusing the deviant-consent key.
163-169:⚠️ Potential issue | 🟡 Minor
BreakOnMove = trueнеэффективен в escape DoAfter.Движение цели заблокировано через
OnUpdateCanMove→args.Cancel(), поэтому позиция никогда не меняется иBreakOnMoveникогда не срабатывает. Параметр следует убрать.♻️ Предлагаемое исправление
var doAfterArgs = new DoAfterArgs(EntityManager, uid, escapeDuration, new AndroidRevealEscapeDoAfterEvent(), uid, target: revealer) { - BreakOnMove = true, BreakOnDamage = true, NeedHand = false };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs` around lines 163 - 169, In the DoAfterArgs construction for the Android reveal escape (variable doAfterArgs created with new DoAfterArgs(EntityManager, uid, escapeDuration, new AndroidRevealEscapeDoAfterEvent(), uid, target: revealer)), remove the BreakOnMove = true property from the initializer because movement is already blocked via OnUpdateCanMove (args.Cancel()) so BreakOnMove will never trigger; keep the other flags (BreakOnDamage, NeedHand) as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs`:
- Around line 90-97: The OnAcceptPressed method currently validates name with
string.IsNullOrWhiteSpace but sends the original value, letting leading/trailing
whitespace through; fix it by trimming the input first (var trimmed =
name.Trim()), validate that trimmed is not empty (use string.IsNullOrEmpty or
IsNullOrWhiteSpace on trimmed), and then pass the trimmed value into
AndroidDisguiseNameChosenMessage and Close(); update references in
OnAcceptPressed accordingly.
In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs`:
- Line 49: В строке где объявлен "var target = (EntityUid) ent;" уберите явный
каст: используйте ent напрямую или присвойте его переменной типа EntityUid без
приведения; поправьте места использования переменной target в
AndroidRevealSystem (например в методах/условиях где ожидается EntityUid) чтобы
принимать ent как уже совместимый тип EntityUid или просто заменить target на
ent.
- Around line 179-183: The guard checks in AndroidRevealSystem's DoAfter
handlers include a dead clause "|| args.Handled" because DoAfter events arrive
with Handled always false; remove the args.Handled check from the guard so the
condition becomes just checking args.Cancelled (and any other valid flags)
before calling CleanupReveal(uid, ref comp). Update both the handler shown (the
DoAfter handler that currently does "if (args.Cancelled || args.Handled) {
CleanupReveal(...) return; }") and the similar check in OnEscapeDoAfter to drop
"args.Handled", leaving only the meaningful cancellation/validation checks
(e.g., args.Cancelled) and keep calling CleanupReveal/return behavior unchanged.
- Around line 197-199: Вместо прямого присвоения disguise.State в
AndroidRevealSystem, добавьте в AndroidDisguiseSystem публичный метод (например
StartTransformToAndroidPublic или InitiateTransformToAndroid) который
инкапсулирует текущую логику приватного StartTransformToAndroid (установка
State, NextStateTime, Dirty и любые побочные эффекты) и вызвать этот новый метод
из AndroidRevealSystem; замените прямое присваивание disguise.State =
AndroidDisguiseState.TransformingToAndroid и модификацию NextStateTime в
AndroidRevealSystem на вызов этого публичного метода, чтобы централизовать
побочные эффекты и сохранить согласованное поведение.
---
Duplicate comments:
In `@Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs`:
- Around line 85-88: Remove the redundant override of UpdateState in class
AndroidDisguiseNameUserInterface: the method only calls base.UpdateState(state)
and provides no additional behavior, so delete the entire protected override
void UpdateState(BoundUserInterfaceState state) method to rely on the base
implementation.
- Around line 104-117: In Dispose(bool disposing) in
AndroidDisguiseNameUserInterface, the early return when !disposing prevents
calling base.Dispose(disposing) during finalization; modify the method to only
skip managed cleanup when disposing is false (i.e., if (disposing) { /* detach
_window handlers: _window.AcceptPressed -= OnAcceptPressed;
_window.DeclinePressed -= OnDeclinePressed; _window = null; */ }) and then
always call base.Dispose(disposing) at the end so the base class can free
unmanaged resources.
In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs`:
- Around line 117-123: The localization key used in the _popup.PopupEntity call
is incorrect ("android-deviant-consent-convert-popup") — replace it with a new,
correct key such as "android-reveal-disguise-popup" in the call inside
AndroidRevealSystem (the _popup.PopupEntity invocation) and add the
corresponding entry to the localization files with the proper reveal-disguise
text; ensure the new key is used consistently where forced reveal popups are
shown and remove/avoid reusing the deviant-consent key.
- Around line 163-169: In the DoAfterArgs construction for the Android reveal
escape (variable doAfterArgs created with new DoAfterArgs(EntityManager, uid,
escapeDuration, new AndroidRevealEscapeDoAfterEvent(), uid, target: revealer)),
remove the BreakOnMove = true property from the initializer because movement is
already blocked via OnUpdateCanMove (args.Cancel()) so BreakOnMove will never
trigger; keep the other flags (BreakOnDamage, NeedHand) as-is.
In `@Content.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs`:
- Around line 39-45: The current ternary that sets key to
"android-rk800-examine-fingerprints-one" or "-many" (using total) prevents the
localizer from selecting plural forms like "few"; instead remove the ternary and
single-key approach: call Loc.GetString with one Fluent key (e.g.
"android-rk800-examine-fingerprints") and pass the count parameter ("count",
total) directly into args.PushMarkup/Loc.GetString (replace usage of the key
variable), so the localization layer (AndroidRk800ForensicsSystem,
args.PushMarkup, Loc.GetString) can choose the correct plural form.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.csContent.Server/Imperial/XxRaay/Android/AndroidRevealSystem.csContent.Server/Imperial/XxRaay/Systems/AndroidRk800ForensicsSystem.cs
| private void OnAcceptPressed(string name) | ||
| { | ||
| if (string.IsNullOrWhiteSpace(name)) | ||
| return; | ||
|
|
||
| SendMessage(new AndroidDisguiseNameChosenMessage(name)); | ||
| Close(); | ||
| } |
There was a problem hiding this comment.
Имя не обрезается перед отправкой.
string.IsNullOrWhiteSpace блокирует полностью пробельные строки, но name уходит в AndroidDisguiseNameChosenMessage без Trim(). Ведущие/конечные пробелы попадут в имя персонажа.
🛡️ Предлагаемое исправление
private void OnAcceptPressed(string name)
{
- if (string.IsNullOrWhiteSpace(name))
+ var trimmed = name.Trim();
+ if (string.IsNullOrWhiteSpace(trimmed))
return;
- SendMessage(new AndroidDisguiseNameChosenMessage(name));
+ SendMessage(new AndroidDisguiseNameChosenMessage(trimmed));
Close();
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Client/Imperial/XxRaay/UI/AndroidDisguiseNameUserInterface.cs` around
lines 90 - 97, The OnAcceptPressed method currently validates name with
string.IsNullOrWhiteSpace but sends the original value, letting leading/trailing
whitespace through; fix it by trimming the input first (var trimmed =
name.Trim()), validate that trimmed is not empty (use string.IsNullOrEmpty or
IsNullOrWhiteSpace on trimmed), and then pass the trimmed value into
AndroidDisguiseNameChosenMessage and Close(); update references in
OnAcceptPressed accordingly.
| if (!args.CanAccess || !args.CanInteract) | ||
| return; | ||
|
|
||
| var target = (EntityUid) ent; |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Лишний явный каст к EntityUid.
Entity<AndroidDisguiseComponent> уже неявно приводится к EntityUid — явный каст не нужен.
♻️ Предлагаемое исправление
- var target = (EntityUid) ent;
+ var target = ent.Owner;Либо просто использовать ent напрямую там, где ожидается EntityUid.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs` at line 49, В
строке где объявлен "var target = (EntityUid) ent;" уберите явный каст:
используйте ent напрямую или присвойте его переменной типа EntityUid без
приведения; поправьте места использования переменной target в
AndroidRevealSystem (например в методах/условиях где ожидается EntityUid) чтобы
принимать ent как уже совместимый тип EntityUid или просто заменить target на
ent.
| if (args.Cancelled || args.Handled) | ||
| { | ||
| CleanupReveal(uid, ref comp); | ||
| return; | ||
| } |
There was a problem hiding this comment.
args.Handled на входе в обработчик всегда false — ветка || args.Handled является мёртвым кодом.
DoAfter-событие приходит с Handled = false; никакой предшествующий обработчик на этой компонент-специфичной подписке не устанавливает Handled. Условие || args.Handled никогда не выполняется, но может создать ложное ощущение, что Handled = true тригерит очистку.
♻️ Предлагаемое исправление
- if (args.Cancelled || args.Handled)
+ if (args.Cancelled)
{
CleanupReveal(uid, ref comp);
return;
}Аналогичный паттерн присутствует в OnEscapeDoAfter (строка 209) — там тоже стоит убрать || args.Handled из guard-проверки.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (args.Cancelled || args.Handled) | |
| { | |
| CleanupReveal(uid, ref comp); | |
| return; | |
| } | |
| if (args.Cancelled) | |
| { | |
| CleanupReveal(uid, ref comp); | |
| return; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs` around lines
179 - 183, The guard checks in AndroidRevealSystem's DoAfter handlers include a
dead clause "|| args.Handled" because DoAfter events arrive with Handled always
false; remove the args.Handled check from the guard so the condition becomes
just checking args.Cancelled (and any other valid flags) before calling
CleanupReveal(uid, ref comp). Update both the handler shown (the DoAfter handler
that currently does "if (args.Cancelled || args.Handled) { CleanupReveal(...)
return; }") and the similar check in OnEscapeDoAfter to drop "args.Handled",
leaving only the meaningful cancellation/validation checks (e.g.,
args.Cancelled) and keep calling CleanupReveal/return behavior unchanged.
| disguise.State = AndroidDisguiseState.TransformingToAndroid; | ||
| disguise.NextStateTime = _timing.CurTime + disguise.RetransformDuration; | ||
| Dirty(uid, disguise); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Explore the structure and methods in AndroidDisguiseSystem
echo "=== Looking for AndroidDisguiseSystem file ==="
find . -name "AndroidDisguiseSystem.cs" -type f 2>/dev/null
echo ""
echo "=== Public/internal methods in AndroidDisguiseSystem ==="
rg -n "public|internal" --type cs -A 3 Content.Server/Imperial/XxRaay/Android/AndroidDisguiseSystem.cs 2>/dev/null | head -80
echo ""
echo "=== All usages of TransformingToAndroid ==="
rg -n "TransformingToAndroid" --type cs -B 2 -A 2
echo ""
echo "=== NextStateTime assignments pattern ==="
rg -n "NextStateTime\s*=" --type cs -B 2 -A 2Repository: imperial-space/SS14-public
Length of output: 6120
🏁 Script executed:
#!/bin/bash
# Get full AndroidDisguiseSystem file to see all public methods
echo "=== Full AndroidDisguiseSystem.cs ==="
cat -n Content.Server/Imperial/XxRaay/Android/AndroidDisguiseSystem.cs
echo ""
echo "=== Check AndroidRevealSystem context and imports ==="
head -50 Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.csRepository: imperial-space/SS14-public
Length of output: 8793
🏁 Script executed:
#!/bin/bash
# Get context around the problematic lines in AndroidRevealSystem
echo "=== Context around lines 190-210 in AndroidRevealSystem.cs ==="
sed -n '185,210p' Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs | cat -n
echo ""
echo "=== Check if there are any public methods/events in AndroidDisguiseSystem for transitions ==="
rg -n "public.*Transform|public.*event|public.*Action" Content.Server/Imperial/XxRaay/Android/AndroidDisguiseSystem.cs
echo ""
echo "=== Check if there are any inter-system communication patterns ==="
rg -n "GetEntitySystem|EntitySystem" Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs | head -20Repository: imperial-space/SS14-public
Length of output: 1350
Используйте публичный API вместо прямого изменения disguise.State.
Прямое присвоение disguise.State = AndroidDisguiseState.TransformingToAndroid в AndroidRevealSystem дублирует логику из приватного метода StartTransformToAndroid в AndroidDisguiseSystem и минует централизованное управление состоянием. Это создаёт несогласованный паттерн: если AndroidDisguiseSystem в будущем добавит побочные эффекты (события, обновления UI, обработку именования), AndroidRevealSystem не будет их запускать.
Решение: Создайте публичный метод в AndroidDisguiseSystem для инициации трансформации, который смогут вызывать другие системы (например, через событие или прямой вызов метода).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Content.Server/Imperial/XxRaay/Android/AndroidRevealSystem.cs` around lines
197 - 199, Вместо прямого присвоения disguise.State в AndroidRevealSystem,
добавьте в AndroidDisguiseSystem публичный метод (например
StartTransformToAndroidPublic или InitiateTransformToAndroid) который
инкапсулирует текущую логику приватного StartTransformToAndroid (установка
State, NextStateTime, Dirty и любые побочные эффекты) и вызвать этот новый метод
из AndroidRevealSystem; замените прямое присваивание disguise.State =
AndroidDisguiseState.TransformingToAndroid и модификацию NextStateTime в
AndroidRevealSystem на вызов этого публичного метода, чтобы централизовать
побочные эффекты и сохранить согласованное поведение.
…ate entry for DetroitRk800
There was a problem hiding this comment.
♻️ Duplicate comments (1)
Resources/Prototypes/Imperial/XxRaay/android.yml (1)
546-583:⚠️ Potential issue | 🟠 MajorОтсутствует компонент
MetabolizerвBaseMobAndroid— эффекты Thirium не будут работать.Реагент Thirium использует
MetabolizerTypeConditionсtype: Android(строки 563, 571, 581). Для активации лечебных эффектовModifyBloodLevelиHealthChangeтребуется, чтобы у сущности был компонентMetabolizerсmetabolizerTypes: [ Android ]. ВBaseMobAndroidтакой компонент отсутствует.🐛 Предлагаемое исправление — добавить Metabolizer в BaseMobAndroid
Добавьте в компоненты
BaseMobAndroid(после строки 259):- type: Metabolizer metabolizerTypes: - Android,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Resources/Prototypes/Imperial/XxRaay/android.yml` around lines 546 - 583, BaseMobAndroid is missing a Metabolizer component so MetabolizerTypeCondition checks used by the Thirium reagent (MetabolizerTypeCondition type: Android) never succeed; add a Metabolizer component to the BaseMobAndroid entity (e.g., append to its components list) with metabolizerTypes including "Android" so reagents like Thirium can trigger their ModifyBloodLevel and HealthChange effects. Reference symbols: add a component of type Metabolizer to BaseMobAndroid to satisfy MetabolizerTypeCondition used by Thirium (affecting ModifyBloodLevel and HealthChange).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@Resources/Prototypes/Imperial/XxRaay/android.yml`:
- Around line 546-583: BaseMobAndroid is missing a Metabolizer component so
MetabolizerTypeCondition checks used by the Thirium reagent
(MetabolizerTypeCondition type: Android) never succeed; add a Metabolizer
component to the BaseMobAndroid entity (e.g., append to its components list)
with metabolizerTypes including "Android" so reagents like Thirium can trigger
their ModifyBloodLevel and HealthChange effects. Reference symbols: add a
component of type Metabolizer to BaseMobAndroid to satisfy
MetabolizerTypeCondition used by Thirium (affecting ModifyBloodLevel and
HealthChange).
There was a problem hiding this comment.
♻️ Duplicate comments (1)
Resources/Prototypes/Imperial/XxRaay/android.yml (1)
8-304:⚠️ Potential issue | 🟠 MajorДобавьте
MetabolizerвBaseMobAndroid, иначе лечебный Thirium не активируется.На Line 562-572 и Line 580-582 лечебные эффекты Thirium завязаны на
MetabolizerTypeCondition(type: Android, shouldHave: true), но вBaseMobAndroid(Line 8-304) нет компонентаMetabolizer. В итогеMedicine-ветка для андроидов не срабатывает.🐛 Предлагаемое исправление
- type: AndroidEnergy - type: AndroidDiode + - type: Metabolizer + metabolizerTypes: + - Android - type: Bloodstream bloodReagents: reagents:Also applies to: 546-582
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Resources/Prototypes/Imperial/XxRaay/android.yml` around lines 8 - 304, The BaseMobAndroid prototype is missing a Metabolizer component so the Thirium healing branch gated by MetabolizerTypeCondition(type: Android, shouldHave: true) never triggers; add a Metabolizer component to this prototype's components list (symbol: Metabolizer) configured for Android metabolism so the existing MetabolizerTypeCondition and Thirium medicine effects will activate (reference: MetabolizerTypeCondition, Thirium, BaseMobAndroid).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@Resources/Prototypes/Imperial/XxRaay/android.yml`:
- Around line 8-304: The BaseMobAndroid prototype is missing a Metabolizer
component so the Thirium healing branch gated by MetabolizerTypeCondition(type:
Android, shouldHave: true) never triggers; add a Metabolizer component to this
prototype's components list (symbol: Metabolizer) configured for Android
metabolism so the existing MetabolizerTypeCondition and Thirium medicine effects
will activate (reference: MetabolizerTypeCondition, Thirium, BaseMobAndroid).
Refactor android systems and fix analyzer warnings in Android components
О ПР`е
Тип: feat
Изменения: Ивентовый контент
Технические детали
Нет
Изменения кода официальных разработчиков
Нет
Summary by CodeRabbit