(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
+51 -21
View File
@@ -7,6 +7,7 @@
#include "Components/StaticMeshComponent.h"
#include "InventoryComponent.h"
#include "ItemDataAsset.h"
#include "Net/UnrealNetwork.h"
#define LOCTEXT_NAMESPACE "PickupItem"
@@ -14,6 +15,15 @@ APickupItem::APickupItem()
{
PrimaryActorTick.bCanEverTick = false;
// Acteur du monde : le serveur fait autorite. Un pickup ramasse doit
// disparaitre chez les quatre joueurs, pas seulement chez celui qui l'a pris.
bReplicates = true;
// Un pickup ne bouge plus une fois pose. Couper la replication de mouvement
// evite d'envoyer une transform a chaque joueur qui entre dans sa zone de
// pertinence, alors que celle du spawn suffit.
SetReplicateMovement(false);
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
SetRootComponent(Mesh);
// Purement decoratif : c'est la sphere qui porte la collision.
@@ -29,6 +39,15 @@ APickupItem::APickupItem()
InteractionSphere->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
}
void APickupItem::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(APickupItem, ItemData);
DOREPLIFETIME(APickupItem, Quantity);
DOREPLIFETIME(APickupItem, RemainingUses);
}
void APickupItem::InitPickup(UItemDataAsset* InItemData, int32 InQuantity, int32 InRemainingUses)
{
ItemData = InItemData;
@@ -36,6 +55,19 @@ void APickupItem::InitPickup(UItemDataAsset* InItemData, int32 InQuantity, int32
RemainingUses = InRemainingUses;
}
void APickupItem::ApplyItemVisuals()
{
if (bUseMeshFromItemData && ItemData && ItemData->WorldMesh)
{
ItemData->ApplyWorldVisualsTo(Mesh);
}
}
void APickupItem::OnRep_ItemData()
{
ApplyItemVisuals();
}
void APickupItem::OnConstruction(const FTransform& Transform)
{
Super::OnConstruction(Transform);
@@ -43,10 +75,10 @@ void APickupItem::OnConstruction(const FTransform& Transform)
// Confort d'edition : le mesh suit l'objet choisi, tu vois immediatement
// dans le viewport ce que tu es en train de poser. Vaut aussi a l'execution
// pour les objets jetes, puisque OnConstruction s'execute a FinishSpawning.
if (bUseMeshFromItemData && ItemData && ItemData->WorldMesh)
{
ItemData->ApplyWorldVisualsTo(Mesh);
}
//
// Chez un client, ItemData est encore nul a cet instant : c'est OnRep_ItemData
// qui reposera le visuel quand la propriete arrivera.
ApplyItemVisuals();
}
FText APickupItem::GetInteractionPrompt_Implementation(AActor* Interactor) const
@@ -75,6 +107,16 @@ bool APickupItem::CanInteract_Implementation(AActor* Interactor) const
void APickupItem::Interact_Implementation(AActor* Interactor)
{
// Filet de securite : UInteractionComponent ne nous appelle deja que cote
// autorite, mais un Blueprint ou un futur appelant pourrait l'oublier, et
// un ramassage joue en local donnerait un objet qui reapparait a la
// prochaine replication -- le pire des symptomes, parce qu'il est
// intermittent.
if (!HasAuthority())
{
return;
}
UInventoryComponent* Inventory = Interactor ? Interactor->FindComponentByClass<UInventoryComponent>() : nullptr;
if (!Inventory)
{
@@ -83,30 +125,18 @@ void APickupItem::Interact_Implementation(AActor* Interactor)
}
const int32 Leftover = Inventory->AddItem(ItemData, Quantity, RemainingUses);
const int32 Added = Quantity - Leftover;
// Inventaire plein : on ne detruit surtout pas le tas, on retire seulement
// ce qui est rentre. Le joueur peut revenir chercher le reste.
if (Added <= 0)
if (Leftover >= Quantity)
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Red, TEXT("Inventaire plein"));
}
return;
}
// Retour temporaire, le temps que l'UI d'inventaire existe.
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Green,
FString::Printf(TEXT("+%d %s (total : %d, slots : %d/%d)"),
Added,
*ItemData->DisplayName.ToString(),
Inventory->GetItemCount(ItemData),
Inventory->GetUsedSlotCount(),
Inventory->GetTotalSlotCount()));
}
// Les anciens AddOnScreenDebugMessage ont disparu : en reseau ils
// s'affichaient sur l'ecran de l'HOTE, puisque c'est lui qui execute ce
// code, y compris quand c'est un client qui ramasse. L'UI d'inventaire
// existe desormais et dit la meme chose au bon joueur.
if (Leftover > 0)
{