(Feat) Add mulitplayer
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include "ItemDataAsset.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "NiagaraComponent.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
#include "TimerManager.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "CookingStation"
|
||||
@@ -20,6 +21,14 @@ ACookingStation::ACookingStation()
|
||||
// Tout passe par des timers : la station n'a rien a faire chaque frame.
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
||||
// Acteur du monde. La cuisson et la combustion ne sont comptees QUE par le
|
||||
// serveur : les timers ne partent jamais sur le reseau, seuls leurs
|
||||
// resultats -- l'objet devenu cuit, la buche disparue -- sont repliques.
|
||||
// Quatre clients qui compteraient chacun leur cuisson divergeraient, et le
|
||||
// steak serait brule chez l'un et cru chez l'autre.
|
||||
bReplicates = true;
|
||||
SetReplicateMovement(false);
|
||||
|
||||
BaseMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BaseMesh"));
|
||||
SetRootComponent(BaseMesh);
|
||||
// Le foyer est un obstacle physique, contrairement a un ramassable : on
|
||||
@@ -77,40 +86,83 @@ ACookingStation::ACookingStation()
|
||||
}
|
||||
}
|
||||
|
||||
void ACookingStation::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
DOREPLIFETIME(ACookingStation, Slots);
|
||||
DOREPLIFETIME(ACookingStation, Fuel);
|
||||
DOREPLIFETIME(ACookingStation, bIsLit);
|
||||
}
|
||||
|
||||
void ACookingStation::OnRep_Slots()
|
||||
{
|
||||
// Le mesh d'un emplacement suit son contenu : c'est TOUT l'affichage de la
|
||||
// cuisson, il n'y a aucune interface. Cru, cuit, brule -- le joueur ne lit
|
||||
// que ca.
|
||||
for (int32 Index = 0; Index < Slots.Num(); ++Index)
|
||||
{
|
||||
RefreshSlotMesh(Index);
|
||||
}
|
||||
}
|
||||
|
||||
void ACookingStation::OnRep_Fuel()
|
||||
{
|
||||
RefreshFuelIndicators();
|
||||
}
|
||||
|
||||
void ACookingStation::OnRep_IsLit()
|
||||
{
|
||||
ApplyFireVisuals(bIsLit);
|
||||
}
|
||||
|
||||
void ACookingStation::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
Slots.SetNum(MaxCookingSlots);
|
||||
// Recensement des buches AVANT tout : il fixe la capacite, et il est purement
|
||||
// local -- ce sont des composants du Blueprint, identiques partout.
|
||||
CacheFuelIndicators();
|
||||
|
||||
// Le contenu initial est de l'etat de monde : seul le serveur le pose, les
|
||||
// clients le recevront par replication. Sans cette garde, chaque client se
|
||||
// donnerait ses propres buches de depart en plus de celles du serveur.
|
||||
if (HasAuthority())
|
||||
{
|
||||
Slots.SetNum(MaxCookingSlots);
|
||||
|
||||
if (StartingFuelItem && StartingFuelItem->bIsFuel)
|
||||
{
|
||||
const int32 Count = FMath::Min(StartingFuelCount, GetFuelCapacity());
|
||||
for (int32 Index = 0; Index < Count; ++Index)
|
||||
{
|
||||
FFuelSlotState& NewFuel = Fuel.AddDefaulted_GetRef();
|
||||
NewFuel.Item = StartingFuelItem;
|
||||
NewFuel.RemainingSeconds = FMath::Max(1.f, StartingFuelItem->FuelDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Les meshes de reperage poses dans le Blueprint n'ont plus rien a faire la :
|
||||
// RefreshSlotMesh remet chaque emplacement sur son contenu reel, donc rien.
|
||||
for (int32 Index = 0; Index < MaxCookingSlots; ++Index)
|
||||
// Chez un client Slots est encore vide a cet instant ; OnRep_Slots repassera
|
||||
// des que le contenu reel arrivera.
|
||||
for (int32 Index = 0; Index < Slots.Num(); ++Index)
|
||||
{
|
||||
RefreshSlotMesh(Index);
|
||||
}
|
||||
|
||||
// Avant tout usage du carburant : c'est ce recensement qui fixe la capacite.
|
||||
CacheFuelIndicators();
|
||||
|
||||
if (StartingFuelItem && StartingFuelItem->bIsFuel)
|
||||
{
|
||||
const int32 Count = FMath::Min(StartingFuelCount, GetFuelCapacity());
|
||||
for (int32 Index = 0; Index < Count; ++Index)
|
||||
{
|
||||
FFuelSlotState& NewFuel = Fuel.AddDefaulted_GetRef();
|
||||
NewFuel.Item = StartingFuelItem;
|
||||
NewFuel.RemainingSeconds = FMath::Max(1.f, StartingFuelItem->FuelDuration);
|
||||
}
|
||||
}
|
||||
|
||||
RefreshFuelIndicators();
|
||||
|
||||
// Le grill est vide au demarrage, donc le feu reste eteint quoi qu'il
|
||||
// arrive. On passe quand meme par le point de decision unique plutot que
|
||||
// d'ecrire un cas particulier de plus.
|
||||
ApplyFireVisuals(false);
|
||||
UpdateFireState();
|
||||
|
||||
if (HasAuthority())
|
||||
{
|
||||
UpdateFireState();
|
||||
}
|
||||
}
|
||||
|
||||
void ACookingStation::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
@@ -245,6 +297,14 @@ bool ACookingStation::HasPendingWork() const
|
||||
|
||||
void ACookingStation::UpdateFireState()
|
||||
{
|
||||
// Point de decision unique du feu, donc point de garde unique : bIsLit et
|
||||
// les timers de combustion appartiennent au serveur. Chez un client c'est
|
||||
// OnRep_IsLit qui allume la flamme, sans jamais rien decider.
|
||||
if (!HasAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Un objet DEJA cuit qui peut encore bruler compte comme du travail : sans
|
||||
// ca le feu s'arreterait pile a la fin de la cuisson et la sur-cuisson
|
||||
// n'arriverait jamais. Oublier sa viande doit rester punitif.
|
||||
|
||||
Reference in New Issue
Block a user