Conversation
|
Content.Server/ParticleAccelerator/Components/ParticleAcceleratorControlBoxComponent.cs Content.Shared/_Eclipse/SelfShipyard/BUI/SelfShipyardConsoleInterfaceState.cs |
WalkthroughЭтот pull request добавляет полную систему самостоятельного верфения (Self Shipyard) для игроков. На клиентской стороне реализованы UI-компоненты для консоли верфения, включая меню с отображением баланса, списком доступных кораблей и функциями покупки или продажи. На серверной стороне добавлена модель данных для хранения кораблей игроков, компонент SaveableShuttleComponent для маркировки сохраняемых кораблей, и система SelfShipyardSystem с логикой обработки покупок, продажи кораблей, управления дедом и взаимодействиями с банком. Также обновлена существующая система ShipyardSystem для интеграции с новыми компонентами, и удалены DataField атрибуты из двух старых компонентов. 🚥 Pre-merge checks | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Fix all issues with AI agents
In
`@Content.Client/_DH/SelfShipyard/BUI/SelfShipyardConsoleBoundUserInterface.cs`:
- Around line 1-9: The file imports and namespace use _Eclipse while the UI
types (SelfShipyardConsoleMenu, OwnedVesselRow) live under
Content.Client._DH.SelfShipyard.UI, causing missing-type build errors; update
the using directive to Content.Client._DH.SelfShipyard.UI and change the
namespace declaration for SelfShipyardConsoleBoundUserInterface to
Content.Client._DH.SelfShipyard.BUI (or switch the other files to _Eclipse if
that is the intended branch) so the types SelfShipyardConsoleMenu and
OwnedVesselRow resolve correctly.
In `@Content.Client/_DH/SelfShipyard/UI/SelfShipyardConsoleMenu.xaml.cs`:
- Around line 90-97: Заменить хардкод `"None"` на локализуемую строку: добавить
ключ в .ftl (например "selfshipyard-deed-none") и в
SelfShipyardConsoleMenu.xaml.cs использовать
Loc.GetString("selfshipyard-deed-none") при установке DeedTitle.Text (в блоке,
где проверяется state.ShipDeedTitle). Обновить ресурсный файл .ftl с переводимой
фразой и убедиться, что ключ уникален и соответствует неймингу проекта.
In `@Content.Server.Database/Model.cs`:
- Around line 1403-1418: Add the missing EF table attribute and fix the DH
marker: annotate the OwnedShuttles class with [Table("owned_shuttles")] (apply
System.ComponentModel.DataAnnotations.Schema) so EF uses snake_case, rename the
comment markers from "// DH-Start: Owned Shuttles" and any matching end marker
to "// DH-Tweak-Start" and "// DH-Tweak-End" (or use "// DH-Tweak: ..." for
single-line notes), then generate and verify a migration in
Content.Server.Database/Migrations/Postgres that creates the owned_shuttles
table (ensure the new migration and the snapshot include OwnedShuttles); if
missing, run the EF migration add command and commit the migration files.
In `@Content.Server/_DH/SelfShipyard/Systems/SelfShipyardSystem.Consoles.cs`:
- Around line 244-246: shuttleStation can be null which causes a NullReference
when calling _records.Synchronize(shuttleStation!.Value); update the logic in
SelfShipyardSystem.Consoles (the block that calls _records.Synchronize) to check
shuttleStation for null/HasValue before calling
_records.Synchronize(shuttleStation.Value) — either skip that call or
early-return if shuttleStation is missing; keep the existing
_records.Synchronize(station) behavior unchanged and reference the
shuttleStation variable and _records.Synchronize method when making the guard.
- Around line 238-242: The code writes a hard-coded "Captain" string into
records via _records.CreateGeneralRecord; replace that literal with a localized
string using Loc.GetString(...) and add the corresponding key to your .ftl file
(e.g. selfshipyard-record-position-captain) so the role shown to players is
localizable; update the CreateGeneralRecord call to pass
Loc.GetString("selfshipyard-record-position-captain") instead of "Captain" and
ensure any tests or documentation referencing the literal are updated
accordingly.
In `@Content.Server/_DH/SelfShipyard/Systems/SelfShipyardSystem.cs`:
- Around line 281-319: Сейчас DeleteStation(shuttleStationUid),
CleanGrid(shuttleUid, consoleUid) и _docking.UndockDocks(shuttleUid) выполняются
до проверки средств и успешного сохранения, что приводит к необратимым
изменениям при ошибках; измените поток так, чтобы эти мутации выполнялись только
после успешного TryBankWithdraw(player, bill) и успешного
_mapLoader.TrySaveGrid(shuttleUid, resPath) либо реализуйте явный откат: если вы
решаете сохранять раньше, захватите состояние до изменений и при ошибке
вызывайте _db.RemoveOwnedShuttle(id, ...), _bank.TryBankDeposit(player, bill) и
восстановите станцию/докинг/гриду (или повторно создавайте станцию через
_station.GetOwningStation/DeleteStation обратным действием), иначе просто
переместите вызовы DeleteStation, CleanGrid и _docking.UndockDocks в блок после
успешного AddOwnedShuttle и успешного _mapLoader.TrySaveGrid; используйте
идентификаторы функций DeleteStation, CleanGrid, _docking.UndockDocks,
TryBankWithdraw, AddOwnedShuttle, TrySaveGrid/_mapLoader.TrySaveGrid,
RemoveOwnedShuttle и TryBankDeposit для навигации по коду.
- Around line 167-182: The code treats a failed dock attempt as a successful
purchase: if _shuttle.TryFTLDock(shuttleGrid.Value, shuttleComponent,
targetGrid.Value, out var config) returns false you must undo the purchase by
deleting the loaded shuttle grid (shuttleGrid) and return false instead of
setting shuttleEntityUid and returning true; update the flow in the method
containing TryFTLDock so that on a false result you call the appropriate grid
cleanup/removal routine for shuttleGrid (or unload it via the same subsystem
used to spawn it), log the failure, ensure no dockName/shuttleEntityUid are set,
and then return false to indicate the purchase failed.
🧹 Nitpick comments (4)
Content.Server/_DH/SelfShipyard/Components/SaveableShuttleComponent.cs (1)
1-9: Рекомендую добавить XML-документацию.Компонент важен для системы сохранения шаттлов. Согласно правилам проекта, для важных классов желательна XML-документация.
📝 Предлагаемые изменения
+using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; + namespace Content.Server._DH.SelfShipyard.Components { + /// <summary> + /// Компонент для маркировки шаттлов, которые могут быть сохранены в базу данных игрока. + /// </summary> [RegisterComponent] public sealed partial class SaveableShuttleComponent : Component { + /// <summary> + /// Идентификатор прототипа корабля для восстановления при загрузке. + /// </summary> [DataField] public string? PrototypeId; } }Content.Server/_NF/Shipyard/Systems/ShipyardSystem.Consoles.cs (1)
60-60: Добавь маркер DH-Tweak для using.Согласно правилам проекта, одиночные изменения вне папок
/_DH/должны быть помечены комментарием.📝 Предлагаемые изменения
-using Content.Server._DH.SelfShipyard.Components; +using Content.Server._DH.SelfShipyard.Components; // DH-TweakContent.Client/_DH/SelfShipyard/UI/OwnedVesselRow.xaml (1)
17-17: Пустой ToolTip.Атрибут
ToolTip=""пуст. Если подсказка планируется — лучше использовать локализованную строку. Если не нужна — можно убрать атрибут.Content.Server.Database/Model.cs (1)
384-390: Отсутствует индекс на PlayerUserId и поведение OnDelete.Для оптимизации запросов по игроку рекомендуется добавить индекс. Также стоит явно указать поведение при удалении игрока.
📝 Предлагаемые изменения
// DH-Start: Owned Shuttles modelBuilder.Entity<OwnedShuttles>() .HasOne(s => s.Player) .WithMany(player => player.OwnedShuttles) .HasForeignKey(s => s.PlayerUserId) - .HasPrincipalKey(player => player.UserId); + .HasPrincipalKey(player => player.UserId) + .OnDelete(DeleteBehavior.Cascade); + + modelBuilder.Entity<OwnedShuttles>() + .HasIndex(s => s.PlayerUserId); // DH-End
| using Content.Client._Eclipse.SelfShipyard.UI; | ||
| using Content.Shared.Containers.ItemSlots; | ||
| using Content.Shared._Eclipse.SelfShipyard.BUI; | ||
| using Content.Shared._Eclipse.SelfShipyard.Events; | ||
| using static Robust.Client.UserInterface.Controls.BaseButton; | ||
|
|
||
| namespace Content.Client._Eclipse.SelfShipyard.BUI; | ||
|
|
||
| public sealed class SelfShipyardConsoleBoundUserInterface : BoundUserInterface |
There was a problem hiding this comment.
Несовпадение неймспейсов _Eclipse/_DH ломает сборку UI.
SelfShipyardConsoleMenu и OwnedVesselRow объявлены в Content.Client._DH.SelfShipyard.UI, а здесь подключается _Eclipse, и сам класс находится в _Eclipse‑неймспейсе. В результате типы не найдутся. Нужна единая ветка неймспейсов и соответствующие using/namespace.
💡 Возможный фикс (если целевая ветка — _DH)
-using Content.Client._Eclipse.SelfShipyard.UI;
+using Content.Client._DH.SelfShipyard.UI;
...
-namespace Content.Client._Eclipse.SelfShipyard.BUI;
+namespace Content.Client._DH.SelfShipyard.BUI;🤖 Prompt for AI Agents
In `@Content.Client/_DH/SelfShipyard/BUI/SelfShipyardConsoleBoundUserInterface.cs`
around lines 1 - 9, The file imports and namespace use _Eclipse while the UI
types (SelfShipyardConsoleMenu, OwnedVesselRow) live under
Content.Client._DH.SelfShipyard.UI, causing missing-type build errors; update
the using directive to Content.Client._DH.SelfShipyard.UI and change the
namespace declaration for SelfShipyardConsoleBoundUserInterface to
Content.Client._DH.SelfShipyard.BUI (or switch the other files to _Eclipse if
that is the intended branch) so the types SelfShipyardConsoleMenu and
OwnedVesselRow resolve correctly.
| if (state.ShipDeedTitle != null) | ||
| { | ||
| DeedTitle.Text = state.ShipDeedTitle; | ||
| } | ||
| else | ||
| { | ||
| DeedTitle.Text = $"None"; | ||
| } |
There was a problem hiding this comment.
Нелокализованная строка в UI.
"None" показывается игрокам; вынесите в .ftl и используйте Loc.GetString(...). Согласно coding guidelines.
💡 Вариант исправления
- DeedTitle.Text = $"None";
+ DeedTitle.Text = Loc.GetString("shipyard-console-no-deed");🤖 Prompt for AI Agents
In `@Content.Client/_DH/SelfShipyard/UI/SelfShipyardConsoleMenu.xaml.cs` around
lines 90 - 97, Заменить хардкод `"None"` на локализуемую строку: добавить ключ в
.ftl (например "selfshipyard-deed-none") и в SelfShipyardConsoleMenu.xaml.cs
использовать Loc.GetString("selfshipyard-deed-none") при установке
DeedTitle.Text (в блоке, где проверяется state.ShipDeedTitle). Обновить
ресурсный файл .ftl с переводимой фразой и убедиться, что ключ уникален и
соответствует неймингу проекта.
| // DH-Start: Owned Shuttles | ||
| public class OwnedShuttles | ||
| { | ||
| [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ShuttleId { get; set; } | ||
| [Required, ForeignKey("Player")] public Guid PlayerUserId { get; set; } | ||
| public Player Player { get; set; } = default!; | ||
|
|
||
| [Required] public string ShuttlePrototypeId { get; set; } = default!; | ||
|
|
||
| [Required] public string ShuttleName { get; set; } = default!; | ||
|
|
||
| public string? ShuttleDescription { get; set; } | ||
| [Required] public int ShuttleSavePrice { get; set; } | ||
|
|
||
| [Required] public string ShuttlePath { get; set; } = default!; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Поиск других определений таблиц с [Table] атрибутом в Model.cs
fd -e cs Content.Server.Database | head -20Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 59
🏁 Script executed:
# Ищем примеры использования [Table] в проекте
rg -B2 "\[Table\(" --type cs | head -50Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 2304
🏁 Script executed:
# Ищем миграции, связанные с OwnedShuttles
fd -e cs . | xargs rg "OwnedShuttles" | grep -i "migration\|Migrations"Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 59
🏁 Script executed:
# Проверим общую структуру определений сущностей в Model.cs
rg "public class.*\n\s*\{" Content.Server.Database/Model.cs -A 1 | head -30Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 268
🏁 Script executed:
# Прочитаем точно те строки из Model.cs
sed -n '1403,1418p' Content.Server.Database/Model.csRepository: Dark-Haven-inc/dh-sector-frontier
Length of output: 729
🏁 Script executed:
# Ищем папку с миграциями
fd -type d -name "*migrations*" -o -name "*Migrations*"Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 247
🏁 Script executed:
# Ищем файлы миграций
fd -type f -path "*igrations*" -name "*.cs" | head -20Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 247
🏁 Script executed:
# Проверим другие DH-отмеченные блоки для правильного формата
rg "// DH-" Content.Server.Database/Model.cs | head -10Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 385
🏁 Script executed:
# Ищем миграции другим способом
find . -name "*.cs" -path "*Migrations*" 2>/dev/null | head -10Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 894
🏁 Script executed:
# Поищем папку Migrations в Content.Server.Database
find Content.Server.Database -type d -name "*igration*"Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 111
🏁 Script executed:
# Ищем файлы, которые содержат "CreateTable" или "OwnedShuttles"
rg "CreateTable.*OwnedShuttles|OwnedShuttles" --type cs --type txtRepository: Dark-Haven-inc/dh-sector-frontier
Length of output: 870
🏁 Script executed:
# Проверим структуру папок в Content.Server.Database
ls -la Content.Server.Database/Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 818
🏁 Script executed:
# Поищем в последних миграциях упоминание OwnedShuttles
ls Content.Server.Database/Migrations/Postgres/ | sort | tail -10Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 422
🏁 Script executed:
# Проверим последние миграции для OwnedShuttles
rg "OwnedShuttles" Content.Server.Database/Migrations/Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 59
🏁 Script executed:
# Посчитаем всего миграций
ls Content.Server.Database/Migrations/Postgres/ | wc -lRepository: Dark-Haven-inc/dh-sector-frontier
Length of output: 80
🏁 Script executed:
# Посмотрим на самую последнюю миграцию
ls Content.Server.Database/Migrations/Postgres/ | sort | tail -1 | xargs -I {} head -30 Content.Server.Database/Migrations/Postgres/{}Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 1085
🏁 Script executed:
# Ищем OwnedShuttles в всех файлах миграций
rg -l "OwnedShuttles" Content.Server.Database/Migrations/Postgres/Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 59
🏁 Script executed:
# Посмотрим последний snapshot для наличия OwnedShuttles
rg "OwnedShuttles" Content.Server.Database/Migrations/Postgres/PostgresServerDbContextModelSnapshot.csRepository: Dark-Haven-inc/dh-sector-frontier
Length of output: 59
🏁 Script executed:
# Проверим последние миграции на предмет создания таблицы owned_shuttles
for file in $(ls Content.Server.Database/Migrations/Postgres/*.cs | sort -r | head -5); do echo "=== $file ==="; grep -i "shuttles\|owned" "$file" || echo "not found"; doneRepository: Dark-Haven-inc/dh-sector-frontier
Length of output: 560
🏁 Script executed:
# Посмотрим на ModelBuilder конфигурацию OwnedShuttles в Model.cs
rg -A 10 "modelBuilder.Entity<OwnedShuttles>" Content.Server.Database/Model.csRepository: Dark-Haven-inc/dh-sector-frontier
Length of output: 573
🏁 Script executed:
# Проверим, есть ли миграция именно для добавления OwnedShuttles таблицы
grep -r "CreateTable.*shuttles\|scaffolded\|AddEntityType.*OwnedShuttles" Content.Server.Database/Migrations/Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 59
🏁 Script executed:
# Проверим полный список последних миграций с датами
ls -lh Content.Server.Database/Migrations/Postgres/*.cs | grep -v Designer | tail -5Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 705
🏁 Script executed:
# Проверим, есть ли какие-то файлы миграций содержащие "Shuttle"
find Content.Server.Database/Migrations -type f -name "*.cs" -exec grep -l -i "shuttle" {} \;Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 59
🏁 Script executed:
# Посмотрим на текущий DbContext, чтобы убедиться что OwnedShuttles там зарегистрирован
rg "public DbSet<OwnedShuttles>" Content.Server.Database/ -B 2 -A 2Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 557
🏁 Script executed:
# Проверим, есть ли какой-нибудь миграционный файл, который содержит определение OwnedShuttles
find Content.Server.Database/Migrations -name "*.cs" -type f -exec wc -l {} + | sort -n | tail -1 | awk '{print $NF}' | xargs head -100Repository: Dark-Haven-inc/dh-sector-frontier
Length of output: 143
🏁 Script executed:
# Проверим основной snapshot для наличия информации о OwnedShuttles таблице
grep -i "owned" Content.Server.Database/Migrations/Postgres/PostgresServerDbContextModelSnapshot.csRepository: Dark-Haven-inc/dh-sector-frontier
Length of output: 59
🏁 Script executed:
# Посмотрим на размер и содержание последней миграции
head -50 Content.Server.Database/Migrations/Postgres/20251226151249_DynamicMarket.csRepository: Dark-Haven-inc/dh-sector-frontier
Length of output: 1487
Добавь атрибут [Table("owned_shuttles")] и проверь наличие миграции.
Проект использует snake_case для имён таблиц (см. [Table("player")], [Table("server_ban")] и другие). Без явного указания EF создаст таблицу с именем OwnedShuttles, что нарушит соглашение о именовании.
Кроме того, в миграциях (Content.Server.Database/Migrations/Postgres/) OwnedShuttles не найден — ни в одном файле и ни в snapshot. Убедись, что миграция для этой таблицы была создана, иначе таблица не будет создана в базе данных.
Также исправь комментарий маркера: по гайдам должно быть // DH-Tweak-Start и // DH-Tweak-End для блоков, а // DH-Tweak: пояснение для отдельных строк.
📝 Необходимые изменения
- // DH-Start: Owned Shuttles
+ [Table("owned_shuttles")]
+ // DH-Tweak-Start: Owned Shuttles
public class OwnedShuttles
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ShuttleId { get; set; }🤖 Prompt for AI Agents
In `@Content.Server.Database/Model.cs` around lines 1403 - 1418, Add the missing
EF table attribute and fix the DH marker: annotate the OwnedShuttles class with
[Table("owned_shuttles")] (apply System.ComponentModel.DataAnnotations.Schema)
so EF uses snake_case, rename the comment markers from "// DH-Start: Owned
Shuttles" and any matching end marker to "// DH-Tweak-Start" and "//
DH-Tweak-End" (or use "// DH-Tweak: ..." for single-line notes), then generate
and verify a migration in Content.Server.Database/Migrations/Postgres that
creates the owned_shuttles table (ensure the new migration and the snapshot
include OwnedShuttles); if missing, run the EF migration add command and commit
the migration files.
| TryComp<FingerprintComponent>(player, out var fingerprintComponent); | ||
| TryComp<DnaComponent>(player, out var dnaComponent); | ||
| TryComp<StationRecordsComponent>(shuttleStation, out var stationRec); | ||
| _records.CreateGeneralRecord(shuttleStation.Value, targetId, profile.Name, profile.Age, profile.Species, profile.Gender, $"Captain", fingerprintComponent!.Fingerprint, dnaComponent!.DNA, profile, stationRec!); | ||
| } |
There was a problem hiding this comment.
Жёсткая строка должности без локализации.
"Captain" попадёт в записи и видна игрокам; вынесите строку в .ftl и используйте Loc.GetString(...). Согласно coding guidelines.
💡 Вариант исправления
- _records.CreateGeneralRecord(shuttleStation.Value, targetId, profile.Name, profile.Age, profile.Species, profile.Gender, $"Captain", fingerprintComponent!.Fingerprint, dnaComponent!.DNA, profile, stationRec!);
+ _records.CreateGeneralRecord(shuttleStation.Value, targetId, profile.Name, profile.Age, profile.Species, profile.Gender, Loc.GetString("self-shipyard-captain-title"), fingerprintComponent!.Fingerprint, dnaComponent!.DNA, profile, stationRec!);📝 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.
| TryComp<FingerprintComponent>(player, out var fingerprintComponent); | |
| TryComp<DnaComponent>(player, out var dnaComponent); | |
| TryComp<StationRecordsComponent>(shuttleStation, out var stationRec); | |
| _records.CreateGeneralRecord(shuttleStation.Value, targetId, profile.Name, profile.Age, profile.Species, profile.Gender, $"Captain", fingerprintComponent!.Fingerprint, dnaComponent!.DNA, profile, stationRec!); | |
| } | |
| TryComp<FingerprintComponent>(player, out var fingerprintComponent); | |
| TryComp<DnaComponent>(player, out var dnaComponent); | |
| TryComp<StationRecordsComponent>(shuttleStation, out var stationRec); | |
| _records.CreateGeneralRecord(shuttleStation.Value, targetId, profile.Name, profile.Age, profile.Species, profile.Gender, Loc.GetString("self-shipyard-captain-title"), fingerprintComponent!.Fingerprint, dnaComponent!.DNA, profile, stationRec!); | |
| } |
🤖 Prompt for AI Agents
In `@Content.Server/_DH/SelfShipyard/Systems/SelfShipyardSystem.Consoles.cs`
around lines 238 - 242, The code writes a hard-coded "Captain" string into
records via _records.CreateGeneralRecord; replace that literal with a localized
string using Loc.GetString(...) and add the corresponding key to your .ftl file
(e.g. selfshipyard-record-position-captain) so the role shown to players is
localizable; update the CreateGeneralRecord call to pass
Loc.GetString("selfshipyard-record-position-captain") instead of "Captain" and
ensure any tests or documentation referencing the literal are updated
accordingly.
| _records.Synchronize(shuttleStation!.Value); | ||
| _records.Synchronize(station); | ||
|
|
There was a problem hiding this comment.
Возможен NullReference при отсутствии shuttleStation.
Если GameMapPrototype не найден, shuttleStation остаётся null, но далее вызывается _records.Synchronize(shuttleStation!.Value). Нужна проверка на null перед вызовом.
🐛 Возможный фикс
- _records.Synchronize(shuttleStation!.Value);
+ if (shuttleStation != null)
+ _records.Synchronize(shuttleStation.Value);📝 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.
| _records.Synchronize(shuttleStation!.Value); | |
| _records.Synchronize(station); | |
| if (shuttleStation != null) | |
| _records.Synchronize(shuttleStation.Value); | |
| _records.Synchronize(station); | |
🤖 Prompt for AI Agents
In `@Content.Server/_DH/SelfShipyard/Systems/SelfShipyardSystem.Consoles.cs`
around lines 244 - 246, shuttleStation can be null which causes a NullReference
when calling _records.Synchronize(shuttleStation!.Value); update the logic in
SelfShipyardSystem.Consoles (the block that calls _records.Synchronize) to check
shuttleStation for null/HasValue before calling
_records.Synchronize(shuttleStation.Value) — either skip that call or
early-return if shuttleStation is missing; keep the existing
_records.Synchronize(station) behavior unchanged and reference the
shuttleStation variable and _records.Synchronize method when making the guard.
| _sawmill.Info($"Shuttle {shuttlePath} was purchased at {ToPrettyString(stationUid)} for {price:f2}"); | ||
| //can do TryFTLDock later instead if we need to keep the shipyard map paused | ||
| if (_shuttle.TryFTLDock(shuttleGrid.Value, shuttleComponent, targetGrid.Value, out var config)) | ||
| { | ||
| foreach (var (_, _, dockA, dockB) in config.Docks) | ||
| { | ||
| if (dockB.Name is not null) | ||
| { | ||
| dockName = Loc.GetString(dockB.Name); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| shuttleEntityUid = shuttleGrid; | ||
| return true; |
There was a problem hiding this comment.
Провал стыковки сейчас считается успешной покупкой.
Если TryFTLDock возвращает false, метод всё равно возвращает true и отдаёт UID шаттла; в итоге покупка считается успешной, но корабль остаётся на верфи. Лучше трактовать это как ошибку, удалить загруженный грид и вернуть false.
🐛 Возможный фикс
- if (_shuttle.TryFTLDock(shuttleGrid.Value, shuttleComponent, targetGrid.Value, out var config))
+ if (_shuttle.TryFTLDock(shuttleGrid.Value, shuttleComponent, targetGrid.Value, out var config))
{
foreach (var (_, _, dockA, dockB) in config.Docks)
{
if (dockB.Name is not null)
{
dockName = Loc.GetString(dockB.Name);
break;
}
}
}
+ else
+ {
+ QueueDel(shuttleGrid);
+ shuttleEntityUid = null;
+ return false;
+ }🤖 Prompt for AI Agents
In `@Content.Server/_DH/SelfShipyard/Systems/SelfShipyardSystem.cs` around lines
167 - 182, The code treats a failed dock attempt as a successful purchase: if
_shuttle.TryFTLDock(shuttleGrid.Value, shuttleComponent, targetGrid.Value, out
var config) returns false you must undo the purchase by deleting the loaded
shuttle grid (shuttleGrid) and return false instead of setting shuttleEntityUid
and returning true; update the flow in the method containing TryFTLDock so that
on a false result you call the appropriate grid cleanup/removal routine for
shuttleGrid (or unload it via the same subsystem used to spawn it), log the
failure, ensure no dockName/shuttleEntityUid are set, and then return false to
indicate the purchase failed.
| //just yeet and delete for now. Might want to split it into another function later to send back to the shipyard map first to pause for something | ||
| //also superman 3 moment | ||
| if (_station.GetOwningStation(shuttleUid) is { Valid: true } shuttleStationUid) | ||
| { | ||
| _station.DeleteStation(shuttleStationUid); | ||
| } | ||
|
|
||
| if (TryComp<SelfShipyardConsoleComponent>(consoleUid, out var comp)) | ||
| { | ||
| CleanGrid(shuttleUid, consoleUid); | ||
| } | ||
|
|
||
| var shuttle_cost = (int)_pricing.AppraiseGrid(shuttleUid, LacksPreserveOnSaleComp); | ||
|
|
||
| var bill = (int)(shuttle_cost * _percentSaveRate) + _constantSaveRate; | ||
|
|
||
| if (!_bank.TryBankWithdraw(player, bill)) | ||
| { | ||
| result.Error = ShipyardSaleError.InsufficientFunds; | ||
| return (result, bill); | ||
| } | ||
|
|
||
| _docking.UndockDocks(shuttleUid); | ||
|
|
||
| var id = await _db.AddOwnedShuttle(playerSession.UserId, saveableShuttle.PrototypeId, shuttleName, null, shuttle_cost, ResPath.Root); | ||
|
|
||
| string path = $"/OwnedShuttles/{playerSession.UserId}/{id}.yml"; | ||
|
|
||
| var resPath = new ResPath(path); | ||
|
|
||
| _resMan.UserData.CreateDir(resPath.Directory); | ||
|
|
||
| if (!_mapLoader.TrySaveGrid(shuttleUid, resPath)) | ||
| { | ||
| await _db.RemoveOwnedShuttle(id, playerSession.UserId); | ||
| _bank.TryBankDeposit(player, bill); | ||
| result.Error = ShipyardSaleError.InvalidShip; | ||
| return (result, bill); | ||
| } |
There was a problem hiding this comment.
Необратимые операции выполняются до подтверждения сделки.
DeleteStation, CleanGrid и UndockDocks идут до списания средств и до успешного сохранения. При недостатке средств или ошибке сохранения шаттл уже изменён/расстыкован и станция удалена. Перенесите эти действия на успешный путь или добавьте откат, чтобы при отказе состояние сохранялось.
🤖 Prompt for AI Agents
In `@Content.Server/_DH/SelfShipyard/Systems/SelfShipyardSystem.cs` around lines
281 - 319, Сейчас DeleteStation(shuttleStationUid), CleanGrid(shuttleUid,
consoleUid) и _docking.UndockDocks(shuttleUid) выполняются до проверки средств и
успешного сохранения, что приводит к необратимым изменениям при ошибках;
измените поток так, чтобы эти мутации выполнялись только после успешного
TryBankWithdraw(player, bill) и успешного _mapLoader.TrySaveGrid(shuttleUid,
resPath) либо реализуйте явный откат: если вы решаете сохранять раньше,
захватите состояние до изменений и при ошибке вызывайте
_db.RemoveOwnedShuttle(id, ...), _bank.TryBankDeposit(player, bill) и
восстановите станцию/докинг/гриду (или повторно создавайте станцию через
_station.GetOwningStation/DeleteStation обратным действием), иначе просто
переместите вызовы DeleteStation, CleanGrid и _docking.UndockDocks в блок после
успешного AddOwnedShuttle и успешного _mapLoader.TrySaveGrid; используйте
идентификаторы функций DeleteStation, CleanGrid, _docking.UndockDocks,
TryBankWithdraw, AddOwnedShuttle, TrySaveGrid/_mapLoader.TrySaveGrid,
RemoveOwnedShuttle и TryBankDeposit для навигации по коду.
|
ЭЭээ бля ХРЕНЬ! лучше не делайте, лучше помогите нам сделать полный сейв! оригинальный пр: space-wizards/RobustToolbox#6166 Мои продолжения Lua-Frontier/RobustToolbox#1 |
О пулл-реквесте
Перенос отсюда https://github.com/Apxumekm0p/Eclipse-New-Frontier/pull/18/changes#diff-13e289574cbdac6cc3ef402f1de552c66b36d65474a4323f4a3f60ac5d0fdb0e
Технические детали
Нет
Изменения кода официальных разработчиков
Нет
Журнал изменений
🆑