(Feat) Add mulitplayer
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include "InteractionComponent.h"
|
||||
#include "InventoryComponent.h"
|
||||
#include "ItemDataAsset.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
#include "PickupItem.h"
|
||||
#include "SurvivalStatsComponent.h"
|
||||
#include "SurvivalUserSettings.h"
|
||||
@@ -448,14 +449,58 @@ void AFpsPlayer::StartSprint()
|
||||
return;
|
||||
}
|
||||
|
||||
bIsSprinting = true;
|
||||
GetCharacterMovement()->MaxWalkSpeed = SprintSpeed;
|
||||
SetSprinting(true);
|
||||
}
|
||||
|
||||
void AFpsPlayer::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
|
||||
// COND_SkipOwner : celui qui sprinte le sait deja, il vient de l'appliquer
|
||||
// en local. Le renvoyer ecraserait son etat courant par une valeur qui a un
|
||||
// aller-retour de retard -- exactement ce qui fait "sauter" un sprint qu'on
|
||||
// relance vite.
|
||||
DOREPLIFETIME_CONDITION(AFpsPlayer, bIsSprinting, COND_SkipOwner);
|
||||
}
|
||||
|
||||
void AFpsPlayer::StopSprint()
|
||||
{
|
||||
bIsSprinting = false;
|
||||
GetCharacterMovement()->MaxWalkSpeed = WalkSpeed;
|
||||
SetSprinting(false);
|
||||
}
|
||||
|
||||
void AFpsPlayer::SetSprinting(bool bNewSprinting)
|
||||
{
|
||||
if (bIsSprinting == bNewSprinting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bIsSprinting = bNewSprinting;
|
||||
ApplySprintSpeed();
|
||||
|
||||
// Applique en local d'abord pour que la vitesse soit instantanee sous les
|
||||
// doigts, puis previent le serveur. Le sens inverse -- attendre la reponse --
|
||||
// donnerait un sprint qui demarre avec un temps de retard.
|
||||
if (!HasAuthority())
|
||||
{
|
||||
Server_SetSprinting(bNewSprinting);
|
||||
}
|
||||
}
|
||||
|
||||
void AFpsPlayer::Server_SetSprinting_Implementation(bool bNewSprinting)
|
||||
{
|
||||
bIsSprinting = bNewSprinting;
|
||||
ApplySprintSpeed();
|
||||
}
|
||||
|
||||
void AFpsPlayer::OnRep_IsSprinting()
|
||||
{
|
||||
ApplySprintSpeed();
|
||||
}
|
||||
|
||||
void AFpsPlayer::ApplySprintSpeed()
|
||||
{
|
||||
GetCharacterMovement()->MaxWalkSpeed = bIsSprinting ? SprintSpeed : WalkSpeed;
|
||||
}
|
||||
|
||||
void AFpsPlayer::HandleSprintReleased()
|
||||
@@ -471,7 +516,33 @@ void AFpsPlayer::HandleSprintReleased()
|
||||
|
||||
void AFpsPlayer::UseSelectedItem()
|
||||
{
|
||||
const FInventorySlot Selected = InventoryComponent->GetSelectedSlot();
|
||||
const int32 SelectedIndex = InventoryComponent->GetSelectedHotbarIndex();
|
||||
|
||||
// L'hote agit tout de suite, le client demande. On envoie meme si le slot
|
||||
// parait vide chez nous : c'est le serveur qui fait foi, et son inventaire
|
||||
// peut avoir une frame d'avance sur le notre.
|
||||
if (!HasAuthority())
|
||||
{
|
||||
Server_UseItem(SelectedIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
PerformUseItem(SelectedIndex);
|
||||
}
|
||||
|
||||
void AFpsPlayer::Server_UseItem_Implementation(int32 SlotIndex)
|
||||
{
|
||||
PerformUseItem(SlotIndex);
|
||||
}
|
||||
|
||||
void AFpsPlayer::PerformUseItem(int32 SlotIndex)
|
||||
{
|
||||
if (!HasAuthority() || !InventoryComponent->GetSlots().IsValidIndex(SlotIndex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FInventorySlot Selected = InventoryComponent->GetSlots()[SlotIndex];
|
||||
if (Selected.IsEmpty())
|
||||
{
|
||||
return;
|
||||
@@ -493,7 +564,7 @@ void AFpsPlayer::UseSelectedItem()
|
||||
// usages multiples (une charge en moins, l'objet reste tant qu'il en a).
|
||||
// On vise le slot actif precisement, et pas RemoveItem qui piocherait
|
||||
// n'importe quelle pile du meme objet, y compris dans le sac.
|
||||
InventoryComponent->ConsumeUse(InventoryComponent->GetSelectedHotbarIndex());
|
||||
InventoryComponent->ConsumeUse(SlotIndex);
|
||||
}
|
||||
|
||||
FVector AFpsPlayer::PlaceOnGround(const FVector& Start) const
|
||||
@@ -543,6 +614,11 @@ bool AFpsPlayer::DropSlot(int32 SlotIndex, int32 Quantity)
|
||||
return DropFromInventory(InventoryComponent, SlotIndex, Quantity);
|
||||
}
|
||||
|
||||
void AFpsPlayer::Server_DropFromInventory_Implementation(UInventoryComponent* Inventory, int32 SlotIndex, int32 Quantity)
|
||||
{
|
||||
DropFromInventory(Inventory, SlotIndex, Quantity);
|
||||
}
|
||||
|
||||
bool AFpsPlayer::DropFromInventory(UInventoryComponent* Inventory, int32 SlotIndex, int32 Quantity)
|
||||
{
|
||||
if (!Inventory)
|
||||
@@ -550,6 +626,16 @@ bool AFpsPlayer::DropFromInventory(UInventoryComponent* Inventory, int32 SlotInd
|
||||
return false;
|
||||
}
|
||||
|
||||
// Jeter engendre un acteur dans le monde : c'est une action d'autorite.
|
||||
// La position de depot est calculee cote SERVEUR a partir de la camera
|
||||
// repliquee du pawn -- a quelques centimetres pres du point vise par le
|
||||
// client, ce qui n'a aucune importance pour un objet pose au sol.
|
||||
if (!HasAuthority())
|
||||
{
|
||||
Server_DropFromInventory(Inventory, SlotIndex, Quantity);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!DroppedPickupClass)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("AFpsPlayer : DroppedPickupClass n'est pas assignee, impossible de jeter un objet."));
|
||||
@@ -618,6 +704,14 @@ void AFpsPlayer::HandleCraftOverflow(UItemDataAsset* Item, int32 Quantity, int32
|
||||
|
||||
void AFpsPlayer::DropAllItems()
|
||||
{
|
||||
// Declenche par la mort, qui sera arbitree par le serveur. La garde est la
|
||||
// pour le jour ou un client l'appellerait : il engendrerait des pickups
|
||||
// visibles de lui seul, qui disparaitraient au premier nettoyage reseau.
|
||||
if (!HasAuthority())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DroppedPickupClass)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning, TEXT("AFpsPlayer : DroppedPickupClass n'est pas assignee, le butin est perdu."));
|
||||
|
||||
Reference in New Issue
Block a user