Step 1: the Salty project, two modules, tests and the gym
Salty.uproject (UE 5.8) from the Third Person template with class redirects, the SaltyCore and Salty modules, the three build targets, USaltyAssetManager calling InitGlobalData, Config/Tags with the 23 root namespaces, Scripts/run-tests.sh, build.sh and Authoring/create_gym.py, L_Gym, Git LFS attributes and the placeholder test. Template variants kept as reference (D-41). The four Fab packs stay out of the repository for now (~10 GB). The editor serves the engine MCP plugin on 127.0.0.1:8000 through DefaultEditorPerProjectUserSettings.ini. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
0e61a77346
commit
4f2c55cd2a
@@ -0,0 +1,49 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
|
||||
#include "CombatActivationVolume.h"
|
||||
#include "Components/BoxComponent.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "CombatActivatable.h"
|
||||
|
||||
ACombatActivationVolume::ACombatActivationVolume()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
||||
// create the box volume
|
||||
RootComponent = Box = CreateDefaultSubobject<UBoxComponent>(TEXT("Box"));
|
||||
check(Box);
|
||||
|
||||
// set the box's extent
|
||||
Box->SetBoxExtent(FVector(500.0f, 500.0f, 500.0f));
|
||||
|
||||
// set the default collision profile to overlap all dynamic
|
||||
Box->SetCollisionProfileName(FName("OverlapAllDynamic"));
|
||||
|
||||
// bind the begin overlap
|
||||
Box->OnComponentBeginOverlap.AddDynamic(this, &ACombatActivationVolume::OnOverlap);
|
||||
}
|
||||
|
||||
void ACombatActivationVolume::OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
|
||||
{
|
||||
// has a Character entered the volume?
|
||||
ACharacter* PlayerCharacter = Cast<ACharacter>(OtherActor);
|
||||
|
||||
if (PlayerCharacter)
|
||||
{
|
||||
// is the Character controlled by a player
|
||||
if (PlayerCharacter->IsPlayerControlled())
|
||||
{
|
||||
// process the actors to activate list
|
||||
for (AActor* CurrentActor : ActorsToActivate)
|
||||
{
|
||||
// is the referenced actor activatable?
|
||||
if(ICombatActivatable* Activatable = Cast<ICombatActivatable>(CurrentActor))
|
||||
{
|
||||
Activatable->ActivateInteraction(PlayerCharacter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "CombatActivationVolume.generated.h"
|
||||
|
||||
class UBoxComponent;
|
||||
|
||||
/**
|
||||
* A simple volume that activates a list of actors when the player pawn enters.
|
||||
*/
|
||||
UCLASS()
|
||||
class ACombatActivationVolume : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Collision box volume */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category ="Components", meta = (AllowPrivateAccess = "true"))
|
||||
UBoxComponent* Box;
|
||||
|
||||
protected:
|
||||
|
||||
/** List of actors to activate when this volume is entered */
|
||||
UPROPERTY(EditAnywhere, Category="Activation Volume")
|
||||
TArray<AActor*> ActorsToActivate;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
ACombatActivationVolume();
|
||||
|
||||
protected:
|
||||
|
||||
/** Handles overlaps with the box volume */
|
||||
UFUNCTION()
|
||||
void OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
|
||||
#include "CombatCheckpointVolume.h"
|
||||
#include "CombatCharacter.h"
|
||||
#include "CombatPlayerController.h"
|
||||
|
||||
ACombatCheckpointVolume::ACombatCheckpointVolume()
|
||||
{
|
||||
// create the box volume
|
||||
RootComponent = Box = CreateDefaultSubobject<UBoxComponent>(TEXT("Box"));
|
||||
check(Box);
|
||||
|
||||
// set the box's extent
|
||||
Box->SetBoxExtent(FVector(500.0f, 500.0f, 500.0f));
|
||||
|
||||
// set the default collision profile to overlap all dynamic
|
||||
Box->SetCollisionProfileName(FName("OverlapAllDynamic"));
|
||||
|
||||
// bind the begin overlap
|
||||
Box->OnComponentBeginOverlap.AddDynamic(this, &ACombatCheckpointVolume::OnOverlap);
|
||||
}
|
||||
|
||||
void ACombatCheckpointVolume::OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
|
||||
{
|
||||
// has the player entered this volume?
|
||||
ACombatCharacter* PlayerCharacter = Cast<ACombatCharacter>(OtherActor);
|
||||
|
||||
if (PlayerCharacter)
|
||||
{
|
||||
if (ACombatPlayerController* PC = Cast<ACombatPlayerController>(PlayerCharacter->GetController()))
|
||||
{
|
||||
// update the player's respawn checkpoint
|
||||
PC->SetRespawnTransform(PlayerCharacter->GetActorTransform());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "Components/BoxComponent.h"
|
||||
#include "CombatCheckpointVolume.generated.h"
|
||||
|
||||
UCLASS(abstract)
|
||||
class ACombatCheckpointVolume : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Collision box volume */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Components, meta = (AllowPrivateAccess = "true"))
|
||||
UBoxComponent* Box;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
ACombatCheckpointVolume();
|
||||
|
||||
protected:
|
||||
|
||||
/** Handles overlaps with the box volume */
|
||||
UFUNCTION()
|
||||
void OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
|
||||
#include "CombatDamageableBox.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "TimerManager.h"
|
||||
#include "Engine/World.h"
|
||||
|
||||
ACombatDamageableBox::ACombatDamageableBox()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
||||
// create the mesh
|
||||
RootComponent = Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
|
||||
|
||||
// set the collision properties
|
||||
Mesh->SetCollisionProfileName(FName("BlockAllDynamic"));
|
||||
|
||||
// enable physics
|
||||
Mesh->SetSimulatePhysics(true);
|
||||
|
||||
// disable navigation relevance so boxes don't affect NavMesh generation
|
||||
Mesh->bNavigationRelevant = false;
|
||||
}
|
||||
|
||||
void ACombatDamageableBox::RemoveFromLevel()
|
||||
{
|
||||
// destroy this actor
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void ACombatDamageableBox::EndPlay(EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
Super::EndPlay(EndPlayReason);
|
||||
|
||||
// clear the death timer
|
||||
GetWorld()->GetTimerManager().ClearTimer(DeathTimer);
|
||||
}
|
||||
|
||||
void ACombatDamageableBox::ApplyDamage(float Damage, AActor* DamageCauser, const FVector& DamageLocation, const FVector& DamageImpulse)
|
||||
{
|
||||
// only process damage if we still have HP
|
||||
if (CurrentHP > 0.0f)
|
||||
{
|
||||
// apply the damage
|
||||
CurrentHP -= Damage;
|
||||
|
||||
// are we dead?
|
||||
if (CurrentHP <= 0.0f)
|
||||
{
|
||||
HandleDeath();
|
||||
}
|
||||
|
||||
// apply a physics impulse to the box, ignoring its mass
|
||||
Mesh->AddImpulseAtLocation(DamageImpulse * Mesh->GetMass(), DamageLocation);
|
||||
|
||||
// call the BP handler to play effects, etc.
|
||||
OnBoxDamaged(DamageLocation, DamageImpulse);
|
||||
}
|
||||
}
|
||||
|
||||
void ACombatDamageableBox::HandleDeath()
|
||||
{
|
||||
// change the collision object type to Visibility so we ignore most interactions but still retain physics collisions
|
||||
Mesh->SetCollisionObjectType(ECC_Visibility);
|
||||
|
||||
// call the BP handler to play effects, etc.
|
||||
OnBoxDestroyed();
|
||||
|
||||
// set up the death cleanup timer
|
||||
GetWorld()->GetTimerManager().SetTimer(DeathTimer, this, &ACombatDamageableBox::RemoveFromLevel, DeathDelayTime);
|
||||
}
|
||||
|
||||
void ACombatDamageableBox::ApplyHealing(float Healing, AActor* Healer)
|
||||
{
|
||||
// stub
|
||||
}
|
||||
|
||||
void ACombatDamageableBox::NotifyDanger(const FVector& DangerLocation, AActor* DangerSource)
|
||||
{
|
||||
// stub
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "CombatDamageable.h"
|
||||
#include "CombatDamageableBox.generated.h"
|
||||
|
||||
/**
|
||||
* A simple physics box that reacts to damage through the ICombatDamageable interface
|
||||
*/
|
||||
UCLASS(abstract)
|
||||
class ACombatDamageableBox : public AActor, public ICombatDamageable
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Damageable box mesh */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
|
||||
UStaticMeshComponent* Mesh;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
ACombatDamageableBox();
|
||||
|
||||
protected:
|
||||
|
||||
/** Amount of HP this box starts with. */
|
||||
UPROPERTY(EditAnywhere, Category="Damage")
|
||||
float CurrentHP = 3.0f;
|
||||
|
||||
/** Time to wait before we remove this box from the level. */
|
||||
UPROPERTY(EditAnywhere, Category="Damage", meta = (ClampMin = 0, ClampMax = 10, Units = "s"))
|
||||
float DeathDelayTime = 6.0f;
|
||||
|
||||
/** Timer to defer destruction of this box after its HP are depleted */
|
||||
FTimerHandle DeathTimer;
|
||||
|
||||
/** Blueprint damage handler for effect playback */
|
||||
UFUNCTION(BlueprintImplementableEvent, Category="Damage")
|
||||
void OnBoxDamaged(const FVector& DamageLocation, const FVector& DamageImpulse);
|
||||
|
||||
/** Blueprint destruction handler for effect playback */
|
||||
UFUNCTION(BlueprintImplementableEvent, Category="Damage")
|
||||
void OnBoxDestroyed();
|
||||
|
||||
/** Timer callback to remove the box from the level after it dies */
|
||||
void RemoveFromLevel();
|
||||
|
||||
public:
|
||||
|
||||
/** EndPlay cleanup */
|
||||
void EndPlay(EEndPlayReason::Type EndPlayReason) override;
|
||||
|
||||
// ~Begin CombatDamageable interface
|
||||
|
||||
/** Handles damage and knockback events */
|
||||
virtual void ApplyDamage(float Damage, AActor* DamageCauser, const FVector& DamageLocation, const FVector& DamageImpulse) override;
|
||||
|
||||
/** Handles death events */
|
||||
virtual void HandleDeath() override;
|
||||
|
||||
/** Handles healing events */
|
||||
virtual void ApplyHealing(float Healing, AActor* Healer) override;
|
||||
|
||||
/** Allows reaction to incoming attacks */
|
||||
virtual void NotifyDanger(const FVector& DangerLocation, AActor* DangerSource) override;
|
||||
|
||||
// ~End CombatDamageable interface
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
|
||||
#include "CombatDummy.h"
|
||||
#include "Components/SceneComponent.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "PhysicsEngine/PhysicsConstraintComponent.h"
|
||||
|
||||
ACombatDummy::ACombatDummy()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
|
||||
// create the root
|
||||
Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
|
||||
SetRootComponent(Root);
|
||||
|
||||
// create the base plate
|
||||
BasePlate = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Base Plate"));
|
||||
BasePlate->SetupAttachment(RootComponent);
|
||||
|
||||
// create the dummy
|
||||
Dummy = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Dummy"));
|
||||
Dummy->SetupAttachment(RootComponent);
|
||||
|
||||
Dummy->SetSimulatePhysics(true);
|
||||
|
||||
// create the physics constraint
|
||||
PhysicsConstraint = CreateDefaultSubobject<UPhysicsConstraintComponent>(TEXT("Physics Constraint"));
|
||||
PhysicsConstraint->SetupAttachment(RootComponent);
|
||||
|
||||
PhysicsConstraint->SetConstrainedComponents(BasePlate, NAME_None, Dummy, NAME_None);
|
||||
}
|
||||
|
||||
void ACombatDummy::ApplyDamage(float Damage, AActor* DamageCauser, const FVector& DamageLocation, const FVector& DamageImpulse)
|
||||
{
|
||||
// apply impulse to the dummy
|
||||
Dummy->AddImpulseAtLocation(DamageImpulse, DamageLocation);
|
||||
|
||||
// call the BP handler
|
||||
BP_OnDummyDamaged(DamageLocation, DamageImpulse.GetSafeNormal());
|
||||
}
|
||||
|
||||
void ACombatDummy::HandleDeath()
|
||||
{
|
||||
// unused
|
||||
}
|
||||
|
||||
void ACombatDummy::ApplyHealing(float Healing, AActor* Healer)
|
||||
{
|
||||
// unused
|
||||
}
|
||||
|
||||
void ACombatDummy::NotifyDanger(const FVector& DangerLocation, AActor* DangerSource)
|
||||
{
|
||||
// unused
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "CombatDamageable.h"
|
||||
#include "CombatDummy.generated.h"
|
||||
|
||||
class UStaticMeshComponent;
|
||||
class UPhysicsConstraintComponent;
|
||||
|
||||
/**
|
||||
* A simple invincible combat training dummy
|
||||
*/
|
||||
UCLASS(abstract)
|
||||
class ACombatDummy : public AActor, public ICombatDamageable
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Root component */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
|
||||
USceneComponent* Root;
|
||||
|
||||
/** Static base plate */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
|
||||
UStaticMeshComponent* BasePlate;
|
||||
|
||||
/** Physics enabled dummy mesh */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
|
||||
UStaticMeshComponent* Dummy;
|
||||
|
||||
/** Physics constraint holding the dummy and base plate together */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true"))
|
||||
UPhysicsConstraintComponent* PhysicsConstraint;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
ACombatDummy();
|
||||
|
||||
// ~Begin CombatDamageable interface
|
||||
|
||||
/** Handles damage and knockback events */
|
||||
virtual void ApplyDamage(float Damage, AActor* DamageCauser, const FVector& DamageLocation, const FVector& DamageImpulse) override;
|
||||
|
||||
/** Handles death events */
|
||||
virtual void HandleDeath() override;
|
||||
|
||||
/** Handles healing events */
|
||||
virtual void ApplyHealing(float Healing, AActor* Healer) override;
|
||||
|
||||
/** Allows reaction to incoming attacks */
|
||||
virtual void NotifyDanger(const FVector& DangerLocation, AActor* DangerSource) override;
|
||||
|
||||
// ~End CombatDamageable interface
|
||||
|
||||
protected:
|
||||
|
||||
/** Blueprint handle to apply damage effects */
|
||||
UFUNCTION(BlueprintImplementableEvent, Category="Combat", meta = (DisplayName = "On Dummy Damaged"))
|
||||
void BP_OnDummyDamaged(const FVector& Location, const FVector& Direction);
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
|
||||
#include "CombatLavaFloor.h"
|
||||
#include "CombatDamageable.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
|
||||
ACombatLavaFloor::ACombatLavaFloor()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
||||
// create the mesh
|
||||
RootComponent = Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
|
||||
|
||||
// bind the hit handler
|
||||
Mesh->OnComponentHit.AddDynamic(this, &ACombatLavaFloor::OnFloorHit);
|
||||
}
|
||||
|
||||
void ACombatLavaFloor::OnFloorHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
|
||||
{
|
||||
// check if the hit actor is damageable by casting to the interface
|
||||
if (ICombatDamageable* Damageable = Cast<ICombatDamageable>(OtherActor))
|
||||
{
|
||||
// damage the actor
|
||||
Damageable->ApplyDamage(Damage, this, Hit.ImpactPoint, FVector::ZeroVector);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "CombatLavaFloor.generated.h"
|
||||
|
||||
class UStaticMeshComponent;
|
||||
class UPrimitiveComponent;
|
||||
|
||||
/**
|
||||
* A basic actor that applies damage on contact through the ICombatDamageable interface.
|
||||
*/
|
||||
UCLASS(abstract)
|
||||
class ACombatLavaFloor : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Floor mesh */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components", meta = (AllowPrivateAccess = "true"))
|
||||
UStaticMeshComponent* Mesh;
|
||||
|
||||
protected:
|
||||
|
||||
/** Amount of damage to deal on contact */
|
||||
UPROPERTY(EditAnywhere, Category="Damage")
|
||||
float Damage = 10000.0f;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
ACombatLavaFloor();
|
||||
|
||||
protected:
|
||||
|
||||
/** Blocking hit handler */
|
||||
UFUNCTION()
|
||||
void OnFloorHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
|
||||
};
|
||||
Reference in New Issue
Block a user