struct FTrackedEMFSpot
{
UPROPERTY()
AEMFSpot Spot;
UPROPERTY()
int Strength;
UPROPERTY()
FVector Location;
}
struct FTrackedSpotChange
{
UPROPERTY()
bool bAdded;
UPROPERTY()
FTrackedEMFSpot Spot;
FTrackedSpotChange(bool bInAdded, FTrackedEMFSpot InSpot)
{
Spot = InSpot;
bAdded = bInAdded;
}
}
class AEMF : AGadget
{
UPROPERTY(DefaultComponent)
USphereComponent DetectionSphere;
default DetectionSphere.CollisionProfileName = CollisionProfiles::EMFDetect;
default DetectionSphere.GenerateOverlapEvents = true;
UPROPERTY(DefaultComponent)
UHearableAudioComponent OnSound;
default OnSound.bAutoActivate = false;
UPROPERTY(DefaultComponent)
UHearableAudioComponent OffSound;
default OffSound.bAutoActivate = false;
UPROPERTY(ReplicatedUsing = OnRep_bIsOn)
bool bIsOn = false;
TArray TrackedSpots;
UPROPERTY(ReplicatedUsing = OnRep_SpotChanges)
TArray SpotChanges;
UMaterialInstanceDynamic MID;
UFUNCTION(BlueprintOverride)
void BeginPlay()
{
Super::BeginPlay();
DetectionSphere.OnComponentBeginOverlap.AddUFunction(this, n"OnDetectedEMF");
DetectionSphere.OnComponentEndOverlap.AddUFunction(this, n"OnStoppedDetectingEMF");
}
UFUNCTION(BlueprintOverride)
void Tick(float DeltaSeconds)
{
SortSpots();
}
UFUNCTION()
void OnDetectedEMF(UPrimitiveComponent OverlappedComponent, AActor OtherActor,
UPrimitiveComponent OtherComp, int OtherBodyIndex, bool bFromSweep,
const FHitResult&in SweepResult)
{
if (System::IsServer())
{
if (OtherActor.IsA(AEMFSpot::StaticClass()))
{
FTrackedEMFSpot Tracked;
Tracked.Spot = Cast(OtherActor);
Tracked.Strength = Tracked.Spot.Strength;
Tracked.Location = Tracked.Spot.ActorLocation;
OtherActor.OnDestroyed.AddUFunction(this, n"OnEMFSpotDestroyed");
AddSpot(Tracked, true);
}
}
}
UFUNCTION()
void OnStoppedDetectingEMF(UPrimitiveComponent OverlappedComponent, AActor OtherActor,
UPrimitiveComponent OtherComp, int OtherBodyIndex)
{
if (System::IsServer())
{
RemoveSpot(OtherActor, true);
}
}
UFUNCTION()
void OnEMFSpotDestroyed(AActor DestroyedActor)
{
RemoveSpot(DestroyedActor, true);
}
private void AddSpot(FTrackedEMFSpot Tracked, bool bRecordChanges)
{
if(TrackedSpots.Num() == 0)
{
RecordedAdd(Tracked, 0, bRecordChanges);
return;
}
float DistanceToNewSpot = Tracked.Location.Distance(ActorLocation);
bool bAdded = false;
for(int i = 0; i < TrackedSpots.Num(); i++)
{
float ThisDistance = TrackedSpots[i].Location.Distance(ActorLocation);
if(DistanceToNewSpot < ThisDistance)
{
RecordedAdd(Tracked, i, bRecordChanges);
bAdded = true;
break;
}
}
if(!bAdded)
{
RecordedAdd(Tracked, TrackedSpots.Num(), bRecordChanges);
}
}
private void RemoveSpot(AActor Actor, bool bRecordChanges)
{
for (int i = TrackedSpots.Num() - 1; i >= 0; i--)
{
if (TrackedSpots[i].Spot == Actor)
{
RecordedRemove(i, bRecordChanges);
break;
}
}
}
private void RecordedAdd(FTrackedEMFSpot Spot, int Index, bool bRecordChange)
{
TrackedSpots.Insert(Spot, Index);
if (bRecordChange)
{
SpotChanges.Add(FTrackedSpotChange(true, Spot));
}
OnAddedSpot(Spot, Index);
}
private void RecordedRemove(int Index, bool bRecordChange)
{
if (bRecordChange)
{
SpotChanges.Add(FTrackedSpotChange(false, TrackedSpots[Index]));
}
OnRemovedSpot(TrackedSpots[Index], Index);
TrackedSpots.RemoveAt(Index);
}
void OnAddedSpot(FTrackedEMFSpot TrackedSpot, int Index) { }
void OnRemovedSpot(FTrackedEMFSpot TrackedSpot, int Index) { }
private void SortSpots()
{
int Num = TrackedSpots.Num();
bool bSwapped = false;
for (int i = 0; i < Num; i++)
{
bSwapped = false;
for (int j = 0; j < Num - i - 1; j++)
{
if (TrackedSpots[j].Location.Distance(ActorLocation) > TrackedSpots[j + 1].Location.Distance(ActorLocation))
{
TrackedSpots.Swap(j, j + 1);
bSwapped = true;
}
}
if (!bSwapped)
{
break;
}
}
}
void OnSecondaryInteractEnd(AActor InteractingActor) override
{
Super::OnSecondaryInteractEnd(InteractingActor);
bIsOn = !bIsOn;
}
void NewOnState(){}
void PlayActivateSound()
{
if(bIsOn)
{
OnSound.Play();
OnSound.OnPlaying.Broadcast(OnSound);
}
else
{
OffSound.Play();
OffSound.OnPlaying.Broadcast(OffSound);
}
}
UFUNCTION()
private void OnRep_SpotChanges(TArray PreviousChanges)
{
if (SpotChanges.Num() > PreviousChanges.Num())
{
TArray AddedSpots;
TArray RemovedSpots;
for (int i = PreviousChanges.Num(); i < SpotChanges.Num(); i++)
{
if (SpotChanges[i].bAdded)
{
AddedSpots.Add(SpotChanges[i].Spot);
}
else
{
RemovedSpots.Add(SpotChanges[i].Spot.Spot);
}
}
for(auto Spot : AddedSpots)
{
AddSpot(Spot, false);
}
for(auto Spot : RemovedSpots)
{
RemoveSpot(Spot, false);
}
}
}
UFUNCTION()
void OnRep_bIsOn()
{
NewOnState();
PlayActivateSound();
}
}