Studio Games Team Dev Log Docs Contact
Internal Docs · Starbud Station · UE5.4

C++ Framework

UE 5.4 C++ Co-op 14 Systems Framework Complete

The complete C++ gameplay framework for Starbud Station — a co-op sci-fi dispensary management game. All 14 core systems are implemented in C++ with server-authoritative replication. Blueprints are used only for layout, asset data, and per-widget visual setup.

01

Framework

The core Unreal Framework layer establishes the game session lifecycle, business day logic, player wallet, and input routing. AStarbudGameState hosts four manager components that own major gameplay subsystems, keeping them server-authoritative and replicated from a single authority actor.

The business day system drives all customer and shop activity. A day is started from the in-game ShopTerminal; customers only spawn when a business day is active and only purchase listed items.

UStarbudGameInstance
Persistent session container. Holds save manager subsystem reference and handles transitions between levels.
GameInstance
AStarbudGameMode
Server-only authority. Configures default pawn class, player controller, and game state. Manages business day start/end flow.
GameMode
AStarbudGameState
Replicated game state. Hosts CustomerManagerComponent, TraderManagerComponent, BuildingManagerComponent, and StationManagerComponent as direct subobjects.
GameState
AStarbudPlayerState
Per-player replicated state. Stores wallet balance (currency) and is the source of truth for money transactions.
PlayerState
AStarbudPlayerController
Manages Enhanced Input setup, input mode switching, and delegates interaction and UI requests to the appropriate managers.
PlayerController
Architecture Note

The four manager components on AStarbudGameState are the preferred location for systems that need to exist exactly once per session and be accessible to all actors. Never cache pointers to these directly — always retrieve via GetWorld()->GetGameState().

02

Interaction

The interaction system uses a lean interface + component pattern. Any actor can become interactable by implementing IInteractable and attaching an UInteractTargetComponent. The player's UInteractionManagerComponent performs a sphere trace each tick to find the nearest valid target and drives the interaction prompt UI.

IInteractable
Plain C++ virtuals with MinimalAPI. No BlueprintNativeEvent. Implemented by any actor that supports interaction (terminals, machines, traders, storage, planters).
Interface
UInteractTargetComponent
Lightweight UActorComponent. Carries interaction range, prompt text, and enabled state. Never call SetupAttachment on this component.
Component
UInteractionManagerComponent
Lives on the player character. Runs the trace loop, maintains the current interaction target, and fires Interact() on the server via RPC when the player presses the interaction key.
Component
Design Rule

IInteractable uses plain C++ virtuals — not BlueprintNativeEvent. All interaction logic lives in C++. Blueprint child classes cannot override interaction behavior directly, keeping authority on the server side.

03

Inventory

A replicated slot-based inventory that can be attached to any actor. Items are identified by UItemDefinition data assets — no hard-coded item types. Category filters allow specific storage actors or machine slots to restrict accepted item types without touching code.

EItemCategory
Enum categorizing items (Cannabis, Seed, Consumable, Equipment, Material, Currency). Used for category-based filtering on slots and storage.
Enum
FItemInstance
Lightweight runtime item representation. Holds a soft reference to UItemDefinition plus quantity. Used in all inventory and save flows.
Struct
FInventorySlot
A single slot in the inventory grid. Contains FItemInstance, allowed category filter, and lock state. Replicated as part of the inventory array.
Struct
UItemDefinition
PrimaryDataAsset defining an item — display name, description, category, base value, max stack size, icon, mesh. Never subclassed per-item; all variance is data-driven.
DataAsset
UInventoryComponent
Replicated UActorComponent. Fixed-size slot grid with category filtering, add/remove/move/split operations, and DisplayName for UI. Server-authoritative — all mutations go through server RPCs.
Component
04

UI

A screen-stack UI manager keeps input mode and widget lifecycle fully controlled from C++. Each screen is a C++ class with Blueprint child classes for layout and visuals. The subsystem enforces that only one screen is active at a time and handles the transition from Game-only to UI-and-Game input mode automatically.

UUIManagerSubsystem
ULocalPlayerSubsystem managing the full screen stack. Push/pop screens, enforce input mode policy, and provide a single access point for all UI operations. Never bypass this to show widgets.
Subsystem
UUIScreenWidget
Base C++ UUserWidget all screens inherit from. Exposes OnScreenOpened/OnScreenClosed BlueprintImplementableEvents for BP visual setup.
Widget
UUISettings
ProjectSettings-registered config object. Maps EStarbudScreen enum values to Blueprint widget classes at startup. Allows designers to swap widget implementations without touching C++.
Settings
UHUDWidget
Persistent HUD overlay. Always visible during gameplay — shows player wallet, active business day status, and notification toasts.
Widget

Nine dedicated screens cover all major player interactions:

ScreenTrigger
PlayerInventoryScreenTab key — use, drop, split items
StorageScreenAStorageActor — dual-panel transfer
MachineScreenAMachineActor — recipe, progress, controls
PlanterScreenAPlanterActor — grow status, harvest
ShopTerminalScreenAShopTerminalActor — listings, business day
ShopCounterScreenAShopCounterActor — restock, live sales
TraderScreenATraderActor — buy/sell with wallet
BuildMenuScreenABuildStationActor — upgrade tech tree
PauseScreenEscape key — save, settings, quit
05

Character

The player character wires together camera, interaction, and inventory into a single controllable pawn. All input actions use Enhanced Input. The character delegates interaction logic to UInteractionManagerComponent and inventory operations to its UInventoryComponent, keeping the character class thin.

Spring-arm camera with configurable boom length and pitch limits
UInteractionManagerComponent — sphere-trace based target detection and interact dispatch
UInventoryComponent — 24 fixed slots, all item categories permitted by default
Enhanced Input actions: Move, Look, Interact, ToggleInventory, CloseUI, Pause
Full interaction→UI screen wiring through UIManagerSubsystem
Server-authoritative movement — standard UCharacterMovementComponent, no custom prediction
Co-op Note

Each connected player has their own character instance. Inventory is per-player and fully replicated. The shared 24-slot grid is owned by the player state's pawn — not by a global or shared component.

06

Grow / Planter

The grow system manages plant lifecycle from seed to harvest. Plants are defined by UPlantDefinition data assets which encode growth time, yield, and trait profiles. The grow component uses FTimerManager for tick-free progression and supports save/load restoration via ApplyFromSave.

Strain genetics integrate directly here — each FPlantInstance carries a strain ID referencing the strain registry. At harvest, actual yield and quality are calculated from the strain's trait profile multiplied by grow health.

PlantTypes
EPlantStage enum (Seed, Seedling, Vegetative, Flowering, Mature, Harvested), FPlantInstance struct with stage, water, nutrients, strain ID, and timer state.
Types
UPlantDefinition
PrimaryDataAsset defining a plant species — growth stages with durations, base yield, water/nutrient consumption rates, and display metadata.
DataAsset
UGrowComponent
Manages plant progression through growth stages using FTimerManager (no per-tick updates). Exposes water, feed, and harvest operations. ApplyFromSave restores in-progress growth from serialized state.
Component
APlanterActor
Physical planter object in the world. Implements IInteractable to open PlanterScreen. Attaches UGrowComponent and UInteractTargetComponent. Supports variable slot counts per planter tier.
Actor
Strain Integration

Actual harvest yield = BaseHarvest × StrainYieldMultiplier × GrowHealthFactor. Grow health is determined by how consistently the plant was watered and fed throughout its growth cycle. Neglected plants yield less regardless of strain genetics.

07

Shop / Listing

The shop system handles product listings, active business day management, reputation tracking, and revenue reporting. Listings are set up via the ShopTerminal; customers reference active listings when deciding what to purchase. The shop counter provides a quick-access restock interface and shows live sale notifications during a business day.

ShopTypes
EShopListingState (Active, Paused, SoldOut), FShopListing struct (item def, price, quantity, state), FDailySalesReport struct for end-of-day revenue summary.
Types
UShopComponent
Core shop logic component. Manages the listings array, processes sales, tracks revenue and reputation, and exposes ApplyFromSave for full state restoration. Server-authoritative.
Component
AShopTerminalActor
The in-game computer terminal. Implements IInteractable to open ShopTerminalScreen. Hosts UShopComponent. Allows players to create/edit listings, start the business day, and view sales reports. Station-bound — each station has its own terminal.
Actor
AShopCounterActor
Physical shop counter. Opens ShopCounterScreen for quick restock and delist operations. Also displays live sale notifications during an active business day.
Actor
08

Customer

Customers are AI-driven NPCs that enter the shop during a business day, browse active listings, make a purchase, and leave. Each customer type is defined by a data asset encoding trait preferences, budget range, patience, and visit behavior. The customer manager spawns and despawns customers according to the business day schedule.

CustomerTypes
ECustomerState enum (Entering, Browsing, Purchasing, Leaving, Impatient), FCustomerPreferences struct encoding trait affinity (high THC, high CBD, flavor tags), budget range, and patience duration.
Types
UCustomerDataAsset
PrimaryDataAsset defining a customer archetype — display name, mesh reference, visit frequency, spend range, trait preferences, and patience multiplier. Connoisseur, Budget, Medical, and Casual archetypes ship by default.
DataAsset
ACustomerActor
AI NPC driven by a simple state machine. Navigates to shop counter via navmesh, evaluates listed products against preferences, triggers a purchase RPC if a match is found, then moves to exit. Owned and replicated by the server.
Actor
UCustomerManagerComponent
Lives on GameState. Manages the spawn queue for each business day, tracks active customers, and fires events on purchase completion (triggers sale notifications, reputation updates, revenue logging).
Component
09

Trader

Traders are buy/sell NPCs. They come in two forms: preplaced marketplace or blackmarket stalls configured in the editor, and dynamic car traders that arrive via the event system for a limited time. Both use the same UTraderComponent for all trading logic — the only difference is how they enter the world and their editor-configured availability windows.

TraderTypes
ETraderCategory (Marketplace, Blackmarket, Event), FTraderSlot struct (item def, quantity, buy price, sell price, bUnlimited), and the restock policy enum.
Types
UTraderDataAsset
PrimaryDataAsset defining a trader's stock template — base stock entries, random extras with spawn probability, default buy/sell price multipliers, and restock policy.
DataAsset
ATraderActor
Single actor class covering both marketplace and blackmarket traders. Editor-configurable: TraderID, bIsBlackmarket, availability hours, days active, and TraderDataAsset. Hosts UTraderComponent and UInteractTargetComponent.
Actor
UTraderManagerComponent
Lives on GameState. Manages schedule-based trader availability, drives restock on new business day, and handles dynamic car-trader arrival/departure via the event system. All stock changes are replicated to clients.
Component
Blackmarket vs Normal

Both trader types use the same ATraderActor class. The bIsBlackmarket flag on the actor instance configures pricing multipliers, inventory content (via a different UTraderDataAsset), and availability hours. No separate actor class is needed.

10

Storage

Storage actors provide passive item storage in the world. Each storage unit carries its own inventory component with configurable category filters, allowing specific units to be designated for seeds, harvested product, materials, or any mix. A lock flag prevents unauthorized access in co-op.

AStorageActor
Self-contained storage object. Attaches UInteractTargetComponent, UInventoryComponent (category filter configurable per-instance), and a static mesh. Opens StorageScreen on interact for dual-panel transfer between player and storage inventory. Supports a lock state for co-op access control.
Actor
Per-instance category filter — restrict storage to seeds, product, materials, or mixed
Configurable slot count per storage tier (small crate vs. large vault)
Lock support — flagged storage requires ownership check before interaction
Full inventory replication — all connected players see live stock changes
Save/load compatible — inventory state serialized via SaveManagerSubsystem
11

Building / Upgrade

The building system implements a directed acyclic graph (DAG) tech tree for shop upgrades. Each upgrade is a data asset that encodes prerequisites, currency cost, gameplay effects via GameplayTags, and optionally an actor to spawn in the world when purchased. The BuildingManager handles wallet checks, prerequisite validation, and state restoration on load.

BuildingTypes
EUpgradeState (Locked, Available, Purchased), FUpgradeEffect struct (GameplayTag + float value for loose coupling to gameplay systems), FUpgradeNode struct for the tech tree DAG.
Types
UUpgradeDataAsset
PrimaryDataAsset defining one upgrade — display name, description, cost, prerequisite upgrade IDs (DAG edges), a list of FUpgradeEffects as GameplayTag/float pairs, and an optional actor class to spawn on purchase.
DataAsset
UBuildingManagerComponent
Lives on GameState. Owns the full upgrade registry, validates prerequisites and wallet balance before approving a purchase, applies tag-based effects to the relevant systems, and calls ApplyFromSave to restore purchased state on load.
Component
ABuildStationActor
In-world upgrade terminal. Opens BuildMenuScreen on interact. Displays the upgrade tech tree with category filtering and handles the purchase flow through UBuildingManagerComponent.
Actor
Upgrade Effects Pattern

Upgrade effects are encoded as GameplayTag → float pairs (e.g., Upgrade.Shop.PriceMultiplier → 1.15). Systems query the BuildingManager for active effect values rather than being directly modified. This keeps gameplay systems decoupled from the upgrade system entirely.

12

Machine / Automation

Machines are interactable actors that process items over time according to recipes. A machine has input slots, output slots, and a processing cycle driven by FTimerManager (not per-tick). Recipe data assets define which items are consumed, what is produced, and how long each cycle takes. This system covers processing equipment, the breeding station, and any future automation machinery.

MachineTypes
EMachineState (Idle, Processing, Finished, Error), FMachineSlot struct for typed input/output slots with category and quantity constraints.
Types
UMachineRecipeDataAsset
PrimaryDataAsset defining one recipe — required input items and quantities, output items and quantities, processing duration in seconds, and optional unlock requirement (upgrade tag).
DataAsset
UMachineComponent
Manages machine state, active recipe, processing progress, and input/output inventory slots. Processing runs via FTimerManager — no per-tick replication. Fires OnCycleComplete delegate when processing finishes.
Component
AMachineActor
Physical machine in the world. Attaches UMachineComponent, UInteractTargetComponent, and mesh. Opens MachineScreen on interact — three-panel layout with input slots, output slots, recipe selector, progress bar, and start/stop controls.
Actor
Timer-based processing — no per-tick updates, no per-frame replication overhead
Recipe selector UI shows all available and locked recipes for the machine type
Processing progress persisted in save data — machine resumes on load
Breeding Station implemented as a specialized machine recipe type within this system
Unlock gates via GameplayTags — recipes can require specific upgrades to be purchased
13

Save / Data

The save system is a UGameInstanceSubsystem that orchestrates a full gather-and-apply save flow. On save, it queries all registered saveable systems and aggregates their state into a single UStarbudSaveGame object. On load, it distributes the saved data back to each system's ApplyFromSave function. Actor positions and placed objects use FSoftObjectPath in save data — never raw pointers.

SaveTypes
FWorldSaveData aggregate struct, FInventorySaveData, FShopSaveData, FGrowSaveData, FBuildingSaveData, FStationSaveData, and FStrainRegistry for genetics persistence.
Types
UStarbudSaveGame
USaveGame subclass. The serializable data container — holds FWorldSaveData which aggregates all system save data. One save slot per session, versioned for forward compatibility.
SaveGame
USaveManagerSubsystem
UGameInstanceSubsystem (not LocalPlayer). Coordinates the full save/load flow: gather phase (query all systems), serialize to UStarbudSaveGame, write slot. On load: deserialize, distribute via ApplyFromSave, respawn any placed actors that were saved by soft path. Async save to avoid hitches.
Subsystem
Critical Rule

All save data uses FSoftObjectPath instead of raw object pointers. Never store a raw UObject* in save data. Do not test ServerTravel flows in PIE — use Standalone or Packaged builds only for save/load and level transition testing.

14

Station

The station system manages the multi-island world architecture. The game world uses a persistent level with station islands as streamable sub-levels. Each island is a self-contained ASpaceStation that contains one or more AStationRoom actors. Players can rent, purchase, or release stations; the starter station cannot be released.

Each station has a configurable purpose (Selling, Production, Storage, Mixed) which controls which gameplay systems activate on that island, and a condition tier (Derelict through Luxury) that governs the visual state via Blueprint material events.

StationTypes
EStationPurpose (Selling, Production, Storage, Mixed), EStationCondition (Derelict, Worn, Standard, Premium, Luxury), EStationOwnership (Unowned, Rented, Owned), FStationInfo registry struct.
Types
ASpaceStation
Logical root anchor actor per island — no mesh. Discovers AStationRoom children at BeginPlay and registers with StationManagerComponent on GameState. Station ID, purpose, condition, and ownership are configured per-instance.
Actor
AStationRoom
Logical room within a station. Has a RoomBounds collision box and BuildZone reference for placement validation. Rooms can be locked/unlocked independently. Visuals are free-built meshes in the sub-level — no mesh on the actor itself.
Actor
StationManagerComponent
Lives on GameState. Maintains the full multi-station registry, manages sub-level streaming (load/unload islands), handles ownership transactions (rent/buy/release), and tracks which station is currently active. All shop terminals are bound to their station by StationID.
Component
StationID Binding

Every system that operates per-station — ShopTerminal, ShopComponent, CustomerManager spawn queues — binds to a StationID. When working with shop, terminal, or customer logic, always consider which station is active. A player on Station 2 should not affect Station 1's shop state.