Skip to content
CRUSHFORMV1.1.0
GET IT ON FAB

REFERENCECOMPONENTS

UCFDeformComponent

MODULECrushformINCLUDECFDeformComponent.hPARENTUActorComponent

Dents and paint wear of one actor whose root component is its simulated body. Without a profile it does nothing, except that OnWheelSurfaceChanged and GetWheelSurface need neither a profile nor a dirt grid. The lattice is spanned over the body's collision in root component space when play begins.

The server holds the real lattice and publishes it in 4x4x4 chunks. The client that simulates the body reports its hits to the server and draws them at once as a prediction; every other client draws the chunks it received.

Functions

AUTHORITY · server, every machineLOCAL · this machinePURE · read only
void SetCrushformHost(UObject* NewHost)
C++ ONLY

Who answers ICFDeformHost for this component; null = the registry's host for the owner, else the owner. Call before BeginPlay: the component reads its meshes and glass from the host once.

UObject* GetCrushformHost() const
PUREC++ ONLY

The explicit host, else UCFHostRegistry::FindHost(Owner, UCFDeformHost), else null.

void AddWheelHostPrerequisite(UActorComponent& Host)
C++ ONLY

Makes both of this component's ticks wait for Host's tick: the main one and the one that reads the wheel surfaces. For a host that builds the frame's wheel contacts in its own tick, so this component never reads last frame's.

void Repair()
AUTHORITY

Authority only: clears every dent and scratch, on every machine. The dirt stays; Wash removes it.

Category
Crushform
void Wash()
AUTHORITY

Authority only: washes every dirt channel (dust, mud, snow and wetness) off the body, on every machine. The dents stay; Repair removes them.

Category
Crushform
bool FillDirt(const FCFDirtValues& Floor)
LOCALC++ ONLY

Raises the dirt of this body to at least these amounts per channel (0..1) as a long drive leaves it, measured from the ground under the wheels the way driving measures it: most at the ground line, thinning upwards by each channel's shape in the profile, a splash channel full again around each axle. A body in the air is measured from its bottom. Local to this machine: dirt never travels on the network. A debugging aid; the wheels go on adding and shedding as before. False where no dirt is drawn. It sends no OnDirtChanged of its own: the next dirt update reports the change.

void AddDirt(FVector WorldPoint, float Radius, FCFDirtValues Amount)
LOCAL

Adds Amount of each channel around a world point, thickest at the point and gone at Radius (cm). Local to this machine: call it on every machine that should see it. Does nothing where no dirt is drawn.

Category
Crushform|Dirt
void WashAt(FVector WorldPoint, float Radius)
LOCAL

Washes the dirt of every channel off around a world point, most at the point and none at Radius (cm), and fires OnWashed with bPartial when it took any off. Local to this machine: call it on every machine that should see it. Wash is the networked wash of the whole body.

Category
Crushform|Dirt
FCFDirtValues GetDirtAt(FVector WorldPoint) const
PURE

The dirt of each channel at a world point of this machine's body, 0..1. All zero where no dirt is drawn.

Category
Crushform|Dirt
FCFDirtZones GetDirtZones() const
PURE

The mean dirt of each channel over each side of the body, as OnDirtChanged reports it. All zero where no dirt is drawn.

Category
Crushform|Dirt
FCFDamageZones GetDamageZones() const
PURE

How dented each side of the body is (the sides of Get Dirt Zones): per side the deepest node and the mean over its nodes, a node's displacement over the profile's Max Displacement, 0..1. Read from the damage the server confirmed, so every machine reads the same: this machine's own unconfirmed hits are left out. All zero while the body has no lattice.

Category
Crushform|Damage
FCFDamageValues GetDamageInBox(const FBox& Box) const
PURE

The damage over the lattice nodes a point inside Box is drawn from: Max is the deepest of them over the profile's Max Displacement, Mean their mean displacement over it, each clamped to 1. Box is in the space of the owner's root component, like a pane's Crush Link Box. All zero while the body has no lattice, Box misses it or Box is unset. A Box with its corners swapped reads the box they span.

Category
Crushform|Damage
FCFWheelSurface GetWheelSurface(int32 WheelIndex) const
PURE

What the host's wheel with this WheelIndex stands on right now, read from the host at the call. WheelIndex is INDEX_NONE in the result when the host reports no such wheel. Works whether or not any dirt is drawn.

Category
Crushform|Dirt
bool ApplyLatticeHit(const FCFHitInput& Hit)
C++ ONLY

Applies a hit given in lattice space, as if physics reported it here: on the authority to the lattice, on the client that simulates the body as a prediction it reports. False when this machine may not apply hits to the owner, and when the profile takes no dents.

bool ApplyWorldHit(const FVector& WorldPoint, const FVector& WorldNormal, float DeltaV)
C++ ONLY

A hit given in world space by gameplay rather than by physics, such as a prop the body broke without touching it. WorldPoint lies on or near the body; WorldNormal may point either way; DeltaV is in m/s. Same machine rules as ApplyLatticeHit; also false when the point is outside the lattice or the hit is too soft to dent, and when the profile takes no dents.

void DentFromBrokenUnit(UPrimitiveComponent& Body, const FVector& UnitPoint, const FVector& VelocityCmS, float SpeedFraction)
C++ ONLY

A breakable unit gave way under Body, which never touches units physically: dents the body where it is nearest to UnitPoint, as hard as SpeedFraction of the body's speed into the unit. Does nothing on a machine that does not simulate the body (IsImpactSourceHere), where the simulating client's own report carries the dent. Body is not const because tracing a component is not.

bool CrushByPlane(const FVector& WorldPoint, const FVector& WorldDirection, float Softness, float Bulge)
AUTHORITYC++ ONLY

Authority only: presses a flat plate into the body, its face through WorldPoint and travelling along WorldDirection (FCFLattice::ApplyPlaneCrush; Softness in cm, Bulge as a fraction of the push). Not predicted: clients see it as chunks arrive. False on a machine without authority over the lattice, when the profile takes no dents, and when nothing moved.

float GetGivingWayMass(const UPrimitiveComponent* OtherComp, FName BoneName)
C++ ONLY

Mass that gives way when OtherComp is struck, kg: the struck body with what pushes it along, its welded parts, the rest of its skeleton, the simulated body of the actor it is attached to (a vehicle's jointed boom). 0 for a body that does not move: static, kinematic or not simulated.

float GetEnergyScale(float OwnMass, float GivingWayMass)
C++ ONLY

From a body's own speed change in a hit to the speed into a fixed wall that takes the same energy: sqrt(1 + OwnMass / GivingWayMass), the ratio capped at CF::MaxGivingWayMassRatio. 1 when nothing gives way.

float GetSupportSpeed(const UWorld* World, float NormalZ)
C++ ONLY

Speed change, cm/s, a contact whose normal has this Z gives a body resting on it every physics step just to hold it up: part of every hit's impulse, and all of a resting one's. Hits come one per solver step, so the step is the async fixed step when physics ticks async, else the frame's as the engine clamps it.

bool ComputeLatticeLayout(const AActor& Owner, const FCFDeformHostCaller& Host, const UCFProfile& Profile, FCFLatticeLayout& OutLayout)
C++ ONLY

The lattice Profile gives Owner: which meshes deform, the box over the body's collision and the grid over it. False when the owner has no root component or no mesh deforms. Asks Host, which the caller binds to the owner's policy, so it works before BeginPlay, on a Blueprint's preview actor too.

bool IsDeformEnabled() const
PUREC++ ONLY

Whether the body has a lattice on this machine, so that it can be dented. False without a profile.

const FCFDirtGrid& GetDirtGrid() const
PUREC++ ONLY

This machine's dirt (dust, mud, snow and wetness) on the body; not initialized where nothing draws it.

const FCFBodyCollision& GetBodyCollision() const
PUREC++ ONLY

The root's collision following the visible lattice; not initialized where the profile leaves the collision alone.

uint8 GetWashCount() const
PUREC++ ONLY

How many times this body was washed; replicated, so a client's count follows the server's.

const FVector3f& GetGridOrigin() const
PUREC++ ONLY

Root component space position of lattice node (0, 0, 0), cm.

const FBox& GetMeshBounds() const
PUREC++ ONLY

Box around the deformed meshes in the owner's root space, without the lattice's margin; invalid until the lattice is built.

const UCFProfile* GetProfile() const
PUREC++ ONLY

The profile this component uses; null when none is set.

const FCFDeformStats& GetStats() const
PUREC++ ONLY

The counters Crushform.Stats prints for this component.

const TArray<FCFDebugHit>& GetDebugHits() const
PUREC++ ONLY

The latest hits this machine applied, oldest first; recorded in builds that have the debug overlay only.

int32 GetNumPendingReports() const
PUREC++ ONLY

Hits this client sent that the server has not yet confirmed or refused.

uint8 GetGeneration() const
PUREC++ ONLY

How many repairs the body has had; replicated. Reports and chunks of another generation are not applied.

const TArray<TObjectPtr<UCFHingeComponent>>& GetHinges() const
PUREC++ ONLY

The hinges this component drives, by part index: sorted by name, so that every machine numbers them alike.

UCFGlassUnitsComponent* GetGlass() const
PUREC++ ONLY

The owner's glass units (ICFDeformHost::GetCrushformGlass), set in BeginPlay; null without any.

float GetPartDamage(int32 PartIndex) const
PUREC++ ONLY

Deepest dent around a hinged part, cm, in the lattice this machine draws; 0 for an index out of range.

FCFPartDamage GetPartDamageDetail(int32 PartIndex) const
PUREC++ ONLY

The three measures of a hinged part's dents in the lattice this machine draws; zeros for an index out of range.

bool IsPartDetached(int32 PartIndex) const
PUREC++ ONLY

Whether the authority has this part off in the current generation.

FBox GetPartCutBox(int32 PartIndex) const
PUREC++ ONLY

The place, cm, in the owner's root space that the body's collision gives way for once this part comes off: the box of the part's simple collision at its closed pose (its mesh's bounds when it has none), joined with its glass panes', grown by the Collision Block Tolerance. The same on every machine and whether or not the part is off now; the body's collision is cut there only while Deform Collision is on. An invalid box for a part index out of range.

bool IsPartLetSwing(int32 PartIndex) const
PUREC++ ONLY

Whether the impact source let this part swing in the current generation: its word replicated, or this machine sent it.

bool IsPartOffOrReportedOff(int32 PartIndex) const
PUREC++ ONLY

Whether the part is off for what is judged on it: the authority's mask has it, or this machine, as the impact source, has reported it off. The server sets the mask before it reads anything sent after the report, so hits after it are judged alike on both machines.

bool IsPartHullBuilt(int32 PartIndex) const
PUREC++ ONLY

Whether a loose part's body holds the hull of its dented collision in place of its own shapes (UpdatePartCollision); false for an index out of range.

void CarryLooseParts(const FTransform& FromRoot)
C++ ONLY

Call right after teleporting the owner, with the root's transform from just before. A swinging part is a body of its own that a teleport leaves behind, and its joint would tear it off for everyone: this moves each one with the body, at the root's new velocity, so no joint error is left.

FTransform GetLatticeToWorld() const
PUREC++ ONLY

Lattice space to world space, for debug drawing.

Properties

TObjectPtr<UCFProfile> Profile

Set it before play begins: in the class defaults, or between SpawnActorDeferred and FinishSpawning.

Category
Crushform

Events

FCFOnDirtChangedDynamicDelegate OnDirtChanged
(const FCFDirtZones& Zones)

This machine's dirt moved: the mean over each side of the body, at most once per Dirt Event Interval and only when some side changed by more than the Dirt Event Threshold. Never on a machine that draws no dirt. The changes of AddDirt, WashAt, Wash and FillDirt are reported by the next dirt update.

Category
Crushform|Dirt
FCFOnWashedDynamicDelegate OnWashed
(bool bPartial)

This machine's dirt was washed off: bPartial for WashAt, not for a wash of the whole body. Never on a machine that draws no dirt.

Category
Crushform|Dirt
FCFOnWheelSurfaceChangedDynamicDelegate OnWheelSurfaceChanged
(const FCFWheelSurface& Surface)

A wheel's PhysicalMaterial or grounded state changed since it was last reported, and when the wheel is first seen: checked every frame on a machine that is not a dedicated server, whether or not any dirt is drawn. A change of SurfaceSpeed alone does not fire; the event carries the current one. A wheel in the air reports a null PhysicalMaterial, so a material change while it is airborne fires nothing. Only for wheels the host names (FCFWheelContact::WheelIndex).

Category
Crushform|Dirt
FCFOnDamageChangedDynamicDelegate OnDamageChanged
(const FCFDamageZones& Zones)

This machine's damage changed: Get Damage Zones differs from what the latest event carried. Read at most once a frame, after the lattice changed, on every machine (the dedicated server too), from the damage the server confirmed: a hit this machine predicts fires nothing until the server confirms it. A repair fires it with zeros; a player who joins late gets it once the replicated chunks have built the lattice. While the world is paused it waits for the first frame that is not. Read Get Damage Zones for the state before the first event.

Category
Crushform|Damage
FCFOnDamageChangedDelegate OnDamageChangedNative
C++ ONLY
(const FCFDamageZones&)

OnDamageChanged for C++: broadcast just before it, with the same zones.