Это Dynamic Data System для моей игры...

На коленке
На коленке

Искусственному интеллекту я объяснял на ~40 страницах А4, что это такое, как оно работает.

Поэтому вкратце:

1. Обобщение работы с данными, однородное хранение (через 8-байтовую переменную).

2. Кэширование результата (именованные поля в таблице данных).

3. Автокоррекция значения в таблице данных (обрезка).

4. Поддержка модификаторов (с сохранением исходного значения).

5. Вся архитектура подразумевает возможность работы на различных реализациях контейнеров (можно уложить данные в плоские массивы и сериализировать в "один клик").

В: Для чего?

О: Мне так понадобилось.

Основная причина - возможность удаления модификаторов без влияния на остальную часть цепочки вычислений.

Реализация таблицы данных на std::unordered_map дала порядка ~300 мс на обработку 5'000'000 модификаторов. Перевод таблицы на std::vector выдал ~70 мс:

// ... std::cout << "Packet test\n"; auto start = std::chrono::high_resolution_clock::now(); { for( int i = 0; i < SLOTS; ++i ){ e.table->bus().at( i ).opts = game::arch::s_cell::e_opt( e.table->bus().at( i ).opts | game::arch::s_cell::CURRENT_ACCUM /* | game::arch::s_cell::BOUND_UPPER */ | game::arch::s_cell::TYPE_INT ); if( rand() % 2 ){ e.table->bus().at( i ).opts = game::arch::s_cell::e_opt( e.table->bus().at( i ).opts | game::arch::s_cell::BOUND_UPPER ); e.table->bus().at( i ).b.i = ( rand() % 60 ) * ( rand() % 10 ); } } for( long long i = 0; i < 5'000'000; ++i ){ auto idx = rand() % SLOTS; a.prop = idx; a.opts = game::e_opt::POWER; auto rs = rand() % 3; switch( rs ){ case 0: a.inopt( game::e_opt::DATA_SET ); a.dat.inint( rand() % 60000 ); break; case 1: a.inopt( game::e_opt::DATA_ADD ); a.dat.inint( rand() % 9 ); break; case 2: a.inopt( game::e_opt::DATA_SUB ); a.dat.inint( -rand() % 9 ); break; } e.table->insert( a, 0 ); } auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>( end - start ); std::cout << "Insert 5'000'000 blocks for: " << duration.count() << " ms\n"; } { auto start = std::chrono::high_resolution_clock::now(); e.table->tick(); auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>( end - start ); std::cout << "Tick time for 5'000'000 blocks: " << duration.count() << " ms\n"; } std::cout << "Vales after tick: " << std::endl; // ...

К слову, такой код:

for( long long i = 0; i < 5'000'000; ++i ){ aa += bb; bb += 12 / aa + 1; if( aa > bb ) aa = 0; else bb = 3; }

занимает порядка 30 мс:

Packet test Insert 5'000'000 blocks for: 673 ms Tick time for 5'000'000 blocks: 76 ms Vales after tick: 0x0000000000000000 : 0xbc00000000000000 0000000000000000 0000000000000000 bc00000082280000 0x0100000000000000 : 0xee12000000000000 0000000000000000 0000000000000000 0000000002280000 0x0200000000000000 : 0x2000000000000000 0000000000000000 0000000000000000 2000000082280000 0x0300000000000000 : 0x124e000000000000 0000000000000000 0000000000000000 0000000002280000 0x0400000000000000 : 0x8f58000000000000 0000000000000000 0000000000000000 0000000002280000 0x0500000000000000 : 0x4637000000000000 0000000000000000 0000000000000000 0000000002280000 0x0600000000000000 : 0x0500000000000000 0000000000000000 0000000000000000 0500000082280000 0x0700000000000000 : 0x0100000000000000 0000000000000000 0000000000000000 0100000082280000 0x0800000000000000 : 0x0e00000000000000 0000000000000000 0000000000000000 0e00000082280000 0x0900000000000000 : 0x6063000000000000 0000000000000000 0000000000000000 0000000002280000 Adds 5'000'000 counts for: 29 ms

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

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

Я на самом деле не знаю, насколько это круто...

2
1