// Copyright Pacificao. All Rights Reserved. #include "AgrarianShelterActor.h" #include "AgrarianPersistentActorComponent.h" #include "Components/BoxComponent.h" #include "Components/StaticMeshComponent.h" #include "Net/UnrealNetwork.h" AAgrarianShelterActor::AAgrarianShelterActor() { bReplicates = true; NetCullDistanceSquared = FMath::Square(6000.0f); Mesh = CreateDefaultSubobject(TEXT("Mesh")); RootComponent = Mesh; ProtectionVolume = CreateDefaultSubobject(TEXT("ProtectionVolume")); ProtectionVolume->SetupAttachment(RootComponent); ProtectionVolume->SetBoxExtent(FVector(250.0f, 250.0f, 180.0f)); ProtectionVolume->SetCollisionProfileName(TEXT("OverlapAllDynamic")); PersistentActorComponent = CreateDefaultSubobject(TEXT("PersistentActorComponent")); PersistentActorComponent->ActorTypeId = TEXT("primitive_shelter"); } void AAgrarianShelterActor::BeginPlay() { Super::BeginPlay(); ClampStructureHealth(); } float AAgrarianShelterActor::TakeDamage(float DamageAmount, const FDamageEvent& DamageEvent, AController* EventInstigator, AActor* DamageCauser) { const float PreviousHealth = CurrentStructureHealth; ApplyStructureDamage(DamageAmount, DamageCauser); return FMath::Max(0.0f, PreviousHealth - CurrentStructureHealth); } void AAgrarianShelterActor::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(AAgrarianShelterActor, MaxStructureHealth); DOREPLIFETIME(AAgrarianShelterActor, CurrentStructureHealth); } void AAgrarianShelterActor::CapturePersistentState_Implementation(UAgrarianPersistentActorComponent* PersistentComponent) const { if (!PersistentComponent) { return; } PersistentComponent->NumberState.Add(TEXT("max_structure_health"), MaxStructureHealth); PersistentComponent->NumberState.Add(TEXT("current_structure_health"), CurrentStructureHealth); } void AAgrarianShelterActor::ApplyPersistentState_Implementation(UAgrarianPersistentActorComponent* PersistentComponent) { if (!HasAuthority() || !PersistentComponent) { return; } if (const float* SavedMaxHealth = PersistentComponent->NumberState.Find(TEXT("max_structure_health"))) { MaxStructureHealth = FMath::Max(1.0f, *SavedMaxHealth); } if (const float* SavedCurrentHealth = PersistentComponent->NumberState.Find(TEXT("current_structure_health"))) { CurrentStructureHealth = *SavedCurrentHealth; } ClampStructureHealth(); } bool AAgrarianShelterActor::ApplyStructureDamage(float DamageAmount, AActor* DamageCauser) { if (!HasAuthority() || DamageAmount <= 0.0f || CurrentStructureHealth <= 0.0f) { return false; } CurrentStructureHealth = FMath::Clamp(CurrentStructureHealth - DamageAmount, 0.0f, MaxStructureHealth); if (CurrentStructureHealth <= 0.0f && bDestroyWhenHealthDepleted) { Destroy(); } return true; } bool AAgrarianShelterActor::RepairStructure(float RepairAmount) { if (!HasAuthority() || RepairAmount <= 0.0f || CurrentStructureHealth >= MaxStructureHealth) { return false; } CurrentStructureHealth = FMath::Clamp(CurrentStructureHealth + RepairAmount, 0.0f, MaxStructureHealth); return true; } bool AAgrarianShelterActor::Deconstruct(AActor* RequestingActor) { if (!HasAuthority() || !bCanBeDeconstructed) { return false; } Destroy(); return true; } float AAgrarianShelterActor::GetStructureHealthRatio() const { return MaxStructureHealth > 0.0f ? FMath::Clamp(CurrentStructureHealth / MaxStructureHealth, 0.0f, 1.0f) : 0.0f; } bool AAgrarianShelterActor::IsStructureDamaged() const { return CurrentStructureHealth < MaxStructureHealth; } void AAgrarianShelterActor::OnRep_StructureHealth() { ClampStructureHealth(); } void AAgrarianShelterActor::ClampStructureHealth() { MaxStructureHealth = FMath::Max(1.0f, MaxStructureHealth); CurrentStructureHealth = FMath::Clamp(CurrentStructureHealth, 0.0f, MaxStructureHealth); }