(Feat) Add mulitplayer
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user