(Feat) Add mulitplayer
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include "InventoryComponent.h"
|
||||
|
||||
#include "ItemDataAsset.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
UInventoryComponent::UInventoryComponent()
|
||||
{
|
||||
@@ -11,6 +12,9 @@ UInventoryComponent::UInventoryComponent()
|
||||
|
||||
// Necessaire pour que InitializeComponent() soit appele.
|
||||
bWantsInitializeComponent = true;
|
||||
|
||||
// Le contenu appartient au serveur et descend vers les clients.
|
||||
SetIsReplicatedByDefault(true);
|
||||
}
|
||||
|
||||
void UInventoryComponent::InitializeComponent()
|
||||
@@ -22,6 +26,30 @@ void UInventoryComponent::InitializeComponent()
|
||||
SelectedHotbarIndex = FMath::Clamp(SelectedHotbarIndex, 0, FMath::Max(0, GetHotbarSlotCount() - 1));
|
||||
}
|
||||
|
||||
void UInventoryComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
DOREPLIFETIME(UInventoryComponent, Slots);
|
||||
}
|
||||
|
||||
void UInventoryComponent::OnRep_Slots()
|
||||
{
|
||||
// Pas de BroadcastChanged() ici : le regroupement differe ne sert qu'a
|
||||
// eviter vingt reconstructions d'UI pendant un "Tout ranger" execute en
|
||||
// local. La replication, elle, arrive deja groupee -- le serveur a fini son
|
||||
// lot avant d'envoyer quoi que ce soit.
|
||||
OnInventoryChanged.Broadcast();
|
||||
}
|
||||
|
||||
/**
|
||||
* SelectedHotbarIndex n'est volontairement PAS replique : le slot actif est une
|
||||
* intention purement locale, chaque joueur choisit le sien et personne d'autre
|
||||
* n'a besoin de le connaitre. Le jour ou l'objet en main devra etre visible par
|
||||
* les autres, ce sera une propriete du PAWN -- ce qu'on tient dans sa main est
|
||||
* une donnee de corps, pas de sac.
|
||||
*/
|
||||
|
||||
void UInventoryComponent::SelectHotbarSlot(int32 Index)
|
||||
{
|
||||
const int32 Count = GetHotbarSlotCount();
|
||||
@@ -178,8 +206,27 @@ int32 UInventoryComponent::RemoveItem(UItemDataAsset* Item, int32 Quantity)
|
||||
return Removed;
|
||||
}
|
||||
|
||||
void UInventoryComponent::Server_TransferAllTo_Implementation(UInventoryComponent* From, UInventoryComponent* To, int32 FirstIndex)
|
||||
{
|
||||
if (From)
|
||||
{
|
||||
From->TransferAllTo(To, FirstIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void UInventoryComponent::Server_ConsumeUse_Implementation(int32 SlotIndex)
|
||||
{
|
||||
ConsumeUse(SlotIndex);
|
||||
}
|
||||
|
||||
bool UInventoryComponent::ConsumeUse(int32 SlotIndex)
|
||||
{
|
||||
if (!HasInventoryAuthority())
|
||||
{
|
||||
Server_ConsumeUse(SlotIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Slots.IsValidIndex(SlotIndex))
|
||||
{
|
||||
return false;
|
||||
@@ -419,6 +466,28 @@ bool UInventoryComponent::ApplySlotMove(FInventorySlot& From, FInventorySlot& To
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UInventoryComponent::HasInventoryAuthority() const
|
||||
{
|
||||
const AActor* Owner = GetOwner();
|
||||
return Owner && Owner->HasAuthority();
|
||||
}
|
||||
|
||||
UInventoryComponent* UInventoryComponent::FindNetProxy(UInventoryComponent* A, UInventoryComponent* B)
|
||||
{
|
||||
auto IsLocalPawnInventory = [](const UInventoryComponent* Inventory)
|
||||
{
|
||||
const APawn* OwnerPawn = Inventory ? Cast<APawn>(Inventory->GetOwner()) : nullptr;
|
||||
return OwnerPawn && OwnerPawn->IsLocallyControlled();
|
||||
};
|
||||
|
||||
if (IsLocalPawnInventory(A))
|
||||
{
|
||||
return A;
|
||||
}
|
||||
|
||||
return IsLocalPawnInventory(B) ? B : nullptr;
|
||||
}
|
||||
|
||||
bool UInventoryComponent::TransferSlot(UInventoryComponent* From, int32 FromIndex, UInventoryComponent* To, int32 ToIndex, int32 Quantity)
|
||||
{
|
||||
if (!From || !To || Quantity <= 0)
|
||||
@@ -426,6 +495,43 @@ bool UInventoryComponent::TransferSlot(UInventoryComponent* From, int32 FromInde
|
||||
return false;
|
||||
}
|
||||
|
||||
// Chez un client : on ne touche a rien, on demande. Le contenu redescendra
|
||||
// par OnRep_Slots, qui rediffuse OnInventoryChanged et rafraichit l'UI.
|
||||
if (!From->HasInventoryAuthority())
|
||||
{
|
||||
UInventoryComponent* Proxy = FindNetProxy(From, To);
|
||||
if (!Proxy)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("UInventoryComponent::TransferSlot : aucun inventaire de joueur local dans l'echange, demande abandonnee."));
|
||||
return false;
|
||||
}
|
||||
|
||||
Proxy->Server_TransferSlot(From, FromIndex, To, ToIndex, Quantity);
|
||||
|
||||
// True signifie ici "demande partie", pas "contenu modifie". Les
|
||||
// appelants s'en servent pour savoir si le geste a ete pris en compte,
|
||||
// ce qui reste exact.
|
||||
return true;
|
||||
}
|
||||
|
||||
return ApplyTransferSlot(From, FromIndex, To, ToIndex, Quantity);
|
||||
}
|
||||
|
||||
void UInventoryComponent::Server_TransferSlot_Implementation(UInventoryComponent* From, int32 FromIndex, UInventoryComponent* To, int32 ToIndex, int32 Quantity)
|
||||
{
|
||||
// From et To arrivent par le reseau : ils peuvent etre nuls si l'acteur a
|
||||
// ete detruit entre l'envoi et l'arrivee -- un coffre casse, un joueur
|
||||
// deconnecte. ApplyTransferSlot les revalide de toute facon.
|
||||
ApplyTransferSlot(From, FromIndex, To, ToIndex, Quantity);
|
||||
}
|
||||
|
||||
bool UInventoryComponent::ApplyTransferSlot(UInventoryComponent* From, int32 FromIndex, UInventoryComponent* To, int32 ToIndex, int32 Quantity)
|
||||
{
|
||||
if (!From || !To || Quantity <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Meme inventaire et meme case : rien a faire. Le test doit porter sur le
|
||||
// couple et non sur l'index seul, deux inventaires differents ayant tous
|
||||
// les deux une case 3.
|
||||
@@ -491,6 +597,21 @@ int32 UInventoryComponent::QuickTransferSlot(UInventoryComponent* From, int32 Fr
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!From->HasInventoryAuthority())
|
||||
{
|
||||
if (UInventoryComponent* Proxy = FindNetProxy(From, To))
|
||||
{
|
||||
Proxy->Server_QuickTransferSlot(From, FromIndex, To);
|
||||
|
||||
// Le nombre reellement deplace n'est connu que du serveur. On rend
|
||||
// une valeur non nulle pour que l'appelant sache que le clic a ete
|
||||
// pris en compte ; l'affichage, lui, viendra de OnRep_Slots.
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int32 Moved = From->PushSlotInto(FromIndex, *To);
|
||||
if (Moved > 0)
|
||||
{
|
||||
@@ -500,6 +621,11 @@ int32 UInventoryComponent::QuickTransferSlot(UInventoryComponent* From, int32 Fr
|
||||
return Moved;
|
||||
}
|
||||
|
||||
void UInventoryComponent::Server_QuickTransferSlot_Implementation(UInventoryComponent* From, int32 FromIndex, UInventoryComponent* To)
|
||||
{
|
||||
QuickTransferSlot(From, FromIndex, To);
|
||||
}
|
||||
|
||||
int32 UInventoryComponent::TransferAllTo(UInventoryComponent* To, int32 FirstIndex)
|
||||
{
|
||||
if (!To || To == this)
|
||||
@@ -507,6 +633,17 @@ int32 UInventoryComponent::TransferAllTo(UInventoryComponent* To, int32 FirstInd
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!HasInventoryAuthority())
|
||||
{
|
||||
if (UInventoryComponent* Proxy = FindNetProxy(this, To))
|
||||
{
|
||||
Proxy->Server_TransferAllTo(this, To, FirstIndex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
To->BeginBatch();
|
||||
|
||||
int32 Moved = 0;
|
||||
|
||||
Reference in New Issue
Block a user