Open-world sandbox game developed in Unity.
- Natural Artificial Life
- Procedural audio synthesis
- Local LLM item descriptions
- Rive scripting language
- Wave Function Collapse
- Infinite world streaming
- SharedHierarchicalBrain
- Gesture recognition
- Dynamic ecosystem
- Burst Jobs
- Object Pooling
- Zero-allocation collections
- MemoryPack serialization
- Chunk streaming
- Spatial hashing
- Native Collections
- Reactive event system
- Unity 6000.3 (3D, URP), C#, Netcode for GameObjects (host/server/client)
- UniTask — async/await everywhere instead of coroutines
- R3 — reactive properties, observables (аналог UniRx)
- LitMotion — tweens/animations
- MemoryPack — binary serialization для сохранений
- ZString / Cysharp.Text — zero-alloc string building
- ZLinq — zero-alloc LINQ
- Unity.Jobs + Burst — высоконагруженные вычисления
- LLMUnity — локальная LLM для описаний предметов
- NaughtyAttributes — editor utilities
Создаёт все глобальные сервисы до загрузки игровой сцены:
RavineLogger→ServiceLocator.ServicesActionMapControllerGlobalSettingsController(настройки качества, трава, управление)WorldRegistry(список миров, текущий мир)AutosaveCoordinatorWorldSettingsController
WorldManagerUI— список миров, создание/удаление/переименованиеWorldSettingsUI— конфиг мира (сложность, autosave interval, timeScale)NetworkUIController— выбор host/server/client, IPSceneLaunchService— переход на игровую сцену
Состояния: BootstrapState → InitialState → LoadingState → GameState
Каждое состояние запускает очередь ISetAble сервисов через ServiceRegisterMachine.
Порядок регистрации сервисов (грубо):
- Bootstrap:
DayCycle,AmbientSystem - Initial:
ObjectSystem,EntitySystem,MobController - Loading:
MapGenerator,MobGenerator,UIInventory,PauseUI
ServiceLocator.Services — Dictionary<Type, object> — игровые сервисы
ServiceLocator.Players — PlayerContainer — зарегистрированные игроки
Dictionary<Type, IComponent> — компоненты
ReactiveProperty<bool> IsActive
ReactiveCommand<Unit> OnUpdate
| Компонент | Назначение |
|---|---|
MainComponent |
имя, prefabID, clientID |
TransformComponent |
entity/model трансформы |
MovementComponent |
BaseSpeed, Acceleration, Deceleration, velocity |
EnergyComponent |
energy, maxEnergy (ReactiveProperty) |
CurrencyComponent |
валюта (SafeInt + ReactiveProperty, только сервер пишет) |
AimComponent |
CrosshairDistance, PickDistance |
EventBusComponent |
EventBus для внутренних событий сущности |
StatePatternComponent |
FSM — текущее состояние (AState) |
SkillComponent |
Dictionary<string, ISkill> |
CameraComponent |
логика камеры (follow + aim offset) |
PlayerEntity— игрок. Init вPlayerModelView.OnNetworkSpawn()BotEntity— NPC с FSM-поведениямиMobEntity— мобы, движение черезRoamMoveController+MobController(Jobs)
AEntityViewModel : NetworkBehaviour— подписывается наEntity.IsActive,Entity.OnUpdateAEntityView : MonoBehaviour— биндинги UI на ViewModelPlayerModelView— конкретная ViewModel игрока, спавнит камеру через ServerRpc
- Архитектура: Host = Server + Client
PlayerModelView.OnNetworkSpawn— инициализация на каждом клиентеDayCycle— NetworkVariable isDay, сервер управляет временемCurrencyNetworkComponent— NetworkVariable, только сервер пишет, RPC от клиентаPlayerController.MoveServerRpc— движение валидируется на сервере
IAsyncPersistentStorage
└── EncryptedPlayerPrefsStorage (AES-CBC + MemoryPack, default)
└── JsonPlayerPrefsStorage (отладка)
IFileManager<TId, TEntity>
└── WorldStateRepository (ключ: "world_data_{id}")
└── WorldConfigRepository (ключ: "world_settings_{id}")
└── GlobalSettingsRepository (ключ: "global_game_settings")
└── ScriptFileManager (ключ: "script_file_{name}")
GlobalSettings— качество, трава, тип управления (MemoryPack)WorldState— seed, позиция игрока, cycleCount, инвентарь[], lastSaveTimeWorldConfiguration— имя мира, сложность, autosave interval, timeScale
Центральный менеджер миров: Create/Load/Unload/Delete/Rename/Save.
AvailableWorlds: ObservableList<string> — UI подписывается напрямую.
Запускает цикл автосохранения. Поддерживает SubscribeBeforeSave(Func<CT, UniTask>) — хуки до сохранения.
- Chunk-based, infinite. ChunkSize=40, Scale=2 (юниты на тайл)
- Шум Перлина через статический
Noise(кешированные октавные офсеты) ChunkData= heightMap[40,40] + temperatureMap[40,40] + SortedSet objectsToInst- Обновление по позиции игрока раз в секунду
EndlessTerrain— обновляет единый Mesh (3x3 чанка), MeshColliderEndlessLiquids— двигает водный planeEndlessObjects— переиспользует объекты черезObjectSystem(pool)
Dictionary<Vector2Int, ObjectInstInfo>— глобальный реестр размещённых объектовPoolManager— Dictionary<prefabID, Queue>ObjectInfoRegistry : ScriptableObject— база всех объектов
Псевдо-экосистема: объекты размножаются/умирают по вероятностям.
BehaviourType: None | NAL | GROW
При смерти/подборе — SpreadPattern (spawn новых объектов вокруг)
Процедурная генерация структур из тайловых правил (TileRuleSO).
Отдельная sandbox-система (не связана с основным EntitySystem):
Двухуровневая иерархия:
- Coordinator (LSTM + DelayedPerceptron) — выбирает Goal: Survive/Hunt/Forage/Social
- Executor[goal] (LSTM + DelayedPerceptron) — выбирает конкретное действие из подмножества
- Continuous-time RNN с τ-весами (время релаксации)
- Обучение: Truncated BPTT (8 шагов назад), reward-weighted
- Exploration: ε-greedy с adaptive epsilon по entropy
- Генетические параметры (
GeneticParameters): LR, lambda, temperature, etc.
Спавн, смерть, размножение (обычное + crossover), эволюция весов (EvolveSharedWeights).
InventoryModel— чистая модель (слоты, стаки, крафт)EventDrivenInventoryProxy— обёртка с событиями (Added/Removed/Changed)UIInventory : ISetAble— View, подписан на PlaceEvent/PickUpEvent из EventBus игрокаCraftService— проверяет рецепты, заполняет прогресс-барUIDragger— drag-and-drop (PC мышь + mobile touch)- LLM-описания:
LLMItemDescriptionServiceс debounce (0.4s), кеш вItemDescriptionRegistry
TimeInvoker : MonoBehaviour(DontDestroyOnLoad) — проблема: используетUniTask.Delay(1/60s)вместоUpdate(),Time.deltaTimeчитается в неправильный моментSyncedTimer— подписывается на события TimeInvoker, поддерживает Pause/Unpause
Terminal : MonoBehaviour— UI консоль с историей (50 строк, ZString)CommandManager— Dictionary команд по имени/псевдониму- Rive — собственный интерпретируемый язык:
- Типы:
int, массивыint[] - Конструкции:
if/else/end,for x = N to M,wait,log,get(stdin),send(interactor, val) ~команда— вызов терминальных команд из скриптаRiveParser→ AST →RiveExecutor(stack-based scopes, MAX 10000 ops)RiveRuntime— реестр программ, built-in функции (abs/min/max/clamp/pow/sqrt/rand)InteractorRegistry— игровые головоломки (DigitalLock, Collatz, Checksum, SequenceValidator)
- Типы:
GestureRecognizer— PDollar+ распознавание жестов → диспетчер команд
ActionMapController— переключение Action Maps: Gameplay / Pause / Inventory / UIInputBindingAdapter— связываетButton.onClick+InputAction.performedв одном объектеIController— абстракция надPCController(мышь+клавиатура) иJoistickControllerDoubleTapDetector— детектор двойного нажатия для буста
StringToAudioGenerator— синтез звука из строки (hash → гармоники → Jobs → AudioClip)AudioSynthesizer—IJobParallelForс BurstCompile, 4 формы волны (Sine/Saw/Square/Triangle)StableHashService— детерминированный хеш строки → ADSR огибающая + гармоники
BoidsBehaviour— Jobs-система:InitSpatialGridJob(hash grid) +AccelerationJob(separation/alignment/cohesion) +MoveJobNativeParallelMultiHashMap<int2, int>— пространственная решётка для поиска соседей- Настраивается через
BoidsInfo : ScriptableObject
| Паттерн | Где |
|---|---|
| Service Locator | ServiceLocator (глобальный) |
| Component | AEntity + IComponent |
| State Machine | StatePatternComponent + AState + FSM игры |
| Command | ICommand (EntitySystem) + ICommand (Terminal) — разные интерфейсы! |
| Repository | WorldStateRepository, WorldConfigRepository, etc. |
| Observer / Reactive | R3 ReactiveProperty, Subject, Observable |
| Object Pool | PoolManager |
| MVVM (частично) | AEntityViewModel + AEntityView |