Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Declaring a class

The goal: a new Unreal class, written in Rust, that the editor and Blueprints treat like any other.

#![allow(unused)]
fn main() {
use bindings::engine::{StaticMeshComponent, SceneComponent};
use bindings::prelude::*;
use rusteal_runtime::{uclass, uclass_impl};

#[uclass(parent = Actor)]
pub struct Barrel {
    #[component(root)]
    root: SceneComponent,

    #[component(attach = "root")]
    mesh: StaticMeshComponent,

    #[uproperty(EditAnywhere, default = 50)]
    health: i32,
}

#[uclass_impl]
impl Barrel {
    #[ufunction(Override)]
    fn receive_begin_play(&mut self) {
        log::info!("[MyGame] crate with {} health", self.health());
    }
}
}

A class is two parts:

  • The struct, marked #[uclass(parent = ...)]: its fields are the class’s properties (#[uproperty]), its components (#[component]) and fields only Rust sees (no attribute).
  • The impl block, marked #[uclass_impl]: its methods marked #[ufunction] are the class’s Unreal functions and events, and #[class_defaults] sets its default values. A class can split them over several #[uclass_impl] blocks, in several files. Plain impl blocks next to them hold the methods only Rust calls.

When the library loads, Rusteal creates the class in the engine under the struct’s name: Barrel above. It can be placed in a level, used as a Blueprint’s parent and picked in any class field of the editor.

Choosing a parent

The parent is an engine class from the bindings, or another Rust class. What the class is follows from it:

ParentWhat the class is
ActorAnything placed in or spawned into a level: props, pickups, volumes, spawners, projectiles.
Pawn, CharacterSomething a player or an AI controls. Character brings a capsule, a skeletal mesh and walking movement.
PlayerController, AIControllerWhat possesses a pawn: input for a player, logic for an AI.
GameModeBase, GameStateBase, PlayerStateThe rules of a level and their state.
PlayerCameraManagerHow the player’s camera is placed every frame.
HUDA canvas drawn over the game.
ActorComponent, SceneComponentBehavior added to actors: an inventory, a health system.
UserWidgetA UMG widget whose layout a Widget Blueprint child draws.
AnimNotifyCode run at a frame of an animation.
SaveGameData written to and read from a save slot.
PrimaryDataAssetA kind of asset, created and edited in the Content Browser.
DeveloperSettingsA page of Project Settings.
StateTreeTaskBlueprintBase, StateTreeConditionBlueprintBaseStateTree tasks and conditions.
EnvQueryContext_BlueprintBaseAn EQS context.
RustealGameInstanceSubsystem, RustealWorldSubsystem…A subsystem. See Subsystems.

The engine classes keep their C++ names without the prefix (AActor is Actor), and come from the module they belong to (bindings::engine::Character, bindings::ai::AIController, bindings::umg::UserWidget).

Reaching the object

Inside the class, self is the Rust side of the object. Three methods connect it to the engine:

MethodWhat it returns
self.as_ref()A reference to the object as its parent class (UObjectRef<Actor> for Barrel), to call engine functions on it.
MyClass::from_obj(object)The Rust class of any object reference, or an error if the object is not of that class.
MyClass::get_default()The class default object, which every instance starts from.
#![allow(unused)]
fn main() {
let me = self.as_ref().checked()?;
let location = me.k2_get_actor_location().to_dvec3();
}
#![allow(unused)]
fn main() {
if let Ok(mut barrel) = Barrel::from_obj(other_actor) {
    barrel.set_health(barrel.health() - 10);
}
}

from_obj is how one Rust class reaches another: an overlap gives an UObjectRef<Actor>, and from_obj turns it into the Rust class, with its getters, setters and methods, when that is what it is. See Object references.

Where the class lives

The game’s classes are in the /Script/Rusteal package: /Script/Rusteal.Barrel is the class path of Barrel, the path an ini file, a redirect or editor Python uses. A plugin’s classes are in its own package (see Plugins).

What a class cannot do yet

  • Replicate properties or call RPCs over the network: Replicated and the RPC specifiers are not accepted yet.

See Known limits.