Убран мёртвый код проигрывания видео; заготовка своей модели ножа

PlayBlackPortalVideoLegacy и BlackPortalVideoPath ниоткуда не вызывались
с 2026-09-09, когда концовку заменили слайдами. Разборы Pause/PlayVideo и
синтаксиса @modfolder перенесены в NoteFlashbackPatch - единственное место,
где эти API ещё вызываются. Перекрёстные ссылки в FinalSlides поправлены,
устаревшее упоминание StayVideoPath/ReturnVideoPath убрано.

В items.xml у necroWpnBladeNecroKnife добавлена закомментированная строка
Meshfile под будущий бандл Resources/necroknife - включать вместе с самим
бандлом, не раньше. Там же снято старое сомнение про TintColor: ваниль сама
тинтит тот же boneShivPrefab, значит механизм на оружии работает.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y3pwyLpTrwz41qBjyjzNSA
This commit is contained in:
AlexCube
2026-09-10 02:07:31 +03:00
co-authored by Claude Opus 5
parent 6e1f42f053
commit 026e006c9c
6 changed files with 77 additions and 93 deletions
+29 -1
View File
@@ -893,9 +893,37 @@
whether melee weapons with ShowQuality="true" (inherited from the base knife)
render TintColor the same way. If it's still not black after this deploy, that's
the next thing to dig into (possibly needs ShowQuality or a cosmetic-slot
workaround), not a guess to make blind right now. -->
workaround), not a guess to make blind right now.
СОМНЕНИЕ СНЯТО 2026-09-10 по самой ванили: meleeWpnBladeT0BoneKnife задаёт себе
TintColor 107, 107, 71 (Data/Config/items.xml:2419) на том же самом
boneShivPrefab, то есть слот тинта у этого меша рабочий и на оружии с
ShowQuality тоже применяется. Копать тут больше нечего; осталось только
посмотреть глазами, достаточно ли чёрный получается клинок. -->
<property name="TintColor" value="0, 0, 0"/>
<!-- СВОЯ МОДЕЛЬ, ЗАГОТОВКА 2026-09-10 - ВКЛЮЧАТЬ ТОЛЬКО ВМЕСТЕ С БАНДЛОМ.
Строка ниже намеренно закомментирована: файла Resources/necroknife в моде ещё
нет, а Meshfile, указывающий в никуда, сломает нож прямо в живой папке мода -
игра читает именно её, и вечерний тест v1.0 идёт с этих же файлов.
Раскомментировать в тот момент, когда бандл лёг в Resources/, и не раньше.
Синтаксис: "#" - грузить из бандла, "@modfolder(NecromancerTome):" - путь от
корня этого мода, "?" отделяет путь к префабу ВНУТРИ бандла. Форма собрана из
двух подтверждённых кусков: ваниль пишет "#Entities/Trees?SnakeweedPrefab.prefab"
(Data/Config/blocks.xml), а поддержка "@modfolder:" лежит в Assembly-CSharp.
Живым примером форма не проверена - первый тестовый бандл с кубом её подтвердит
или опровергнет, до того как рисовать текстуру.
necroknife - имя AssetBundle, заданное префабу в Unity (инспектор, нижняя строка
AssetBundle); necroKnifePrefab.prefab - имя префаба ВНУТРИ бандла. Оба должны
совпасть с тем, что реально собралось, иначе предмет останется без модели молча.
Сборка - Mods/_NecromancerTome_private/tools/UnityEditorScripts/BuildNecroBundles.cs.
Геометрия остаётся ванильной, меняются материал и текстура, поэтому HoldType,
посадка в руке и анимации от базового ножа продолжают подходить без правок. -->
<!-- <property name="Meshfile" value="#@modfolder(NecromancerTome):Resources/necroknife?necroKnifePrefab.prefab"/> -->
<!-- MOD SLOTS ADDED 2026-09-07 (user request: "добавь в нож слоты для
модификаций... модификации там будут особые, именно для ножа
некроманта, а не для обычного ножа"). Tags has to be restated in full here
+6 -8
View File
@@ -44,7 +44,7 @@ namespace NecromancerTome
/// ПАУЗА. Begin ставит GameManager.Instance.Pause(true) один раз на всю сцену и больше её не
/// трогает: снимать паузу незачем, потому что любой выход отсюда ведёт в главное меню, а
/// GameManager.Disconnect() зовёт Pause(false) внутри себя (см. комментарий в
/// PortalStonePatch.ActivateBlackPortal). Как и вся остальная UI-часть этого мода, сцена
/// FinishEnding). Как и вся остальная UI-часть этого мода, сцена
/// рассчитана на локального игрока - Pause вообще работает только в одиночной игре, это
/// ограничение самой ванили, а не мода.
/// </summary>
@@ -258,14 +258,12 @@ namespace NecromancerTome
/// "Конец".
///
/// ВИДЕО ОТСЮДА УБРАНО 2026-09-09 по прямому указанию ("временно, убираем вообще видосы
/// из финала"). Сам вызов XUiC_VideoPlayer.PlayVideo целиком сохранён в
/// PortalStonePatch.PlayBlackPortalVideoLegacy - вернуть видео можно, не восстанавливая
/// код по кускам.
///
/// Файлы Video/FinalStay.webm, FinalReturn.webm и BlackPortal.webm УДАЛЕНЫ ИЗ МОДА
/// 2026-09-09 перед публикацией: все три были побайтовой копией ванильного
/// из финала"). Файлы Video/FinalStay.webm, FinalReturn.webm и BlackPortal.webm тогда же
/// удалены из мода перед публикацией: все три были побайтовой копией ванильного
/// TFP_Intro.webm (заглушка для тестов), а раздавать чужой ассет игры в релизе нельзя.
/// Настоящее видео класть под тем же именем.
/// Мёртвый код проигрывания видео (PortalStonePatch.PlayBlackPortalVideoLegacy и
/// константа с путём) убран 2026-09-10 - живой пример того же вызова, если видео
/// понадобится вернуть, остался в NoteFlashbackPatch.cs.
///
/// Задержки и наезда здесь нет намеренно: смотреть на чёрный экран пять секунд незачем,
/// текст показывается сразу.</summary>
+23 -6
View File
@@ -7,10 +7,21 @@ namespace NecromancerTome
/// <summary>
/// Duke's note ("Записка от Дюка", item noteDuke01) - user request 2026-08-30: "в момент
/// открытия записки, ставить игру на паузу и проигрывать флэшбек" (at the moment the note is
/// opened, pause the game and play a flashback). Reuses the exact pause+video pipeline
/// already built and tested for the Black Portal Stone (see PortalStonePatch.cs's
/// ActivateBlackPortal - GameManager.Instance.Pause/XUiC_VideoPlayer.PlayVideo, both APIs
/// decompiled there already, same reasoning applies unchanged here).
/// opened, pause the game and play a flashback). Built on the pause+video pipeline first
/// written for the Black Portal Stone; since the finale switched to text slides
/// (FinalSlides) and its dead video code was removed 2026-09-10, this patch is the only
/// place in the mod that still calls either API, so both write-ups live here now:
/// - GameManager.Instance.Pause(bool) - decompiled GameManager.updatePauseState: sets
/// Time.timeScale=0 for real, but ONLY takes effect in singleplayer (an SP-only check
/// baked into vanilla itself, not a limitation added by this mod) - a deliberate,
/// documented no-op in multiplayer rather than something silently broken.
/// - XUiC_VideoPlayer.PlayVideo(xui, VideoData, skippable, onFinished) - opens the same
/// fullscreen "VideoPlayer" window vanilla's own TFP intro/menu-background videos use.
/// Decompiled XUiV_Video confirms video playback isn't gated by Time.timeScale, so it
/// keeps playing correctly while paused. skippable=true (Cancel key) so a broken/
/// missing video file can't soft-lock the player - XUiV_Video.OnVideoErrorReceived
/// already auto-closes on a bad file on its own, this is just a second, player-facing
/// way out.
///
/// FINDING THE RIGHT PATCH POINT: noteDuke01 has no custom C# class of its own - it's a
/// plain Class="Eat" item (items.xml) whose entire "reading" experience is a vanilla trick:
@@ -42,8 +53,9 @@ namespace NecromancerTome
/// flashback -> read text -> confirm", rather than overlapping the video with the text box.
///
/// VIDEO FILE: Video/DukeNoteFlashback.mp4 - the user's real flashback clip (delivered
/// 2026-08-30 as exch/flashbback.mp4), kept as .mp4 rather than renamed to .webm like the
/// Black Portal placeholder: Unity's VideoPlayer component (confirmed by decompiling
/// 2026-08-30 as exch/flashbback.mp4), and the only video the mod still ships. Kept as
/// .mp4 rather than renamed to .webm like the since-deleted Black Portal placeholder:
/// Unity's VideoPlayer component (confirmed by decompiling
/// XUiV_Video - it wraps a plain UnityEngine.Video.VideoPlayer) natively decodes MP4/H.264 on
/// Windows via Media Foundation, and re-labeling an actual MP4 container as .webm would just
/// make it fail to decode (VP8/VP9 container expected, not H.264) - not decompiled/proven
@@ -54,6 +66,11 @@ namespace NecromancerTome
[HarmonyPatch(typeof(XUiC_MessageBoxWindowGroup), "ShowOkCancel")]
public static class Patch_XUiC_MessageBoxWindowGroup_ShowOkCancel_NoteFlashback
{
/// <summary>"@modfolder(NecromancerTome):..." is the exact mod-relative path syntax
/// XUiV_Video.startVideo resolves via ModManager.TryPatchModPathString (decompiled to
/// confirm - looks for "@modfolder(&lt;mod name&gt;):" and substitutes the mod's real
/// install path; "NecromancerTome" here is this mod's own ModInfo.xml Name, not its
/// DisplayName).</summary>
public const string NoteFlashbackVideoPath = "@modfolder(NecromancerTome):Video/DukeNoteFlashback.mp4";
/// <summary>Guards the re-entrant call this patch makes to the very method it patches
+19 -78
View File
@@ -159,45 +159,23 @@ namespace NecromancerTome
TeleportToBedroll(player);
}
/// <summary>Black portal confirmation + fullscreen video, user request 2026-08-30
/// ("диалоговое окно... вы уверены... Если Да, то игра останавливается и проигрывается
/// видео"). Real APIs, both decompiled directly:
/// - XUiC_MessageBoxWindowGroup.ShowCustom(xui, title, text, icon, setupCallback, ...) -
/// the same generic Yes/No popup vanilla itself uses (its own delete-item/disconnect
/// confirmations, etc). ShowOkCancel/ShowConfirmCancel exist too but hardcode their
/// button caption keys ("xuiOk"/"xuiCancel"/"btnConfirm") - ShowCustom's
/// _setupCallback is the only variant that lets the two buttons be captioned
/// "xuiYes"/"xuiNo" directly (both are real, already-localized vanilla keys, confirmed
/// against Data/Config/Localization.csv), matching the user's literal "да/нет"
/// wording. Buttons[0]/[2] (not [1]) is the same slot pairing ShowOkCancel/
/// ShowConfirmCancel themselves use internally - Buttons[1] is left unused, same as
/// vanilla's own 2-button dialogs.
/// - GameManager.Instance.Pause(bool) - decompiled GameManager.updatePauseState: sets
/// Time.timeScale=0 for real, but ONLY takes effect in singleplayer (an SP-only check
/// baked into vanilla itself, not a limitation added by this mod) - a deliberate,
/// documented no-op in multiplayer rather than something silently broken.
/// - XUiC_VideoPlayer.PlayVideo(xui, VideoData, skippable, onFinished) - opens the same
/// fullscreen "VideoPlayer" window vanilla's own TFP intro/menu-background videos use.
/// Decompiled XUiV_Video confirms video playback isn't gated by Time.timeScale, so it
/// keeps playing correctly while paused. skippable=true (Cancel key) so a broken/
/// missing video file can't soft-lock the player - XUiV_Video.OnVideoErrorReceived
/// already auto-closes on a bad file on its own, this is just a second, player-facing
/// way out.
/// <summary>Black portal confirmation dialog, user request 2026-08-30
/// ("диалоговое окно... вы уверены"). XUiC_MessageBoxWindowGroup.ShowCustom(xui, title,
/// text, icon, setupCallback, ...) - the same generic Yes/No popup vanilla itself uses (its
/// own delete-item/disconnect confirmations, etc), decompiled directly. ShowOkCancel/
/// ShowConfirmCancel exist too but hardcode their button caption keys ("xuiOk"/"xuiCancel"/
/// "btnConfirm") - ShowCustom's _setupCallback is the only variant that lets the two buttons
/// be captioned "xuiYes"/"xuiNo" directly (both are real, already-localized vanilla keys,
/// confirmed against Data/Config/Localization.csv), matching the user's literal "да/нет"
/// wording. Buttons[0]/[2] (not [1]) is the same slot pairing ShowOkCancel/ShowConfirmCancel
/// themselves use internally - Buttons[1] is left unused, same as vanilla's own 2-button
/// dialogs.
///
/// VIDEO FILE: Video/BlackPortal.webm NO LONGER SHIPS WITH THE MOD. It used to be a
/// byte-for-byte copy of vanilla's own TFP_Intro.webm (from
/// 7DaysToDie_Data/StreamingAssets/Video/), placed there 2026-08-30 as a test stand-in
/// ("Пока файл видео замени заглушкой") - deleted 2026-09-09 before the public release,
/// since redistributing a game asset is not ours to do. This path is dead until a real
/// video is dropped in under the same name; the method below is legacy anyway (the
/// finale plays text epilogues now, see FinalSlides).
/// "@modfolder(NecromancerTome):..." is the exact mod-relative path syntax
/// XUiV_Video.startVideo resolves via ModManager.TryPatchModPathString (decompiled to
/// confirm - looks for "@modfolder(&lt;mod name&gt;):" and substitutes the mod's real
/// install path; "NecromancerTome" here is this mod's own ModInfo.xml Name, not its
/// DisplayName).</summary>
public const string BlackPortalVideoPath = "@modfolder(NecromancerTome):Video/BlackPortal.webm";
/// Второй половины прежнего сценария - паузы и полноэкранного видео - здесь больше нет:
/// после "Да" управление уходит в FinalSlides (см. ActivateBlackPortal ниже), пауза живёт
/// там, а видео из финала убрано 2026-09-09. Разбор GameManager.Instance.Pause и
/// XUiC_VideoPlayer.PlayVideo переехал в NoteFlashbackPatch.cs - единственное место в моде,
/// где обе эти ванильные API ещё вызываются.</summary>
public static void ShowBlackPortalConfirmation(EntityPlayerLocal player)
{
LocalPlayerUI playerUI = LocalPlayerUI.GetUIForPlayer(player);
@@ -220,55 +198,18 @@ namespace NecromancerTome
}
/// <summary>ЗАМЕНЕНО 2026-09-09: раньше отсюда сразу стартовало полноэкранное видео
/// (BlackPortalVideoPath), теперь запускается финальная сцена из шести слайдов с текстом
/// (Video/BlackPortal.webm), теперь запускается финальная сцена из шести слайдов с текстом
/// - FinalSlides.Begin. Причина в BACKLOG.md ("концовка серией диалоговых окон вместо
/// видео"): видео не локализуется, а текст слайдов идёт обычной строкой через
/// Localization.csv. Пауза и выход в главное меню никуда не делись - и то и другое
/// теперь живёт внутри FinalSlides, а видео осталось финальным аккордом ПОСЛЕ выбора
/// концовки на последнем слайде.
///
/// Всё, что описано в комментарии к BlackPortalVideoPath выше, по-прежнему верно и
/// применяется - просто к двум новым файлам (FinalSlides.StayVideoPath /
/// ReturnVideoPath) вместо одного. Сама константа BlackPortalVideoPath больше не
/// используется и оставлена только как документация к разбору "@modfolder(...)" и
/// XUiC_VideoPlayer.PlayVideo, на который FinalSlides ссылается.</summary>
/// теперь живёт внутри FinalSlides. Видео из концовки убрано целиком 2026-09-09 -
/// ни здесь, ни в FinalSlides его больше нет.</summary>
public static void ActivateBlackPortal(EntityPlayerLocal player)
{
Debug.Log("[NecromancerTome] PortalStonePatch: black portal confirmed by owner=" + player.entityId + ", handing over to FinalSlides");
FinalSlides.Begin(player);
}
/// <summary>Прежняя концовка "сразу видео, потом главное меню". Больше ниоткуда не
/// вызывается (см. ActivateBlackPortal выше) - оставлена целиком, потому что весь разбор
/// Pause/PlayVideo/Disconnect в её комментариях остаётся актуальным и на неё ссылается
/// FinalSlides. Удалять при следующей уборке, если так и не понадобится.</summary>
public static void PlayBlackPortalVideoLegacy(EntityPlayerLocal player)
{
Debug.Log("[NecromancerTome] PortalStonePatch: black portal confirmed by owner=" + player.entityId + ", pausing + playing video");
GameManager.Instance.Pause(true);
LocalPlayerUI playerUI = LocalPlayerUI.GetUIForPlayer(player);
VideoData videoData = new VideoData { url = BlackPortalVideoPath };
XUiC_VideoPlayer.PlayVideo(playerUI.xui, videoData, true, delegate(bool skipped)
{
// EXIT TO MAIN MENU after the video, user request 2026-08-30 ("После видео нужно
// выходить из игры в главное меню") - fires whether the video played to the end
// or was skipped (Cancel key / a bad file), same as any other "the video is over"
// outcome. GameManager.Instance.Disconnect() is not a guess - it's the EXACT same
// call the real in-game ESC menu's own "Exit to Main Menu" button uses
// (decompiled XUiC_InGameMenuWindow.exitGame/BtnExit_OnPressed to confirm: it's a
// thin wrapper straight to this method). Handles everything a clean exit needs by
// itself - closes modal windows, un-pauses (calls Pause(false) internally, so no
// separate unpause call needed here), saves/shuts down the local server, and
// returns to XUiC_MainMenu - not reinventing any of that by hand. Replaces the
// earlier "thrownStonePortalBlackNotBound" tooltip placeholder entirely: with a
// real exit-to-menu ending, staying in-game and showing a tooltip no longer makes
// sense (BACKLOG.md item 6's "destination not decided" placeholder is now this
// exit itself, not a tooltip).
Debug.Log("[NecromancerTome] PortalStonePatch: black portal video finished (skipped=" + skipped + "), exiting to main menu");
GameManager.Instance.Disconnect();
});
}
/// <summary>BedrollPos comes from EntityPlayer.PersistentPlayerData (decompiled - reads
/// GameManager.Instance.persistentPlayers.GetPlayerDataFromEntityID(entityId)), the same
/// field the game's own respawn-at-bedroll flow reads (PersistentPlayerData.BedrollPos /
Binary file not shown.
Binary file not shown.