298 lines
8.6 KiB
Ucode
298 lines
8.6 KiB
Ucode
//=============================================================================
|
|
// DynamicSMActor.
|
|
// A non-static version of StaticMeshActor. This class is abstract, but used as a
|
|
// base class for things like KActor and InterpActor.
|
|
// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
|
|
//=============================================================================
|
|
|
|
class DynamicSMActor extends Actor
|
|
native
|
|
abstract;
|
|
|
|
var() const editconst StaticMeshComponent StaticMeshComponent;
|
|
var() const editconst DynamicLightEnvironmentComponent LightEnvironment;
|
|
/** Used to replicate mesh to clients */
|
|
var repnotify transient StaticMesh ReplicatedMesh;
|
|
/** used to replicate the materials in indices 0 and 1 */
|
|
var repnotify MaterialInterface ReplicatedMaterial0, ReplicatedMaterial1;
|
|
/** used to replicate StaticMeshComponent.bForceStaticDecals */
|
|
var repnotify bool bForceStaticDecals;
|
|
|
|
/** Extra component properties to replicate */
|
|
var repnotify vector ReplicatedMeshTranslation;
|
|
var repnotify rotator ReplicatedMeshRotation;
|
|
var repnotify vector ReplicatedMeshScale3D;
|
|
|
|
/** If a Pawn can be 'based' on this KActor. If not, they will 'bounce' off when they try to. */
|
|
var() bool bPawnCanBaseOn;
|
|
/** Pawn can base on this KActor if it is asleep -- Pawn will disable KActor physics while based */
|
|
var() bool bSafeBaseIfAsleep;
|
|
|
|
cpptext
|
|
{
|
|
/**
|
|
* Function that gets called from within Map_Check to allow this actor to check itself
|
|
* for any potential errors and register them with map check dialog.
|
|
*/
|
|
#if WITH_EDITOR
|
|
virtual void CheckForErrors();
|
|
#endif
|
|
|
|
protected:
|
|
#if USE_GAMEPLAY_PROFILER
|
|
/**
|
|
* This function actually does the work for the GetProfilerAssetObject and is virtual.
|
|
* It should only be called from GetProfilerAssetObject as GetProfilerAssetObject is safe to call on NULL object pointers
|
|
*/
|
|
virtual UObject* GetProfilerAssetObjectInternal() const;
|
|
#endif
|
|
/**
|
|
* This function actually does the work for the GetDetailInfo and is virtual.
|
|
* It should only be called from GetDetailedInfo as GetDetailedInfo is safe to call on NULL object pointers
|
|
*/
|
|
virtual FString GetDetailedInfoInternal() const;
|
|
}
|
|
|
|
replication
|
|
{
|
|
if (bNetDirty)
|
|
ReplicatedMesh, ReplicatedMaterial0, ReplicatedMaterial1, ReplicatedMeshTranslation, ReplicatedMeshRotation, ReplicatedMeshScale3D, bForceStaticDecals;
|
|
}
|
|
|
|
event PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
|
|
if( StaticMeshComponent != none )
|
|
{
|
|
ReplicatedMesh = StaticMeshComponent.StaticMesh;
|
|
bForceStaticDecals = StaticMeshComponent.bForceStaticDecals;
|
|
}
|
|
}
|
|
|
|
simulated event ReplicatedEvent(name VarName)
|
|
{
|
|
if (VarName == 'ReplicatedMesh')
|
|
{
|
|
if (ReplicatedMesh != StaticMeshComponent.StaticMesh)
|
|
{
|
|
// Enable the light environment if it is not already
|
|
LightEnvironment.bCastShadows = false;
|
|
LightEnvironment.SetEnabled(TRUE);
|
|
|
|
StaticMeshComponent.SetStaticMesh(ReplicatedMesh);
|
|
}
|
|
}
|
|
else if (VarName == nameof(ReplicatedMaterial0))
|
|
{
|
|
StaticMeshComponent.SetMaterial(0, ReplicatedMaterial0);
|
|
}
|
|
else if (VarName == nameof(ReplicatedMaterial1))
|
|
{
|
|
StaticMeshComponent.SetMaterial(1, ReplicatedMaterial1);
|
|
}
|
|
else if (VarName == 'ReplicatedMeshTranslation')
|
|
{
|
|
StaticMeshComponent.SetTranslation(ReplicatedMeshTranslation);
|
|
}
|
|
else if (VarName == 'ReplicatedMeshRotation')
|
|
{
|
|
StaticMeshComponent.SetRotation(ReplicatedMeshRotation);
|
|
}
|
|
else if (VarName == 'ReplicatedMeshScale3D')
|
|
{
|
|
StaticmeshComponent.SetScale3D(ReplicatedMeshScale3D / 100.0); // remove compensation for replication rounding
|
|
}
|
|
else if (VarName == nameof(bForceStaticDecals))
|
|
{
|
|
StaticMeshComponent.SetForceStaticDecals(bForceStaticDecals);
|
|
}
|
|
else
|
|
{
|
|
Super.ReplicatedEvent(VarName);
|
|
}
|
|
}
|
|
|
|
function OnSetMesh(SeqAct_SetMesh Action)
|
|
{
|
|
local bool bForce;
|
|
if( Action.MeshType == MeshType_StaticMesh )
|
|
{
|
|
bForce = Action.bIsAllowedToMove == StaticMeshComponent.bForceStaticDecals || Action.bAllowDecalsToReattach;
|
|
|
|
if( (Action.NewStaticMesh != None) &&
|
|
(Action.NewStaticMesh != StaticMeshComponent.StaticMesh || bForce) )
|
|
{
|
|
// Enable the light environment if it is not already
|
|
LightEnvironment.bCastShadows = false;
|
|
LightEnvironment.SetEnabled(TRUE);
|
|
// force decals on this mesh to be treated as movable or not (if False then decals will use fastpath)
|
|
bForceStaticDecals = !Action.bIsAllowedToMove;
|
|
StaticMeshComponent.SetForceStaticDecals(bForceStaticDecals);
|
|
// Don't allow decals to reattach since we are changing the static mesh
|
|
StaticMeshComponent.bAllowDecalAutomaticReAttach = Action.bAllowDecalsToReattach;
|
|
StaticMeshComponent.SetStaticMesh( Action.NewStaticMesh, Action.bAllowDecalsToReattach );
|
|
StaticMeshComponent.bAllowDecalAutomaticReAttach = true;
|
|
ReplicatedMesh = Action.NewStaticMesh;
|
|
ForceNetRelevant();
|
|
}
|
|
}
|
|
}
|
|
|
|
function OnSetMaterial(SeqAct_SetMaterial Action)
|
|
{
|
|
StaticMeshComponent.SetMaterial( Action.MaterialIndex, Action.NewMaterial );
|
|
if (Action.MaterialIndex == 0)
|
|
{
|
|
ReplicatedMaterial0 = Action.NewMaterial;
|
|
ForceNetRelevant();
|
|
}
|
|
else if (Action.MaterialIndex == 1)
|
|
{
|
|
ReplicatedMaterial1 = Action.NewMaterial;
|
|
ForceNetRelevant();
|
|
}
|
|
}
|
|
|
|
function SetStaticMesh(StaticMesh NewMesh, optional vector NewTranslation, optional rotator NewRotation, optional vector NewScale3D)
|
|
{
|
|
StaticMeshComponent.SetStaticMesh(NewMesh);
|
|
StaticMeshComponent.SetTranslation(NewTranslation);
|
|
StaticMeshComponent.SetRotation(NewRotation);
|
|
if (!IsZero(NewScale3D))
|
|
{
|
|
StaticMeshComponent.SetScale3D(NewScale3D);
|
|
ReplicatedMeshScale3D = NewScale3D * 100.0; // avoid rounding in replication code
|
|
}
|
|
ReplicatedMesh = NewMesh;
|
|
ReplicatedMeshTranslation = NewTranslation;
|
|
ReplicatedMeshRotation = NewRotation;
|
|
ForceNetRelevant();
|
|
}
|
|
|
|
/**
|
|
* Query to see if this DynamicSMActor can base the given Pawn
|
|
*/
|
|
simulated function bool CanBasePawn( Pawn P )
|
|
{
|
|
// Can base pawn if...
|
|
// Pawns can be based always OR
|
|
// Pawns can be based if physics is not awake
|
|
if( bPawnCanBaseOn ||
|
|
(bSafeBaseIfAsleep &&
|
|
StaticMeshComponent != None &&
|
|
!StaticMeshComponent.RigidBodyIsAwake()) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* If pawn is attached while asleep, turn off physics while pawn is on it
|
|
*/
|
|
event Attach( Actor Other )
|
|
{
|
|
local Pawn P;
|
|
|
|
super.Attach( Other );
|
|
|
|
if( bSafeBaseIfAsleep )
|
|
{
|
|
P = Pawn(Other);
|
|
if( P != None )
|
|
{
|
|
SetPhysics( PHYS_None );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* If pawn is detached, turn back on physics (make sure no other pawns are based on it)
|
|
*/
|
|
event Detach( Actor Other )
|
|
{
|
|
local int Idx;
|
|
local Pawn P, Test;
|
|
local bool bResetPhysics;
|
|
|
|
super.Detach( Other );
|
|
|
|
P = Pawn(Other);
|
|
if( P != None )
|
|
{
|
|
bResetPhysics = TRUE;
|
|
for( Idx = 0; Idx < Attached.Length; Idx++ )
|
|
{
|
|
Test = Pawn(Attached[Idx]);
|
|
if( Test != None && Test != P )
|
|
{
|
|
bResetPhysics = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( bResetPhysics )
|
|
{
|
|
SetPhysics( PHYS_RigidBody );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* This will turn "off" the light environment so it will no longer update.
|
|
* This is useful for having a Timer call this once something has come to a stop and doesn't need 100% correct lighting.
|
|
**/
|
|
simulated final function SetLightEnvironmentToNotBeDynamic()
|
|
{
|
|
if( LightEnvironment != none )
|
|
{
|
|
LightEnvironment.bDynamic = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
defaultproperties
|
|
{
|
|
Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
|
|
`if(`__TW_LIGHTING_MODIFICATIONS_)
|
|
bEnabled=False
|
|
`else
|
|
bEnabled=True
|
|
`endif
|
|
End Object
|
|
LightEnvironment=MyLightEnvironment
|
|
Components.Add(MyLightEnvironment)
|
|
|
|
Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0
|
|
BlockRigidBody=false
|
|
LightEnvironment=MyLightEnvironment
|
|
bUsePrecomputedShadows=FALSE
|
|
End Object
|
|
CollisionComponent=StaticMeshComponent0
|
|
StaticMeshComponent=StaticMeshComponent0
|
|
Components.Add(StaticMeshComponent0)
|
|
|
|
bEdShouldSnap=true
|
|
bWorldGeometry=false
|
|
bGameRelevant=true
|
|
RemoteRole=ROLE_SimulatedProxy
|
|
bPathColliding=true
|
|
|
|
// DynamicSMActor do not have collision as a default. Having collision on them
|
|
// can be very slow (e.g. matinees where the matinee is controlling where
|
|
// the actors move and then they are trying to collide also!)
|
|
// The overall idea is that it is really easy to see when something doesn't
|
|
// collide correct and rectify it. On the other hand, it is hard to see
|
|
// something testing collision when it should not be while you wonder where
|
|
// your framerate went.
|
|
|
|
bCollideActors=false
|
|
bPawnCanBaseOn=true
|
|
|
|
// Automatically shadow parent to whatever this actor is attached to by default
|
|
bShadowParented=true
|
|
}
|