Як вмістити 320 млн точок даних у 3 ГБ RAM. Продовжую ламати стереотипи про GameMaker

Вітаю! На зв’язку знову TerraMedievale-Dev. Я продовжую роботу над грою своєї мрії, і я хотів би більш детально розгорнути те що я почав в своєму 0 Девлозі, про технічну сторону проекту.

Важливо: Це все вже імплементовано, бо корені йдуть в архітектуру проекту, котру я обрав правильно. Але не дивлячись на це, в моєму коді все одно присутні речі, про неефективність котрих я не знав. Ще є простір для оптимізації, але база вже працює, і вражає масштабами.

Де я був?

Останній девлог на DOU я публікував півтора місяці тому. Пауза виникла не через відсутність роботи, а через специфіку платформи: форум тут переважно технічний, тому мої «геймдизайнерські» оновлення (про концепти ШІ, землеробства та погоди) я залишив для свого Discord-сервера.

Проте за ці 1.5 місяці «під капотом» проєкту відбулася справжня революція. Я реалізував будівництво, бойову систему та почав роботу над напів-процедурною генерацією. Але найголовніше — я провів тотальний рефакторинг системи зберігання даних світу, щоб вона відповідала моїм амбіціям. Саме про це — про байт-орієнтований підхід та екстремальну оптимізацію — ми й поговоримо далі.

Масштаби і виклик

Як я писав раніше, моя мета — реалізувати 8К НПС на мапі 1.5Кх1.5К тайлів. Але якщо проведемо просту математику, то з’ясуємо, що це ~281 тайл на 1 НПС. Це ніщо — занадто тісно. Тому я вирішив збільшити мапу... В 7 разів. До 4Кх4К тайлів.

  • Раніше було: 1500×1500 (2.250.000 тайлів)
  • Сучасний план: 4000×4000 (16.000.000 тайлів)

Відповідно розмір демо теж збільшиться. Тут значення інші, мапу я вирішив збільшити в 44 рази:

  • Раніше було: 150×150 (22.500), потім збільшив до 500×500 (250.000)
  • Зараз: 1000×1000 (1.000.000)

Ця мапа вже є в редакторі, і вона дійсно розміром 1Кх1К. Я Вам більше скажу: вона завантажується за 5 секунд. В мене вже є зовнішній файл мапи, тобто пройтися повністю по мапі (двічі, така система) і визначити тип ландшафту займає 5 секунд. Ще пару секунд буде займати ініціалізація: поселень, дорог та руди в скелях.

АЛЕ, це не все. Як я казав, я це роблю на GameMaker, і воно за 5 секунд завантажує на віртуальній машині (VM). Якщо скомпілювати це через YYC (C++ Compiler), то в повністю експортованому вигляді завантаження займає менше секунди.

Але амбіції в мене ще більші. Це не просто мапа 4Кх4К, а ще 20 рівнів висоти. Таким чином в сумі виходить 320М точок даних. І нижче я поясню, як це все поміститься в оперативну пам’ять.

Ренесанс: Буфери і зсуви бітів

Амбіція мати мапу на 320 мільйонів точок даних (16 млн тайлів × 20 шарів інформації) ставить перед нами жорстке питання: як це все помістити в пам’ять?

Тут ми впираємося в архітектуру рушія. У GameMaker (та й у багатьох високорівневих мовах) кожна змінна — це «важка» сутність.

Навіть просте число 0 або 1 може займати 16 байт (через тип Variant/Double).

Якщо зберігати дані мапи в масивах: 320 000 000 * 16 байт = ~5 ГБ.

І це тільки «голі» дані і ЛИШЕ ОДНА ЗМІННА, без накладних витрат на самі структури масивів. Це гарантований краш.

Рішення: Низькорівнева пам’ять

Зараз вся мапа з 1 мільйона тайлів займає лише 9.5 МБ

Ці значення кажуть що один тайл займає лише 80 бітів (64 + 16). Таким чином уся мапа на уся мапа (із 320М точок даних) лише... ~3 ГБ, що вже не такі і великі значення.

Я вирішив перейти на буфери. Що це таке? Просто кажучи, це безперервна лінія бітів в пам’яті. Це гарантує, що кількість виділеної пам’яті буде завжди однакова (Ніколи не змінюватися), бо я вже в коді пишу скільки байтів виділити.

На кількість байтів в буфері впливає розмір мапи і макрос.

Таким чином це дає мені ПОВНИЙ контроль над пам’яттю і даними. Ось як я вміщаю всі данні про тайл в 80 бітів.

  • 0 байт — ID Підлоги і Стелі (по 4 біти, 15 значень)
  • 1 байт — Одночасно ID Стіни і очки рослин (8 бітів, до 255 зн.)
  • 2 байт — Яка рослина посіяна в тайлі (15 зн.)
  • 3 байт — Вологість тайлу (до 127 зн.) та наявність бур’яну (1 зн.)
  • 4 байт — Плодовитість тайлу (До 255 зн.)
  • 5 байт — HP тайлу (До 255 зн.)
  • 6–7 байти — Entity ID (До 65К зн.)

Також окремо існує інший буфер, для айді кімнат, там кожен тайл має також до 65К значень кімнат (16 бітів)

Як цим керувати?

Щоб керувати конкретними бітами існують зсуви. Вони виглядають ось так:

Я упакував координату тайлу в одну змінну (16 байт), замість структури з двох (32 байт + оверхед)

Функція знаходження адреси тайлу. Вона прив’язано до координат тайлу.

Функція геттер для підлоги. Беремо з буфера байт, потім зсуваємо біти.

І я відповім на ваше питання — «Але функції теж мають оверхед».

Безумовно, але в такій системі безпека важливіша. Проте там, де виклики відбуваються дуже часто, я просто зробив макроси, що літають і на VM (Віртуальна машина GM2). Завдяки макросам я зміг зменшити час на другий прохід по мапі для ініціалізації. Було 10 секунд, стало 3 (Ефективність 70%).

Стежте за розробкою

Якщо ви дочитали до кінця — значить, вам цікаві складні системи так само, як і мені.

Я запрошую вас у свій Discord-сервер. Там я буду:

  • Публікувати ексклюзивні скріншоти, які не потраплять у статті.
  • Радитися з вами щодо механік (ваша думка вплине на гру).
  • Набирати перших тестерів для закритих білдів.

👉 Приєднатися до Discord: discord.gg/DSvhXSsx6f

Підписуйтеся на Telegram-канал @gamedev_dou, щоб не пропустити найважливіші статті і новини про геймдев

👍ПодобаєтьсяСподобалось5
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

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

Ви праві. Безумовно всі ці методи відомі (Чанки, лоди, прогружати з сіду, зберігати лише зміни світу)

Але я хотів би реалізувати ідеальну симуляцію, і чим більше точних даних я зможу зберігати — тим краще. До того ж додатковою метою статті було показати який масштаб можна тримати в пам’яті при максимальній оптимізації.

А коли всі заходи оптимізації будуть прийняті (Котрі не на часі зараз), то я все одно зможу тримати в активній пам’яті величезну территорію (Не тільки видиму зону), це буде вражати якістю і точністю симуляції.

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

Подивимось. Можете стежити за розробкою :D

Підписатись на коментарі