Skip to content

Кастомка для Бульбы#100

Open
bzzzbzzbz wants to merge 12 commits into
ArcaneSS14:masterfrom
bzzzbzzbz:custom_bulba
Open

Кастомка для Бульбы#100
bzzzbzzbz wants to merge 12 commits into
ArcaneSS14:masterfrom
bzzzbzzbz:custom_bulba

Conversation

@bzzzbzzbz

Copy link
Copy Markdown
Contributor

Описание PR

Делаю личную кастомку на ксено для Бульбы. ПР ещё не доделан...буду дрочить кролика.

Медиа

Тип PR

  • Feature
  • Fix
  • Tweak
  • Balance
  • Refactor
  • Port
  • Translate
  • Resprite

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@bzzzbzzbz, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 793d6d97-0116-4110-9b77-b0652f498ca3

📥 Commits

Reviewing files that changed from the base of the PR and between ba94aed and f5e7b3e.

📒 Files selected for processing (3)
  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
  • Content.Shared/Preferences/HumanoidCharacterProfile.cs

Walkthrough

Добавлена whitelist-проверка маркингов: данные подключены к MarkingPrototype, доступ проверяется по имени пользователя, а запрещённые маркинги фильтруются в пикерах и профилях. Добавлены три маркинга HumanoidXeno «Рэн» с текстурами и локализацией.

Changes

Whitelist-механизм и его применение

Layer / File(s) Summary
Контракт whitelist и проверка доступа
Content.Shared/_Arcane/MarkingWhitelistData.cs, Content.Shared/Humanoid/Markings/MarkingPrototype.cs, Content.Shared/_Arcane/MarkingWhitelistManager.cs
Добавлены MarkingWhitelistData, поле Whitelist и проверка IsMarkingAllowed по UserName сессии.
Фильтрация в пикерах и профиле
Content.Client/Humanoid/MarkingPicker.xaml.cs, Content.Client/Humanoid/SingleMarkingPicker.xaml.cs, Content.Shared/Preferences/HumanoidCharacterProfile.cs
Запрещённые whitelist-маркинги исключаются из списков выбора и удаляются при проверке профиля.
Маркинги Рэна и ресурсы
Resources/Prototypes/_Arcane/.../humanoid_xeno.yml, Resources/Textures/_Arcane/.../{head,tail,tracheas}.rsi/meta.json, Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
Добавлены хвост, голова и трахеи Рэна с ограничением Bulbo44key, states текстур и русскими названиями.

Estimated code review effort: 3 (Moderate) | ~25 минут

Sequence Diagram(s)

sequenceDiagram
  participant PlayerSession
  participant MarkingPicker
  participant MarkingWhitelistManager
  participant HumanoidCharacterProfile
  PlayerSession->>MarkingPicker: предоставить LocalSession
  MarkingPicker->>MarkingWhitelistManager: проверить MarkingPrototype
  MarkingWhitelistManager-->>MarkingPicker: разрешить или пропустить маркинг
  HumanoidCharacterProfile->>MarkingWhitelistManager: проверить сохранённые маркировки
  MarkingWhitelistManager-->>HumanoidCharacterProfile: удалить запрещённые маркировки
Loading

Suggested reviewers: UmbiMax, Vecortys

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Название кратко и по сути описывает личную кастомку для Бульбы, что соответствует изменениям в PR.
Description check ✅ Passed Описание связано с PR и прямо говорит о личной кастомке ксено для Бульбы, несмотря на незавершённость.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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.

@bzzzbzzbz
bzzzbzzbz marked this pull request as draft June 29, 2026 21:46
@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai в чём проблема?

@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: 3

🤖 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.Client/_Arcane/MarkingWhitelistManager.cs`:
- Around line 4-6: The namespace is misleading because MarkingWhitelistManager
lives in the client-only Content.Client tree but is declared under
Content.Shared.SpecialWhitelist. Update the type’s namespace to a
client-appropriate one, or move the class into the shared project if it is truly
meant to be shared, so the namespace matches its actual assembly and usage.
- Around line 8-27: The whitelist decision in
MarkingWhitelistManager.IsMarkingAllowed is currently client-authoritative in
Content.Client, so move this logic to a server/shared authority path and have
the client only consume the already-approved result. Refactor the check around
MarkingPrototype.Whitelist, ICommonSession, and session.Data.UserName so the
authoritative verdict is produced outside Content.Client, then update the
client-side caller to use that verdict only for display.
- Around line 6-8: `MarkingWhitelistManager` has no instance state or non-static
behavior, so convert the class to a static class and keep `IsMarkingAllowed` as
a static member. Update the `MarkingWhitelistManager` declaration accordingly so
the type clearly communicates utility-only usage and cannot be instantiated.
🪄 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 Plus

Run ID: a0b920fe-5106-4d32-a7d6-1dd781cbd0d4

📥 Commits

Reviewing files that changed from the base of the PR and between 2734662 and 769f899.

📒 Files selected for processing (1)
  • Content.Client/_Arcane/MarkingWhitelistManager.cs
📜 Review details
⏰ Context from checks skipped due to timeout. (5)
  • GitHub Check: YAML Linter
  • GitHub Check: build (ubuntu-latest)
  • GitHub Check: Test Packaging
  • GitHub Check: build (ubuntu-latest)
  • GitHub Check: YAML map schema validator
🧰 Additional context used
📓 Path-based instructions (6)
**/*.cs

📄 CodeRabbit inference engine (GEMINI.md)

**/*.cs: Keep components data-only and behavior in systems
Use On... -> Try... -> Can... -> Do... pattern for gameplay actions
Prefer Entity<T?>, ProtoId<T>, EntProtoId, and localized strings for type usage

**/*.cs: When writing or editing C# gameplay code, load skills: ss14-ecs-components, ss14-ecs-entities, ss14-ecs-prototypes, ss14-ecs-systems, ss14-events, and ss14-prediction.
If the C# change is large or the task needs reviewable notes, load skill ss14-documentation-writing.
If the code touches hot paths, Update(), or frequently raised events, load skill ss14-standard-optimizations.
If the task adds or changes player-facing text, load skills ss14-localization-strings and ss14-localization-code when the change also touches Loc.GetString(...), LocId, popup text, or localized component fields.
If the task touches network events, NetEntity, replicated state routing, or shared/server/client message flow, load skill ss14-netcode.
If the task touches Appearance, GenericVisualizer, visual state enums, or sprite-layer toggles, load skill ss14-graphics-generic-visualizer-appearance.
If the task touches sprites, RSI metadata, overlays, shaders, or custom client visual effects, load skill ss14-sprite-overlays-shaders.
If the task is about learning or explaining SS14 architecture, first features, or where code belongs, load skills ss14-prototype-basics, ss14-ecs-basics, and ss14-client-server-shared.
If the task is about bug hunting, VV, logs, breakpoints, or runtime inspection, load skills ss14-debugging-workflow and ss14-common-api-patterns.
If the task touches common gameplay helpers such as entity-system methods, spawning, prototypes, audio, popups, or random, load skills ss14-common-api-patterns and ss14-audio when the work changes audio routing, sound assets, sound collections, or predicted sound feedback.
If the task ports code or assets from another repository, or needs license or attribution guidance,...

Files:

  • Content.Client/_Arcane/MarkingWhitelistManager.cs
+(Content.Shared|Content.Server|Content.Client|Content.Goobstation.Shared|Content.Goobstation.Server|Content.Goobstation.Client|Content.Goobstation.Common|Content.Goobstation.Maths|Content.Goobstation.UIKit|Content.Server.Database|Content.Shared.Database|Content.Tests|Content.IntegrationTests)/**/*.cs

📄 CodeRabbit inference engine (.cursor/rules/ss14-csharp.mdc)

+(Content.Shared|Content.Server|Content.Client|Content.Goobstation.Shared|Content.Goobstation.Server|Content.Goobstation.Client|Content.Goobstation.Common|Content.Goobstation.Maths|Content.Goobstation.UIKit|Content.Server.Database|Content.Shared.Database|Content.Tests|Content.IntegrationTests)/**/*.cs: Apply C# ECS style rules from ss14-interaction-flow.md
Apply ss14-csharp-style.md rules for C# code formatting and conventions
Follow ss14-naming-conventions for variable, method, and type naming in C# gameplay code

Files:

  • Content.Client/_Arcane/MarkingWhitelistManager.cs
{Content.Client,Content.Goobstation.Client,Content.Goobstation.UIKit}/**/*.{cs,xaml}

📄 CodeRabbit inference engine (.cursor/rules/ss14-ui.mdc)

{Content.Client,Content.Goobstation.Client,Content.Goobstation.UIKit}/**/*.{cs,xaml}: Follow SS14 naming conventions when editing UI, XAML, and client-state files
Maintain upstream compatibility when editing SS14 client code
Follow SS14 UI and BUI conventions when implementing UI components and behavior-driven user interfaces

Files:

  • Content.Client/_Arcane/MarkingWhitelistManager.cs
{Content.Client,Content.Goobstation.Client,Content.Goobstation.UIKit}/**/*.cs

📄 CodeRabbit inference engine (.cursor/rules/ss14-ui.mdc)

{Content.Client,Content.Goobstation.Client,Content.Goobstation.UIKit}/**/*.cs: Apply SS14 prediction patterns when working with predicted client-state in SS14 client code
Follow SS14 localization code practices in UI and client-state implementations

Put main client-only visuals, overlays, XAML, and BUI front-ends in Content.Client/; use Content.Goobstation.Client/ or Content.Goobstation.UIKit/ only when matching existing references and ownership.

Files:

  • Content.Client/_Arcane/MarkingWhitelistManager.cs
**/*.{cs,xaml,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

If the task adds tests or you need to choose the right test layer, load skill ss14-tests-authoring.

Files:

  • Content.Client/_Arcane/MarkingWhitelistManager.cs
Content.Client/**/*.cs

⚙️ CodeRabbit configuration file

Content.Client/**/*.cs: Review Content.Client for presentation-only behavior:

  • Keep authority out of the client.
  • Prefer reading already-networked component state instead of duplicating BUI state unless the pattern requires it.
  • Flag missing localization for player-visible text.
  • Prefer nearby established UI and visual patterns over custom one-off structures.

Files:

  • Content.Client/_Arcane/MarkingWhitelistManager.cs
🧠 Learnings (2)
📚 Learning: 2026-06-04T21:17:36.815Z
Learnt from: MataVsn
Repo: ArcaneSS14/arcane-station PR: 31
File: Content.Client/Fluids/PuddleSystem.cs:41-41
Timestamp: 2026-06-04T21:17:36.815Z
Learning: In this repo (ArcaneSS14/arcane-station), reviewers should use the Arcane inline fork-edit marker naming for single-line edits outside `_Arcane` paths: prefer `// Arcane` or `// Arcane-edit` and do not use `// Orion` for this purpose. Repo-specific AGENTS guidance that mentions `// Orion` does not apply to these single-line changes; only `_Arcane` paths follow the applicable different convention.

Applied to files:

  • Content.Client/_Arcane/MarkingWhitelistManager.cs
📚 Learning: 2026-06-28T19:37:26.732Z
Learnt from: MataVsn
Repo: ArcaneSS14/arcane-station PR: 96
File: Content.Client/IoC/ClientContentIoC.cs:151-151
Timestamp: 2026-06-28T19:37:26.732Z
Learning: For ArcaneSS14/arcane-station C# files whose path is outside any `_Arcane` directories, avoid adding an inline fork marker (e.g., `// Arcane` or `// Arcane-edit`) to `using` directives when the imported namespace already clearly indicates the `_Arcane` fork. For example, if the `using` namespace itself contains `_Arcane` (such as `using Content.Client._Arcane.ERP.Preferences;`), the `// Arcane`/`// Arcane-edit` marker is unnecessary.

Applied to files:

  • Content.Client/_Arcane/MarkingWhitelistManager.cs

Comment on lines +4 to +6
namespace Content.Shared.SpecialWhitelist;

public sealed class MarkingWhitelistManager

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Не маскируйте client-only код под Content.Shared.

Файл лежит в Content.Client/_Arcane, но namespace объявлен как Content.Shared.SpecialWhitelist. Это создаёт ложный shared-контракт: тип выглядит доступным для shared-слоя, хотя физически живёт в client-сборке. Либо переносите утилиту в shared-проект, либо дайте ей client-namespace. As per path instructions, Content.Client should be reviewed for presentation-only behavior.

🤖 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.Client/_Arcane/MarkingWhitelistManager.cs` around lines 4 - 6, The
namespace is misleading because MarkingWhitelistManager lives in the client-only
Content.Client tree but is declared under Content.Shared.SpecialWhitelist.
Update the type’s namespace to a client-appropriate one, or move the class into
the shared project if it is truly meant to be shared, so the namespace matches
its actual assembly and usage.

Source: Path instructions

Comment on lines +6 to +8
public sealed class MarkingWhitelistManager
{
public static bool IsMarkingAllowed(MarkingPrototype marking, ICommonSession? session)

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.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -e cs MarkingWhitelistManager . -x sed -n '1,80p' {}
echo '--- usages ---'
rg -nP --type=cs '\bnew\s+MarkingWhitelistManager\b|\bMarkingWhitelistManager\s*\.' Content.Client Content.Shared Content.Server Content.Tests Content.IntegrationTests

Repository: ArcaneSS14/arcane-station

Length of output: 1113


Сделать MarkingWhitelistManager static class
У класса нет состояния и нестатического API, поэтому static class точнее выражает намерение и исключает случайное создание экземпляра.

🤖 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.Client/_Arcane/MarkingWhitelistManager.cs` around lines 6 - 8,
`MarkingWhitelistManager` has no instance state or non-static behavior, so
convert the class to a static class and keep `IsMarkingAllowed` as a static
member. Update the `MarkingWhitelistManager` declaration accordingly so the type
clearly communicates utility-only usage and cannot be instantiated.

Source: Coding guidelines

Comment thread Content.Shared/_Arcane/MarkingWhitelistManager.cs
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ArcaneSS14/arcane-station"
pr="100"

echo "== PR reviews =="
gh pr view "$pr" --repo "$repo" --json reviews --jq '
  .reviews[]
  | select(.author.login=="coderabbitai")
  | {
      author: .author.login,
      state: .state,
      submittedAt: .submittedAt,
      body: .body
    }'

echo
echo "== PR review comments by coderabbitai =="
gh api "repos/$repo/pulls/$pr/comments?per_page=100" --paginate | jq -r '
  .[]
  | select(.user.login=="coderabbitai")
  | "ID: \(.id)\nPath: \(.path)\nLine: \(.line // .original_line // "n/a")\nCreated: \(.created_at)\nBody:\n\(.body)\n---"'

Length of output: 816


@bzzzbzzbz Не вижу конкретной проблемы с моей стороны: в PR #100 сейчас нет ни review-комментариев, ни review-ревью от coderabbitai.

Если ты имел в виду конкретный тред/аннотацию — кинь ссылку на комментарий или цитату текста, и я разберу точечно, что именно там не так.

(/_・)/ 🐇

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai MarkingPrototype не содержит определения Whitelist и из-за этого файл некорректный. что делать?

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Candidate files =="
fd -i 'MarkingPrototype|MarkingWhitelistManager' .

echo
echo "== MarkingPrototype declarations/usages =="
rg -n -C3 --glob '!**/bin/**' --glob '!**/obj/**' '\bMarkingPrototype\b|\bWhitelist\b' .

Length of output: 258378


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate MarkingPrototype file =="
fd 'MarkingPrototype.cs' .

echo
echo "== Outline MarkingPrototype =="
ast-grep outline $(fd 'MarkingPrototype.cs' . | head -n1) --view expanded

echo
echo "== MarkingPrototype source =="
sed -n '1,220p' "$(fd 'MarkingPrototype.cs' . | head -n1)"

echo
echo "== New client file =="
sed -n '1,220p' Content.Client/_Arcane/MarkingWhitelistManager.cs

echo
echo "== Marking picker snippets =="
sed -n '200,320p' Content.Client/Humanoid/MarkingPicker.xaml.cs
sed -n '90,170p' Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

Length of output: 10782


@bzzzbzzbz да, проблема реальная.

Что не так:

  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs не имеет поля Whitelist.
  • Content.Client/_Arcane/MarkingWhitelistManager.cs поэтому не компилируется.
  • Дополнительно файл лежит в Content.Client/..., но объявлен в namespace Content.Shared.SpecialWhitelist — это ещё и риск по placement/assembly.

Что делать:

  1. Если это незавершённая фича — лучше убрать файл из PR сейчас.
    Это самый безопасный вариант без регрессий.

  2. Если whitelist для marking действительно нужен — делать надо через shared-модель, а не только client helper:

    • добавить поле в Content.Shared/Humanoid/Markings/MarkingPrototype.cs, например:
      [DataField("whitelist")]
      public MarkingWhitelistData? Whitelist { get; private set; }
    • добавить сам тип MarkingWhitelistData в Shared:
      public sealed partial class MarkingWhitelistData
      {
          [DataField("allowed")]
          public List<string> Allowed { get; private set; } = new();
      }
    • после этого уже фильтровать разметки в:
      • Content.Client/Humanoid/MarkingPicker.xaml.cs
      • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
  3. Namespace исправить обязательно.
    Если файл остаётся в клиенте, namespace должен быть клиентский, не Content.Shared.*.

Итого:
для текущего PR рекомендую просто удалить Content.Client/_Arcane/MarkingWhitelistManager.cs до тех пор, пока не будет добавлен whitelist в MarkingPrototype и прототипы/YAML под него.

(╯°□°)╯︵ 🐇


✏️ Learnings added
Learnt from: bzzzbzzbz
URL: https://github.com/ArcaneSS14/arcane-station/pull/100

Timestamp: 2026-06-29T22:15:54.401Z
Learning: В репозитории ArcaneSS14/arcane-station тип `Content.Shared.Humanoid.Markings.MarkingPrototype` в файле `Content.Shared/Humanoid/Markings/MarkingPrototype.cs` не содержит свойства `Whitelist`; клиентский helper `Content.Client/_Arcane/MarkingWhitelistManager.cs`, обращающийся к `marking.Whitelist`, некорректен без предварительного добавления shared-модели в прототип.

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

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai почему пишет, что нейспейс MarkingWhitelistData не найден?

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find MarkingWhitelistData =="
rg -n -C2 --glob '!**/bin/**' --glob '!**/obj/**' '\bMarkingWhitelistData\b' .

echo
echo "== Locate MarkingPrototype file =="
fd 'MarkingPrototype.cs' .

mp="$(fd 'MarkingPrototype.cs' . | head -n1)"
if [ -n "${mp:-}" ]; then
  echo
  echo "== Outline MarkingPrototype =="
  ast-grep outline "$mp" --view expanded

  echo
  echo "== Top of MarkingPrototype =="
  sed -n '1,120p' "$mp"
fi

if [ -f "Content.Client/_Arcane/MarkingWhitelistManager.cs" ]; then
  echo
  echo "== MarkingWhitelistManager =="
  sed -n '1,160p' "Content.Client/_Arcane/MarkingWhitelistManager.cs"
fi

Length of output: 5057


@bzzzbzzbz проблема не в отсутствии типа, а в namespace mismatch.

Что есть по факту:

  • В Content.Shared/_Arcane/MarkingWhitelistManager.cs на Line 4 объявлен namespace:
    Content.Shared._Arcane.SpecialWhitelist
  • Там же на Line 6 объявлен тип:
    MarkingWhitelistData
  • В Content.Shared/Humanoid/Markings/MarkingPrototype.cs на Line 74 используется:
    MarkingWhitelistData? Whitelist
  • Но вверху MarkingPrototype.cs нет
    using Content.Shared._Arcane.SpecialWhitelist;

Поэтому компилятор и пишет, что MarkingWhitelistData не найден.

Что делать:

  1. Либо добавить в Content.Shared/Humanoid/Markings/MarkingPrototype.cs:
    using Content.Shared._Arcane.SpecialWhitelist;
  2. Либо писать тип полностью:
    public Content.Shared._Arcane.SpecialWhitelist.MarkingWhitelistData? Whitelist { get; private set; }

Дополнительно:

  • имя файла Content.Shared/_Arcane/MarkingWhitelistManager.cs сейчас сбивает с толку: в нём лежит MarkingWhitelistData, а не manager.
  • мой прошлый вывод про отсутствие Whitelist в MarkingPrototype уже неактуален для текущего состояния ветки.

(•᷄ ﻌ •᷅)


✏️ Learnings added
Learnt from: bzzzbzzbz
URL: https://github.com/ArcaneSS14/arcane-station/pull/100

Timestamp: 2026-06-29T22:25:38.044Z
Learning: В репозитории ArcaneSS14/arcane-station на текущей ветке PR `#100` тип `Content.Shared._Arcane.SpecialWhitelist.MarkingWhitelistData` объявлен в файле `Content.Shared/_Arcane/MarkingWhitelistManager.cs`, а `Content.Shared.Humanoid.Markings.MarkingPrototype` в файле `Content.Shared/Humanoid/Markings/MarkingPrototype.cs` использует `MarkingWhitelistData` в свойстве `Whitelist` на Line 74 без видимого `using Content.Shared._Arcane.SpecialWhitelist;`, поэтому ошибка связана с namespace/import mismatch, а не с отсутствием типа.

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

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai стоит ли переименовать файл в MarkingWhitelistData? в конечном итоге нужно сделать так, чтобы некоторые маркинги могли использовать только те, кто занесён в вайтлист этих самых маркингов. нужно ли создавать ещё один файл?

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Candidate files =="
fd -i 'MarkingWhitelistManager.cs|MarkingPrototype.cs|MarkingPicker.xaml.cs|SingleMarkingPicker.xaml.cs' .

echo
shared_file="$(fd '^MarkingWhitelistManager\.cs$' . | rg '^Content\.Shared/' | head -n1 || true)"
proto_file="$(fd '^MarkingPrototype\.cs$' . | head -n1 || true)"

if [ -n "${shared_file:-}" ]; then
  echo "== Outline: $shared_file =="
  ast-grep outline "$shared_file" --view expanded
  echo
  echo "== Source: $shared_file =="
  sed -n '1,220p' "$shared_file"
fi

if [ -n "${proto_file:-}" ]; then
  echo
  echo "== Outline: $proto_file =="
  ast-grep outline "$proto_file" --view expanded
  echo
  echo "== Relevant slice: $proto_file =="
  sed -n '1,160p' "$proto_file"
fi

echo
echo "== Usages of MarkingWhitelistData / IsMarkingAllowed / Whitelist =="
rg -n -C2 --glob '!**/bin/**' --glob '!**/obj/**' '\bMarkingWhitelistData\b|\bIsMarkingAllowed\s*\(|\bWhitelist\b' Content.Shared Content.Client

Length of output: 189617


@bzzzbzzbz да, переименовать/разделить стоит.

Рекомендация по структуре:

  1. MarkingWhitelistData — отдельный файл в Shared

    • файл: Content.Shared/_Arcane/SpecialWhitelist/MarkingWhitelistData.cs
    • namespace: Content.Shared._Arcane.SpecialWhitelist
    • там только data-класс для [DataField("whitelist")]
  2. Логику проверки — в отдельный файл

    • если это только фильтр UI, то лучше в Client:
      Content.Client/_Arcane/SpecialWhitelist/MarkingWhitelistManager.cs
    • если хочешь, чтобы ограничение было необходным, нужна ещё server/shared validation, а не только клиентский фильтр.

То есть: да, нужен ещё один файл.
Сейчас у тебя в одном MarkingWhitelistManager.cs смешаны:

  • data-модель MarkingWhitelistData
  • логика IsMarkingAllowed(...)

Это и вызывает путаницу с namespace/import.

Минимально нормально так:

// Content.Shared/_Arcane/SpecialWhitelist/MarkingWhitelistData.cs
using Robust.Shared.Serialization;

namespace Content.Shared._Arcane.SpecialWhitelist;

[DataDefinition]
public sealed partial class MarkingWhitelistData
{
    [DataField("allowed")]
    public List<string> Allowed { get; private set; } = new();
}
// Content.Shared/Humanoid/Markings/MarkingPrototype.cs
using Content.Shared._Arcane.SpecialWhitelist;

А проверку доступа — отдельно.

Важно по рискам:

  • Если оставить только client-фильтрацию, это не защита.
  • Пользователь сможет обойти UI и прислать запрещённый marking другим путём, если сервер это не валидирует.
  • Поэтому для конечной цели “использовать могут только whitelisted” нужен не только picker, но и проверка на применении/сохранении персонажа.

Итог:

  • MarkingWhitelistData вынести в отдельный shared-файл — да.
  • Ещё один файл для логики — да.
  • Не смешивать data и manager в одном файле.
  • Если нужна настоящая защита, добавить server-side validation.

( •ᵕ• )૭


✏️ Learnings added
Learnt from: bzzzbzzbz
URL: https://github.com/ArcaneSS14/arcane-station/pull/100

Timestamp: 2026-06-29T22:30:43.874Z
Learning: В репозитории ArcaneSS14/arcane-station для PR `#100` цель фичи с `Content.Shared.Humanoid.Markings.MarkingPrototype.Whitelist` — ограничить использование отдельных маркингов только пользователями, перечисленными в whitelist конкретного маркинга; для этой задачи одного клиентского фильтра в picker недостаточно, требуется авторитативная проверка при применении или сохранении персонажа.

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

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai всё ли сейчас будет работать? как сделать так, чтобы определённые маркинги в кастомизации теперь привязывались к отдельным сикеям?

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Candidate files =="
fd -i 'MarkingPrototype.cs|MarkingWhitelist*.cs|MarkingPicker.xaml.cs|SingleMarkingPicker.xaml.cs|HumanoidProfile*.cs|Profile*.cs|Character*.cs' Content.Shared Content.Client Content.Server 2>/dev/null || true

echo
proto="$(fd '^MarkingPrototype\.cs$' Content.Shared | head -n1 || true)"
if [ -n "${proto:-}" ]; then
  echo "== Outline: $proto =="
  ast-grep outline "$proto" --view expanded
  echo
  echo "== Source slice: $proto =="
  sed -n '1,180p' "$proto"
fi

echo
for f in $(fd -i 'MarkingWhitelist*.cs' Content.Shared Content.Client 2>/dev/null); do
  echo "== Outline: $f =="
  ast-grep outline "$f" --view expanded || true
  echo
  echo "== Source: $f =="
  sed -n '1,220p' "$f"
  echo
done

for f in Content.Client/Humanoid/MarkingPicker.xaml.cs Content.Client/Humanoid/SingleMarkingPicker.xaml.cs; do
  if [ -f "$f" ]; then
    echo "== Outline: $f =="
    ast-grep outline "$f" --view expanded || true
    echo
    echo "== Relevant slice: $f =="
    sed -n '1,260p' "$f"
    echo
  fi
done

echo "== Usages of MarkingWhitelistData / IsMarkingAllowed / '.Whitelist' =="
rg -n -C2 --glob '!**/bin/**' --glob '!**/obj/**' '\bMarkingWhitelistData\b|\bIsMarkingAllowed\s*\(|\.Whitelist\b' Content.Shared Content.Client Content.Server

echo
echo "== Potential profile/validation touchpoints for markings =="
rg -n -C3 --glob '!**/bin/**' --glob '!**/obj/**' '\bMarkings\b|\bmarkings\b|\bValidate.*Profile\b|\bGetValid.*Marking\b|\bEnsure.*Marking\b|\bHumanoidProfile\b' Content.Shared Content.Server Content.Client

Length of output: 212863


@bzzzbzzbz сейчас — скорее всего скомпилируется, но фича ещё не “работает как защита”.

Что видно по ветке:

  • MarkingWhitelistData теперь должен резолвиться: в Content.Shared/Humanoid/Markings/MarkingPrototype.cs есть using Content.Shared._Arcane.SpecialWhitelist; на Line 20.
  • Но по поиску не видно вызовов IsMarkingAllowed(...).
  • Значит whitelist-данные у маркинга могут уже существовать, но ни UI, ни сервер их по факту не применяют.

То есть:

  1. Компиляция — вероятно ок.
  2. Скрытие маркингов в кастомизации — пока не гарантировано.
  3. Запрет выбора “чужого” маркинга — точно не гарантирован без server-side проверки.

Как привязать конкретные маркинги к конкретным ckey:

1) Хранить список ckey в YAML у самого маркинга

Пример:

- type: marking
  id: BulbaTail
  bodyPart: Tail
  markingCategory: Tail
  sprites:
  - sprite: _Arcane/Mobs/Customization/bulba_tail.rsi
    state: tail
  whitelist:
    allowed:
    - bulba
    - another_ckey

Лучше хранить allowed в нижнем регистре.

2) На клиенте фильтровать список в пикере

Подключить проверку в:

  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • при необходимости Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

Логика:

  • получить текущую сессию;
  • перед добавлением маркинга в список доступных проверить:
MarkingWhitelistManager.IsMarkingAllowed(proto, session)

Это даст правильное поведение в кастомизации: чужие маркинги просто не показываются.

3) На сервере валидировать профиль

Это обязательный шаг, если нужен реальный запрет, а не только UI-фильтр.

Сейчас стандартная валидация маркингов в shared-коде учитывает:

  • существование прототипа,
  • species,
  • sex,

но не ckey/session.

Нужно добавить отдельную серверную проверку в месте, где профиль:

  • сохраняется,
  • принимается от клиента,
  • или применяется к персонажу.

Минимум:

  • пройтись по profile.Appearance.Markings,
  • для каждого MarkingId найти MarkingPrototype,
  • если у прототипа есть Whitelist, проверить ckey игрока,
  • неразрешённые маркинги либо:
    • удалять из профиля,
    • либо отклонять сохранение профиля с ошибкой.

4) Волосы/борода — отдельно

Если хочешь привязывать hair / facial hair тоже к ckey, надо валидировать ещё:

  • profile.Appearance.HairStyleId
  • profile.Appearance.FacialHairStyleId

Потому что они хранятся отдельно от Appearance.Markings.

Что рекомендую по итогу

  • Да, MarkingWhitelistData лучше держать в отдельном shared-файле.
  • Да, клиентский helper/manager оставить отдельным файлом.
  • И да, нужен ещё один серверный шаг валидации, иначе whitelist можно обойти.

Если коротко:
сейчас не всё готово; чтобы маркинги реально привязывались к отдельным ckey, нужны оба слоя:

  • client filtering в MarkingPicker,
  • server validation при сохранении/применении профиля.

( •ᵕ• )/

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

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

Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi

State Old New Status
ren_head Added

Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi

State Old New Status
ren_tail Added
ren_tail_grad Added

Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi

State Old New Status
ren_tubes Added

Edit: diff updated after f5e7b3e

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Content.Shared/_Arcane/MarkingWhitelistManager.cs (1)

19-19: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Замени session.Data.UserName на session.Name.
У ICommonSession нет публичного Data.UserName; здесь это выглядит как ошибка API и сломает сборку.

🤖 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/_Arcane/MarkingWhitelistManager.cs` at line 19, Use the
session’s public name property instead of the internal data user name in
MarkingWhitelistManager, since ICommonSession does not expose Data.UserName.
Update the ckey assignment in the code that handles session identity to read
from session.Name so the API usage matches the interface and the build stays
valid.
🤖 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/_Arcane/MarkingWhitelistData.cs`:
- Around line 8-9: The [DataField("allowed")] annotation on
MarkingWhitelistData.Allowed is redundant because it matches the default
camelCase name; simplify it to a bare [DataField] unless a non-default
serialized name is required. Update the Allowed property in MarkingWhitelistData
to use the convention preferred by the serializer guidelines and keep the
property name as the unique reference point.

In `@Content.Shared/_Arcane/MarkingWhitelistManager.cs`:
- Line 8: Rename the check method in MarkingWhitelistManager from
IsMarkingAllowed to a Can...-style name, such as CanApplyMarking, to match the
project’s convention for predicate/check methods. Update the method declaration
and every call site or reference that uses IsMarkingAllowed so the API name is
consistent and clearly communicates that it returns whether marking can be
applied.

In `@Content.Shared/Humanoid/Markings/MarkingPrototype.cs`:
- Around line 73-76: Remove the explicit DataField name from MarkingPrototype.
The Whitelist property already matches the default serialized name, so update
the MarkingPrototype.Whitelist declaration to use [DataField] without the
"whitelist" string, keeping the existing Arcane comment markers unchanged.

In
`@Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml`:
- Around line 120-133: The three Ren humanoid xeno markings are only gated by
the client-side whitelist, so add server-side validation in the character
profile apply/save path to reject unauthorized markings. Update the logic around
HumanoidXenoTailRen, HumanoidXenoHeadRen, and HumanoidXenoTracheasRen so the
server checks the allowed user before persisting or applying the profile, rather
than relying on MarkingWhitelistManager/UI filtering alone.

---

Outside diff comments:
In `@Content.Shared/_Arcane/MarkingWhitelistManager.cs`:
- Line 19: Use the session’s public name property instead of the internal data
user name in MarkingWhitelistManager, since ICommonSession does not expose
Data.UserName. Update the ckey assignment in the code that handles session
identity to read from session.Name so the API usage matches the interface and
the build stays valid.
🪄 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 Plus

Run ID: a1362e26-ec6f-456e-a332-aa4f1cf80230

📥 Commits

Reviewing files that changed from the base of the PR and between 769f899 and f0b0522.

⛔ Files ignored due to path filters (4)
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/ren_head.png is excluded by !**/*.png
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/ren_tail.png is excluded by !**/*.png
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/ren_tail_grad.png is excluded by !**/*.png
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/ren_tubes.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
  • Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
  • Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json
📜 Review details
🧰 Additional context used
📓 Path-based instructions (15)
Resources/**/*.{yml,ftl,json}

📄 CodeRabbit inference engine (.cursor/rules/ss14-resources.mdc)

Resources/**/*.{yml,ftl,json}: Follow SS14 naming conventions when editing prototype, localization, and resource files
Follow SS14 upstream maintenance practices when editing resource files

Files:

  • Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json
  • Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml
Resources/**/*.ftl

📄 CodeRabbit inference engine (.cursor/rules/ss14-resources.mdc)

Follow SS14 localization string standards and formatting rules

Files:

  • Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
Resources/**/*.{yml,ftl}

📄 CodeRabbit inference engine (.cursor/rules/ss14-resources.mdc)

Follow SS14 prototype locale integration rules and practices

Files:

  • Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
  • Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml
**/*.ftl

📄 CodeRabbit inference engine (AGENTS.md)

Use specific kebab-case localization IDs.

Files:

  • Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
Resources/Locale/**/*.ftl

📄 CodeRabbit inference engine (AGENTS.md)

Resources/Locale/**/*.ftl: Add or update FTL entries under Resources/Locale/, starting with en-US; add/update matching ru-RU entries when the same feature already maintains Russian locale or the change is Orion-facing and you can do so without guessing translations.
Use specific kebab-case localization IDs.

Files:

  • Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl

⚙️ CodeRabbit configuration file

Resources/Locale/**/*.ftl: Treat localization as mandatory:

  • Every player-facing string should be localized.
  • Prefer specific kebab-case keys.
  • Flag raw strings in code or gameplay/resource changes that are missing locale updates.
  • Check consistency when prototype names, descriptions, markings, or UI text changed.

Files:

  • Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl
**/*.cs

📄 CodeRabbit inference engine (GEMINI.md)

**/*.cs: Keep components data-only and behavior in systems
Use On... -> Try... -> Can... -> Do... pattern for gameplay actions
Prefer Entity<T?>, ProtoId<T>, EntProtoId, and localized strings for type usage

**/*.cs: When writing or editing C# gameplay code, load skills: ss14-ecs-components, ss14-ecs-entities, ss14-ecs-prototypes, ss14-ecs-systems, ss14-events, and ss14-prediction.
If the C# change is large or the task needs reviewable notes, load skill ss14-documentation-writing.
If the code touches hot paths, Update(), or frequently raised events, load skill ss14-standard-optimizations.
If the task adds or changes player-facing text, load skills ss14-localization-strings and ss14-localization-code when the change also touches Loc.GetString(...), LocId, popup text, or localized component fields.
If the task touches network events, NetEntity, replicated state routing, or shared/server/client message flow, load skill ss14-netcode.
If the task touches Appearance, GenericVisualizer, visual state enums, or sprite-layer toggles, load skill ss14-graphics-generic-visualizer-appearance.
If the task touches sprites, RSI metadata, overlays, shaders, or custom client visual effects, load skill ss14-sprite-overlays-shaders.
If the task is about learning or explaining SS14 architecture, first features, or where code belongs, load skills ss14-prototype-basics, ss14-ecs-basics, and ss14-client-server-shared.
If the task is about bug hunting, VV, logs, breakpoints, or runtime inspection, load skills ss14-debugging-workflow and ss14-common-api-patterns.
If the task touches common gameplay helpers such as entity-system methods, spawning, prototypes, audio, popups, or random, load skills ss14-common-api-patterns and ss14-audio when the work changes audio routing, sound assets, sound collections, or predicted sound feedback.
If the task ports code or assets from another repository, or needs license or attribution guidance,...

Files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
Content.Shared/**

📄 CodeRabbit inference engine (Content.Shared/AGENTS.md)

Content.Shared/**: Load ss14-naming-conventions agent notes for Content.Shared work
Load ss14-ecs-prototypes, ss14-ecs-components, ss14-ecs-entities, and ss14-ecs-systems agent notes for Content.Shared work
Load ss14-upstream-maintenance agent notes for Content.Shared work
Load ss14-events agent notes for Content.Shared work
Load ss14-prediction and ss14-netcode agent notes for Content.Shared work
Load ss14-localization-code agent notes when shared code emits player text or stores LocId
Load ss14-graphics-generic-visualizer-appearance agent notes when shared gameplay state drives Appearance or GenericVisualizer
Load ss14-audio agent notes when shared components or events carry sound specifiers or predicted audio intent
Load ss14-atmos agent notes when shared components, UI messages, or enums belong to atmos features
Load ss14-transform-physics agent notes for shared coordinates, movement, collision, anchoring, or physics contracts
Load ss14-pvs agent notes for PVS-sensitive shared/network contracts
Load ss14-npc-ai agent notes for shared NPC, HTN, steering, pathfinding, or debug contracts
Shared code must own replicated state, shared events, and prediction-aware logic without adding direct client-only or server-only dependencies

Files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
+(Content.Shared|Content.Server|Content.Client|Content.Goobstation.Shared|Content.Goobstation.Server|Content.Goobstation.Client|Content.Goobstation.Common|Content.Goobstation.Maths|Content.Goobstation.UIKit|Content.Server.Database|Content.Shared.Database|Content.Tests|Content.IntegrationTests)/**/*.cs

📄 CodeRabbit inference engine (.cursor/rules/ss14-csharp.mdc)

+(Content.Shared|Content.Server|Content.Client|Content.Goobstation.Shared|Content.Goobstation.Server|Content.Goobstation.Client|Content.Goobstation.Common|Content.Goobstation.Maths|Content.Goobstation.UIKit|Content.Server.Database|Content.Shared.Database|Content.Tests|Content.IntegrationTests)/**/*.cs: Apply C# ECS style rules from ss14-interaction-flow.md
Apply ss14-csharp-style.md rules for C# code formatting and conventions
Follow ss14-naming-conventions for variable, method, and type naming in C# gameplay code

Files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
{Content.Shared,Content.Goobstation.Shared,Content.Goobstation.Common,Content.Goobstation.Maths,Content.Shared.Database}/**/*.cs

📄 CodeRabbit inference engine (.cursor/rules/ss14-shared.mdc)

{Content.Shared,Content.Goobstation.Shared,Content.Goobstation.Common,Content.Goobstation.Maths,Content.Shared.Database}/**/*.cs: Apply SS14 C# style guidelines from @.agents/rules/ss14-csharp-style.md
Follow SS14 ECS component patterns as defined in @.agents/skills/ss14-ecs-components/SKILL.md
Follow SS14 ECS entity patterns as defined in @.agents/skills/ss14-ecs-entities/SKILL.md
Follow SS14 ECS system patterns as defined in @.agents/skills/ss14-ecs-systems/SKILL.md
Follow SS14 event patterns as defined in @.agents/skills/ss14-events/SKILL.md
Follow SS14 prediction-aware gameplay code patterns as defined in @.agents/skills/ss14-prediction/SKILL.md
Follow SS14 netcode patterns as defined in @.agents/skills/ss14-netcode/SKILL.md
Follow SS14 localization identifier patterns as defined in @.agents/skills/ss14-localization-code/SKILL.md

Files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
**/*.{cs,xaml,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

If the task adds tests or you need to choose the right test layer, load skill ss14-tests-authoring.

Files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
  • Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml
{Content.Shared,Content.Goobstation.Shared}/**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

{Content.Shared,Content.Goobstation.Shared}/**/*.cs: Put main shared data, shared events, networked state, and predicted logic in Content.Shared/; use Content.Goobstation.Shared/ only for code that belongs to that existing module path.
Do not make shared projects depend on client-only or server-only projects.
Predicted systems and their relevant components belong in Content.Shared/. Shared predicted components should use NetworkedComponent, AutoGenerateComponentState, and AutoNetworkedField where appropriate.

Files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
Content.Shared/**/*.cs

⚙️ CodeRabbit configuration file

Content.Shared/**/*.cs: Review Content.Shared as shared gameplay and prediction code:

  • Shared owns replicated state, shared events, prediction, and data both client and server must understand.
  • Flag client-only or server-only dependencies in Shared.
  • For local-player actions, verify prediction support instead of accepting delayed server-only UX.
  • When state is networked, check NetworkedComponent, AutoGenerateComponentState, AutoNetworkedField, and Dirty/DirtyField usage.
  • Prefer entity-system APIs and Entity<T?> / Resolve patterns over ad-hoc tuples or old-style access.
  • Flag EntityUid.Invalid used as a "missing" sentinel.

Files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
Resources/**/*.json

📄 CodeRabbit inference engine (AGENTS.md)

Keep RSI meta.json ordered as version, license, copyright, size, states with 4-space indentation.

Files:

  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json

⚙️ CodeRabbit configuration file

Resources/**/*.json: Review resource JSON files for path correctness and consistency.
For RSI meta.json files, check ordering, state/layout consistency, and whether referenced prototypes or visualizers still match the available states.

Files:

  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json
Resources/**/*.yml

📄 CodeRabbit inference engine (.cursor/rules/ss14-resources.mdc)

Resources/**/*.yml: Follow SS14 ECS prototype patterns and conventions
Follow SS14 graphics generic visualizer appearance conventions and patterns

Resources/**/*.yml: Load ss14-naming-conventions documentation for Resources work
Load ss14-ecs-prototypes documentation for Resources work
Load ss14-upstream-maintenance documentation for Resources work
Load ss14-prototypes-locale documentation for Resources work
Load ss14-localization-strings documentation for Resources work
Load ss14-sprite-overlays-shaders documentation when working with RSI metadata, textures, sprite layers, overlays, or shader resources
Validate YAML after edits

Run dotnet run --project Content.YAMLLinter/Content.YAMLLinter.csproj -c DebugOpt to validate YAML and resource edits.

Files:

  • Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml
Resources/Prototypes/**/*.yml

📄 CodeRabbit inference engine (AGENTS.md)

Resources/Prototypes/**/*.yml: Put prototypes under the most specific existing subtree in Resources/Prototypes/. If you introduce a new prototype parent tree, put parent prototypes in base.yml and variants in sibling files.
Keep entity prototype field order as type, abstract, parent, id, categories, name, suffix, description, components. Do not insert blank lines between - type: entries inside a components: list. Separate prototype blocks with one blank line.
Prefer suffix for spawn-menu distinctions instead of changing prototype name.

Files:

  • Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml

⚙️ CodeRabbit configuration file

Resources/Prototypes/**/*.yml: Review SS14 prototypes carefully:

  • Use the narrowest existing subtree and avoid duplicating nearby prototype files or parent trees.
  • Keep entity field order as: type, abstract, parent, id, categories, name, suffix, description, components.
  • Prefer base.yml for parent trees and sibling files for variants.
  • Do not add blank lines inside components lists.
  • Call out broken inheritance, risky prototype ID changes, missing paired locale updates, and Appearance / GenericVisualizer mismatches.

Files:

  • Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml
🧠 Learnings (6)
📚 Learning: 2026-06-04T21:17:36.815Z
Learnt from: MataVsn
Repo: ArcaneSS14/arcane-station PR: 31
File: Content.Client/Fluids/PuddleSystem.cs:41-41
Timestamp: 2026-06-04T21:17:36.815Z
Learning: In this repo (ArcaneSS14/arcane-station), reviewers should use the Arcane inline fork-edit marker naming for single-line edits outside `_Arcane` paths: prefer `// Arcane` or `// Arcane-edit` and do not use `// Orion` for this purpose. Repo-specific AGENTS guidance that mentions `// Orion` does not apply to these single-line changes; only `_Arcane` paths follow the applicable different convention.

Applied to files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
📚 Learning: 2026-06-28T19:37:26.732Z
Learnt from: MataVsn
Repo: ArcaneSS14/arcane-station PR: 96
File: Content.Client/IoC/ClientContentIoC.cs:151-151
Timestamp: 2026-06-28T19:37:26.732Z
Learning: For ArcaneSS14/arcane-station C# files whose path is outside any `_Arcane` directories, avoid adding an inline fork marker (e.g., `// Arcane` or `// Arcane-edit`) to `using` directives when the imported namespace already clearly indicates the `_Arcane` fork. For example, if the `using` namespace itself contains `_Arcane` (such as `using Content.Client._Arcane.ERP.Preferences;`), the `// Arcane`/`// Arcane-edit` marker is unnecessary.

Applied to files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
📚 Learning: 2026-06-28T12:09:12.409Z
Learnt from: MataVsn
Repo: ArcaneSS14/arcane-station PR: 96
File: Content.Shared/Humanoid/HumanoidVisualLayers.cs:65-67
Timestamp: 2026-06-28T12:09:12.409Z
Learning: In ArcaneSS14/arcane-station, for any C# enum annotated with `[NetSerializable]` in shared code, treat the enum member order/implicit underlying numeric values as part of the network wire-protocol. During code review, disallow inserting new enum members in the middle (or otherwise changing existing members’ numeric values), since it breaks network compatibility. Instead, add new members only at the end or explicitly pin stable values by assigning numeric literals to members.

Applied to files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
📚 Learning: 2026-07-01T17:19:52.100Z
Learnt from: UmbiMax
Repo: ArcaneSS14/arcane-station PR: 101
File: Content.Shared/Mobs/MobState.cs:0-0
Timestamp: 2026-07-01T17:19:52.100Z
Learning: When reviewing ArcaneSS14/arcane-station C# code, ensure all usages of the `MobState` enum (`MobState.Dead`, `MobState.SoftCritical`, `MobState.HardCritical`, `MobState.Critical`) reference the enum members symbolically rather than via hardcoded numeric literals or casts from numeric values (e.g., avoid patterns like `(MobState)4` or `MobState` comparisons to `byte`/`int` literals). Treat direct numeric usage as a code-level dependency that should be flagged. Also avoid persisting `MobState` numeric values in `Content.Server.Database` or `Content.Replay`; if persistence/replay of the raw byte value is introduced, renumbering the `[NetSerializable] MobState : byte` enum becomes a data-compatibility risk. Renumbering the enum is compile-safe as long as there are no numeric literal dependencies, but the remaining risk is network wire-protocol mismatch if mixed old/new client-server builds are running during a rolling update—coordinate deployment to maintain net compatibility.

Applied to files:

  • Content.Shared/_Arcane/MarkingWhitelistData.cs
  • Content.Shared/Humanoid/Markings/MarkingPrototype.cs
  • Content.Shared/_Arcane/MarkingWhitelistManager.cs
📚 Learning: 2026-06-19T22:21:36.179Z
Learnt from: MataVsn
Repo: ArcaneSS14/arcane-station PR: 69
File: Resources/Textures/_Arcane/Mobs/Silicon/Medical/k4tmed.rsi/meta.json:14-16
Timestamp: 2026-06-19T22:21:36.179Z
Learning: When reviewing RSI texture meta.json files under Resources/Textures/_Arcane (including borg chassis variants like k4t*.rsi), do not flag a difference in `directions` for rest-state entries. If the state name is a rest state (e.g., `*-rest`) for these borg chassis sprites, `directions: 1` is an intentional art choice and should not be treated as a mismatch against other variants that use `directions: 4`. Only raise an issue if the `directions` value is invalid for the file/spec (e.g., not the expected numeric options) or if it occurs on non-rest states.

Applied to files:

  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json
📚 Learning: 2026-06-29T05:34:31.137Z
Learnt from: Alazell
Repo: ArcaneSS14/arcane-station PR: 99
File: Resources/Prototypes/Entities/Clothing/Belt/belts.yml:973-974
Timestamp: 2026-06-29T05:34:31.137Z
Learning: В SS14 YAML-прототипах для компонента `Storage` поле `grid` задаёт **включительные** координаты прямоугольника. При подсчёте вместимости учитывайте оффсет-инклюзивность: прямоугольник `x1,y1,x2,y2` означает размеры `width = (x2 - x1 + 1)` и `height = (y2 - y1 + 1)`, а число ячеек `width * height`. Например, `0,0,0,0` = 1 ячейка, а `0,0,6,2` = (6-0+1)*(2-0+1)=7*3=21. При ревью файлов наподобие `Resources/Prototypes/Entities/Clothing/Belt/belts.yml` не интерпретируйте `x2/y2` как эксклюзивные (чтобы не ошибиться на 1 в ширине/высоте).

Applied to files:

  • Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml
🔇 Additional comments (7)
Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json (1)

69-77: LGTM!

Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json (1)

37-41: LGTM!

Resources/Locale/ru-RU/_Arcane/markings/humanoid_xeno.ftl (1)

11-11: LGTM!

Also applies to: 25-25, 40-40

Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json (1)

140-149: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Дублирующийся state worker_teeth в meta.json.

Строки 141-145 добавляют повторную запись "worker_teeth" — она уже присутствует на строке 139-140. Это не намеренное добавление нового стейта (в diff-контексте видно ren_head, а не второй worker_teeth). Дубликат имени state в RSI-манифесте — риск конфликта/непредсказуемого поведения при загрузке спрайта.

🐛 Предлагаемое исправление
         {
             "name": "worker_teeth",
             "directions": 4
         },
         {
-            "name": "worker_teeth",
-            "directions": 4
-        },
-        {
             "name": "ren_head",
             "directions": 4
         }
			> Likely an incorrect or invalid review comment.
Content.Shared/_Arcane/MarkingWhitelistData.cs (1)

1-10: LGTM!

Content.Shared/Humanoid/Markings/MarkingPrototype.cs (1)

20-20: LGTM!

Content.Shared/_Arcane/MarkingWhitelistManager.cs (1)

8-28: 🎯 Functional Correctness

Открытый вопрос: где реально вызывается эта проверка?

Класс теперь в Content.Shared — прошлое замечание про клиентскую авторитативность формально снято (сама возможность вызвать это с сервера появилась). Но в текущем кохорте не видно точки вызова: используется ли IsMarkingAllowed при серверной валидации профиля/применения маркинга, или пока только в клиентском picker'е? Из объектов PR прямо следует требование серверной проверки при сохранении персонажа — без неё whitelist остаётся чисто косметическим ограничением UI, легко обходимым модифицированным клиентом.

Прошу подтвердить в связанных файлах (не входящих в этот кохорт), что серверная валидация профиля действительно вызывает эту функцию.

Comment on lines +8 to +9
[DataField("allowed")]
public List<string> Allowed { get; private set; } = new();

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.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Явное имя [DataField("allowed")] избыточно.

Строковое имя совпадает с дефолтным (camelCase от Allowed), так что атрибут можно упростить.

♻️ Предложение
-    [DataField("allowed")]
+    [DataField]
     public List<string> Allowed { get; private set; } = new();

As per coding guidelines, "Prefer [DataField] without string field names on new code unless serializer compatibility or a non-default data name is required."

📝 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
[DataField("allowed")]
public List<string> Allowed { get; private set; } = new();
[DataField]
public List<string> Allowed { get; private set; } = new();
🤖 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/_Arcane/MarkingWhitelistData.cs` around lines 8 - 9, The
[DataField("allowed")] annotation on MarkingWhitelistData.Allowed is redundant
because it matches the default camelCase name; simplify it to a bare [DataField]
unless a non-default serialized name is required. Update the Allowed property in
MarkingWhitelistData to use the convention preferred by the serializer
guidelines and keep the property name as the unique reference point.

Source: Coding guidelines


public static class MarkingWhitelistManager
{
public static bool IsMarkingAllowed(MarkingPrototype marking, ICommonSession? session)

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.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Наименование check-метода не соответствует конвенции.

IsMarkingAllowed — это проверочный метод, по конвенции такие должны называться через Can... (например, CanApplyMarking).

As per coding guidelines, "Check methods should prefer Can...."

🤖 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/_Arcane/MarkingWhitelistManager.cs` at line 8, Rename the
check method in MarkingWhitelistManager from IsMarkingAllowed to a Can...-style
name, such as CanApplyMarking, to match the project’s convention for
predicate/check methods. Update the method declaration and every call site or
reference that uses IsMarkingAllowed so the API name is consistent and clearly
communicates that it returns whether marking can be applied.

Source: Coding guidelines

Comment on lines +73 to +76
// Arcane - Start
[DataField("whitelist")]
public MarkingWhitelistData? Whitelist { get; private set; }
// Arcane - End

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.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Явное имя [DataField("whitelist")] тоже избыточно.

Совпадает с дефолтным именем от Whitelist — то же замечание, что и для MarkingWhitelistData.

♻️ Предложение
-        // Arcane - Start
-        [DataField("whitelist")]
+        // Arcane - Start
+        [DataField]
         public MarkingWhitelistData? Whitelist { get; private set; }
         // Arcane - End

Маркировка // Arcane - Start/End для многострочной вставки в файле вне _Arcane-пути соответствует уже принятому в файле паттерну (см. /// Impstation start/end рядом) — нареканий нет.

As per coding guidelines, "Prefer [DataField] without string field names on new code unless serializer compatibility or a non-default data name is required."

📝 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
// Arcane - Start
[DataField("whitelist")]
public MarkingWhitelistData? Whitelist { get; private set; }
// Arcane - End
// Arcane - Start
[DataField]
public MarkingWhitelistData? Whitelist { get; private set; }
// Arcane - End
🤖 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/Humanoid/Markings/MarkingPrototype.cs` around lines 73 - 76,
Remove the explicit DataField name from MarkingPrototype. The Whitelist property
already matches the default serialized name, so update the
MarkingPrototype.Whitelist declaration to use [DataField] without the
"whitelist" string, keeping the existing Arcane comment markers unchanged.

Source: Coding guidelines

Comment on lines +120 to +133
- type: marking
id: HumanoidXenoTailRen
bodyPart: Tail
markingCategory: Tail
speciesRestriction: [HumanoidXeno]
sprites:
- sprite: _Arcane/Mobs/Customization/HumanoidXeno/tail.rsi
state: ren_tail
- sprite: _Arcane/Mobs/Customization/HumanoidXeno/tail.rsi
state: ren_tail_grad
whitelist:
allowed:
- Bulbo44key

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.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Whitelist только на клиенте — фильтр обходится напрямую.

Три новых маркинга (HumanoidXenoTailRen, HumanoidXenoHeadRen, HumanoidXenoTracheasRen) ограничены через whitelist.allowed: Bulbo44key. Судя по описанию PR, MarkingWhitelistManager — чисто клиентская/shared проверка без серверной валидации при сохранении/применении профиля. Игрок может обойти клиентский пикер и выставить этот маркинг напрямую (например, через редактирование профиля/сети), и сервер это не проверит.

Нужна серверная валидация профиля персонажа (при применении/сохранении), а не только фильтрация в UI-пикере.

Also applies to: 298-309, 440-451

🤖 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
`@Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml`
around lines 120 - 133, The three Ren humanoid xeno markings are only gated by
the client-side whitelist, so add server-side validation in the character
profile apply/save path to reject unauthorized markings. Update the logic around
HumanoidXenoTailRen, HumanoidXenoHeadRen, and HumanoidXenoTracheasRen so the
server checks the allowed user before persisting or applying the profile, rather
than relying on MarkingWhitelistManager/UI filtering alone.

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai проверь на ошибки. почему при заходе на сервер модельки ломаются и становятся прозначными?

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== RSI meta.json files touched =="
fd -i 'meta.json' Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno

echo
echo "== Directory listing for tail.rsi =="
fd . Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi

echo
echo "== Directory listing for head.rsi =="
fd . Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi

echo
echo "== Directory listing for tracheas.rsi =="
fd . Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi

echo
echo "== meta.json contents =="
for f in $(fd -i 'meta.json' Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno); do
  echo "--- $f ---"
  cat "$f"
  echo
done

echo
echo "== YAML marking definitions for Ren =="
rg -n -C5 'Ren' Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml

echo
echo "== Check for missing PNG state files vs meta.json states =="
python3 - <<'EOF'
import json, os, glob

rsi_dirs = glob.glob("Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/*.rsi")
for d in rsi_dirs:
    meta_path = os.path.join(d, "meta.json")
    if not os.path.exists(meta_path):
        continue
    with open(meta_path) as f:
        meta = json.load(f)
    states = meta.get("states", [])
    for s in states:
        name = s.get("name")
        # check for png with that name
        png = os.path.join(d, f"{name}.png")
        if not os.path.exists(png):
            print(f"MISSING PNG: {png}")
EOF

echo
echo "== Check markingCategory / bodyPart validity against enums =="
rg -n 'enum MarkingCategories' -A30 Content.Shared/Humanoid/Markings/MarkingCategories.cs 2>/dev/null || fd -i 'MarkingCategories' Content.Shared

echo
echo "== Check HumanoidVisualLayers for Tracheas / Tail / Head related to xeno =="
rg -n 'Tracheas|HumanoidXeno' Content.Shared/Humanoid -r

Length of output: 19317


@bzzzbzzbz, нашёл конкретный баг.

Найдена ошибка: дублирующийся state в head.rsi/meta.json

Файл: Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json

В массиве states объект "worker_teeth" объявлен два раза:

{
    "name": "worker_teeth",
    "directions": 4
},
{
    "name": "worker_teeth",
    "directions": 4
},
{
    "name": "ren_head",
    "directions": 4
}

Это и есть вероятная причина проблемы с прозрачными/поломанными моделями:

  • RSI-загрузчик Robust Toolbox строит словарь состояний по имени (Dictionary<string, State>).
  • При дублирующемся ключе он бросает исключение при добавлении второго элемента с тем же name.
  • Если загрузка head.rsi падает с exception, слой(и) головы у мобов, использующих этот RSI (HumanoidXeno), либо не рисуются, либо заменяются на error/прозрачный спрайт — именно это выглядит как "модельки ломаются и становятся прозрачными".

Фикс

Удалить один из дублирующихся блоков worker_teeth:

         {
             "name": "worker_teeth",
             "directions": 4
         },
-        {
-            "name": "worker_teeth",
-            "directions": 4
-        },
         {
             "name": "ren_head",
             "directions": 4
         }

Остальное

  • PNG-файлы для новых states (ren_head, ren_tail, ren_tail_grad, ren_tubes) на месте, соответствие state ↔ png ↔ YAML корректно.
  • markingCategory: Tracheas / bodyPart: Chest для HumanoidXenoTracheasRen — валидны по enum MarkingCategories (Content.Shared/Humanoid/Markings/MarkingCategories.cs).
  • Whitelist-код (MarkingWhitelistData/MarkingWhitelistManager) с этим багом не связан — проблема чисто в ресурсах RSI.

Сначала убери дубль в meta.json, пересобери и проверь на сервере — это самая вероятная причина прозрачности.

(◕‸◕)


✏️ Learnings added
Learnt from: bzzzbzzbz
URL: https://github.com/ArcaneSS14/arcane-station/pull/100

Timestamp: 2026-07-03T19:44:29.648Z
Learning: В репозитории ArcaneSS14/arcane-station в PR `#100` обнаружен дублирующийся объект state `"worker_teeth"` в файле `Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json` (два одинаковых объекта `{"name": "worker_teeth", "directions": 4}` подряд перед добавленным `ren_head`). Дублирующийся ключ в states массиве RSI meta.json может вызывать исключение при построении словаря состояний в загрузчике RSI и приводить к поломанным/прозрачным спрайтам у мобов, использующих этот RSI (HumanoidXeno).

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

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai энтити всё ещё прозрачные. почему? имеются ли ошибки в коде или дело не в этом?

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== head.rsi meta.json current state (check if fix applied) =="
cat Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json

echo
echo "== tail.rsi meta.json =="
cat Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tail.rsi/meta.json

echo
echo "== tracheas.rsi meta.json =="
cat Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/tracheas.rsi/meta.json

echo
echo "== Check for duplicate names across all touched rsi meta.json =="
python3 - <<'EOF'
import json, glob, os
for d in glob.glob("Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/*.rsi"):
    meta_path = os.path.join(d, "meta.json")
    if not os.path.exists(meta_path):
        continue
    with open(meta_path) as f:
        meta = json.load(f)
    names = [s.get("name") for s in meta.get("states", [])]
    dupes = set(n for n in names if names.count(n) > 1)
    if dupes:
        print(f"DUPLICATES in {meta_path}: {dupes}")
    else:
        print(f"OK: {meta_path} - {len(names)} states, no dupes")
EOF

echo
echo "== Check png files exist for all states =="
python3 - <<'EOF'
import json, os, glob
for d in glob.glob("Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/*.rsi"):
    meta_path = os.path.join(d, "meta.json")
    if not os.path.exists(meta_path):
        continue
    with open(meta_path) as f:
        meta = json.load(f)
    for s in meta.get("states", []):
        name = s.get("name")
        png = os.path.join(d, f"{name}.png")
        if not os.path.exists(png):
            print(f"MISSING PNG: {png}")
EOF

echo
echo "== Check meta.json validity (schema version, size, etc.) =="
for f in $(fd -i 'meta.json' Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno); do
  echo "--- $f ---"
  jq -r '.version, .size, (.states|length)' "$f" 2>&1 || echo "INVALID JSON"
done

echo
echo "== Check entity prototypes referencing HumanoidXeno for sprite layer setups =="
rg -n -C5 'HumanoidXeno' Resources/Prototypes/_Arcane/Entities/Mobs --glob '*.yml' | head -150

echo
echo "== Check YAML markings for consistent bodyPart/markingCategory/sprite paths =="
cat Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml

Length of output: 40783


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== List actual files in rsi dirs for ren_* states =="
fd -i 'ren_' Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno

echo
echo "== File sizes/types for ren_* pngs =="
for f in $(fd -i 'ren_.*\.png$' Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno); do
  echo "--- $f ---"
  file "$f"
  ls -la "$f"
done

echo
echo "== Try to read actual pixel dimensions with python (Pillow) =="
pip install --quiet pillow 2>/dev/null || true
python3 - <<'EOF'
import glob
try:
    from PIL import Image
except ImportError:
    print("Pillow not available")
    raise SystemExit(0)

for f in glob.glob("Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/*.rsi/ren_*.png"):
    try:
        im = Image.open(f)
        print(f, im.size, im.mode)
    except Exception as e:
        print(f, "ERROR", e)
EOF

echo
echo "== Check git history / diff stats for these png files (are they actual new binary or empty stub) =="
git log --oneline -1 -- Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/ren_head.png || true
git show --stat HEAD -- Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno 2>/dev/null | head -50 || true

echo
echo "== Check size field in meta.json vs actual sprite bodyPart usage in entity/species prototype (layer keys) =="
rg -n -C5 'HumanoidXeno' Resources/Prototypes/_Arcane/Entities/Mobs/Player/humanoid_xeno.yml 2>/dev/null || fd -i 'humanoid_xeno' Resources/Prototypes/_Arcane/Entities/Mobs/Player 2>/dev/null

echo
echo "== Search species prototype for HumanoidXeno base layers referencing head/tail/tracheas rsi =="
rg -n -C3 'HumanoidXeno' Resources/Prototypes/_Arcane/Species 2>/dev/null || fd -i 'species' Resources/Prototypes/_Arcane

echo
echo "== Check for other markings possibly referencing non-existent states now (sanity re-check) =="
python3 - <<'EOF'
import re, json, os

yml_path = "Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml"
with open(yml_path) as f:
    content = f.read()

# extract sprite/state pairs naively
entries = re.findall(r'sprite:\s*(\S+)\s*\n\s*state:\s*(\S+)', content)
rsi_cache = {}
for sprite, state in entries:
    if not sprite.startswith("_Arcane"):
        continue
    rsi_dir = os.path.join("Resources/Textures", sprite)
    if rsi_dir not in rsi_cache:
        meta_path = os.path.join(rsi_dir, "meta.json")
        if os.path.exists(meta_path):
            with open(meta_path) as mf:
                meta = json.load(mf)
            rsi_cache[rsi_dir] = set(s.get("name") for s in meta.get("states", []))
        else:
            rsi_cache[rsi_dir] = None
    states = rsi_cache[rsi_dir]
    if states is None:
        continue
    if state not in states:
        print(f"MISSING STATE: {sprite} -> {state}")
EOF

Length of output: 3658


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== File sizes for ren_* pngs =="
for f in $(fd -i 'ren_.*\.png$' Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno); do
  ls -la "$f"
  head -c 16 "$f" | xxd | head -3
  echo "---"
done

echo
echo "== Try to read actual pixel dimensions with python (Pillow) =="
pip install --quiet pillow 2>/dev/null || true
python3 - <<'EOF'
import glob
try:
    from PIL import Image
except ImportError:
    print("Pillow not available")
    raise SystemExit(0)

for f in glob.glob("Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/*.rsi/ren_*.png"):
    try:
        im = Image.open(f)
        im.verify()
        print(f, im.size, im.mode)
    except Exception as e:
        print(f, "ERROR", e)
EOF

echo
echo "== Compare pixel size of ren_* png vs meta.json declared size (32x32) and vs other same-category pngs =="
python3 - <<'EOF'
import glob, os
from PIL import Image

groups = {
    "head.rsi": ["ren_head.png", "worker_head.png"],
    "tail.rsi": ["ren_tail.png", "neomorph_tail.png"],
    "tracheas.rsi": ["ren_tubes.png", "neomorph_tubes.png"],
}
base = "Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno"
for rsi, files in groups.items():
    for fn in files:
        p = os.path.join(base, rsi, fn)
        if os.path.exists(p):
            im = Image.open(p)
            print(p, im.size, im.mode, "frames" if hasattr(im,'n_frames') else "")
        else:
            print(p, "MISSING")
EOF

echo
echo "== Check species prototype dir for HumanoidXeno layers =="
fd -i 'humanoidxeno' Resources/Prototypes/_Arcane --type f | grep -iv Markings | grep -iv Customization

echo
echo "== Search for BaseSprite/layers config referencing head.rsi/tail.rsi directly (non-marking) =="
rg -n -C3 'Customization/HumanoidXeno/(head|tail|tracheas)\.rsi' Resources/Prototypes/_Arcane --glob '!*Markings*'

Length of output: 2364


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== File sizes for ren_* pngs =="
for f in $(fd -i 'ren_.*\.png$' Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno); do
  ls -la "$f"
  od -An -tx1 -N16 "$f" || true
  echo "---"
done

echo
echo "== Try to read actual pixel dimensions with python (Pillow) =="
pip install --quiet pillow 2>/dev/null || true
python3 - <<'EOF'
import glob
try:
    from PIL import Image
except ImportError:
    print("Pillow not available")
    raise SystemExit(0)

for f in glob.glob("Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/*.rsi/ren_*.png"):
    try:
        im = Image.open(f)
        im.verify()
        print(f, im.size, im.mode)
    except Exception as e:
        print(f, "ERROR", e)
EOF

echo
echo "== Compare pixel size of ren_* png vs meta.json declared size (32x32) and vs other same-category pngs =="
python3 - <<'EOF'
import glob, os
try:
    from PIL import Image
except ImportError:
    raise SystemExit(0)

groups = {
    "head.rsi": ["ren_head.png", "worker_head.png"],
    "tail.rsi": ["ren_tail.png", "neomorph_tail.png"],
    "tracheas.rsi": ["ren_tubes.png", "neomorph_tubes.png"],
}
base = "Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno"
for rsi, files in groups.items():
    for fn in files:
        p = os.path.join(base, rsi, fn)
        if os.path.exists(p):
            im = Image.open(p)
            print(p, im.size, im.mode)
        else:
            print(p, "MISSING")
EOF

echo
echo "== Check species prototype dir for HumanoidXeno layers =="
fd -i 'humanoidxeno' Resources/Prototypes/_Arcane --type f | grep -iv Markings | grep -iv Customization || true

echo
echo "== Search for BaseSprite/layers config referencing head.rsi/tail.rsi directly (non-marking) =="
rg -n -C3 'Customization/HumanoidXeno/(head|tail|tracheas)\.rsi' Resources/Prototypes/_Arcane --glob '!*Markings*' || true

Length of output: 4046


@bzzzbzzbz, по статическому анализу ресурсов новых ошибок в этом PR не нашёл — предыдущий баг (дублирующийся worker_teeth в head.rsi/meta.json) уже исправлен, дублей больше нет.

Что проверил:

  • head.rsi, tail.rsi, tracheas.rsi — в states дублей нет.
  • Все PNG для новых states (ren_head, ren_tail, ren_tail_grad, ren_tubes) физически существуют.
  • Размеры файлов: 64×64 RGBA — совпадает с уже рабочими state'ами (worker_head.png, neomorph_tail.png, neomorph_tubes.png), т.е. формат не отличается от того, что уже работает.
  • Все пары sprite/state из humanoid_xeno.yml резолвятся на реально существующие states — несоответствий нет.
  • Whitelist-код (MarkingWhitelistData) — это чисто data/filter слой, он никак не участвует в рендеринге спрайтов и не может быть причиной прозрачности.

Вывод: на уровне того, что я могу проверить статически (YAML/RSI/PNG/C#), причины прозрачности сейчас не видно — ресурсы консистентны.

Что стоит проверить дальше (у меня нет доступа к раннему серверу/клиенту, поэтому нужны логи):

  1. Логи клиента (client.log / консоль) на момент коннекта — ищи exceptions по RSI, SpriteComponent, Marking.
  2. Пересборка ресурсов — если сервер запускался со старой закешированной версией head.rsi (до фикса дубля), нужен полный ребилд/перезапуск, а не hot-reload.
  3. Проверь другие маркинги/слои того же вида, не тронутые этим PR — если прозрачны все слои энтити (а не только Ren-маркинги), проблема может быть не в этом PR, а в чём-то более общем (например, в species-прототипе HumanoidXeno, который я не нашёл по стандартному пути — возможно, он лежит под другим именем).
  4. Проверь, воспроизводится ли без выбора Ren-маркингов — если прозрачность есть даже без них, значит дело точно не в изменениях этого PR.

Если можешь — пришли текст ошибки/exception из лога (клиент или сервер), это даст точную причину, а не догадки.

(・_・?)

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai система вайтлиста для маркингов рабочая?

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== IsMarkingAllowed usages =="
rg -n -C2 --glob '!**/bin/**' --glob '!**/obj/**' '\bIsMarkingAllowed\s*\(' Content.Shared Content.Client Content.Server || echo "NONE FOUND"

echo
echo "== Whitelist field usages outside definition =="
rg -n -C2 --glob '!**/bin/**' --glob '!**/obj/**' '\.Whitelist\b' Content.Shared Content.Client Content.Server || echo "NONE FOUND"

echo
echo "== Current MarkingWhitelistManager.cs content =="
fd -i 'MarkingWhitelistManager.cs' Content.Shared Content.Client 2>/dev/null | xargs -I{} sh -c 'echo "--- {} ---"; cat "{}"'

echo
echo "== Check MarkingPicker/SingleMarkingPicker for whitelist filtering calls =="
rg -n -C3 'Whitelist' Content.Client/Humanoid/MarkingPicker.xaml.cs Content.Client/Humanoid/SingleMarkingPicker.xaml.cs 2>/dev/null || echo "NO REFS IN PICKERS"

echo
echo "== Check server-side profile validation for markings =="
rg -n -C3 'MarkingWhitelist|IsMarkingAllowed' Content.Server 2>/dev/null || echo "NO SERVER USAGE"

Length of output: 186526


@bzzzbzzbz, нет, сейчас система не рабочая — она только скомпилируется, но ничего не ограничивает.

Факт по коду:

  • MarkingWhitelistManager.IsMarkingAllowed(...) определён и логически верен.
  • Но метод нигде не вызывается:
    • в Content.Client/Humanoid/MarkingPicker.xaml.cs — нет упоминаний Whitelist/IsMarkingAllowed;
    • в Content.Client/Humanoid/SingleMarkingPicker.xaml.cs — тоже нет;
    • в Content.Server — нет вообще никаких упоминаний whitelist-проверки маркингов.

Итог: любой маркинг с whitelist.allowed в YAML сейчас виден и доступен всем, потому что фильтр просто не подключён к пайплайну кастомизации.

Что нужно сделать для рабочей системы:

  1. Client — фильтрация в пикерах.
    В MarkingPicker.xaml.cs / SingleMarkingPicker.xaml.cs, там где формируется список доступных MarkingPrototype для отображения, добавить проверку:

    var session = _playerManager.LocalSession; // получить текущую клиентскую сессию
    if (!MarkingWhitelistManager.IsMarkingAllowed(marking, session))
        continue; // не добавлять в список
  2. Server — обязательная валидация.
    Без этого шага фильтр — чисто косметика: клиент можно обойти (мод-клиент, прямая правка запроса и т.п.). Нужно найти точку, где сервер принимает/сохраняет HumanoidCharacterProfile (валидация профиля), и там для каждого маркинга в profile.Appearance.Markings проверять IsMarkingAllowed(prototype, session); при провале — убирать маркинг из профиля или отклонять сохранение.

Пока эти два пункта не сделаны, whitelist в YAML — просто данные без эффекта.

(・_・;)


✏️ Learnings added
Learnt from: bzzzbzzbz
URL: https://github.com/ArcaneSS14/arcane-station/pull/100

Timestamp: 2026-07-03T20:05:19.412Z
Learning: В репозитории ArcaneSS14/arcane-station на ветке PR `#100` метод `Content.Shared._Arcane.SpecialWhitelist.MarkingWhitelistManager.IsMarkingAllowed(MarkingPrototype, ICommonSession?)` (файл `Content.Shared/_Arcane/MarkingWhitelistManager.cs`) реализован и компилируется, но не вызывается ни в `Content.Client/Humanoid/MarkingPicker.xaml.cs`, ни в `Content.Client/Humanoid/SingleMarkingPicker.xaml.cs`, ни где-либо в `Content.Server`. Это значит, что whitelist-ограничение маркингов по ckey определено в данных, но не применяется фактически ни на клиенте, ни на сервере.

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

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai что нужно сделать, чтобы вайтлист работал?

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@bzzzbzzbz, чтобы вайтлист реально заработал, нужно подключить IsMarkingAllowed(...) в двух местах — сейчас он существует, но никуда не встроен.

1. Client — фильтрация в пикерах

Content.Client/Humanoid/MarkingPicker.xaml.cs и Content.Client/Humanoid/SingleMarkingPicker.xaml.cs — там, где строится список доступных MarkingPrototype для UI (обычно перед AddItem/populate списка), добавить:

if (!MarkingWhitelistManager.IsMarkingAllowed(marking, _playerManager.LocalSession))
    continue;

Это скроет маркинг из выбора для пользователей не из allowed.

2. Server — обязательная валидация профиля

Без этого шага фильтр — чисто косметика, обходится модклиентом/прямой правкой запроса. Нужно найти точку приёма/сохранения HumanoidCharacterProfile на сервере (валидация профиля перед сохранением/применением к персонажу) и там для каждого маркинга из profile.Appearance.Markings:

foreach (var markingId in profile.Appearance.Markings.ToList())
{
    if (!_prototypeManager.TryIndex<MarkingPrototype>(markingId.MarkingId, out var proto))
        continue;

    if (!MarkingWhitelistManager.IsMarkingAllowed(proto, session))
        profile.Appearance.Markings.Remove(markingId); // либо reject профиль
}

Без серверной проверки любой игрок может применить whitelisted-маркинг напрямую, минуя UI.

3. Волосы/борода — отдельно, если тоже нужно ограничить

profile.Appearance.HairStyleId и FacialHairStyleId хранятся отдельно от Markings — если хочешь привязать их к ckey, валидировать нужно отдельно этим же методом.

Итог: пока не добавлены оба вызова IsMarkingAllowed (client + server), whitelist.allowed в YAML — просто мёртвые данные без эффекта.

Хочешь, заведу отдельный follow-up issue на подключение серверной валидации, чтобы не потерялось после мержа этого PR?

( •_•)>⌐■-■

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai какие библиотеки требуется добавить в указанные файлы?

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== MarkingWhitelistManager.cs usings =="
sed -n '1,15p' Content.Shared/_Arcane/MarkingWhitelistManager.cs

echo
echo "== MarkingPicker.xaml.cs usings =="
sed -n '1,25p' Content.Client/Humanoid/MarkingPicker.xaml.cs

echo
echo "== SingleMarkingPicker.xaml.cs usings =="
sed -n '1,25p' Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

echo
echo "== Search for IPlayerManager / LocalSession usage patterns in client =="
rg -n 'IPlayerManager|LocalSession|LocalPlayer' Content.Client/Humanoid/MarkingPicker.xaml.cs Content.Client/Humanoid/SingleMarkingPicker.xaml.cs Content.Client/_Arcane 2>/dev/null || echo "NONE"

echo
echo "== Find ICommonSession namespace =="
rg -n 'using Robust.Shared.Player' Content.Shared Content.Client -g '*.cs' | head -5

echo
echo "== Search server-side profile validation entry points for using hints =="
rg -n 'class HumanoidCharacterProfile' -A5 Content.Shared 2>/dev/null | head -20
rg -n 'HumanoidCharacterProfile' Content.Server --glob '*.cs' -l | head -10

Length of output: 6057


@bzzzbzzbz, по usings — конкретно:

Content.Shared/_Arcane/MarkingWhitelistManager.cs

Уже всё есть, ничего добавлять не нужно:

using Content.Shared.Humanoid.Markings; // для MarkingPrototype
using Robust.Shared.Player;             // для ICommonSession

Content.Client/Humanoid/MarkingPicker.xaml.cs

Сейчас нет доступа ни к менеджеру вайтлиста, ни к текущей сессии. Нужно добавить:

using Content.Shared._Arcane.SpecialWhitelist; // MarkingWhitelistManager
using Robust.Client.Player;                    // IPlayerManager, чтобы получить локальную ICommonSession

И добавить зависимость:

[Dependency] private readonly IPlayerManager _playerManager = default!;

Сессию брать как _playerManager.LocalSession (или _playerManager.LocalPlayer?.Session, зависит от версии RT).

Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

Аналогично — сейчас нет ни одного нужного using:

using Content.Shared._Arcane.SpecialWhitelist;
using Robust.Client.Player;
  • та же зависимость IPlayerManager.

Серверная валидация (Content.Server)

Явной единой точки валидации HumanoidCharacterProfile под маркинги я не нашёл — HumanoidCharacterProfile объявлен в Content.Shared/Preferences/HumanoidCharacterProfile.cs, но серверный код, который бы уже проверял маркинги на whitelist, не существует. Там, где будет добавлена проверка (обычно в системе, обрабатывающей PreferencesManager/SetProfile), понадобится:

using Content.Shared._Arcane.SpecialWhitelist; // MarkingWhitelistManager
using Robust.Shared.Prototypes;                 // IPrototypeManager, чтобы получить MarkingPrototype по id
using Robust.Shared.Player;                     // ICommonSession

Без Content.Shared._Arcane.SpecialWhitelist в client/server-файлах вызов MarkingWhitelistManager.IsMarkingAllowed(...) просто не скомпилируется — это тот же namespace-mismatch, что был у MarkingPrototype ранее.

( ・_・)ノ

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai файлы работают неправильно. почему и как это исправить?

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@bzzzbzzbz, вопрос слишком общий — уточни, пожалуйста:

  1. Какие именно файлы? (путь/имя)
  2. В чём проявляется «неправильно»?
    • ошибка компиляции (текст ошибки),
    • runtime exception (лог клиента/сервера),
    • визуальный баг (спрайты/маркинги),
    • или вайтлист не фильтрует маркинги как ожидалось?

Без текста ошибки или конкретного симптома гадать бессмысленно. По текущему состоянию PR #100 мне известна одна точно не исправленная проблема:

  • MarkingWhitelistManager.IsMarkingAllowed(...) определён, но не вызывается ни в Content.Client/Humanoid/MarkingPicker.xaml.cs, ни в Content.Client/Humanoid/SingleMarkingPicker.xaml.cs, ни в Content.Server. Поэтому вайтлист сейчас не ограничивает ничего — это ожидаемое (хоть и неполное) поведение, а не баг компиляции.

Если проблема именно в этом — смотри мой предыдущий ответ с конкретным планом подключения (client filter + server validation). Если проблема другая (например, конкретное исключение при заходе на сервер) — пришли текст ошибки или укажи файл, тогда разберу точечно.

( ・_・)?

@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: 4

🤖 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.Client/Humanoid/MarkingPicker.xaml.cs`:
- Around line 185-189: Keep the IsMarkingAllowed check in MarkingPicker as
presentation-only, and add authoritative server-side validation in the profile
save/apply path so disallowed markings cannot be persisted or applied through
alternate paths. Reuse the existing marking whitelist and player/session
validation symbols where available, while preserving the UI filter.
- Around line 185-189: Remove both Arcane whitelist blocks from
SetupCategoryButtons, including the invalid marking/session check and continue
outside the loop. Apply the marking whitelist filter in Populate inside the
foreach (var marking in sortedMarkings) loop, using the current marking before
adding it to the list.

In `@Content.Client/Humanoid/SingleMarkingPicker.xaml.cs`:
- Around line 315-320: Перенеси получение session и проверку
MarkingWhitelistManager.IsMarkingAllowed(marking, session) внутрь цикла foreach
метода PopulateList, чтобы marking и continue находились в корректной области
видимости. Добавь зависимость IPlayerManager в SingleMarkingPicker через
существующий механизм DI и используй её для получения LocalSession.

In `@Content.Shared/Preferences/HumanoidCharacterProfile.cs`:
- Around line 1300-1309: Перенеси блок фильтрации markings из тела класса в
метод EnsureValid(ICommonSession session, IDependencyCollection collection),
используя доступные там session и IPrototypeManager. Удали foreach после
закрывающей скобки Clone(), а в EnsureValid сохрани проверку MarkingPrototype и
удаление запрещённых элементов через MarkingWhitelistManager.IsMarkingAllowed.
🪄 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 Plus

Run ID: cc449b1a-001f-47e8-9717-8df06ae832ab

📥 Commits

Reviewing files that changed from the base of the PR and between f0b0522 and ba94aed.

📒 Files selected for processing (4)
  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json
💤 Files with no reviewable changes (1)
  • Resources/Textures/_Arcane/Mobs/Customization/HumanoidXeno/head.rsi/meta.json
📜 Review details
🧰 Additional context used
📓 Path-based instructions (12)
**/*.cs

📄 CodeRabbit inference engine (GEMINI.md)

**/*.cs: Keep components data-only and behavior in systems
Use On... -> Try... -> Can... -> Do... pattern for gameplay actions
Prefer Entity<T?>, ProtoId<T>, EntProtoId, and localized strings for type usage

**/*.cs: When writing or editing C# gameplay code, load skills: ss14-ecs-components, ss14-ecs-entities, ss14-ecs-prototypes, ss14-ecs-systems, ss14-events, and ss14-prediction.
If the C# change is large or the task needs reviewable notes, load skill ss14-documentation-writing.
If the code touches hot paths, Update(), or frequently raised events, load skill ss14-standard-optimizations.
If the task adds or changes player-facing text, load skills ss14-localization-strings and ss14-localization-code when the change also touches Loc.GetString(...), LocId, popup text, or localized component fields.
If the task touches network events, NetEntity, replicated state routing, or shared/server/client message flow, load skill ss14-netcode.
If the task touches Appearance, GenericVisualizer, visual state enums, or sprite-layer toggles, load skill ss14-graphics-generic-visualizer-appearance.
If the task touches sprites, RSI metadata, overlays, shaders, or custom client visual effects, load skill ss14-sprite-overlays-shaders.
If the task is about learning or explaining SS14 architecture, first features, or where code belongs, load skills ss14-prototype-basics, ss14-ecs-basics, and ss14-client-server-shared.
If the task is about bug hunting, VV, logs, breakpoints, or runtime inspection, load skills ss14-debugging-workflow and ss14-common-api-patterns.
If the task touches common gameplay helpers such as entity-system methods, spawning, prototypes, audio, popups, or random, load skills ss14-common-api-patterns and ss14-audio when the work changes audio routing, sound assets, sound collections, or predicted sound feedback.
If the task ports code or assets from another repository, or needs license or attribution guidance,...

Files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
Content.Shared/**

📄 CodeRabbit inference engine (Content.Shared/AGENTS.md)

Content.Shared/**: Load ss14-naming-conventions agent notes for Content.Shared work
Load ss14-ecs-prototypes, ss14-ecs-components, ss14-ecs-entities, and ss14-ecs-systems agent notes for Content.Shared work
Load ss14-upstream-maintenance agent notes for Content.Shared work
Load ss14-events agent notes for Content.Shared work
Load ss14-prediction and ss14-netcode agent notes for Content.Shared work
Load ss14-localization-code agent notes when shared code emits player text or stores LocId
Load ss14-graphics-generic-visualizer-appearance agent notes when shared gameplay state drives Appearance or GenericVisualizer
Load ss14-audio agent notes when shared components or events carry sound specifiers or predicted audio intent
Load ss14-atmos agent notes when shared components, UI messages, or enums belong to atmos features
Load ss14-transform-physics agent notes for shared coordinates, movement, collision, anchoring, or physics contracts
Load ss14-pvs agent notes for PVS-sensitive shared/network contracts
Load ss14-npc-ai agent notes for shared NPC, HTN, steering, pathfinding, or debug contracts
Shared code must own replicated state, shared events, and prediction-aware logic without adding direct client-only or server-only dependencies

Files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
+(Content.Shared|Content.Server|Content.Client|Content.Goobstation.Shared|Content.Goobstation.Server|Content.Goobstation.Client|Content.Goobstation.Common|Content.Goobstation.Maths|Content.Goobstation.UIKit|Content.Server.Database|Content.Shared.Database|Content.Tests|Content.IntegrationTests)/**/*.cs

📄 CodeRabbit inference engine (.cursor/rules/ss14-csharp.mdc)

+(Content.Shared|Content.Server|Content.Client|Content.Goobstation.Shared|Content.Goobstation.Server|Content.Goobstation.Client|Content.Goobstation.Common|Content.Goobstation.Maths|Content.Goobstation.UIKit|Content.Server.Database|Content.Shared.Database|Content.Tests|Content.IntegrationTests)/**/*.cs: Apply C# ECS style rules from ss14-interaction-flow.md
Apply ss14-csharp-style.md rules for C# code formatting and conventions
Follow ss14-naming-conventions for variable, method, and type naming in C# gameplay code

Files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
{Content.Shared,Content.Goobstation.Shared,Content.Goobstation.Common,Content.Goobstation.Maths,Content.Shared.Database}/**/*.cs

📄 CodeRabbit inference engine (.cursor/rules/ss14-shared.mdc)

{Content.Shared,Content.Goobstation.Shared,Content.Goobstation.Common,Content.Goobstation.Maths,Content.Shared.Database}/**/*.cs: Apply SS14 C# style guidelines from @.agents/rules/ss14-csharp-style.md
Follow SS14 ECS component patterns as defined in @.agents/skills/ss14-ecs-components/SKILL.md
Follow SS14 ECS entity patterns as defined in @.agents/skills/ss14-ecs-entities/SKILL.md
Follow SS14 ECS system patterns as defined in @.agents/skills/ss14-ecs-systems/SKILL.md
Follow SS14 event patterns as defined in @.agents/skills/ss14-events/SKILL.md
Follow SS14 prediction-aware gameplay code patterns as defined in @.agents/skills/ss14-prediction/SKILL.md
Follow SS14 netcode patterns as defined in @.agents/skills/ss14-netcode/SKILL.md
Follow SS14 localization identifier patterns as defined in @.agents/skills/ss14-localization-code/SKILL.md

Files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
**/*.{cs,xaml,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

If the task adds tests or you need to choose the right test layer, load skill ss14-tests-authoring.

Files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
{Content.Shared,Content.Goobstation.Shared}/**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

{Content.Shared,Content.Goobstation.Shared}/**/*.cs: Put main shared data, shared events, networked state, and predicted logic in Content.Shared/; use Content.Goobstation.Shared/ only for code that belongs to that existing module path.
Do not make shared projects depend on client-only or server-only projects.
Predicted systems and their relevant components belong in Content.Shared/. Shared predicted components should use NetworkedComponent, AutoGenerateComponentState, and AutoNetworkedField where appropriate.

Files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
Content.Shared/**/*.cs

⚙️ CodeRabbit configuration file

Content.Shared/**/*.cs: Review Content.Shared as shared gameplay and prediction code:

  • Shared owns replicated state, shared events, prediction, and data both client and server must understand.
  • Flag client-only or server-only dependencies in Shared.
  • For local-player actions, verify prediction support instead of accepting delayed server-only UX.
  • When state is networked, check NetworkedComponent, AutoGenerateComponentState, AutoNetworkedField, and Dirty/DirtyField usage.
  • Prefer entity-system APIs and Entity<T?> / Resolve patterns over ad-hoc tuples or old-style access.
  • Flag EntityUid.Invalid used as a "missing" sentinel.

Files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
{Content.Client,Content.Goobstation.Client,Content.Goobstation.UIKit}/**/*.{cs,xaml}

📄 CodeRabbit inference engine (.cursor/rules/ss14-ui.mdc)

{Content.Client,Content.Goobstation.Client,Content.Goobstation.UIKit}/**/*.{cs,xaml}: Follow SS14 naming conventions when editing UI, XAML, and client-state files
Maintain upstream compatibility when editing SS14 client code
Follow SS14 UI and BUI conventions when implementing UI components and behavior-driven user interfaces

Files:

  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
{Content.Client,Content.Goobstation.Client,Content.Goobstation.UIKit}/**/*.cs

📄 CodeRabbit inference engine (.cursor/rules/ss14-ui.mdc)

{Content.Client,Content.Goobstation.Client,Content.Goobstation.UIKit}/**/*.cs: Apply SS14 prediction patterns when working with predicted client-state in SS14 client code
Follow SS14 localization code practices in UI and client-state implementations

Put main client-only visuals, overlays, XAML, and BUI front-ends in Content.Client/; use Content.Goobstation.Client/ or Content.Goobstation.UIKit/ only when matching existing references and ownership.

Files:

  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
{Content.Client,Content.Goobstation.Client,Content.Goobstation.UIKit}/**/*.{xaml,xaml.cs}

📄 CodeRabbit inference engine (.cursor/rules/ss14-ui.mdc)

Use proper localization strings in SS14 client XAML and UI code

Files:

  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
**/*.xaml{,.cs}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.xaml{,.cs}: If the task edits XAML windows, controls, code-behind, or client UI layout, load skill ss14-ui-xaml.
Keep .xaml paired with .xaml.cs and the relevant BUI/client system.

Files:

  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
Content.Client/**/*.cs

⚙️ CodeRabbit configuration file

Content.Client/**/*.cs: Review Content.Client for presentation-only behavior:

  • Keep authority out of the client.
  • Prefer reading already-networked component state instead of duplicating BUI state unless the pattern requires it.
  • Flag missing localization for player-visible text.
  • Prefer nearby established UI and visual patterns over custom one-off structures.

Files:

  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
🧠 Learnings (5)
📚 Learning: 2026-06-04T21:17:36.815Z
Learnt from: MataVsn
Repo: ArcaneSS14/arcane-station PR: 31
File: Content.Client/Fluids/PuddleSystem.cs:41-41
Timestamp: 2026-06-04T21:17:36.815Z
Learning: In this repo (ArcaneSS14/arcane-station), reviewers should use the Arcane inline fork-edit marker naming for single-line edits outside `_Arcane` paths: prefer `// Arcane` or `// Arcane-edit` and do not use `// Orion` for this purpose. Repo-specific AGENTS guidance that mentions `// Orion` does not apply to these single-line changes; only `_Arcane` paths follow the applicable different convention.

Applied to files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
📚 Learning: 2026-06-28T19:37:26.732Z
Learnt from: MataVsn
Repo: ArcaneSS14/arcane-station PR: 96
File: Content.Client/IoC/ClientContentIoC.cs:151-151
Timestamp: 2026-06-28T19:37:26.732Z
Learning: For ArcaneSS14/arcane-station C# files whose path is outside any `_Arcane` directories, avoid adding an inline fork marker (e.g., `// Arcane` or `// Arcane-edit`) to `using` directives when the imported namespace already clearly indicates the `_Arcane` fork. For example, if the `using` namespace itself contains `_Arcane` (such as `using Content.Client._Arcane.ERP.Preferences;`), the `// Arcane`/`// Arcane-edit` marker is unnecessary.

Applied to files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
📚 Learning: 2026-07-04T03:37:47.373Z
Learnt from: UmbiMax
Repo: ArcaneSS14/arcane-station PR: 101
File: Content.Goobstation.Server/Chemistry/EntitySystems/EnergyReagentDispenserSystem.cs:59-59
Timestamp: 2026-07-04T03:37:47.373Z
Learning: In ArcaneSS14/arcane-station, C# source files must never have fork-edit markers (e.g., comments like `// Arcane`, `// Arcane-edit`, `// Orion`) on `using` directives. During code review, do not flag existing markers on any `using` line and do not suggest adding/removing them based on `_Arcane` folder placement or whether the imported namespace contains `_Arcane`—this rule applies universally to all `using` statements.

Applied to files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
📚 Learning: 2026-06-28T12:09:12.409Z
Learnt from: MataVsn
Repo: ArcaneSS14/arcane-station PR: 96
File: Content.Shared/Humanoid/HumanoidVisualLayers.cs:65-67
Timestamp: 2026-06-28T12:09:12.409Z
Learning: In ArcaneSS14/arcane-station, for any C# enum annotated with `[NetSerializable]` in shared code, treat the enum member order/implicit underlying numeric values as part of the network wire-protocol. During code review, disallow inserting new enum members in the middle (or otherwise changing existing members’ numeric values), since it breaks network compatibility. Instead, add new members only at the end or explicitly pin stable values by assigning numeric literals to members.

Applied to files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
📚 Learning: 2026-07-01T17:19:52.100Z
Learnt from: UmbiMax
Repo: ArcaneSS14/arcane-station PR: 101
File: Content.Shared/Mobs/MobState.cs:0-0
Timestamp: 2026-07-01T17:19:52.100Z
Learning: When reviewing ArcaneSS14/arcane-station C# code, ensure all usages of the `MobState` enum (`MobState.Dead`, `MobState.SoftCritical`, `MobState.HardCritical`, `MobState.Critical`) reference the enum members symbolically rather than via hardcoded numeric literals or casts from numeric values (e.g., avoid patterns like `(MobState)4` or `MobState` comparisons to `byte`/`int` literals). Treat direct numeric usage as a code-level dependency that should be flagged. Also avoid persisting `MobState` numeric values in `Content.Server.Database` or `Content.Replay`; if persistence/replay of the raw byte value is introduced, renumbering the `[NetSerializable] MobState : byte` enum becomes a data-compatibility risk. Renumbering the enum is compile-safe as long as there are no numeric literal dependencies, but the remaining risk is network wire-protocol mismatch if mixed old/new client-server builds are running during a rolling update—coordinate deployment to maintain net compatibility.

Applied to files:

  • Content.Shared/Preferences/HumanoidCharacterProfile.cs
  • Content.Client/Humanoid/MarkingPicker.xaml.cs
  • Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

Comment thread Content.Client/Humanoid/MarkingPicker.xaml.cs Outdated
Comment thread Content.Client/Humanoid/SingleMarkingPicker.xaml.cs Outdated
Comment thread Content.Shared/Preferences/HumanoidCharacterProfile.cs Outdated
@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai сделал, как ты сказал, но файлы в vscode всё равно горят красным. проверь на ошибки

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== MarkingPrototype.cs =="
fd 'MarkingPrototype.cs' Content.Shared | xargs -I{} sh -c 'echo "--- {} ---"; cat -n "{}"'

echo
echo "== MarkingWhitelistManager.cs / MarkingWhitelistData.cs =="
fd -i 'MarkingWhitelist' Content.Shared Content.Client 2>/dev/null | xargs -I{} sh -c 'echo "--- {} ---"; cat -n "{}"'

echo
echo "== MarkingPicker.xaml.cs (full) =="
cat -n Content.Client/Humanoid/MarkingPicker.xaml.cs

echo
echo "== SingleMarkingPicker.xaml.cs (full) =="
cat -n Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

echo
echo "== HumanoidCharacterProfile.cs relevant section =="
rg -n -B5 -A20 'Whitelist|MarkingWhitelistManager' Content.Shared/Preferences/HumanoidCharacterProfile.cs

echo
echo "== Check for IPlayerManager dependency injection style across client codebase =="
rg -n 'IoCManager.Resolve<IPlayerManager>|\[Dependency\].*IPlayerManager' Content.Client -g '*.cs' | head -10

echo
echo "== Check LocalSession vs LocalPlayer usage across codebase (RT version hint) =="
rg -n '_playerManager\.LocalSession|_playerManager\.LocalPlayer' Content.Client -g '*.cs' | head -20

echo
echo "== Check ICommonSession namespace used in Shared HumanoidCharacterProfile.cs =="
sed -n '1,30p' Content.Shared/Preferences/HumanoidCharacterProfile.cs

Length of output: 52052


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== HumanoidCharacterProfile.cs context around lines 1060-1130 =="
sed -n '1060,1130p' Content.Shared/Preferences/HumanoidCharacterProfile.cs

echo
echo "== Check method signature enclosing this block (search backwards for method start) =="
awk 'NR>=1000 && NR<=1125' Content.Shared/Preferences/HumanoidCharacterProfile.cs | grep -n 'public\|private\|static\|void\|EnsureValid' 

echo
echo "== Check brace balance in file =="
python3 - <<'EOF'
path = "Content.Shared/Preferences/HumanoidCharacterProfile.cs"
depth = 0
with open(path) as f:
    for i, line in enumerate(f, 1):
        for ch in line:
            if ch == '{':
                depth += 1
            elif ch == '}':
                depth -= 1
        if 1100 <= i <= 1130:
            print(i, depth, line.rstrip())
EOF

Length of output: 5159


@bzzzbzzbz, файлы горят красным не просто «по мелочи» — там реальные ошибки компиляции, все три вставки Arcane-кода вставлены не в тот контекст. Разбор по файлам:

1. Content.Client/Humanoid/MarkingPicker.xaml.cs — Line 185-206

Блок вставлен внутрь SetupCategoryButtons(), который итерируется по категориям (MarkingCategories), а не по маркингам. Отсюда:

  • marking — не существует в этом скоупе (CS0103);
  • continue — вне цикла (CS0139, "no enclosing loop");
  • блок продублирован два раза.

Убрать оба блока из SetupCategoryButtons() и добавить проверку в Populate(), где реально есть foreach (var marking in sortedMarkings):

foreach (var marking in sortedMarkings)
{
    if (_currentMarkings.TryGetMarking(_selectedMarkingCategory, marking.ID, out _))
        continue;

    // Arcane - Start
    if (!MarkingWhitelistManager.IsMarkingAllowed(marking, _playerManager.LocalSession))
        continue;
    // Arcane - End

    var item = CMarkingsUnused.AddItem($"{GetMarkingName(marking)}", _sprite.Frame0(marking.Sprites[0]));
    item.Metadata = marking;
}

2. Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

using Robust.Client.Player; добавлен, но поле _playerManager не объявлено_playerManager.LocalSession = CS0103. Плюс проверка стоит после MarkingList.AddItem(...), то есть маркинг уже добавлен в UI до continue — логика не работает даже если исправить компиляцию.

Добавь зависимость:

[Dependency] private readonly MarkingManager _markingManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!; // Arcane

И перенеси проверку перед AddItem:

foreach (var (id, marking) in sortedMarkings)
{
    // Arcane - Start
    if (!MarkingWhitelistManager.IsMarkingAllowed(marking, _playerManager.LocalSession))
        continue;
    // Arcane - End

    var item = MarkingList.AddItem(Loc.GetString($"marking-{id}"), _sprite.Frame0(marking.Sprites[0]));
    item.Metadata = marking.ID;

    if (_markings[Slot].MarkingId == id)
    {
        _ignoreItemSelected = true;
        item.Selected = true;
        _ignoreItemSelected = false;
    }
}

3. Content.Shared/Preferences/HumanoidCharacterProfile.cs — Line 1114-1122

Блок вставлен сразу после foreach (var value in toRemove) {...}, без своего foreach. Отсюда:

  • continue вне цикла (CS0139);
  • markingId не объявлена (CS0103);
  • profile не существует в этом методе — тут работает this/Appearance, а не параметр profile (CS0103);
  • лишняя } рвёт баланс скобок метода.

Правильно (используя имеющийся в методе параметр prototypeManager и собственное свойство Appearance):

foreach (var value in toRemove)
{
    _loadouts.Remove(value);
}

// Arcane - Start
foreach (var markingId in Appearance.Markings.ToList())
{
    if (!prototypeManager.TryIndex<MarkingPrototype>(markingId.MarkingId, out var proto))
        continue;

    if (!MarkingWhitelistManager.IsMarkingAllowed(proto, session))
        Appearance.Markings.Remove(markingId);
}
// Arcane - End

(без лишней } после — она уже закрывает сам метод, ничего дополнительно закрывать не нужно).


Итог: все три места — не «намespace»-проблема, а вставка кода вне корректного цикла/скоупа. Исправь по diff'ам выше, тогда VSCode должен перестать подсвечивать эти три файла.

(◕⌓◕)


✏️ Learnings added
Learnt from: bzzzbzzbz
URL: https://github.com/ArcaneSS14/arcane-old/pull/100

Timestamp: 2026-07-11T23:57:15.561Z
Learning: В репозитории ArcaneSS14/arcane-station в PR `#100` пользователь bzzzbzzbz при интеграции whitelist-проверки маркингов допустил три отдельные ошибки компиляции из-за вставки кода вне корректного цикла/скоупа: (1) в `Content.Client/Humanoid/MarkingPicker.xaml.cs` блок с `MarkingWhitelistManager.IsMarkingAllowed(...)` и `continue` был вставлен в `SetupCategoryButtons()` (итерация по `MarkingCategories`, не по маркингам) вместо `Populate()` (где есть `foreach (var marking in sortedMarkings)`), из-за чего `marking` не определена и `continue` вне цикла; (2) в `Content.Client/Humanoid/SingleMarkingPicker.xaml.cs` не было объявлено поле `[Dependency] private readonly IPlayerManager _playerManager` при использовании `_playerManager.LocalSession`, и проверка whitelist стояла после `MarkingList.AddItem(...)`, что не давало эффекта даже при компиляции; (3) в `Content.Shared/Preferences/HumanoidCharacterProfile.cs` (метод, где выполняются присваивания `Age = age; Appearance = appearance;` и `loadouts.EnsureValid(...)`) блок с whitelist-проверкой маркингов был вставлен без охватывающего `foreach` и использовал неопределённые `markingId`/`profile` — нужно использовать `foreach (var markingId in Appearance.Markings.ToList())` и оперировать `Appearance.Markings`/параметром `prototypeManager`, а не `profile`.

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

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai нужны ли ещё какие-то библиотеки? есть ли ошибки?

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== MarkingPicker.xaml.cs full =="
cat -n Content.Client/Humanoid/MarkingPicker.xaml.cs

echo
echo "== SingleMarkingPicker.xaml.cs full =="
cat -n Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

echo
echo "== HumanoidCharacterProfile.cs around whitelist block =="
rg -n -B10 -A15 'MarkingWhitelistManager|Arcane' Content.Shared/Preferences/HumanoidCharacterProfile.cs

echo
echo "== Check usings at top of files =="
sed -n '1,30p' Content.Client/Humanoid/MarkingPicker.xaml.cs
echo "---"
sed -n '1,30p' Content.Client/Humanoid/SingleMarkingPicker.xaml.cs
echo "---"
sed -n '1,30p' Content.Shared/Preferences/HumanoidCharacterProfile.cs

echo
echo "== Check IPlayerManager field declarations =="
rg -n 'IPlayerManager|_playerManager' Content.Client/Humanoid/MarkingPicker.xaml.cs Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

echo
echo "== Check MarkingWhitelistManager.cs current namespace/content =="
fd -i 'MarkingWhitelist' Content.Shared Content.Client 2>/dev/null | xargs -I{} sh -c 'echo "--- {} ---"; cat -n "{}"'

echo
echo "== Check ICommonSession/session param in HumanoidCharacterProfile EnsureValid method signature =="
rg -n 'EnsureValid|ICommonSession' Content.Shared/Preferences/HumanoidCharacterProfile.cs | head -30

Length of output: 57606


@bzzzbzzbz, новых библиотек не нужно — все using уже на месте. Но осталась одна реальная ошибка компиляции + один мусорный момент.

1. Ошибка: Content.Client/Humanoid/MarkingPicker.xaml.cs, SetupCategoryButtons() (Line 198-202)

Ты добавил корректный блок в Populate() (Line 250-255) — молодец, там всё верно. Но старый нерабочий блок в SetupCategoryButtons() не удалён:

        // Arcane - Start
        if (!MarkingWhitelistManager.IsMarkingAllowed(marking, _playerManager.LocalSession))
    continue;
    // Arcane - End
    }

Проблема:

  • marking тут не существует — метод итерируется по category, а не по marking (CS0103);
  • continue вне цикла (CS0139).

Удали этот блок целиком, оставив метод так:

        else
        {
            _selectedMarkingCategory = MarkingCategories.Chest;
        }
    }

2. Content.Shared/Preferences/HumanoidCharacterProfile.cs — сам whitelist-блок (Line 1114-1123) теперь корректен

Логика верна: foreach (var markingId in Appearance.Markings.ToList()), prototypeManager.TryIndex, session — всё ок.

Но добавлены дублирующиеся using на Line 74-75:

using Robust.Shared.Prototypes; // дубль, уже на Line 68
using Robust.Shared.Player;     // дубль, уже на Line 67

Это не ошибка (CS0105 warning), но лучше убрать дубли — оставить только using Content.Shared._Arcane.SpecialWhitelist; в Arcane-блоке.

3. SingleMarkingPicker.xaml.cs — ошибок не нашёл, всё исправлено корректно.

Итог: убери мёртвый блок из SetupCategoryButtons() в MarkingPicker.xaml.cs, почисти дубли usings в HumanoidCharacterProfile.cs — и красное в VSCode должно уйти.

(⌐■_■)

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai файлы в vscode всё ещё красные

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== MarkingPicker.xaml.cs full =="
cat -n Content.Client/Humanoid/MarkingPicker.xaml.cs

echo
echo "== SingleMarkingPicker.xaml.cs full =="
cat -n Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

echo
echo "== HumanoidCharacterProfile.cs usings + whitelist block =="
sed -n '1,90p' Content.Shared/Preferences/HumanoidCharacterProfile.cs
echo "---"
rg -n -B10 -A15 'MarkingWhitelistManager|Arcane' Content.Shared/Preferences/HumanoidCharacterProfile.cs

echo
echo "== MarkingWhitelistManager.cs / MarkingWhitelistData.cs =="
fd -i 'MarkingWhitelist' Content.Shared Content.Client 2>/dev/null | xargs -I{} sh -c 'echo "--- {} ---"; cat -n "{}"'

echo
echo "== Brace balance checks =="
python3 - <<'EOF'
for path in [
    "Content.Client/Humanoid/MarkingPicker.xaml.cs",
    "Content.Client/Humanoid/SingleMarkingPicker.xaml.cs",
    "Content.Shared/Preferences/HumanoidCharacterProfile.cs",
]:
    depth = 0
    with open(path) as f:
        for i, line in enumerate(f, 1):
            for ch in line:
                if ch == '{':
                    depth += 1
                elif ch == '}':
                    depth -= 1
    print(path, "final depth:", depth)
EOF

Length of output: 56380


@bzzzbzzbz, нашёл — всё дело только в Content.Client/Humanoid/MarkingPicker.xaml.cs. Баланс скобок файла: -1, т.е. файл гарантированно не компилируется. SingleMarkingPicker.xaml.cs и HumanoidCharacterProfile.cs сейчас в порядке (баланс скобок 0, логика верна).

Проблема 1 — мёртвый блок в SetupCategoryButtons() (Line 198-201)

Старый нерабочий кусок так и не удалён:

        // Arcane - Start
        if (!MarkingWhitelistManager.IsMarkingAllowed(marking, _playerManager.LocalSession))
            continue;
        // Arcane - End
    }

marking тут не существует (метод про category, не про marking), continue вне цикла — CS0103/CS0139.

Удали целиком, метод должен заканчиваться так:

        else
        {
            _selectedMarkingCategory = MarkingCategories.Chest;
        }
    }

Проблема 2 — испорченный блок в Populate() (Line 244-259)

Сейчас там мусор вместо реальной проверки:

foreach (var marking in sortedMarkings)
{
    if (_currentMarkings.TryGetMarking(_selectedMarkingCategory, marking.ID, out _))
    {
        continue;
    }
    // Arcane - Start
    else
    {
    _   selectedMarkingCategory = MarkingCategories.Chest;
    }
}
    // Arcane - End
    var item = CMarkingsUnused.AddItem($"{GetMarkingName(marking)}", _sprite.Frame0(marking.Sprites[0]));
    item.Metadata = marking;
}

Тут опечатка _ selectedMarkingCategory (CS1002) и лишняя } обрывает foreach раньше — item/marking оказываются вне скоупа цикла.

Замени на:

foreach (var marking in sortedMarkings)
{
    if (_currentMarkings.TryGetMarking(_selectedMarkingCategory, marking.ID, out _))
    {
        continue;
    }

    // Arcane - Start
    if (!MarkingWhitelistManager.IsMarkingAllowed(marking, _playerManager.LocalSession))
        continue;
    // Arcane - End

    var item = CMarkingsUnused.AddItem($"{GetMarkingName(marking)}", _sprite.Frame0(marking.Sprites[0]));
    item.Metadata = marking;
}

После этих двух правок баланс скобок файла станет 0, и VSCode должен перестать подсвечивать MarkingPicker.xaml.cs.

(⌐■_■)

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai MarkingPicker: The name 'marking' does not exist in the current context. что делать?

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== MarkingPicker.xaml.cs full =="
cat -n Content.Client/Humanoid/MarkingPicker.xaml.cs

Length of output: 23931


@bzzzbzzbz, всё ещё не удалён мёртвый блок — вот причина.

Content.Client/Humanoid/MarkingPicker.xaml.cs, метод SetupCategoryButtons(), Line 198-201

        // Arcane - Start
        if (!MarkingWhitelistManager.IsMarkingAllowed(marking, _playerManager.LocalSession))
            continue;
        // Arcane - End
    }

Этот метод итерируется только по category (см. Line 172: var category = _markingCategories[i];), переменной marking в нём никогда не было — отсюда CS0103 The name 'marking' does not exist in the current context.

Фикс — просто удали этот блок целиком. Метод должен заканчиваться так, без Arcane-вставки:

        else
        {
            _selectedMarkingCategory = MarkingCategories.Chest;
        }
    }

Нужная проверка whitelist'а уже стоит там, где нужно — в Populate() на Line 251-254:

foreach (var marking in sortedMarkings)
{
    if (_currentMarkings.TryGetMarking(_selectedMarkingCategory, marking.ID, out _))
    {
        continue;
    }

    // Arcane - Start
    if (!MarkingWhitelistManager.IsMarkingAllowed(marking, _playerManager.LocalSession))
        continue;
    // Arcane - End

    var item = CMarkingsUnused.AddItem($"{GetMarkingName(marking)}", _sprite.Frame0(marking.Sprites[0]));
    item.Metadata = marking;
}

Этот кусок трогать не нужно — он корректен.

Удали дублирующийся блок в SetupCategoryButtons() — и ошибка marking does not exist in the current context уйдёт.

( ̄~ ̄;)

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai HumanoidCharacterProfile: The type or namespace name 'MarkingPrototype' could not be found (are you missing a using directive or an assembly reference?). Что делать?

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== HumanoidCharacterProfile.cs top usings =="
sed -n '1,90p' Content.Shared/Preferences/HumanoidCharacterProfile.cs

echo
echo "== Check MarkingPrototype namespace =="
rg -n 'namespace' Content.Shared/Humanoid/Markings/MarkingPrototype.cs

echo
echo "== Check current whitelist block in HumanoidCharacterProfile.cs =="
rg -n -B5 -A15 'MarkingWhitelistManager|Arcane' Content.Shared/Preferences/HumanoidCharacterProfile.cs

Length of output: 16658


@bzzzbzzbz, не хватает using для namespace, где объявлен MarkingPrototype.

Тип MarkingPrototype лежит в Content.Shared.Humanoid.Markings (Content.Shared/Humanoid/Markings/MarkingPrototype.cs, Line 22), а в Content.Shared/Preferences/HumanoidCharacterProfile.cs этот namespace не подключён — есть только Content.Shared.Humanoid и Content.Shared.Humanoid.Prototypes.

Фикс — добавь в блок usings:

using Content.Shared.Humanoid.Markings;

Например, рядом с существующим Arcane-блоком (Line 72-74):

using Content.Shared.Humanoid.Markings;
// Arcane - Start
using Content.Shared._Arcane.SpecialWhitelist;
// Arcane - End

После этого prototypeManager.TryIndex<MarkingPrototype>(...) на Line 1115 должен резолвиться корректно.

Кстати
Мозг привык: в Robust Toolbox прототипы (MarkingPrototype, SpeciesPrototype, TraitPrototype и т.д.) лежат в разных под-namespace от основного модуля — при добавлении нового вызова к типу из другого файла всегда проверяй его namespace в исходнике, а не полагайся на то, что он "рядом".

( ̄ω ̄)

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai теперь система рабочая?

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== MarkingPicker.xaml.cs =="
cat -n Content.Client/Humanoid/MarkingPicker.xaml.cs

echo
echo "== SingleMarkingPicker.xaml.cs =="
cat -n Content.Client/Humanoid/SingleMarkingPicker.xaml.cs

echo
echo "== HumanoidCharacterProfile.cs usings + whitelist block =="
sed -n '1,90p' Content.Shared/Preferences/HumanoidCharacterProfile.cs
echo "---"
rg -n -B10 -A15 'MarkingWhitelistManager|Arcane' Content.Shared/Preferences/HumanoidCharacterProfile.cs

echo
echo "== Brace balance checks =="
python3 - <<'EOF'
for path in [
    "Content.Client/Humanoid/MarkingPicker.xaml.cs",
    "Content.Client/Humanoid/SingleMarkingPicker.xaml.cs",
    "Content.Shared/Preferences/HumanoidCharacterProfile.cs",
]:
    depth = 0
    with open(path) as f:
        for i, line in enumerate(f, 1):
            for ch in line:
                if ch == '{':
                    depth += 1
                elif ch == '}':
                    depth -= 1
    print(path, "final depth:", depth)
EOF

echo
echo "== IsMarkingAllowed usages =="
rg -n -C2 'IsMarkingAllowed\(' Content.Shared Content.Client Content.Server || echo "NONE"

Length of output: 56415


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== IPlayerManager LocalSession check =="
rg -n 'LocalSession' Content.Client -g '*.cs' | head -5

echo
echo "== Marking struct / MarkingId field check =="
rg -n 'MarkingId' Content.Shared/Humanoid/Markings/Marking.cs

echo
echo "== HairMarking / Appearance.Markings type =="
rg -n 'public.*Markings' Content.Shared/Humanoid/Markings/MarkingSet.cs Content.Shared/Humanoid/HumanoidCharacterAppearance.cs 2>/dev/null

echo
echo "== MarkingWhitelistManager.cs full =="
cat -n Content.Shared/_Arcane/MarkingWhitelistManager.cs

echo
echo "== MarkingPrototype.cs Whitelist field =="
rg -n -B3 -A3 'Whitelist' Content.Shared/Humanoid/Markings/MarkingPrototype.cs

Length of output: 2442


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== MarkingWhitelistManager.cs full =="
cat -n Content.Shared/_Arcane/MarkingWhitelistManager.cs || echo "FILE NOT FOUND"

echo
echo "== find whitelist files =="
fd -i whitelist Content.Shared

echo
echo "== MarkingPrototype.cs Whitelist field =="
grep -n -B3 -A3 'Whitelist' Content.Shared/Humanoid/Markings/MarkingPrototype.cs || echo "no match"

Length of output: 3004


@bzzzbzzbz, да, теперь система рабочая.

Проверил все три точки интеграции:

  1. Content.Client/Humanoid/MarkingPicker.xaml.cs — мёртвый блок в SetupCategoryButtons() удалён, рабочая проверка стоит в Populate() внутри foreach (var marking in sortedMarkings) перед AddItem. Баланс скобок файла = 0.
  2. Content.Client/Humanoid/SingleMarkingPicker.xaml.cs_playerManager объявлен, проверка стоит перед AddItem. Баланс = 0.
  3. Content.Shared/Preferences/HumanoidCharacterProfile.cs — блок в EnsureValid(...) синтаксически верен: foreach (var markingId in Appearance.Markings.ToList()), prototypeManager.TryIndex<MarkingPrototype>(...), Appearance.Markings.Remove(markingId) — итерация идёт по копии списка (.ToList()), поэтому модификация коллекции безопасна.

Дополнительно подтвердил:

  • IPlayerManager.LocalSession — валидный API (используется в других client-файлах, например Content.Client/Lathe/UI/LatheMenu.xaml.cs).
  • Marking.MarkingId — существующее поле.
  • Namespace Content.Shared._Arcane.SpecialWhitelist в MarkingWhitelistManager.cs/MarkingWhitelistData.cs совпадает с using в MarkingPrototype.cs (Line 20).

Итог: компиляция должна проходить, и теперь EnsureValid — это уже серверная (authoritative) проверка, а не только UI-фильтр, т.к. вызывается при валидации профиля.

Остаточные ограничения (не блокеры, но учти):

  • Волосы/борода не покрыты. HairStyleId/FacialHairStyleId хранятся отдельно от Appearance.Markings — если нужно ограничить и их, потребуется отдельная проверка в том же EnsureValid.
  • Сравнение идёт по session.Data.UserName, а не по UserId — рабочий вариант, но менее устойчив при возможном изменении логина/регистра; для строгой идентификации лучше UserId, если целостность важнее удобства чтения YAML.

Рекомендую протестировать: зайти под ckey не из allowed списка и убедиться, что Ren-маркинги не отображаются в пикере, а при попытке форсированного применения профиль их вырезает при EnsureValid.

(^▽^)

@bzzzbzzbz

Copy link
Copy Markdown
Contributor Author

@coderabbitai и как тогда человек, который должен использовать эти маркинги, получит их, если по сикею не получится?

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "== whitelist allowed values in humanoid_xeno.yml =="
rg -n -B3 -A3 'whitelist' Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml

Length of output: 906


@bzzzbzzbz, доступ даётся не автоматически "по роли/владельцу фичи", а строго по совпадению ckey со значением в allowed.

Сейчас в Resources/Prototypes/_Arcane/Entities/Mobs/Customization/Markings/humanoid_xeno.yml во всех трёх Ren-маркингах (HumanoidXenoTailRen, HumanoidXenoHeadRen, HumanoidXenoTracheasRen) указано:

whitelist:
  allowed:
  - Bulbo44key

Т.е. человек, которому эти маркинги предназначены (Бульба), получит их только если его реальный ckey совпадает буквально с Bulbo44key (регистр не важен — сравнение через OrdinalIgnoreCase, но состав символов должен быть точным).

Что нужно сделать:

  1. Проверить точный ckey Бульбы — через панель админа/БД сервера, а не по нику в игре или Discord.
  2. Если Bulbo44key — не настоящий ckey, а плейсхолдер/опечатка, заменить во всех трёх местах YAML на реальный ckey.
  3. Если человеку нужно выдать доступ к нескольким маркингам сразу — ckey просто дублируется в каждом allowed списке, как сейчас.
  4. Если позже понадобится выдавать доступ нескольким людям — просто добавляй ckey в тот же список:
    whitelist:
      allowed:
      - Bulbo44key
      - another_ckey

Важно: раз проверка теперь и серверная (в HumanoidCharacterProfile.EnsureValid), маркинг пропадёт из профиля сразу после сохранения, если ckey не совпал — то есть неправильный ckey в YAML полностью заблокирует доступ даже нужному человеку, без явной ошибки в UI. Рекомендую сразу сверить Bulbo44key с реальным ckey перед мержем.

ヽ(・_・;)ノ

@bzzzbzzbz
bzzzbzzbz marked this pull request as ready for review July 12, 2026 19:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant