Back to Projects

Out of Time

Multiplayer rogue-lite game with Core-to-UE automation pipeline

Unreal Engine 4/5BlueprintC++PythonPowerShellJenkins
Company

Manticore Games

Year

2020

Role

Product Developer / Senior Technical Artist

Category
PIPELINE

Context

Multiplayer rogue-lite game built on Core Engine with a Core-to-Unreal automation pipeline for large-scale map iteration and optimization.

My Contribution

Built and maintained the Core-to-UE automation workflow, map layer setup, optimization passes, Jenkins rebuild jobs, and VAT performance strategy for large mob counts.

Impact / Outcome

Enabled faster iteration on large open-world maps and major runtime performance improvements, including approximately 90% draw-call reduction for VAT mob rendering.

Outcome Summary

Out of Time Dev and Tools

Table of Contents

Game Overview

Out of Time is a multiplayer rogue-lite built on Core, centered on large era-themed wilderness maps, repeatable combat encounters, and high enemy counts. The project combined the rapid iteration benefits of Core Editor with production requirements that pushed beyond what a fully dynamic runtime representation could support at scale.

My work focused on the technical art and pipeline side of that challenge: converting static environment content from Core into optimized native Unreal levels, organizing large maps through World Partition and Data Layers, automating repeated rebuilds through Jenkins, and building VAT-based mob rendering to keep large groups of animated enemies performant, including on Steam Deck.

Map Layers Setup

imageimage

Each wilds map is 2k×2k in size, with one map per timeline era. The source map is authored in Core Editor, then processed through the Core-to-UE pipeline to transfer most static environment assets into native Unreal levels. The next section breaks down that conversion workflow in more detail.

We chose a single large map per era for several production reasons. Because all four zones share the same time period, keeping them in one map helps maintain visual consistency across the full environment. It also simplifies the artist workflow: shared assets only need to exist once, while each zone hides content that should not be visible when that zone loads.

We used World Partition as the base map-loading strategy, distributing zone content across separate Data Layers so each zone loads only what it needs. A shared "always-on" data layer holds vista objects visible from all four zones.

At the asset level, content is grouped into Packed Level Actors and regular Level Instances, organized around clearly distinguishable prefabs such as buildings, castles, bridges, and similar structures. Sparse items are handled through World Partition cell grids, which divide them into separate level instances. A layered HLOD system manages distant objects beyond the player's immediate view.

Core to UE Pipeline

The game is built in Core Editor first. Core's editing model is highly dynamic by design: every mesh requires a Core-level proxy actor, and assets such as materials and VFX retain full runtime editability. That flexibility makes Core powerful for rapid iteration, but it also carries a significant performance cost. The Core-to-UE pipeline was built to address this by transferring non-interactive environment assets into native UE assets, stripping away runtime editing overhead, and converting them into fully static representations. The entire transfer process runs offline.

Not all assets are transferred — Core provides many useful built-in features for gameplay systems that we continue to rely on. The pipeline targets environment assets specifically, where the static conversion yields the greatest performance gains.

The basic structure of the Core map and Unreal map: imageimage

Maps were under active development and iterated on rapidly. In the Core Client, environment changes are visible immediately after a game republish; in Unreal, each adjustment requires a full build cycle. As a result, whenever an environment artist updated a zone, the Core-to-UE process needed to be re-run for that era.

Here is how the iteration works: imageimage

In the Core wilds map, each asset bundle is rooted under a custom object called a CUE node. All items under a CUE node are processed by the pipeline and converted into native Unreal level assets, including static meshes, spline meshes, decals, visual effects, sound effects, and lights. Each asset type has its own transfer rules, with the core mechanic being: capture all asset state during a UE Play-In-Editor session and write it out to the native level.

The pipeline also handles source control on both sides, managing asset updates across Git and Perforce automatically.

Here is the overall pipeline flow: imageimage

During each rebuild, several optimization passes are applied:

  • Instance all static meshes that share the same mesh asset
  • Merge actors with many small parts into a single mesh actor
  • Merge spline mesh sections into one static mesh — this alone yielded a notable FPS improvement in the Dark Forest zone of the Medieval map
  • imageimage
  • imageimage
  • Optimize materials to reduce instruction counts, increase use of static switches, and strip unused logic branches that were only needed in the Core Editor environment — most eligible materials achieved over 80 instruction reductions
  • Bake runtime data into blueprints to eliminate dynamic logic where possible

The entire process runs automatically as a Jenkins job. Each map has its own dedicated job that can be queued independently, and the pipeline has successfully completed over 500 runs.

Mob VATs

This system addresses the performance cost of rendering large numbers of mobs simultaneously. Keeping many skeletal meshes on screen with active animations is expensive, so beyond a certain distance from the player we switch to Vertex Animated Textures (VATs).

We bake the vertex animation for each mob's attack and run cycles into a texture, then drive a vertex shader on a static mesh version of the mob to simulate skeletal animation. These static mesh stand-ins replace the skeletal mesh mobs beyond a configurable distance threshold, allowing the game to keep over 200 animated mobs visible on screen simultaneously.

Every non-boss mob in the game went through the VAT generation process. Replacing skeletal meshes with VAT meshes alone reduced draw calls by approximately 90%. On top of that, we applied additional optimizations to the VAT meshes — mesh instancing, collision adjustments, and lighting setup — to reach the performance targets needed to support the game on Steam Deck.