7768541f12ccfc75e7fba13ae2c7eb97a4919c3b
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7768541f12 |
Торговцы-призраки: настоящая прозрачность тела, матовость, консоль
Прозрачность у торговцев управляла только бородой. Причина была напечатана
зондом ещё при первом заходе: у шейдера тела (Game/Character) нет НИ цвета с
альфой, НИ режима смешивания - оба рычага ApplyTransparency существуют только
у шейдера волос (Game/Autodesk). Никакое значение альфы тело бы не тронуло.
Сначала добавлен третий рычаг - _Fade, собственный рычаг игры:
EntityModel.SetFade пишет ровно это свойство и отбирает материалы проверкой
HasProperty("_Fade") && shader.name.Contains("Game/Character"), а стоящий рядом
SetVisible(renderFade > 0.01f) закрывает направление: 1 = сплошной, 0 = исчез.
В игре выяснилось, что шейдер реализует его screen-door дизерингом - "тело
гаснет, но идёт мелкой сеточкой". Рычаг рабочий, но пиксели не смешиваются, а
выбрасываются, и никакое число этого не исправит. Оставлен как режим dither.
РАБОЧЕЕ РЕШЕНИЕ - перешивка тела на шейдер волос, у которого есть прозрачный
проход. Доказательство лежало на той же модели в том же кадре: борода всё это
время гасла плавно. Шейдер берётся С МОДЕЛИ - первый материал, умеющий
смешивать (есть цвет с альфой И режим смешивания); Shader.Find оставлен
запасным путём, потому что мод уже дважды получал null/негатив от семейства
Unlit. Решение принимается по способностям материала, имя шейдера нигде не
зашито. Переносятся только альбедо и нормаль: _RMOE - упакованная
roughness/metallic/occlusion/emission, а _MetallicGlossMap ждёт металл в R и
гладкость в A, каналы не совпадают, и связывание "на авось" даёт мокрый пластик
или негатив. Цена названа прямо: тело теряет собственную световую модель
шейдера персонажа и получает стандартную.
МАТОВОСТЬ по просьбе пользователя - три рычага, ломаются по-разному:
_Glossiness в 0 (чистая математика шейдера, работает всегда - несущая
половина); _SpecularHighlights и _GlossyReflections в 0 ВМЕСТЕ с ключевыми
словами _SPECULARHIGHLIGHTS_OFF / _GLOSSYREFLECTIONS_OFF, потому что это
[ToggleOff]-пара и запись одного флоата не делает ничего; карты глянца
очищаются, если непусты, - карта побеждает флоат. Оба keyword'а -
shader_feature, Unity вырезает такие на сборке, если их не выставляет ни один
материал игры, поэтому шершавость сделана основным рычагом, а не запасным.
Применяется ко всем призрачным материалам: волосы нарисованы тем же шейдером и
сохраняли свой блеск, а матовое тело под глянцевой бородой читалось бы хуже.
КОНСОЛЬНАЯ КОМАНДА necroghost (алиас necrotrader): проценты прозрачности,
blend/dither, reset. Балансировать рендер можно только глядя на него, а шаг без
команды стоил пересборки, перезапуска и ~4 минут пешком до торговца. Проценты,
а не альфа: это единица, в которой просьба формулировалась, и они идут в разные
стороны. Регистрации нет и не требуется - SdtdConsole.RegisterCommands ищет
через ReflectionHelpers.FindTypesImplementingBase, который обходит
ModManager.GetLoadedAssemblies(), а LoadMods() стоит на три строки раньше
RegisterCommands(). IsExecuteOnClient = true: команда меняет пиксели.
Две мины, обе реальные. Повторное применение не должно умножать: материалы
кэшируются, и sharedMaterials после первого прохода возвращает наши же клоны,
так что наивный повторный свип дал бы 0.9, потом 0.8 = 0.72; запоминается
базовое значение, живое всегда base * GhostAlpha. Запятая: StringParsers не
зависит от локали, но читает "," как разделитель ТЫСЯЧ, и "necroghost 12,5"
молча стало бы 125 - запятая заменяется на точку до парсинга.
DefaultGhostAlpha 0.9 -> 0.3: 70% прозрачности, найденные в игре. Путь был
1% -> 10% -> 70%, и последний скачок не смена вкуса - на 10% тело ещё
дизерилось, а дизеринг терпим лишь пока слаб. Поэтому же переписана заметка
"ниже ~0.7 силуэт разваливается": предел принадлежал технике, а не глазу.
---
Ghost traders: the body really blends, matte finish, console command
The transparency only ever reached the beard. The probe had already printed
why: the body's shader (Game/Character) has NEITHER a colour with an alpha NOR
a blend mode - both of ApplyTransparency's levers exist only on the hair's
shader (Game/Autodesk). No value of the alpha was ever going to touch it.
A third lever was added first - _Fade, the game's own: EntityModel.SetFade
writes exactly that property and guards it with HasProperty("_Fade") &&
shader.name.Contains("Game/Character"), and the SetVisible(renderFade > 0.01f)
sitting next to it settles the direction: 1 = solid, 0 = gone. In game the
shader turned out to implement it as screen-door dithering - "the body fades,
but goes to a fine grid". The lever works, but pixels are thrown away rather
than blended, and no number fixes that. It is kept as the dither mode.
WHAT ACTUALLY WORKS is re-shading the body onto the hair's shader, which does
have a transparent pass. The existence proof was on the same model in the same
frame: the beard had been fading smoothly all along. The shader is taken OFF
THE MODEL - the first material that can blend (a colour with an alpha AND a
blend mode); Shader.Find is kept only as a fallback, because this mod has twice
been handed null or a negative by the Unlit family. The decision is made on
what a material can do; no shader name is hard-coded. Only albedo and normal
are carried over: _RMOE is a packed roughness/metallic/occlusion/emission map
while _MetallicGlossMap wants metallic in R and smoothness in A - the channels
do not line up, and wiring them by hope is how a character ends up looking like
wet plastic or a negative. The trade is stated plainly: the body loses the
character shader's own lighting response and gets standard lighting instead.
MATTE, as requested - three levers that fail differently: _Glossiness to 0
(plain shader maths, always works - the load-bearing half); _SpecularHighlights
and _GlossyReflections to 0 TOGETHER WITH the _SPECULARHIGHLIGHTS_OFF /
_GLOSSYREFLECTIONS_OFF keywords, because they are a [ToggleOff] pair and
setting the float alone does nothing; and the gloss maps cleared if anything is
in them, since a map beats the float. Both keywords are shader_feature, which
Unity strips at build time if no material in the game sets them - which is why
roughness is the main lever and not the fallback. Applied to every ghost
material: the hair uses the same shader and kept its own shine, and a matte
body under a glossy beard would have read worse than either.
CONSOLE COMMAND necroghost (alias necrotrader): transparency in percent,
blend/dither, reset. A rendering balance can only be judged by looking at it,
and without the command each step cost a rebuild, a restart and a four-minute
walk to a trader. Percent rather than alpha: percent is the unit the request
was made in, and the two run in opposite directions. No registration is needed
- SdtdConsole.RegisterCommands goes through
ReflectionHelpers.FindTypesImplementingBase, which walks
ModManager.GetLoadedAssemblies(), and LoadMods() runs three lines before
RegisterCommands(). IsExecuteOnClient = true: the command changes pixels.
Two real traps. Re-applying must not compound: materials are cached and
sharedMaterials hands back our own clones after the first pass, so a naive
second sweep would give 0.9, then 0.8 = 0.72; the base value is remembered and
the live one is always base * GhostAlpha. The comma: StringParsers is
culture-independent but reads "," as a THOUSANDS separator, so "necroghost
12,5" would silently have become 125 - the comma is turned into a point first.
DefaultGhostAlpha 0.9 -> 0.3: the 70% transparency settled on in game. The road
was 1% -> 10% -> 70%, and the last jump was not a change of taste - at 10% the
body was still dithering, and a dither is bearable only while it is faint. For
the same reason the old "below ~0.7 the silhouette falls apart" note was
rewritten: that limit belonged to the technique, not to the eye.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XN8J75vnum2qAVrtRUMKf7
|
||
|
|
29431990f6 |
Хранилище браслета переживает перезапуск; торговцы чёрно-белые
Исправляет первый баг-репорт мода на Nexus (youkia96581, 11.09.2026): "Items stored in the space bracelet will disappear after leaving the game and going online again". Причина была записана в коде как нерешённая: PlayerVaults - обычный статический Dictionary, save/load не существовало. ХРАНИЛИЩЕ ТЕПЕРЬ ЖИВЁТ В PlayerDataFile, рядом с рюкзаком игрока. Так решено после вопроса пользователя "почему не сделать принцип как у ящика?": ящик хранит вещи тем, что они лежат в чанке (у TileEntity единственный конструктор TileEntity(Chunk)), а браслету нужен был дом в чём-то, что движок и так сохраняет. Четыре постфикса - FromPlayer/Write/Read/ToPlayer, блоб с магией "NECROVLT" и явной длиной дописывается после всего ванильного. Байтовая часть - в сателлитной сборке: PooledBinaryWriter.Write не резолвится из основного проекта (CS7069), как и у PyramidWardWriteHelper. Два дефекта, найденные и убитые по дороге живыми тестами: 1. ModEvents.WorldShuttingDown приходит ПЕРЕД финальным сохранением игрока (GameManager.SaveAndCleanupWorld: событие на IL_0026, SaveLocalPlayerData на IL_00c4). Обработчик, чистивший там кэш, затирал хранилище на каждом корректном выходе. Обработчик убран; свежесть решает авторитетность ToPlayer, а не таймер. 2. Пустой сессионный кэш трактовался как "хранилища нет" и записывался поверх настоящего. Путь восстановления имеет право не сработать, удалять он права не имеет - добавлена страховка LastLoadedVault. Проверено в игре: положил -> вышел -> запустил заново -> вещи на месте, блоб на 54 байта сверен в .ttp побайтово. ТОРГОВЦЫ (npcTraderJoel/Rekt/Bob/Hugh/Jen) - чёрно-белые. Шейдер НЕ подменяется: материал клонируется со своим шейдером, меняется только текстура альбедо на обесцвеченную копию, так что свет, нормали и скиннинг остаются движковыми. Альбедо ищется обходом свойств шейдера, а не по имени: тело - Game/Character/_Albedo, волосы - Game/Autodesk/_MainTex. Плюс 1% прозрачности с сохранением _ZWrite. Опрос раз в 2 с, потому что торговцы стримятся на подходе, а Джен собирается в рантайме. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEXvXg1FSAQJHrvYbeAKqq |
||
|
|
ab1b3eadaf |
Версия 2.0: свои модели ножа и крови, своя краска блоков через патч атласа
Нож некроманта и Кровь некроманта получили собственные модели, а Пирамида духов - собственную поверхность. Три разных способа, каждый выбран по тому, как устроен сам предмет. НОЖ И КРОВЬ - свои префабы в бандлах мода. Форма записи "#@modfolder(...)?prefab" подтверждена живым примером; геометрия у обоих ванильная, меняются материал и текстура. Текстуры генерируются скриптами (см. _private/tools), а не рисуются: правка вида сводится к правке констант и одному запуску. Нож: состаренная кость, почти чёрная обмотка, пурпур во впадинах, плюс слой под ручную роспись рун - он подмешивается в альбедо и в эмиссию, поэтому руны светятся. Слой пользовательский, генератор его никогда не перезаписывает. Положение росписи посчитано по геометрии: развёртка выгружена из меша, и подобрано смещение, при котором вся роспись ложится на одну плоскую грань. Раньше она перегибалась через кромку, обращённую к игроку. Кровь: банка вместо мешка. Заодно чинится расхождение, жившее с самого начала - описание предмета говорило "Банка, наполненная кровью", а наследуемый medicalBloodBag показывал sackPrefab, обычный мешок. Жидкость перерисована по маскам мешей, а не перекрашена тинтом: тинт предмета на этот меш не действует вовсе, у шейдера Game_EntityTintMaskSSS выигрывает _Color материала. ПИРАМИДА - своя краска в атласе блоков через собственный Harmony-патч. Ваниль своих текстур блоков не умеет: Texture у блока это индекс в готовом атласе, а запись краски несёт только TextureId/PaintCost/Group/SortIndex и никогда путь к картинке. Поэтому CustomBlockPaintPatch дописывает наш слой в массивы атласа на лету. Путь через свою модель (Shape="ModelEntity") пробовался и отложен: там остались нерешёнными столкновения и маджента на дальних экземплярах. Краска лучше тем, что блок остаётся обычным Shape="New" - со всеми работающими столкновениями, наведением по E и правильной посадкой, - а поверхность у него своя. Побочно краска доступна кисточкой под именем "Некротический прах". Параметры атласа не угаданы, а замерены в игре (BlockAtlasProbePatch): 512x512, DXT1 для альбедо и DXT5 для нормалей со specular, 10 мип-уровней, массивы нечитаемые - отсюда GPU-копирование и явные настройки импорта текстур. Зонд оставлен намеренно: номер краски в blocks.xml (608) это длина ванильного uvMapping, и после обновления игры он может сдвинуться - зонд печатает фактические числа при каждом запуске. Патчи обёрнуты целиком: они работают внутри загрузки игры, где вылетевшее исключение срывает шаг загрузки. Resources/necropyramid в коммит не идёт - на него никто не ссылается. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W5F3AVwsusZHMqPBcSQcVJ |
||
|
|
026e006c9c |
Убран мёртвый код проигрывания видео; заготовка своей модели ножа
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 |
||
|
|
e8f064f5ec |
Книга некроманта 1.0 — первая публичная версия
Мод для 7 Days to Die 3.2: навык «Некромантия», растущий от счётчика убитых зомби, тёмное оружие с шестью собственными модами, призывная нежить, пирамида духов и сюжетный финал через Чёрный портал. Локализация на 13 языках. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MaNro5hAGTzcQ7rJNN2tCX |