Skip to content

[PORT] Порт Граба с доработкой#4469

Draft
banumbas wants to merge 8 commits into
space-sunrise:masterfrom
banumbas:grab
Draft

[PORT] Порт Граба с доработкой#4469
banumbas wants to merge 8 commits into
space-sunrise:masterfrom
banumbas:grab

Conversation

@banumbas

@banumbas banumbas commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Краткое описание | Short description

это топ
space-wizards/space-station-14#30011
я там поделал ревью метала и чёто ещё вообщем нормалды сделал, но делал я ещё давно поэтому точно не помню что изменял

При попытке тащить человека когда вы его уже тащите при этом находясь в боевом режиме позволит вам начать захват.
Захват имеет три стадии:
Софт - вы просто захватили человека, не представляет никакой угрозы потому что выбратся можно за секунду.
Хард град - фффффффффффф начиная с этого захвата можно кидать цели
Удушающий - человек не может говорить и задыхается, шанс выбраться минимальный.

Силу захвата(софт, хард, удушение) можно усилить ещё одной попыткой тащить человека, уменьшить силу захвата можно по хоткею "Перестать тащить", как для того кто тащит так и для того кого тащат, либо же по нажатию иконки граба.

из пра визденов граб имеет фиксированные проценты выбраться, и допустим если ты много раз пытался выбратся у тебя шансы на следующую попытку не повышаются, у меня же они суммируются.

Ссылка на багрепорт/Предложение | Related Issue/Bug Report

#4463
fixed #2381

Медиа (Видео/Скриншоты) | Media (Video/Screenshots)

будет

Changelog

🆑 banumbas

  • add: Добавлена система захвата(граб). При попытке тащить человека когда вы его уже тащите при этом находясь в боевом режиме позволит вам начать захват.

Summary by CodeRabbit

  • New Features
    • Многоуровневая механика захватов: стадии Soft/Hard/Suffocate, возможность бросать захваченные объекты, виртуальные предметы для стадий, новые алерты и локализация UI/попапов.
  • Bug Fixes / Behavior
    • Улучшено поведение pull/toggle при захватах: корректная обработка повторных попыток, продолжение движения при «жёстких» захватах.
    • Респираторы и удушье теперь корректно реагируют на блоки дыхания и низкую насыщенность.

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

RSI Diff Bot; head commit 027df6f merging into 385f11e
This PR makes changes to 1 or more RSIs. Here is a summary of all changes:

Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi

State Old New Status
grab-choke Added
grab-hard Added
grab-soft Added
grabbed-choke Added
grabbed-hard Added
grabbed-soft Added
pulled Added
pulling Added

Edit: diff updated after 027df6f

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 93923321-a97e-4cab-babd-4ff8971a877a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Реализована механика staged-grab: новые контракты (компоненты, enum, события), SharedGrabSystem с управлением стадий и побегов, поддержка виртуальных предметов и throwing, интеграция с Respiration/Pulling и добавлены UI/локализация/алерты.

Changes

Система захвата и удержания

Layer / File(s) Summary
Контракты и компоненты grab
Content.Shared/_Sunrise/Grab/GrabStage.cs, Content.Shared/_Sunrise/Grab/Components/GrabbedComponent.cs, Content.Shared/_Sunrise/Grab/Components/GrabberComponent.cs, Content.Shared/_Sunrise/Grab/Components/GrabWhileGrabbedComponent.cs, Content.Shared/_Sunrise/Grab/Components/GrabThrownComponent.cs, Content.Shared/_Sunrise/Grab/Events/PullToggleAttemptEvent.cs, Content.Server/Body/Systems/RespiratorSystem.cs
Добавлены enum GrabStage, компоненты GrabberComponent, GrabbedComponent, GrabWhileGrabbedComponent, GrabThrownComponent, by-ref событие PullToggleAttemptEvent и CanBreatheEvent для интеграции дыхания.
Core: SharedGrabSystem
Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.cs
Реализован SharedGrabSystem с инициализацией, lifecycle-хендлерами, публичным API (TryStartOrTightenGrab, TryEscapeGrab, CanStartOrTightenGrab), сменой стадий, расчётом шансов побега и отправкой popups/alert-ов.
Виртуальные предметы (lifecycle)
Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.VirtualItems.cs, Content.Shared/Hands/HandEvents.cs, Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs
Добавлена логика spawn/trim/cleanup виртуальных предметов под стадии grab; VirtualItemDeletedEvent расширено полями VirtualItem и Handled, SharedVirtualItemSystem и SharedGrabSystem обрабатывают удаление и корректируют стадию при необходимости.
Механика бросания
Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.Throwing.cs
Добавлены проверки перед броском, создание GrabThrownComponent с параметрами урона/stamina, одноразовая обработка столкновений и отложенное удаление маркера.
Интеграция с Respiration и Pulling
Content.Server/Body/Systems/RespiratorSystem.cs, Content.Server/_Sunrise/Body/GrabRespiratorSystem.cs, Content.Shared/Movement/Pulling/Systems/PullingSystem.cs
RespiratorSystem теперь поднимает CanBreatheEvent и учитывает его; GrabRespiratorSystem отменяет дыхание при suffocate; PullingSystem интегрирован с новыми событиями и handled-флагом виртуальных предметов, добавлена обработка PullToggleAttemptEvent.
UI и локализация
Resources/Locale/en-US/_strings/_sunrise/interaction/grab.ftl, Resources/Locale/ru-RU/_strings/_sunrise/interaction/grab.ftl, Resources/Prototypes/_Sunrise/Alerts/grab.yml, Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi/meta.json
Добавлены локализации для стадий/действий grab, прототипы алертов Grabbed/Grabbing и RSI метаданные для иконок/состояний.

Sequence Diagram

sequenceDiagram
  participant Grabber
  participant SharedGrabSystem
  participant Grabbed
  participant RespiratorSystem
  Grabber->>SharedGrabSystem: TryStartOrTightenGrab
  SharedGrabSystem->>SharedGrabSystem: Validate -> set Stage, update VirtualItems
  SharedGrabSystem->>Grabbed: Add/Update GrabbedComponent
  RespiratorSystem->>RespiratorSystem: RaiseLocalEvent(CanBreatheEvent)
  GrabRespiratorSystem->>RespiratorSystem: sets args.Cancelled when Stage >= Suffocate
  RespiratorSystem->>RespiratorSystem: Skip inhale/exhale or apply suffocation damage
  Grabbed->>SharedGrabSystem: TryEscapeGrab
  SharedGrabSystem->>SharedGrabSystem: Calculate escape chance -> Lower stage or increase bonus
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • Orvex07

Poem

🐰 Я кролик в кустах сижу, радуюсь новизне,
Граб пришёл, стадии вечны — коду пируете в душе,
Виртуальный мешок рук, бросок, попап и табличка,
Дышать запрет — или нет? Я прыгаю, как крошка-лисичка,
Код скрипит и мерцает — ура, флафф и новая фичка.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Ss14 Bridge Sync ❌ Error PR изменил 77 canonical файлов в .agent/ (3 правила и 74 файла навыков), но не обновил 140 соответствующих bridge-файлов в .agents/, .claude/, .cursor/, и .github/. Синхронизировать все 35 пропущенных файлов в каждом из 4 bridges: 140 файлов, включая references в подпапках и файлы agents/openai.yaml.
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Заголовок PR '[PORT] Порт Граба с доработкой' чётко описывает основное изменение - портирование системы захвата с дополнениями.
Linked Issues check ✅ Passed Система захвата успешно реализована согласно требованиям issue #2381: добавлены компоненты (GrabbedComponent, GrabberComponent), три стадии (Soft, Hard, Suffocate), механика побега с накопительными шансами, система виртуальных предметов и локализация.
Out of Scope Changes check ✅ Passed Все изменения относятся к реализации системы захвата: компоненты, события, система управления, локализация и ресурсы. Дополнительные изменения в RespiratorSystem и PullingSystem являются необходимой интеграцией захвата с существующими системами.
Ss14 C# Rules ✅ Passed All C# files follow SS14 rules: component/system naming, dependency prefixes, Try/Can/Do pattern, proper by-ref events, fork code in _Sunrise with markers.
Ss14 Yaml/Ftl Rules ✅ Passed All YAML and FTL files conform to SS14 rules: prototype IDs in PascalCase, FTL keys in kebab-case, no hardcoded non-English YAML text, proper _Sunrise prefixing, consistent localization.
Ss14 Prototype ↔ Ftl Parity ✅ Passed All new player-facing alert prototypes (Grabbed, Grabbing) have matching FTL entries in both en-US and ru-RU locale files with proper key naming conventions.
Ss14 Prediction Safety ✅ Passed All Content.Shared changes use deterministic prediction: RandomPredictedSystem, PopupPredicted with guards, PlayPredicted, PredictedQueueDel, RemCompDeferred, and proper component networking.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.cs`:
- Around line 91-105: The handler currently marks args.Handled = true before
verifying the grab can actually occur; change OnPullToggleAttempt so you call
TryStartOrTightenGrab(args.Puller, ent.Owner) first, store its boolean result,
and only set args.Handled = true and args.Result = result when that call returns
true (i.e., when the grab actually started/tightened). Keep the existing early
return for non-active grabs outside combat (_combatMode.IsInCombatMode) but
ensure you don't swallow the original toggle by setting args.Handled prior to
checking TryStartOrTightenGrab in the OnPullToggleAttempt method.

In `@Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.Throwing.cs`:
- Around line 11-44: The event handlers OnBeforeThrow and OnGrabThrowHit should
be reduced to thin routers and the validation/state-mutation logic moved into
public Try/Can/Do methods; create public methods like
CanBeforeThrow(Entity<GrabberComponent> ent, BeforeThrowEvent args),
TryBeforeThrow(Entity<GrabberComponent> ent, ref BeforeThrowEvent args) and
DoBeforeThrow(EntityUid grabbed, GrabberComponent grabComp, BeforeThrowEvent
args) (and analogous Can/Try/Do trio for the grab-hit flow) and move all checks
(args.Cancelled, ent.Comp.Grabbed presence, Stage check, virtual/pullable
lookup, _pulling.TryStopPull) and state mutations
(EnsureComp<GrabThrownComponent>, setting
DamageOnCollide/WallDamageOnCollide/StaminaDamageOnCollide, Dirty, and modifying
args.ItemUid/args.ThrowSpeed) into those methods; then make OnBeforeThrow simply
call TryBeforeThrow and short-circuit based on the result, and do the same
pattern for OnGrabThrowHit so handlers only route and the heavy logic lives in
named Try/Can/Do methods.

In `@Content.Shared/Movement/Pulling/Systems/PullingSystem.cs`:
- Around line 2-3: The two new using directives "using
Content.Shared._Sunrise.Grab;" and "using Content.Shared._Sunrise.Grab.Events;"
were added to a vanilla file but lack Sunrise fork markers; add inline Sunrise
markers to each one-line edit by appending "// Sunrise-Edit" (or wrap a block
with "/* Sunrise edit start */" and "/* Sunrise edit end */" if you prefer a
block), so the added using statements are clearly marked for upstream
maintenance and follow the /**/!(_{Sunrise,Scp,Fish,Lust})/**/*.cs guideline.
- Around line 253-256: Нужно зафиксировать порядок обработки
VirtualItemDeletedEvent: текущая проверка args.Handled в PullingSystem (в месте
с комментарием Sunrise) безопасна лишь если SharedGrabSystem.VirtualItems
обрабатывает событие раньше — исправьте это, найдите где подписывается
обработчик VirtualItemDeletedEvent в SharedGrabSystem (метод VirtualItems) и в
PullingSystem (обработчик, где вызывается TryStopPull/проверяется args.Handled)
и задайте при подписке явный приоритет/порядок (например через
SubscribeLocalEvent с параметром priority или соответствующий атрибут) так,
чтобы SharedGrabSystem обрабатывался до PullingSystem; альтернативно измените
приоритет в PullingSystem на более «поздний», чтобы гарантировать корректную
работу args.Handled.

In `@Resources/Locale/en-US/_strings/_sunrise/interaction/grab.ftl`:
- Around line 4-6: Both alerts "alerts-grabbed-desc" and "alerts-grabbing-desc"
contain UI/control instructions but lack the required OOC marker; update the
string values for alerts-grabbed-desc and alerts-grabbing-desc to prefix the
user-facing instruction with "OOC: " (e.g., "OOC: You are being grabbed. Click
the alert to loosen the grab.") so all out-of-character hints/controls in
Resources/Locale/**/*.ftl are explicitly marked.

In `@Resources/Locale/ru-RU/_strings/_sunrise/interaction/grab.ftl`:
- Around line 4-6: Update the two out-of-character UI hint strings by prefixing
them with "OOC:" so they follow the locale guideline: change the value of
alerts-grabbed-desc (currently "Вас крепко держат. Нажмите на индикатор, чтобы
ослабить захват.") and alerts-grabbing-desc (currently "Вы кого-то держите.
Нажмите на индикатор, чтобы ослабить захват.") to start with "OOC: " before the
existing text, preserving the rest of the wording and markup (e.g., keep
[color=yellow] in alerts-grabbing-name unchanged).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 10516c09-4334-4c57-845e-9b82ce7cd7bd

📥 Commits

Reviewing files that changed from the base of the PR and between b5344dc and 6b9dc0c.

⛔ Files ignored due to path filters (8)
  • Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi/grab-choke.png is excluded by !**/*.png
  • Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi/grab-hard.png is excluded by !**/*.png
  • Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi/grab-soft.png is excluded by !**/*.png
  • Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi/grabbed-choke.png is excluded by !**/*.png
  • Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi/grabbed-hard.png is excluded by !**/*.png
  • Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi/grabbed-soft.png is excluded by !**/*.png
  • Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi/pulled.png is excluded by !**/*.png
  • Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi/pulling.png is excluded by !**/*.png
📒 Files selected for processing (18)
  • Content.Server/Body/Systems/RespiratorSystem.cs
  • Content.Server/_Sunrise/Body/GrabRespiratorSystem.cs
  • Content.Shared/Hands/HandEvents.cs
  • Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs
  • Content.Shared/Movement/Pulling/Systems/PullingSystem.cs
  • Content.Shared/_Sunrise/Grab/Components/GrabThrownComponent.cs
  • Content.Shared/_Sunrise/Grab/Components/GrabWhileGrabbedComponent.cs
  • Content.Shared/_Sunrise/Grab/Components/GrabbedComponent.cs
  • Content.Shared/_Sunrise/Grab/Components/GrabberComponent.cs
  • Content.Shared/_Sunrise/Grab/Events/PullToggleAttemptEvent.cs
  • Content.Shared/_Sunrise/Grab/GrabStage.cs
  • Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.Throwing.cs
  • Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.VirtualItems.cs
  • Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.cs
  • Resources/Locale/en-US/_strings/_sunrise/interaction/grab.ftl
  • Resources/Locale/ru-RU/_strings/_sunrise/interaction/grab.ftl
  • Resources/Prototypes/_Sunrise/Alerts/grab.yml
  • Resources/Textures/_Sunrise/Interface/Alerts/grab.rsi/meta.json

Comment on lines +91 to +105
private void OnPullToggleAttempt(Entity<PullableComponent> ent, ref PullToggleAttemptEvent args)
{
if (args.Handled)
return;

var activeGrab = _grabberQuery.TryComp(args.Puller, out var grabber) &&
grabber.Grabbed == ent.Owner &&
grabber.Stage > GrabStage.No;

if (!activeGrab && !_combatMode.IsInCombatMode(args.Puller))
return;

args.Handled = true;
args.Result = TryStartOrTightenGrab(args.Puller, ent.Owner);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Не перехватывайте toggle pull до проверки, что grab реально может выполниться.

На Line 103 событие помечается Handled до проверки валидности grab-пути. В combat mode это глушит штатный toggle/stop pull даже когда TryStartOrTightenGrab заведомо вернёт false (например, цель без MobStateComponent по Line 290-291).

Предлагаемая правка
 private void OnPullToggleAttempt(Entity<PullableComponent> ent, ref PullToggleAttemptEvent args)
 {
     if (args.Handled)
         return;

     var activeGrab = _grabberQuery.TryComp(args.Puller, out var grabber) &&
                      grabber.Grabbed == ent.Owner &&
                      grabber.Stage > GrabStage.No;

     if (!activeGrab && !_combatMode.IsInCombatMode(args.Puller))
         return;
+
+    // Для не-активного grab не перехватываем событие, если старт grab невозможен:
+    // даём PullingSystem выполнить обычный toggle/stop.
+    if (!activeGrab && !CanStartOrTightenGrab(args.Puller, ent.Owner, quiet: true))
+        return;

     args.Handled = true;
     args.Result = TryStartOrTightenGrab(args.Puller, ent.Owner);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.cs` around lines 91 -
105, The handler currently marks args.Handled = true before verifying the grab
can actually occur; change OnPullToggleAttempt so you call
TryStartOrTightenGrab(args.Puller, ent.Owner) first, store its boolean result,
and only set args.Handled = true and args.Result = result when that call returns
true (i.e., when the grab actually started/tightened). Keep the existing early
return for non-active grabs outside combat (_combatMode.IsInCombatMode) but
ensure you don't swallow the original toggle by setting args.Handled prior to
checking TryStartOrTightenGrab in the OnPullToggleAttempt method.

Comment on lines +11 to +44
private void OnBeforeThrow(Entity<GrabberComponent> ent, ref BeforeThrowEvent args)
{
if (args.Cancelled ||
ent.Comp.Grabbed is not { } grabbed ||
ent.Comp.Stage < GrabStage.Hard)
{
return;
}

if (!_virtualQuery.TryComp(args.ItemUid, out var virtualItem) || virtualItem.BlockingEntity != grabbed)
return;

if (!_pullableQuery.TryComp(grabbed, out var pullable))
{
args.Cancelled = true;
return;
}

if (!_pulling.TryStopPull(grabbed, pullable))
{
args.Cancelled = true;
return;
}

var thrown = EnsureComp<GrabThrownComponent>(grabbed);
var damage = ent.Comp.ThrowDamage * ent.Comp.ThrowDamageModifier;
thrown.DamageOnCollide = new DamageSpecifier(damage);
thrown.WallDamageOnCollide = new DamageSpecifier(damage);
thrown.StaminaDamageOnCollide = ent.Comp.ThrowStaminaDamage;
Dirty(grabbed, thrown);

args.ItemUid = grabbed;
args.ThrowSpeed = ent.Comp.ThrowSpeed;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

# Find and examine the file mentioned in the review
find . -name "SharedGrabSystem.Throwing.cs" -type f

Repository: space-sunrise/sunrise-station

Length of output: 141


🏁 Script executed:

# Get the file size first to determine how to read it
wc -l Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.Throwing.cs

Repository: space-sunrise/sunrise-station

Length of output: 142


🏁 Script executed:

# Read the entire file to understand the context
cat -n Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.Throwing.cs

Repository: space-sunrise/sunrise-station

Length of output: 3123


Разделите handler-методы по обязательному interaction flow.

Методы OnBeforeThrow (строки 11–44) и OnGrabThrowHit (строки 46–71) содержат валидацию и мутацию состояния, что нарушает паттерн OnEvent → TryDo → CanDo → Do. Оставьте обработчики тонкими роутерами и вынесите логику в публичные методы Try, проверки Can и действия Do.

Пример рефакторинга для OnBeforeThrow:

Возможный каркас рефактора
- private void OnBeforeThrow(Entity<GrabberComponent> ent, ref BeforeThrowEvent args)
- {
-     if (args.Cancelled ||
-         ent.Comp.Grabbed is not { } grabbed ||
-         ent.Comp.Stage < GrabStage.Hard)
-     {
-         return;
-     }
-     ...
- }
+ private void OnBeforeThrow(Entity<GrabberComponent> ent, ref BeforeThrowEvent args)
+ {
+     TryPrepareGrabThrow(ent, ref args);
+ }
+
+ public bool TryPrepareGrabThrow(Entity<GrabberComponent> ent, ref BeforeThrowEvent args)
+ {
+     if (!CanPrepareGrabThrow(ent, args, out var grabbed, out var virtualItem, out var pullable))
+         return false;
+
+     DoPrepareGrabThrow(ent, ref args, grabbed, pullable);
+     return true;
+ }
+
+ private bool CanPrepareGrabThrow(
+     Entity<GrabberComponent> ent,
+     BeforeThrowEvent args,
+     out EntityUid grabbed,
+     out VirtualItemComponent virtualItem,
+     out PullableComponent pullable)
+ {
+     grabbed = default;
+     virtualItem = default;
+     pullable = default;
+
+     if (args.Cancelled ||
+         ent.Comp.Grabbed is not { } g ||
+         ent.Comp.Stage < GrabStage.Hard)
+         return false;
+
+     grabbed = g;
+     return _virtualQuery.TryComp(args.ItemUid, out virtualItem) &&
+            virtualItem.BlockingEntity == grabbed &&
+            _pullableQuery.TryComp(grabbed, out pullable);
+ }
+
+ private void DoPrepareGrabThrow(
+     Entity<GrabberComponent> ent,
+     ref BeforeThrowEvent args,
+     EntityUid grabbed,
+     PullableComponent pullable)
+ {
+     _pulling.TryStopPull(grabbed, pullable);
+     var thrown = EnsureComp<GrabThrownComponent>(grabbed);
+     var damage = ent.Comp.ThrowDamage * ent.Comp.ThrowDamageModifier;
+     thrown.DamageOnCollide = new DamageSpecifier(damage);
+     thrown.WallDamageOnCollide = new DamageSpecifier(damage);
+     thrown.StaminaDamageOnCollide = ent.Comp.ThrowStaminaDamage;
+     Dirty(grabbed, thrown);
+     args.ItemUid = grabbed;
+     args.ThrowSpeed = ent.Comp.ThrowSpeed;
+ }

Аналогичный рефакторинг требуется для OnGrabThrowHit.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Shared/_Sunrise/Grab/Systems/SharedGrabSystem.Throwing.cs` around
lines 11 - 44, The event handlers OnBeforeThrow and OnGrabThrowHit should be
reduced to thin routers and the validation/state-mutation logic moved into
public Try/Can/Do methods; create public methods like
CanBeforeThrow(Entity<GrabberComponent> ent, BeforeThrowEvent args),
TryBeforeThrow(Entity<GrabberComponent> ent, ref BeforeThrowEvent args) and
DoBeforeThrow(EntityUid grabbed, GrabberComponent grabComp, BeforeThrowEvent
args) (and analogous Can/Try/Do trio for the grab-hit flow) and move all checks
(args.Cancelled, ent.Comp.Grabbed presence, Stage check, virtual/pullable
lookup, _pulling.TryStopPull) and state mutations
(EnsureComp<GrabThrownComponent>, setting
DamageOnCollide/WallDamageOnCollide/StaminaDamageOnCollide, Dirty, and modifying
args.ItemUid/args.ThrowSpeed) into those methods; then make OnBeforeThrow simply
call TryBeforeThrow and short-circuit based on the result, and do the same
pattern for OnGrabThrowHit so handlers only route and the heavy logic lives in
named Try/Can/Do methods.

Comment thread Content.Shared/Movement/Pulling/Systems/PullingSystem.cs
Comment on lines +253 to +256
// Sunrise added start - fork-specific virtual item handlers may consume extra pull-like items.
if (args.Handled)
return;
// Sunrise added end

@coderabbitai coderabbitai Bot Jun 5, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Зафиксируйте порядок обработки VirtualItemDeletedEvent, иначе Handled может не сработать.

Проверка args.Handled здесь безопасна только если grab-хендлер (SharedGrabSystem.VirtualItems) гарантированно выполняется раньше PullingSystem. Сейчас это не закреплено, поэтому при обратном порядке удаление grab-виртуального предмета может преждевременно вызвать TryStopPull и сорвать захват.

Вариант правки
@@
-        SubscribeLocalEvent<PullerComponent, VirtualItemDeletedEvent>(OnVirtualItemDeleted);
+        SubscribeLocalEvent<PullerComponent, VirtualItemDeletedEvent>(
+            OnVirtualItemDeleted,
+            after: [typeof(SharedGrabSystem)]);
📝 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.

Suggested change
// Sunrise added start - fork-specific virtual item handlers may consume extra pull-like items.
if (args.Handled)
return;
// Sunrise added end
SubscribeLocalEvent<PullerComponent, VirtualItemDeletedEvent>(
OnVirtualItemDeleted,
after: [typeof(SharedGrabSystem)]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Content.Shared/Movement/Pulling/Systems/PullingSystem.cs` around lines 253 -
256, Нужно зафиксировать порядок обработки VirtualItemDeletedEvent: текущая
проверка args.Handled в PullingSystem (в месте с комментарием Sunrise) безопасна
лишь если SharedGrabSystem.VirtualItems обрабатывает событие раньше — исправьте
это, найдите где подписывается обработчик VirtualItemDeletedEvent в
SharedGrabSystem (метод VirtualItems) и в PullingSystem (обработчик, где
вызывается TryStopPull/проверяется args.Handled) и задайте при подписке явный
приоритет/порядок (например через SubscribeLocalEvent с параметром priority или
соответствующий атрибут) так, чтобы SharedGrabSystem обрабатывался до
PullingSystem; альтернативно измените приоритет в PullingSystem на более
«поздний», чтобы гарантировать корректную работу args.Handled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Вот в твоём Commitable suggestion убирается Sunrise эдиты, верни их.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@banumbas, извините за ошибку — вот исправленный вариант с Sunrise-маркерами:

        SubscribeLocalEvent<PullerComponent, VirtualItemDeletedEvent>(OnVirtualItemDeleted, after: [typeof(SharedGrabSystem)]); // Sunrise-Edit

И соответствующий OnVirtualItemDeleted остаётся без изменений:

    private void OnVirtualItemDeleted(EntityUid uid, PullerComponent component, VirtualItemDeletedEvent args)
    {
        // Sunrise added start - fork-specific virtual item handlers may consume extra pull-like items.
        if (args.Handled)
            return;
        // Sunrise added end

        // If client deletes the virtual hand then stop the pull.
        if (component.Pulling == null)
            return;

        if (component.Pulling != args.BlockingEntity)
            return;

        if (TryComp(args.BlockingEntity, out PullableComponent? comp))
        {
            TryStopPull(args.BlockingEntity, comp);
        }
    }

(ˆ ε ˆ)


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

Learnt from: 3ndorf1n
Repo: space-sunrise/sunrise-station PR: 4199
File: Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs:172-175
Timestamp: 2026-04-11T14:04:41.055Z
Learning: In space-sunrise/sunrise-station, whenever a system raises a predictive/local client-side event via `RaisePredictiveEvent`, the corresponding subscription for handling that event in the shared system must use `SubscribeAllEvent<T>`—NOT `SubscribeNetworkEvent<T>`. Using `SubscribeNetworkEvent` will skip the local prediction raise and defer UI updates until the server round-trip completes. Apply this rule to all predictive events raised with `RaisePredictiveEvent`, e.g., in `SharedStorageSystem` for events like `StorageToggleItemPriorityEvent`.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

сука ну comittable suggestion знаешь что такое?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@banumbas, приношу извинения за раздражение. К сожалению, я не могу создавать коммитируемые suggestion-блоки (в формате GitHub). Вот изменение в виде diff, которое нужно применить вручную:

- SubscribeLocalEvent<PullerComponent, VirtualItemDeletedEvent>(OnVirtualItemDeleted);
+ SubscribeLocalEvent<PullerComponent, VirtualItemDeletedEvent>(OnVirtualItemDeleted, after: [typeof(SharedGrabSystem)]); // Sunrise-Edit

Это единственное изменение — в Initialize(), строка с подпиской на VirtualItemDeletedEvent. Тело OnVirtualItemDeleted трогать не нужно.

(ˆ _ ˆ;)


🧠 Learnings used
Learnt from: banumbas
Repo: space-sunrise/sunrise-station PR: 4469
File: Content.Shared/Movement/Pulling/Systems/PullingSystem.cs:2-3
Timestamp: 2026-06-07T18:51:55.103Z
Learning: In this fork (space-sunrise/sunrise-station), do not require explicit `// Sunrise-Edit` markers for C# `using` directives whose namespace contains the `_Sunrise` segment (e.g., `using Content.Shared._Sunrise.Grab;`). The presence of `_Sunrise` in the imported namespace name is sufficient to identify fork-specific additions, including when such lines are introduced into vanilla upstream files. In future reviews, skip requesting `// Sunrise-Edit` for `using` statements matching this rule.

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

Learnt from: 3ndorf1n
Repo: space-sunrise/sunrise-station PR: 4199
File: Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs:172-175
Timestamp: 2026-04-11T14:04:41.055Z
Learning: In space-sunrise/sunrise-station, whenever a system raises a predictive/local client-side event via `RaisePredictiveEvent`, the corresponding subscription for handling that event in the shared system must use `SubscribeAllEvent<T>`—NOT `SubscribeNetworkEvent<T>`. Using `SubscribeNetworkEvent` will skip the local prediction raise and defer UI updates until the server round-trip completes. Apply this rule to all predictive events raised with `RaisePredictiveEvent`, e.g., in `SharedStorageSystem` for events like `StorageToggleItemPriorityEvent`.

Comment thread Resources/Locale/en-US/_strings/_sunrise/interaction/grab.ftl
Comment thread Resources/Locale/ru-RU/_strings/_sunrise/interaction/grab.ftl

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Content.Server/Body/Systems/RespiratorSystem.cs`:
- Around line 519-525: The Sunrise marker comments around the new
CanBreatheEvent record (the lines containing "// Sunrise-Start" and "//
Sunrise-End" surrounding the record struct CanBreatheEvent) don't follow repo
conventions; replace them with the repository-standard markers using the Sunrise
prefix and the required wording (e.g., "// Sunrise added start - reason" and "//
Sunrise added end" or the alternative "// Sunrise-Edit added start" / "//
Sunrise-Edit added end") so the insertion is clearly flagged for upstream merges
and matches other edits; update only the two marker comment lines around the
CanBreatheEvent declaration to the correct format and leave the record and
attributes unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9c700743-b975-43c3-8a92-d272913e7951

📥 Commits

Reviewing files that changed from the base of the PR and between 477a451 and cec17ad.

📒 Files selected for processing (1)
  • Content.Server/Body/Systems/RespiratorSystem.cs

Comment thread Content.Server/Body/Systems/RespiratorSystem.cs Outdated

@Orvex07 Orvex07 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  1. Доделайте и дождитесь одобрение issues.
  2. Нужны какие-то анимации захвата (смотрел видео с ПРа виздена), слишком непонятно обычным игрокам.
  3. Нужно больше актуальных данных насчёт данного ПРа. Видео, скриншоты.
  4. Переделать changelog

Не буду пока закрывать ПР, пробуйте, тестируй. Повторюсь, первый пункт <-- Новые п правила контрибьютинга.

Что могу сказать насчёт кода -> Насчёт кода, многие моменты нужно вынести в директорию sunrise в сделать как partial класс.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@banumbas

Copy link
Copy Markdown
Contributor Author

Если что я не забросил ПР, просто в данный момент нету возможности с ним работать.

@banumbas

Copy link
Copy Markdown
Contributor Author
  1. Доделайте и дождитесь одобрение issues.

    1. Нужны какие-то анимации захвата (смотрел видео с ПРа виздена), слишком непонятно обычным игрокам.

    2. Нужно больше актуальных данных насчёт данного ПРа. Видео, скриншоты.

    3. Переделать changelog

Не буду пока закрывать ПР, пробуйте, тестируй. Повторюсь, первый пункт <-- Новые п правила контрибьютинга.

Что могу сказать насчёт кода -> Насчёт кода, многие моменты нужно вынести в директорию sunrise в сделать как partial класс.

Насчёт того что ты сказал насчёт кода не знаю, я и так вроде по максимуму в партиал вывел

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: НЕ РАЗОБРАНО

Development

Successfully merging this pull request may close these issues.

Перенос граба.

2 participants