Обновить
-3

Пользователь

0,1
Рейтинг
Отправить сообщение

Ну, декаданс не мы придумали, тема известная и рабочая. Как и иные экстримы, впрочем.

Я просто идиллической картинкой из статьи был... впечатлён ;)

Похоже, мы всегда недооценивали идею Кирилла

Концепт игры

Коротко: 3D экшен с тремя игровыми фракциями — лесные эльфы, дворцовая охрана и злодей — каждая с уникальным геймплеем, целями и стилем прохождения. Игрок выбирает фракцию и проходит кампанию, открывает навыки, участвует в динамических стычках и миссиях в открытом мире с деревнями, лесами, дорогами и караванами для грабежа.

Выбранный объём и допущения

Я предполагаю, что под «корованы» вы имели в виду караваны — передвижные торговые колонны, которые можно грабить. Я также беру за основу одиночную кампанию с опцией кооператива и PvP-арен. Если нужно изменить — скажите, и я адаптирую.

Фракции и их особенности

  • Лесные эльфы

    • Стиль: скрытность, паркур по деревьям, дальний бой с луком и ловушки.

    • Цели: защищать лес, саботировать дворцовые отряды, грабить караваны, спасать деревенских.

    • Уникальные механики: маскировка в листве; перемещение по кронам; духи леса как времальные помощники.

  • Дворцовая охрана

    • Стиль: тяжёлая броня, стройная тактика, осадные орудия.

    • Цели: удерживать контроль над дорогами и поселениями, охранять караваны, подавлять мятежи.

    • Уникальные механики: построение заслонов; командные приказы NPC; осадные машины.

  • Злодей

    • Стиль: гибрид магии и хитрости; может вербовать наёмников и создавать ловушки.

    • Цели: сеять хаос, подкупать фракции, захватывать ключевые точки.

    • Уникальные механики: влияние на мир через интриги; возможность менять правила миссии (например, вызвать разбойников).

Мир и уровни

  • Открытый региональный мир: леса, дороги, деревни, дворцовый комплекс, караванные маршруты.

  • Деревянные домики в лесных поселениях, укреплённые посты вдоль дорог, скрытые тропы в кронах.

  • Динамическая система событий: рейды, караваны, патрули, сезонные погодные эффекты, которые влияют на видимость и передвижение.

Ядро геймплея и механики

  • Боевая система: ближний бой с комбо, парирование и уклонения; дальний бой с баллистикой; магические способности с кулдаунами.

  • Стелс и паркур: эльфы получают бонусы за скрытность; паркур по деревьям открывает альтернативные маршруты.

  • Грабёж караванов: караван — движущаяся цель с охраной; можно атаковать в пути, устраивать засады или подкупать охрану. Награды: золото, ресурсы, редкие предметы.

  • Система репутации: действия игрока влияют на отношение фракций и NPC; грабёж караванов повышает репутацию у разбойников, понижает у торговцев.

  • Управление отрядами: дворцовая охрана может отдавать приказы NPC; злодей вербует наёмников; эльфы используют духовых союзников.

Прогрессия и экономика

  • Дерево навыков для каждой фракции с ветками: бой, тактика, выживание, магия.

  • Лут и крафт: ресурсы с караванов и окружения; улучшение оружия и снаряжения; создание ловушек и зелий.

  • Экономика мира: торговцы реагируют на безопасность дорог; успешные грабежи повышают цены на редкие товары.

Примеры миссий и сценариев

  • Эльфы: «Ночная засада» — остановить караван, не убивая мирных торговцев; спасти похищенных.

  • Охрана: «Эскорт каравана» — провести караван через лес, отбивая засады; защитить ценный груз.

  • Злодей: «Подкуп и саботаж» — подкупить командира охраны и устроить диверсию в деревне.

  • Случайные события: лесной пожар, нападение хищников, смена погодных условий.

Искусственный интеллект и баланс

  • AI патрулей с разными поведениями: агрессивные, осторожные, кордоны.

  • Реакция на шум и следы: стелс-детекторы, следы на земле, разведчики.

  • Баланс: сильные стороны фракций компенсируются слабостями; система матчмейкинга для PvP по уровню и стилю игры.

Технические и художественные решения

  • Движок: Unreal Engine или Unity (в зависимости от команды и бюджета).

  • Архитектура: модульная — боёвка, AI, мир, экономика отдельно.

  • Арт: стилизованный реализм; тёплые деревянные текстуры для деревень, зелёные и мшистые тона для леса, контрастные металлы для дворца.

  • Звук: амбиент леса, динамическая музыка, звуки шагов по листве, сигналы караванов.

Мультиплеер и режимы

  • Кооператив: до 4 игроков в кампании; роли дополняют друг друга.

  • PvP: фракционные битвы за контроль точек; режим «караван против налётчиков».

  • Асинхронные события: мировые ивенты, где действия одних игроков влияют на мир других.

План прототипа и следующие шаги

  1. Прототип боёвки (две фракции, базовые атаки и уклонения).

  2. Мини-карта мира с одной деревней, дорогой и караваном для грабежа.

  3. AI патруля и система обнаружения.

  4. Прототип миссии эскорта/засады.

  5. Игровой тест и баланс; собрать фидбек и расширять контент.

Если хотите, я могу дальше:

  • расписать детально одну миссию шаг за шагом;

  • предложить набор способностей для каждой фракции;

  • сделать план разработки на 3–6 месяцев с ролями команды и приоритетами.

Что предпочитаете дальше — детализировать миссию, способности или план разработки?

https://www.youtube.com/watch?v=DzUcBE5DKGs

Не мог не оставить это здесь ;)

А великий и многими любимый Пётр Ильич в вашей реплике - он как-бы метафора упомянутых мною богемных экспатов или самого Берлина в описываемую эпоху?

Нравится мне, когда восторженно описываются все эти "люди с неопределённым статусом", все эти движухи до упора - и забывают рассказать о героиновой волне, детско-молодёжной проституции включая гомо и прочей питательной среде всего этого ;)

Ещё прикольно, что у многих (большинства?) упомянутых богемных экспатов в те годы как раз был жестко-героиновый период творчества, так скажем - совпадение? ...хотя они, конечно, и не в берлине бы нашли.

Справедливости ради, JIT-компиляторы вполне себе не-детерминистик, особенно те, что используют динамическое профилирование и tiered оптимизации.

...но уровень не-дерминированности иной, конечно ;)

Отличная серия, спасибо.

...эту ещё не читал, но одобряю ;)

Ну вот именно это, да: байтоебля, ковбои, "за любой unsafe код насмехаются", "удачи вашему продакшну" - именно в этом статья и... на любителя.
Что статья, что ответ - очень aligned, иф ю ноу вот ай мин.

Итак, статья.

Во-первых, я читал её давно, когда она была опубликована. Сейчас, когда увидел её в списке ваших - вспомнил, в том числе то, что был "во многом не согласен" и особенно - с достаточно безапеляционным тоном рекомендаций. При этом, запомнил её как полезную.
Сейчас перечитываю, отвечу по пунктам.

Что однозначно хорошо - напоминание про работу GC и связанные риски неуправляемых указателей (fixed/pinned контексты и риски утекания указателей за их пределы).

Что, возможно, ещё более важно - напоминание о хранении невалидных указателей в управляемых ref var - типа ref arr[-1] или ref arr[arr.Length + 1].
Об этом вполне возможно никогда и не задуматься, сам исправлял подобные собственные ошибки несколько лет назад.

С чем не согласен:

"9. Удаление проверок границ (bounds check)"
Там все советы можно свести к "не обходите проверки границ". Что, как по мне - плохой совет, потому, что если уж встал вопрос о том, что стоит от них избавиться - значит нужно избавиться.
Есть масса вариантов, которые никакие эвристики JITа не ускорят: random access, доступ к элементам в "сегменте" массива, границы которого вычисляются сложным алгоритмом или вообще хранятся в условном Dictionary<SegmentKey, (int offset, int length)>, обработка в не-заинлайненом методе.
При этом совет использовать Debug.Assert для выявления ошибок - это чисто проверка того, что ваши тесты запущенные в Дебаг-режиме написаны для happy pass.
Я бы советовал подготовить необходимые данные и карты/рейнжи, убедиться, что они валидны - а потом использовать их без лишних проверок.

10. Объединение доступа к памяти (Memory access coalescing)
Тоже самое. Напрмер, у меня был тип, содержавший список структур, состоявших из множества полей примитивных типов (от byte до long), тип использовался как ключ в Dictionary. Угадаете, как были написаны GetHashCode и Equal? - да, как GetHashCode/Equal над спаном байтов начиная с адреса list[0] и до list[count].
И это был самый быстрый и эффективный вариант, остальные работали в разы медленнее.
О чём я бы отдельно напомнил в этом разделе - о паддингах, которые могут содержать мусор.

12. Бинарная (де)сериализация структур с паддингами или non-blittable членами
С non-blittable членами всё понятно, их нужно обрабатывать отдельно.А вот с blittable, и даже с паддингами - почему бы и нет?
Я бы здесь отдельно напомнил об endianness - должны совпадать для источника и получателя, но в целом - вполне себе оптимизация для контролируемых случаев.

13. Null управляемые указатели
Вполне валидный случай, как и null для nullable переменных - почему нет?
Я бы советовал проверять с Unsafe.IsNullRef и пользоваться со спокойной совестью.

15. Буферы фиксированного размера (Fixed-size buffers)
"буферы фиксированного размера могут иметь ненулевое содержимое в определенных сценариях" как риск, так и экономия на очистке - главное об этом помнить.

16. Передача непрерывных данных как указатели + длины
Тут вообще не понимаю проблемы.
Самый дешевый способ передать (или хранить в ref struct) буфер для bounds unchecked обработки.
Не забываем, что new Span/AsSpan сам по себе проверяет границы - а нам, может быть, уже и не надо? - разве сто создавать спан с помощью MemoryMarshal.CreateSpan(ref T reference, int length), ха-ха. И на каждом обращении к индексеру (не в "удачном" цикле) - тоже проверяет.
Дальше, на х64 спан занимает 16 байт, тогда как размер без паддинга - 12. Для единственного инстанса ок, но представим, что вы храните несколько ссылок на буферы в ref struct, которая кроме этого содержит и множество полей - вполне себе оверхед при передаче по значению.

18. Ручной IL код (например, System.Reflection.Emit и Mono.Cecil)
Тут всё просто: сложно в написании и отладке - но раз надо - значит надо.

19. Неинициализированные локальные переменные [SkipLocalsInit] и Unsafe.SkipInit
По мне так сильно преувеличенные риски. Во-первых, GC-переменные JIT всё равно обнуляет. Во-вторых - C# всё равно не позволяет обратиться к неинициализированной переменной.
Отдельно о Unsafe.SkipInit: представьте, у вас тяжелая структура со множеством полей. Ваш конструктор в любом случае инициализируют все их них, так зачем вам предварительная очистка?
Это не говоря о том, что как минимум НЕТ8 (а то и 9), если у вас в структуре overlapped поля (FieldOffset) - то он ухитрялся эмитить MSIL для индивидуальной очистке каждого из этих полей. Не смотрел, что было в асме и не следил, как работает 10/11 - но такое вот было.

Примерно так.

В целом, достаточно было бы объяснить поведение рантайма во всех этих аспектах и свазать "соблюдайте осторожность и сохраняйте здравый смысл" :)
А безапеляционные "советы" выглядят странно.

При этом статья полезная, то, что опубликована и на русском - ещё лучше.
А работа по переводу - так и вообще выще всяких похвал.

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

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

то что вчера надо было костылить сегодня уже работает как надо

При всём моём восхищении от развития НЕТ рантайма, я совершенно уверен, что многие проблемы никогда не смогут быть решены на этом уровне. Так что костылить - вполне себе необходимый навык ;)

Это всё будет требовать unsafe {} контекст.

Будет.

Но и определение unsafe context изменится, и как по мне - так к лучшему, и вполне можно будет держать его компактным и при желании скрытым в приватном скоупе.

Большинство обычного вида циклов не нуждаются в этом, jit вставит оптимальный код как есть

Другой бы спорил, а я не стану.

Но что умеешь - за плечами не носить, как говорится. Лично я был бы рад, если бы в своё время имел возможность начитаться о всякого рода трюках чисто про запас - меньше пришлось бы тратить времени на "изобретения", когда они реально понадобились.

Там, где нужно гарантированно избавиться от bounds checking - ref var, MemoryMarshal.Get*Reference + Unsafe.Add.

При желании, с их помощью можно соорудить цикл с обратным счётчиком и при этом "прямым" доступом к данным - экономим инструкции на загрузке предельного значения в регистр и сравнении счётчика с регистром.

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

Это вполне ожидаемо - АОТ код просто не может быть оптимизирован на столько же, на сколько может быть оптимизирован код JITa. Отсюда же и аллокации, и скорость.

Для исправления скорости интересно было бы попробовать скомпилировать с собранным заранее профилем - я в этом совершенно не имею опыта, но чисто логически - может и поможет. Может быть и с некоторыми аллокациями поможет за счёт guarded devirtualization.

Если проведёте эксперимент - поделитесь результатом, пожалуйста, для общего развития.

Если я вас ни с кем не путаю, то уже во второй ветке я читаю эту вашу интерпретацию боксинга.

Так вот, она неверная.

Ниже вам верно ответили: боксинг - это превращение инстанса типа без заголовка (в .нете - всегда struct) в инстанс типа с заголовком (в .нете всегда любой ссылочный тип)

Интерфейс в .нете - всегда ссылочный тип с заголовком (вкл. vtable)

Не обязательно верить мне, достаточно прочитать о боксинге в документации .нета/clr.

Если же вы так уверены в своей интерпретации - можно получить подтверждающие ссылки на какие-либо авторитетные источники?

Спасибо.

А какие там нюансы, вкратце?

Боксинг это способ впихнуть невпихуемое.

Любопытная интерпретация, но, боюсь, неверная.

Я не утверждал, что он не специфичный.

А вот каждая опробованная мною на данный момент модель старается его трактовать и оценивать как типичный, и в этом проблема.

Да, они "видят" "перформанс-фокус" и "хай оптимизэйшн (хак) денсити", но пока не нагрузишь беседу контекстом и не станешь задавать очень конкретные специфичные вопросы по изучаемой теме -толку очень мало. Опечатки могут поправить и сломать что-нибудь.

При этом, я не отрицаю пользу - но точно не в написании узкоспециализированного или высокооптимизированного кода.

И ещё хорошее:

why Performance engineering quality is just 9?

Because 10/10 means “near-flawless with minimal tradeoffs,” and this code still has measurable performance risk points despite being very strong.

Why 9, not 10:

• Contention risk remains in some shared paths (locks/spin locks, pooled shared structures).

• Very branch-heavy execution logic can hurt branch prediction in mixed workloads.

• Tracing/cancellation hooks add conditional overhead in hot loops (well-managed, but still overhead).

• Complex async/lifecycle machinery is optimized but can regress under edge-case load patterns.

No proof here of absolute best-in-class results across all target TFMs and workload shapes.

So: it is excellent performance engineering, but not “maximal certainty under every production scenario,” which is what 10 would imply.

Типа, ну а вдруг чото не так? И чем докажешь вообще?

При том, что специальные код-генераторы/"чистильщики" и сгенерированный ими hot-clean-probes-free-path версию тех же самых имплементаций он не заметил.

1
23 ...

Информация

В рейтинге
3 218-й
Зарегистрирован
Активность