(Feat) Add mulitplayer

This commit is contained in:
2026-08-03 10:30:47 +02:00
parent 41d6e6a7f3
commit a4cc59a411
41 changed files with 3418 additions and 125 deletions
@@ -4,18 +4,64 @@
#include "SurvivalStatsComponent.h"
#include "Engine/World.h"
#include "Net/UnrealNetwork.h"
#include "TimerManager.h"
USurvivalStatsComponent::USurvivalStatsComponent()
{
// Pas de Tick : tout passe par un timer a basse frequence.
PrimaryComponentTick.bCanEverTick = false;
SetIsReplicatedByDefault(true);
}
void USurvivalStatsComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// COND_OwnerOnly ici, contrairement a l'inventaire : ces jauges n'existent
// que sur un pawn, qui appartient bien a une connexion -- la condition
// fonctionne donc. Et la faim d'un coequipier ne regarde personne d'autre
// que lui. Le jour ou une barre de vie s'affichera au-dessus des allies,
// c'est Health seul qu'il faudra ouvrir a tous.
DOREPLIFETIME_CONDITION(USurvivalStatsComponent, Health, COND_OwnerOnly);
DOREPLIFETIME_CONDITION(USurvivalStatsComponent, Hunger, COND_OwnerOnly);
DOREPLIFETIME_CONDITION(USurvivalStatsComponent, Thirst, COND_OwnerOnly);
DOREPLIFETIME_CONDITION(USurvivalStatsComponent, bDead, COND_OwnerOnly);
}
void USurvivalStatsComponent::OnRep_Stats()
{
OnStatsChanged.Broadcast();
}
void USurvivalStatsComponent::OnRep_Dead()
{
OnStatsChanged.Broadcast();
// bDead ne repasse jamais a vrai sans un nouveau pawn : apres un respawn
// c'est un AUTRE composant qui arrive, plein et vivant. Pas de risque de
// rediffuser une mort deja traitee.
if (bDead)
{
OnDied.Broadcast();
}
}
void USurvivalStatsComponent::BeginPlay()
{
Super::BeginPlay();
// Un client ne simule rien : il recevra les valeurs par replication.
// Sans cette garde, chaque client ferait descendre SA copie des jauges en
// plus de celle du serveur, et les barres sauteraient a chaque OnRep --
// un scintillement qu'on chercherait longtemps.
const AActor* Owner = GetOwner();
if (!Owner || !Owner->HasAuthority())
{
return;
}
Health = MaxHealth;
Hunger = MaxHunger;
Thirst = MaxThirst;
@@ -91,6 +137,15 @@ void USurvivalStatsComponent::UpdateStats()
void USurvivalStatsComponent::ApplyRestore(float HealthAmount, float HungerAmount, float ThirstAmount)
{
// Manger se decide sur le serveur (AFpsPlayer::Server_UseItem). Une
// restauration jouee en local remonterait la barre du client, que le
// prochain OnRep ferait redescendre : un clignotement pour rien.
const AActor* Owner = GetOwner();
if (!Owner || !Owner->HasAuthority())
{
return;
}
if (bDead)
{
return;
@@ -105,6 +160,13 @@ void USurvivalStatsComponent::ApplyRestore(float HealthAmount, float HungerAmoun
void USurvivalStatsComponent::ApplyDamage(float Amount)
{
// Meme regle que ApplyRestore : les degats appartiennent a l'autorite.
const AActor* Owner = GetOwner();
if (!Owner || !Owner->HasAuthority())
{
return;
}
if (bDead || Amount <= 0.f)
{
return;