Download

Different behavior client/server in my code for a FPS

I’m not sure what is happening in my code.
I’m trying to code a FPS and I have a class for my character and one for my weapon.

In the begening, my character spawns a default inventory with some weapons.
Each time a weapon is added in the inventory, one slot is assigned, primary or secondary.
Everythings dépends on that after so it’s very important.

On the server, everythings works fine and , the slot is assigned correctly.

But on the clients, the weapons are added corectly in the inventory butthe slot isn’t assigned and I can’t figure out why.
Anyone can help ?

Here is my code.

Character CPP:



// Fill out your copyright notice in the Description page of Project Settings.

#include "BaseCharacter.h"
#include "Items/Ammo/Ammo.h"
#include "TacticalOps.h"
#include "Game/BaseGameMode.h "
#include "Components/CapsuleComponent.h"

FOnBaseCharacterEquipWeapon ABaseCharacter::NotifyEquipWeapon;
FOnBaseCharacterUnEquipWeapon ABaseCharacter::NotifyUnEquipWeapon;

// Vault
#define VAULT_SWEEP_DIST 20.f
#define VAULT_SWEEP_SPHERE_RADIUS 20.f
#define MIN_VAULT_HEIGHT 70.f
#define MAX_VAULT_HEIGHT 130.f

// Sets default values
ABaseCharacter::ABaseCharacter(const FObjectInitializer & ObjectInitializer) :Super(ObjectInitializer)
{
 //Mesh1P = ObjectInitializer.CreateDefaultSubobject<USkeletalMeshComponent>(this, TEXT("PawnMesh1P"));
 Mesh1P = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("PawnMesh1P"));
 Mesh1P->SetupAttachment(GetCapsuleComponent());
 Mesh1P->bOnlyOwnerSee = true;
 Mesh1P->bOwnerNoSee = false;
 Mesh1P->bCastDynamicShadow = false;
 Mesh1P->bReceivesDecals = false;
 Mesh1P->VisibilityBasedAnimTickOption = EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered;
 Mesh1P->PrimaryComponentTick.TickGroup = TG_PrePhysics;
 Mesh1P->SetCollisionObjectType(ECC_Pawn);
 Mesh1P->SetCollisionEnabled(ECollisionEnabled::NoCollision);
 Mesh1P->SetCollisionResponseToAllChannels(ECR_Ignore);

 GetMesh()->bOnlyOwnerSee = false;
 GetMesh()->bOwnerNoSee = true;
 GetMesh()->bReceivesDecals = false;
 GetMesh()->SetCollisionObjectType(ECC_Pawn);
 GetMesh()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
 //GetMesh()->SetCollisionResponseToChannel(COLLISION_WEAPON, ECR_Block);
 //GetMesh()->SetCollisionResponseToChannel(COLLISION_PROJECTILE, ECR_Block);
 GetMesh()->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);

 //GetCapsuleComponent()->SetCollisionResponseToChannel(ECC_Camera, ECR_Ignore);
 //GetCapsuleComponent()->SetCollisionResponseToChannel(COLLISION_PROJECTILE, ECR_Block);
 //GetCapsuleComponent()->SetCollisionResponseToChannel(COLLISION_WEAPON, ECR_Ignore);

 PrimaryActorTick.bCanEverTick = true;

}


void ABaseCharacter::PostInitializeComponents()
{
 Super::PostInitializeComponents();

 if (Role == ROLE_Authority)
 {
  Health = HealthMax;
  SpawnDefaultInventory();
 }
 // play respawn effects
 if (GetNetMode() != NM_DedicatedServer)
 {
  /*if (RespawnFX)
  {
  UGameplayStatics::SpawnEmitterAtLocation(this, RespawnFX, GetActorLocation(), GetActorRotation());
  }

  if (RespawnSound)
  {
  UGameplayStatics::PlaySoundAtLocation(this, RespawnSound, GetActorLocation());
  }*/
 }
}

// Called when the game starts or when spawned
void ABaseCharacter::BeginPlay()
{
 Super::BeginPlay();


}

void ABaseCharacter::Destroyed()
{
 Super::Destroyed();
 DestroyInventory();
}

void ABaseCharacter::Tick(float DeltaTime)
{
 Super::Tick( DeltaTime);

}



///////////////////////////////////////////////////////
//inventory

void ABaseCharacter::AddPickable(APickable* Picked)
{
 if (Picked && Role == ROLE_Authority)  
 {
  if (ABaseWeapon* weapon = Cast <ABaseWeapon>(Picked))
  {
   AddWeapon(weapon);
  }
  else {
   Picked->OnEnterInventory(this);
   Inventory.AddUnique(Picked);
   CurrentInventoryWeight = CurrentInventoryWeight + Picked->Weight;
   Picked->IsPickable = false;
  }
 }
}

void ABaseCharacter::AddWeapon(ABaseWeapon* weapon)
{
 if (weapon)
 {
  if (weapon->WeapKind == EWeaponKind::SideGun)
  {
   if (SideGun == NULL)
   {
    weapon->OnEnterInventory(this);
    Inventory.AddUnique(weapon);
    SideGun = weapon;
    weapon->CurrentSlot = EWeaponSlot::SideGun;
    if (CurrentWeapon == NULL)
    {
     EquipSideGun();
    }

   }
   else
   {
    RemoveWeapon(SideGun);
    ThrowPickable(SideGun);
    SideGun = NULL;
    weapon->OnEnterInventory(this);
    Inventory.AddUnique(weapon);
    SideGun = weapon;
    weapon->CurrentSlot = EWeaponSlot::SideGun;
    EquipSideGun();
   }

  }
  else
   if (weapon->WeapKind == EWeaponKind::Shotgun || weapon->WeapKind == EWeaponKind::Rifle || weapon->WeapKind == EWeaponKind::SMG)
   {
    if (PrimaryWeapon == NULL)
    {
     weapon->OnEnterInventory(this);
     Inventory.AddUnique(weapon);
     PrimaryWeapon = weapon;
     weapon->CurrentSlot = EWeaponSlot::Primary;
     weapon->IsPickable = false;
     GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("primaryadd"));

     if (CurrentWeapon != NULL)
     {
     }
     else EquipPrimary();

     return;
    }
    if (PrimaryWeapon != NULL && SecondaryWeapon == NULL)
    {
     weapon->OnEnterInventory(this);
     Inventory.AddUnique(weapon);
     SecondaryWeapon = weapon;
     weapon->CurrentSlot = EWeaponSlot::Secondary;
     weapon->IsPickable = false;
     GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("secondaryyadd"));
     return;
    }
    if (PrimaryWeapon != NULL && SecondaryWeapon != NULL)
    {
     if (CurrentWeapon == PrimaryWeapon)
     {
      RemoveWeapon(PrimaryWeapon);
      ThrowPickable(PrimaryWeapon);
      weapon->OnEnterInventory(this);
      Inventory.AddUnique(weapon);
      PrimaryWeapon = weapon;
      weapon->CurrentSlot = EWeaponSlot::Primary;
      weapon->IsPickable = false;
      return;
     }

     if (CurrentWeapon == SecondaryWeapon)
     {
      RemoveWeapon(SecondaryWeapon);
      ThrowPickable(SecondaryWeapon);
      weapon->OnEnterInventory(this);
      Inventory.AddUnique(weapon);
      SecondaryWeapon = weapon;
      weapon->CurrentSlot = EWeaponSlot::Secondary;
      weapon->IsPickable = false;
      return;

     }
     else
     RemoveWeapon(PrimaryWeapon);
     ThrowPickable(PrimaryWeapon);
     weapon->OnEnterInventory(this);
     Inventory.AddUnique(weapon);
     PrimaryWeapon = weapon;
     weapon->CurrentSlot = EWeaponSlot::Primary;
    }
   }
  weapon->IsPickable = false;
 }
}

bool ABaseCharacter::CanAddInventory(APickable* PickableToAdd)
{
 if (PickableToAdd)
 {
  float Pickableweight = PickableToAdd->Weight;
  if (ABaseWeapon* weapon = Cast <ABaseWeapon>(PickableToAdd))
  {
   return true;
  }
  else
  {
   if (Pickableweight + CurrentInventoryWeight < MaxInventoryWeight)
    return true;
  }
 }
 return false;
}


void ABaseCharacter::EquipWeapon(EWeaponSlot weaponslot)
{
 if (Role == ROLE_Authority)
 {

  switch (weaponslot)
  {
  case (EWeaponSlot::Primary):
   if (PrimaryWeapon != NULL)
   {
    CurrentWeapon = PrimaryWeapon;
    CurrentWeapon->OnEquip(CurrentWeapon);

   }
   break;

  case (EWeaponSlot::Secondary):
   if (SecondaryWeapon != NULL)
   {
    CurrentWeapon = SecondaryWeapon;
    CurrentWeapon->OnEquip(CurrentWeapon);

   }
   break;
  case (EWeaponSlot::SideGun):
   if (SideGun != NULL)
   {
    CurrentWeapon = SideGun;
    CurrentWeapon->OnEquip(CurrentWeapon);
   }
   break;
  }
 }


 else
 {
  ServerEquipWeapon(weaponslot);

 }
}

bool ABaseCharacter::ServerEquipWeapon_Validate(EWeaponSlot weaponslot)
{
 GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("true , serverequipweaponvalidate"));

 return true;
}

void ABaseCharacter::ServerEquipWeapon_Implementation( EWeaponSlot weaponslot)
{
 //GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("serverequipweapon with autority"));
 EquipWeapon(  weaponslot);
}

void ABaseCharacter::DestroyInventory()
{
 if (Role < ROLE_Authority)
 {
  return;
 }

 // remove all weapons from inventory and destroy them
 for (int32 i = Inventory.Num() - 1; i >= 0; i--)
 {
  APickable* Weapon = Inventory*;
  if (Weapon)
  {
   //RemovePickable(Weapon);
   Weapon->Destroy();
  }
 }
}

void ABaseCharacter::RemoveWeapon(class ABaseWeapon* weapon)
{
 if (weapon && Role == ROLE_Authority)
 {
  weapon->OnLeaveInventory();
  Inventory.RemoveSingle(weapon);
 }
}

//on jette sur le sol l'objet dont on ne veut plus
void ABaseCharacter::ThrowPickable(APickable* PickableThrow)
{
 PickableThrow->IsPickable = true;
 PickableThrow->OnLeaveInventory();
 //A compléter
}



void ABaseCharacter::SpawnDefaultInventory()
{
 if (Role < ROLE_Authority)
 {
  return;
 }

 int32 NumWeaponClasses = DefaultInventoryClasses.Num();
 for (int32 i = 0; i < NumWeaponClasses; i++)
 {
  if (DefaultInventoryClasses*)
  {
   FActorSpawnParameters SpawnInfo;
   SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
   ABaseWeapon* NewWeapon = GetWorld()->SpawnActor<ABaseWeapon>(DefaultInventoryClasses*, SpawnInfo);
   NewWeapon->OnEnterInventory(this);
   AddWeapon(NewWeapon);
  }
 }
}




void ABaseCharacter::EquipPrimary()
{
 if (CurrentWeapon != PrimaryWeapon && PrimaryWeapon != NULL)
 {//si current weapon n'est pas nul alors il faut déséquiper currrentweapon
  if (CurrentWeapon!=NULL)
  {
   //EWeaponSlot SlotToDesequip=CurrentWeapon->CurrentSlot;
   UnequipWeapon(CurrentWeapon);

   EquipWeapon(EWeaponSlot::Primary);
  }

  else
  {
   EquipWeapon(EWeaponSlot::Primary);
  }
 }
}


void ABaseCharacter::EquipSecondary()
{
 if (CurrentWeapon != SecondaryWeapon && SecondaryWeapon != NULL)
 {//si current weapon n'est pas nul alors il faut déséquiper currrentweapon
  if (CurrentWeapon != NULL)
  {
   EWeaponSlot SlotToDesequip = CurrentWeapon->CurrentSlot;
   UnequipWeapon(CurrentWeapon);

   EquipWeapon(EWeaponSlot::Secondary);
  }

  else
  {
   EquipWeapon(EWeaponSlot::Secondary);
  }

 }

}
void ABaseCharacter::EquipSideGun()
{

}
void ABaseCharacter::EquipThrowable()
{

}


void ABaseCharacter::OnNextWeapon()
{
 GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("next weapon"));

 if (CurrentWeapon != NULL)
 {
  GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("pasnul"));
  switch (CurrentWeapon->CurrentSlot)
  {

  case (EWeaponSlot::Primary):
   if (SecondaryWeapon != NULL)
   {
    GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("next primary"));
    UnequipWeapon(PrimaryWeapon);
    EquipSecondary();
    return;
   }
   if (SideGun != NULL)
   {
    UnequipWeapon(PrimaryWeapon);
    EquipSideGun();
    return;
   }

   if (Throwable!=NULL)
   {
    UnequipWeapon(PrimaryWeapon);
    EquipThrowable();
   }
   break;

  case(EWeaponSlot::Secondary):
   if (SideGun != NULL)
   {
    UnequipWeapon(SecondaryWeapon);
    EquipSideGun();
    return;
   }

   if (Throwable != NULL)
   {
    UnequipWeapon(SecondaryWeapon);
    EquipThrowable();
   }
   if (PrimaryWeapon != NULL)
   {
    UnequipWeapon(SecondaryWeapon);
    EquipPrimary();
    return;
   }
   break;

  }

 }
 else
  //if (PrimaryWeapon = NULL)
 {
  GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("pas de promary ,nul"));
  EquipPrimary();
 }
}


void ABaseCharacter::OnPreviousWeapon()
{
 if (CurrentWeapon != NULL)
 {
  switch (CurrentWeapon->CurrentSlot)
  {
  case (EWeaponSlot::Primary):

   if (Throwable != NULL)
   {
    EquipThrowable();
   }

   if (SideGun != NULL)
   {
    EquipSideGun();
    return;
   }
   if (SecondaryWeapon != NULL)
   {
    EquipSecondary();
    return;
   }
   break;





  case(EWeaponSlot::Secondary):


   if (PrimaryWeapon != NULL)
   {
    UnequipWeapon(SecondaryWeapon);
    EquipPrimary();
    return;
   }
   if (Throwable != NULL)
   {
    UnequipWeapon(SecondaryWeapon);
    EquipThrowable();
   }
   if (SideGun != NULL)
   {
    UnequipWeapon(SecondaryWeapon);
    EquipSideGun();
    return;
   }
   break;


  }
 }

}


void ABaseCharacter::UnequipWeapon(ABaseWeapon* WeaponToUnequip)
{
 if (CurrentWeapon != NULL)
 {

  CurrentWeapon->OnUnEquip();
   CurrentWeapon = NULL;
 }
}

/////////////////////////////////////////////////////////
//Replication


void ABaseCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
 Super::GetLifetimeReplicatedProps(OutLifetimeProps);

 DOREPLIFETIME_CONDITION(ABaseCharacter, Inventory,COND_OwnerOnly);
 //DOREPLIFETIME(ABaseCharacter, DefaultInventoryClasses);
 DOREPLIFETIME(ABaseCharacter, CurrentWeapon);
 DOREPLIFETIME(ABaseCharacter,PrimaryWeapon );
 DOREPLIFETIME(ABaseCharacter, SecondaryWeapon);
 DOREPLIFETIME(ABaseCharacter, SideGun);
 DOREPLIFETIME(ABaseCharacter, Health);

}

void ABaseCharacter::OnRep_CurrentWeapon(class ABaseWeapon* LastWeapon)
{
 if (LastWeapon != NULL)
 {
  LastWeapon->SetOwningPawn(this);
 }
}


//////////////////////////////////////////////////////
//Inputs


// Called to bind functionality to input
void ABaseCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
 Super::SetupPlayerInputComponent(PlayerInputComponent);

 check(PlayerInputComponent);
 PlayerInputComponent->BindAxis("MoveForward", this, &ABaseCharacter::MoveForward);
 PlayerInputComponent->BindAxis("MoveForward", this, &ABaseCharacter::MoveRight);
 PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
 PlayerInputComponent->BindAxis("TurnRate", this, &ABaseCharacter::TurnAtRate);
 PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
 PlayerInputComponent->BindAxis("LookUpRate", this, &ABaseCharacter::LookUpAtRate);

 PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ABaseCharacter::Jump);
 PlayerInputComponent->BindAction("Jump", IE_Released, this, &ABaseCharacter::StopJumping);
 //PlayerInputComponent->BindAction("Crouch", IE_Pressed, this, &ABaseCharacter::Crouch);
 //PlayerInputComponent->BindAction("Crouch", IE_Released, this, &ABaseCharacter::StopCrouching);

 PlayerInputComponent->BindAction("FireMode", IE_Pressed, this, &ABaseCharacter::ChangeFireMode);
 PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ABaseCharacter::Fire);
 PlayerInputComponent->BindAction("Reload", IE_Pressed, this, &ABaseCharacter::Reload);

 PlayerInputComponent->BindAction("NextWeapon", IE_Pressed, this, &ABaseCharacter::OnNextWeapon);
 PlayerInputComponent->BindAction("PreviousWeapon", IE_Pressed, this, &ABaseCharacter::OnPreviousWeapon);
 PlayerInputComponent->BindAction("EquipPrimary", IE_Pressed, this, &ABaseCharacter::EquipPrimary);
 PlayerInputComponent->BindAction("EquipSecondary", IE_Pressed, this, &ABaseCharacter::EquipSecondary);
}




void ABaseCharacter::MoveForward(float Val)
{
 if (Controller && Val != 0.f)
 {
  // Limit pitch when walking or falling
  const bool bLimitRotation = (GetCharacterMovement()->IsMovingOnGround() || GetCharacterMovement()->IsFalling());
  const FRotator Rotation = bLimitRotation ? GetActorRotation() : Controller->GetControlRotation();
  const FVector Direction = FRotationMatrix(Rotation).GetScaledAxis(EAxis::X);
  AddMovementInput(Direction, Val);
 }
}


void ABaseCharacter::MoveRight(float Val)
{
 if (Val != 0.f)
 {
  const FQuat Rotation = GetActorQuat();
  const FVector Direction = FQuatRotationMatrix(Rotation).GetScaledAxis(EAxis::Y);
  AddMovementInput(Direction, Val);
 }
}

void ABaseCharacter::TurnAtRate(float Val)
{
 // calculate delta for this frame from the rate information
 AddControllerYawInput(Val * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}

void ABaseCharacter::LookUpAtRate(float Val)
{
 // calculate delta for this frame from the rate information
 AddControllerPitchInput(Val * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}





void ABaseCharacter::Jump()
{
 FCollisionQueryParams QueryParams;
 QueryParams.AddIgnoredActor(this);

 const float CapsuleHalfHeight = GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
 const float CapsuleRadius = GetCapsuleComponent()->GetScaledCapsuleRadius();
 const FVector ForwardVector = GetActorForwardVector();
 const FVector SweepStart = GetActorLocation() + FVector(0.f, 0.f, CapsuleHalfHeight) + ForwardVector * (CapsuleRadius + VAULT_SWEEP_DIST);
 const FVector SweepEnd = SweepStart - FVector(0.f, 0.f, CapsuleHalfHeight * 2.f);

 FHitResult Hit;
 if (GetWorld()->SweepSingleByChannel(Hit, SweepStart, SweepEnd, FQuat::Identity, ECC_Pawn, FCollisionShape::MakeSphere(VAULT_SWEEP_SPHERE_RADIUS), QueryParams))
 {
  const float ObstacleHeight = Hit.ImpactPoint.Z - SweepEnd.Z;
  if (ObstacleHeight > MIN_VAULT_HEIGHT && ObstacleHeight < MAX_VAULT_HEIGHT)
  {
   Vault();
   return;
  }
 }

 Super::Jump();


}

void ABaseCharacter::Vault()
{
 //PlayAnimMontage(VaultMontage);
}






bool ABaseCharacter::IsFirstPerson() const
{
 return IsAlive() && Controller && Controller->IsLocalPlayerController();
}

bool ABaseCharacter::IsAlive() const
{
 return Health > 0;
}



USkeletalMeshComponent* ABaseCharacter::GetPawnMesh() const
{
 return IsFirstPerson() ? Mesh1P : GetMesh();
}



USkeletalMeshComponent* ABaseCharacter::GetSpecifcPawnMesh(bool WantFirstPerson) const
{

 return WantFirstPerson == true ? Mesh1P : GetMesh();
}



FName ABaseCharacter::GetWeaponAttachPoint() const
{
 return WeaponAttachPoint;
}


/////////////////////////////////////////////////////
//Damage



float ABaseCharacter::TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, class AActor* DamageCauser)
{


 if (Health <= 0.f)
 {
  return 0.f;
 }

 // Modify based on game rules.
 ABaseGameMode* const Game = GetWorld()->GetAuthGameMode<ABaseGameMode>();
 Damage = Game ? Game->ModifyDamage(Damage, this, DamageEvent, EventInstigator, DamageCauser) : 0.f;

 const float ActualDamage = Super::TakeDamage(Damage, DamageEvent, EventInstigator, DamageCauser);
 if (ActualDamage > 0.f)
 {
  Health -= ActualDamage;
  if (Health <= 0)
  {
   Die(ActualDamage, DamageEvent, EventInstigator, DamageCauser);
  }
  /*else
  {
  PlayHit(ActualDamage, DamageEvent, EventInstigator ? EventInstigator->GetPawn() : NULL, DamageCauser);
  }

  MakeNoise(1.0f, EventInstigator ? EventInstigator->GetPawn() : this);*/
 }

 return ActualDamage;
}



bool ABaseCharacter::Die(float KillingDamage, FDamageEvent const& DamageEvent, AController* Killer, AActor* DamageCauser)
{
 /*if (!CanDie(KillingDamage, DamageEvent, Killer, DamageCauser))
 {
 return false;
 }*/

 Health = FMath::Min(0.0f, Health);

 // if this is an environmental death then refer to the previous killer so that they receive credit (knocked into lava pits, etc)
 /*UDamageType const* const DamageType = DamageEvent.DamageTypeClass ? DamageEvent.DamageTypeClass->GetDefaultObject<UDamageType>() : GetDefault<UDamageType>();
 Killer = GetDamageInstigator(Killer, *DamageType);

 AController* const KilledPlayer = (Controller != NULL) ? Controller : Cast<AController>(GetOwner());
 GetWorld()->GetAuthGameMode<AShooterGameMode>()->Killed(Killer, KilledPlayer, this, DamageType);

 NetUpdateFrequency = GetDefault<AShooterCharacter>()->NetUpdateFrequency;
 GetCharacterMovement()->ForceReplicationUpdate();

 OnDeath(KillingDamage, DamageEvent, Killer ? Killer->GetPawn() : NULL, DamageCauser);*/
 return true;
}





//////////////////////////////////////////////////////////////////////////
// Animations

float ABaseCharacter::PlayAnimMontage(class UAnimMontage* AnimMontage, float InPlayRate, FName StartSectionName)
{
 USkeletalMeshComponent* UseMesh = GetPawnMesh();
 if (AnimMontage && UseMesh && UseMesh->AnimScriptInstance)
 {
  return UseMesh->AnimScriptInstance->Montage_Play(AnimMontage, InPlayRate);
 }

 return 0.0f;
}

void ABaseCharacter::StopAnimMontage(class UAnimMontage* AnimMontage)
{
 USkeletalMeshComponent* UseMesh = GetPawnMesh();
 if (AnimMontage && UseMesh && UseMesh->AnimScriptInstance &&
  UseMesh->AnimScriptInstance->Montage_IsPlaying(AnimMontage))
 {
  UseMesh->AnimScriptInstance->Montage_Stop(AnimMontage->BlendOut.GetBlendTime(), AnimMontage);
 }
}

void ABaseCharacter::StopAllAnimMontages()
{
 USkeletalMeshComponent* UseMesh = GetPawnMesh();
 if (UseMesh && UseMesh->AnimScriptInstance)
 {
  UseMesh->AnimScriptInstance->Montage_Stop(0.0f);
 }
}



//////////////////////////////////////////////////////////////////////
//Fire and weapons management


void ABaseCharacter::Fire()
{

 if (CanFire())
 {
  if (Role == ROLE_Authority)
  {

   TriggerPulled = true;
   CurrentWeapon->WeaponFire(true);

  }
  else ServerFire();
 }

}

void ABaseCharacter::OnStopFire()
{
 TriggerPulled = false;
 CurrentWeapon->WeaponFire(false);
}


bool ABaseCharacter::CanFire()
{
 if (CurrentWeapon != NULL && !IsReloading && CurrentWeapon->GetIsEquiped())
 {
  return true;
 }

 else return false;
}

bool ABaseCharacter::ServerFire_Validate()
{
 return true;
}

void ABaseCharacter::ServerFire_Implementation()
{
 Fire();
}


void ABaseCharacter::ChangeFireMode()
{
 if (CurrentWeapon != NULL)
 {
  CurrentWeapon->SetCurrentFireMode();
 }
}



int8 ABaseCharacter::GetAmmo(EAmmoKind Ammo)
{
 int8 AmmoToReturn = 0;

 for (int32 i = Inventory.Num() - 1; i >= 0; i--)
 {
  APickable* Ammotocheck = Inventory*;
  if (AAmmo* ItemTocheck = Cast<AAmmo>(Ammotocheck))
  {
   if (ItemTocheck != NULL && ItemTocheck->AmmoType == Ammo)

   {
    AmmoToReturn = ItemTocheck->AmmoCount;
    if (CurrentWeapon->HasFastExtandedMag)
    {
     ItemTocheck->GetAmmo(CurrentWeapon->MaxAmmoWithExtandedMag);

    }
    else
    {
     ItemTocheck->GetAmmo(CurrentWeapon->MaxAmmo);
    }
   }
  }
 }
 return AmmoToReturn;
}


void ABaseCharacter::Reload()
{
 if (Role == ROLE_Authority)
 {
  if (CurrentWeapon != NULL)
  {
   IsReloading = true;
   CurrentWeapon->WeaponReload();
   IsReloading = false;
  }
 }
 else ServerReload();

}

bool ABaseCharacter::ServerReload_Validate()
{
 return true;
}

void ABaseCharacter::ServerReload_Implementation()
{
 Reload();
}



:

Pickable.h



// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Net/UnrealNetwork.h"
#include "Pickable.generated.h"


class UAnimMontage;
class ABaseCharacter;
class USoundCue;
class UAudioComponent;
class UAnimMontage;
class UParticleSystemComponent;
class UCameraShake;
class UForceFeedbackEffect;

USTRUCT()
struct FPickableAnim
{
GENERATED_USTRUCT_BODY()

/** animation played on pawn (1st person view) */
UPROPERTY(EditDefaultsOnly, Category = Animation)
UAnimMontage* Pawn1P;

/** animation played on pawn (3rd person view) */
UPROPERTY(EditDefaultsOnly, Category = Animation)
UAnimMontage* Pawn3P;
};



UENUM(BlueprintType)
enum class EWeaponSlot : uint8
{

None,
Primary,
Secondary,
SideGun,
Throwable,
Other,
InHand,


};

UCLASS(Abstract, Blueprintable)
class APickable : public AActor
{
GENERATED_UCLASS_BODY()

public:

protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;

virtual void Tick(float DeltaTime) override;

private:
/** weapon mesh: 1st person view */
UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
USkeletalMeshComponent* Mesh1P;

/** weapon mesh: 3rd person view */
UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
USkeletalMeshComponent* Mesh3P;

public:

//nom de l'objet
UPROPERTY(BluePrintReadWrite, EditAnywhere, Category = Items)
FName ItemName;

// Thumbnail for this item used in buymenu and hud
/*UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Items)
UTexture2D * ItemThumbnail;*/


//Socket pour accrocher l'item en vue FPS
UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Mesh)
FTransform FpsSocket;


//Socket pour accrocher l'item en TPS
UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Mesh)
FTransform TpsSocket;

public:

//Socket pour accrocher l'item dans le dos
UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Mesh)
FTransform PrimarySocket;

//Socket pour accrocher l'item dans le dos
UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Mesh)
FTransform SecondarySocket;


UPROPERTY(EditDefaultsOnly, Category = Items)
FPickableAnim EquipAnim;


UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Pickable)
bool IsPickable;

float Weight;

UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Pickable)
EWeaponSlot CurrentSlot;

protected:

/** pawn owner */
UPROPERTY(Transient, ReplicatedUsing = OnRep_MyPawn)
class ABaseCharacter* MyPawn;

//////////////////////////////////////////////////////////////////////////
// Weapon usage helpers
public:

/** play weapon sounds */
UAudioComponent* PlayWeaponSound(USoundCue* Sound);

/** play weapon animations */
float PlayWeaponAnimation(const FPickableAnim& Animation);

/** stop playing weapon animations */
void StopWeaponAnimation(const FPickableAnim& Animation);



//////////////////////////////////////////////////////////////////////////
// Replication & effects

UFUNCTION()
void OnRep_MyPawn();


//////////////////////////////////////////////////////////////////////////
// Inventory

void OnEquip(const APickable* LastWeapon);

void OnEquipFinished();


void OnDesequip(const APickable* LastWeapon);

/** Handle for efficient management of OnEquipFinished timer */
FTimerHandle TimerHandle_OnEquipFinished;

/** [server] weapon was added to pawn's inventory */
virtual void OnEnterInventory(ABaseCharacter* NewOwner);

/** [server] weapon was removed from pawn's inventory */
virtual void OnLeaveInventory();

/** set the weapon's owning pawn */
void SetOwningPawn(ABaseCharacter* AShooterCharacter);

/** check if mesh is already attached */
bool IsAttachedToPawn() const;

UFUNCTION(BluePrintCallable)
void AttachMeshToPawn(EWeaponSlot Pickableslot);

void DetachMeshFromPawn();

/** weapon is holstered by owner pawn */
virtual void OnUnEquip();



protected:
/** is equip animation playing? */
uint32 bPendingEquip : 1;

/** is weapon currently equipped? */
uint32 bIsEquipped : 1;

//is weapon attach hands
bool bIsinHands;

public :
bool GetIsEquiped() const { return bIsEquipped; };

/** equip sound */
UPROPERTY(EditDefaultsOnly, Category = Sound)
USoundCue* EquipSound;

/** unequip sound */
UPROPERTY(EditDefaultsOnly, Category = Sound)
USoundCue* UnEquipSound;

/** last time when this weapon was switched to */
float EquipStartedTime;

/** how much time weapon needs to be equipped */
float EquipDuration;

public:
UPROPERTY(EditDefaultsOnly, Category = Animation)
FPickableAnim PawnEquipAnim;



private:
UPROPERTY(ReplicatedUsing = OnRep_ReplicatedLocation)
FVector ReplicatedLocation;

UFUNCTION()
void OnRep_ReplicatedLocation();
};
[/CODE]
 
Here is Pickable.cpp the code for the baseclass of my weapons




// Fill out your copyright notice in the Description page of Project Settings.

#include “Pickable.h”
#include “TacticalOps.h”
#include “Player/BaseCharacter.h”

// Sets default values
APickable::APickable(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
Mesh1P = ObjectInitializer.CreateDefaultSubobject(this, TEXT(“WeaponMesh1P”));
Mesh1P->VisibilityBasedAnimTickOption = EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered;
Mesh1P->bReceivesDecals = false;
Mesh1P->CastShadow = false;
Mesh1P->SetCollisionObjectType(ECC_WorldDynamic);
Mesh1P->SetCollisionEnabled(ECollisionEnabled::NoCollision);
Mesh1P->SetCollisionResponseToAllChannels(ECR_Ignore);
RootComponent = Mesh1P;

Mesh3P = ObjectInitializer.CreateDefaultSubobject(this, TEXT(“WeaponMesh3P”));
Mesh3P->VisibilityBasedAnimTickOption = EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered;
Mesh3P->bReceivesDecals = false;
Mesh3P->CastShadow = true;
Mesh3P->SetCollisionObjectType(ECC_WorldDynamic);
Mesh3P->SetCollisionEnabled(ECollisionEnabled::NoCollision);
Mesh3P->SetCollisionResponseToAllChannels(ECR_Ignore);
//Mesh3P->SetCollisionResponseToChannel(COLLISION_WEAPON, ECR_Block);
Mesh3P->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
//Mesh3P->SetCollisionResponseToChannel(COLLISION_PROJECTILE, ECR_Block);
Mesh3P->SetupAttachment(Mesh1P);

IsPickable = true;
bPendingEquip = false;
bIsEquipped = false;
bIsinHands = false;

PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.TickGroup = TG_PrePhysics;
SetRemoteRoleForBackwardsCompat(ROLE_SimulatedProxy);
bReplicates = true;
bAlwaysRelevant = true;
bNetUseOwnerRelevancy = false;

}

// Called when the game starts or when spawned
void APickable::BeginPlay()
{
Super::BeginPlay();

}

void APickable::Tick(float DeltaTime)
{
// Tick will only execute when dropped
if (Instigator)
{
SetActorTickEnabled(false);
return;
}

if (GetNetMode() == NM_Client)
{
// Update location on clients
if ((Mesh3P->GetComponentLocation() - ReplicatedLocation).SizeSquared() > 400.f)
{
Mesh3P->SetAllPhysicsPosition(ReplicatedLocation);//(Mesh->GetComponentLocation() + ReplicatedLocation) * 0.5f);
}
}
else
{
// Set replicated location so clients will receive it
ReplicatedLocation = Mesh3P->GetComponentLocation();
}
}

//////////////////////////////////////////////////////////////////////////
// Weapon usage helpers

UAudioComponent* APickable::PlayWeaponSound(USoundCue* Sound)
{
UAudioComponent* AC = NULL;
if (Sound && MyPawn)
{
AC = UGameplayStatics::SpawnSoundAttached(Sound, MyPawn->GetRootComponent());
}

return AC;
}

float APickable::PlayWeaponAnimation(const FPickableAnim& Animation)
{
float Duration = 0.0f;
if (MyPawn)
{
UAnimMontage* UseAnim = MyPawn->IsFirstPerson() ? Animation.Pawn1P : Animation.Pawn3P;
if (UseAnim)
{
Duration = MyPawn->PlayAnimMontage(UseAnim);
}
}

return Duration;
}

void APickable::StopWeaponAnimation(const FPickableAnim& Animation)
{
if (MyPawn)
{
UAnimMontage* UseAnim = MyPawn->IsFirstPerson() ? Animation.Pawn1P : Animation.Pawn3P;
if (UseAnim)
{
MyPawn->StopAnimMontage(UseAnim);
}
}
}

///////////////////////////////////////////////////
//Inventory

void APickable::OnEquip(const APickable* LastWeapon)
{
bPendingEquip = true;
AttachMeshToPawn(EWeaponSlot::InHand);

//DetermineWeaponState();

// Only play animation if last weapon is valid
if (LastWeapon)
{
float Duration = PlayWeaponAnimation(EquipAnim);
if (Duration <= 0.0f)
{
// failsafe
Duration = 0.5f;
}
EquipStartedTime = GetWorld()->GetTimeSeconds();
EquipDuration = Duration;

GetWorldTimerManager().SetTimer(TimerHandle_OnEquipFinished, this, &APickable::OnEquipFinished, Duration, false);
PlayWeaponSound(EquipSound);
}
else
{
OnEquipFinished();
}

if (MyPawn && MyPawn->IsLocallyControlled())
{
PlayWeaponSound(EquipSound);
}

ABaseCharacter::NotifyEquipWeapon.Broadcast(MyPawn, this);
}

void APickable::OnEquipFinished()
{
//AttachMeshToPawn();

bIsEquipped = true;
bPendingEquip = false;

}

void APickable::OnDesequip(const APickable* LastWeapon)
{

AttachMeshToPawn(CurrentSlot);
bIsEquipped = false;
PlayWeaponSound(UnEquipSound);
}

void APickable::OnEnterInventory(ABaseCharacter* NewOwner)
{
SetOwningPawn(NewOwner);
}

void APickable::OnLeaveInventory()
{
if (IsAttachedToPawn())
{
OnUnEquip();
}

if (Role == ROLE_Authority)
{
SetOwningPawn(NULL);
}
}

void APickable::SetOwningPawn(ABaseCharacter* NewOwner)
{
if (MyPawn != NewOwner)
{
Instigator = NewOwner;
MyPawn = NewOwner;
// net owner for RPC calls
SetOwner(NewOwner);
}
}

bool APickable::IsAttachedToPawn() const
{
return bIsEquipped || bPendingEquip;
}

void APickable::AttachMeshToPawn(EWeaponSlot Pickableslot)
{

switch (Pickableslot)
{
case(EWeaponSlot::InHand):
if (MyPawn)
{
FName AttachPoint = MyPawn->GetWeaponAttachPoint();
if (MyPawn->IsLocallyControlled() == true)
{
USkeletalMeshComponent* PawnMesh1p = MyPawn->GetSpecifcPawnMesh(true);
USkeletalMeshComponent* PawnMesh3p = MyPawn->GetSpecifcPawnMesh(false);
Mesh1P->SetHiddenInGame(false);
Mesh3P->SetHiddenInGame(false);
Mesh1P->AttachToComponent(PawnMesh1p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
Mesh3P->AttachToComponent(PawnMesh3p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
FVector NewLocation;
FRotator NewRotation; // = TpsSocket.GetRotation;

SetActorLocationAndRotation(NewLocation, NewRotation, false, 0, ETeleportType::None);
PlayWeaponSound(EquipSound);
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT(“in hands”));
}

}
break;

case (EWeaponSlot::Primary):
if (MyPawn)
{
FName AttachPoint = MyPawn->PrimaryAttachPoint;
USkeletalMeshComponent* PawnMesh3p = MyPawn->GetSpecifcPawnMesh(false);
Mesh1P->SetHiddenInGame(true);
Mesh3P->AttachToComponent(PawnMesh3p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
PlayWeaponSound(EquipSound);

FVector NewLocation= TpsSocket.GetLocation();
FRotator NewRotation;// = TpsSocket.Rotation();
SetActorLocationAndRotation(NewLocation, NewRotation, false, 0, ETeleportType::None);

GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT(“in primary”));
}

break;

case (EWeaponSlot::Secondary):
if (MyPawn)
{
FName AttachPoint = MyPawn->SecondaryAttachPoint;
USkeletalMeshComponent* PawnMesh3p = MyPawn->GetSpecifcPawnMesh(false);
Mesh1P->SetHiddenInGame(true);
Mesh3P->AttachToComponent(PawnMesh3p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
PlayWeaponSound(EquipSound);

FVector NewLocation;
FRotator NewRotation; // = TpsSocket.GetRotation;
SetActorLocationAndRotation(NewLocation, NewRotation, false, 0, ETeleportType::None);
}

break;

case (EWeaponSlot::SideGun):
if (MyPawn)
{
FName AttachPoint = MyPawn->SideGunAttachPoint;
USkeletalMeshComponent* PawnMesh3p = MyPawn->GetSpecifcPawnMesh(false);
Mesh1P->SetHiddenInGame(true);
Mesh3P->AttachToComponent(PawnMesh3p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
PlayWeaponSound(EquipSound);
}
break;
}
}

void APickable::DetachMeshFromPawn()
{

Mesh1P->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform);
Mesh1P->SetHiddenInGame(true);
Mesh3P->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform);
Mesh3P->SetHiddenInGame(true);
PlayWeaponSound(UnEquipSound);
}

void APickable::OnUnEquip()

{
DetachMeshFromPawn();
bIsEquipped = false;
AttachMeshToPawn(CurrentSlot);
PlayWeaponSound(UnEquipSound);
}

//////////////////////////////////////////////////////////////////////////
// Replication & effects

void APickable::OnRep_MyPawn()
{
if (MyPawn)
{
OnEnterInventory(MyPawn);
}
else
{
OnLeaveInventory();
}
}

void APickable::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);

DOREPLIFETIME(APickable, MyPawn);
DOREPLIFETIME(APickable, ReplicatedLocation);

}

void APickable::OnRep_ReplicatedLocation()
{
if (!Instigator)
{
// Move mesh to replicated ragdoll location
Mesh3P->SetAllPhysicsPosition(ReplicatedLocation);
}
}


At quick glance, you set the current slot in a function that is run server only, but you’re not replicating the slot to the client. Just add the replication meta-data to CurrentSlot and add CurrentSlot to the GetLifetimeReplicatedProps function.

Thank you I’m gonna try that.

It works !

Now the slot is working but the skeletalmesh of the weapon dosen’t appear, even if the weapon itself is replicated. Do you know why is that ?

Probably something similar. Look at where you’re attaching the mesh and make sure it’s being called on all sides of the network pond.

What I Don’t understand is if the object itself (the weapon) is replicated , why do I need to replicate also some properties of the object ?

In a nutshell, network optimizations. For the most part, any actor with bReplicates set that is spawned on the server will replicate to relevant clients. BUT, within that actor, only properties that are flagged for replication with UPROPERTY(Replicated) are valid on clients. If every property was sent you would flood your network bandwidth very quickly. So UE4 actors need to opt-in their properties. If you haven’t already I strongly suggest reading this page:

That make sens, thanx for the explanation.

In the shooter exemple they are using the replication graph for that , that’s why they didn’t used the property replicated. Am I correct ?

I haven’t used a replication graph yet so I’m going to say sure???

This is very weird, because I’ve done the same that for" currentslot" with skeletalMesh, replicated it, but doesn’t work this time. The skeletalmesh doesen’t appear on the client.
What am I missign here ?

Did you check if the property is properly replicated. I’m going to guess it’s replicated, but you still need to apply it on the client.



// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Net/UnrealNetwork.h"
#include "Pickable.generated.h"


class UAnimMontage;
class ABaseCharacter;
class USoundCue;
class UAudioComponent;
class UAnimMontage;
class UParticleSystemComponent;
class UCameraShake;
class UForceFeedbackEffect;

USTRUCT()
struct FPickableAnim
{
 GENERATED_USTRUCT_BODY()

  /** animation played on pawn (1st person view) */
  UPROPERTY(EditDefaultsOnly, Category = Animation)
  UAnimMontage* Pawn1P;

 /** animation played on pawn (3rd person view) */
 UPROPERTY(EditDefaultsOnly, Category = Animation)
  UAnimMontage* Pawn3P;
};



UENUM(BlueprintType)
enum class EWeaponSlot : uint8
{

 None,
 Primary,
 Secondary,
 SideGun,
 Throwable,
 Other,
 InHand,


};

UCLASS(Abstract, Blueprintable)
class  APickable : public AActor
{
 GENERATED_UCLASS_BODY()

public:

protected:
 // Called when the game starts or when spawned
 virtual void BeginPlay() override;

 virtual void Tick(float DeltaTime) override;

private:
 /** weapon mesh: 1st person view */
 UPROPERTY(Replicated,VisibleDefaultsOnly, Category = Mesh)
  USkeletalMeshComponent* Mesh1P;

 /** weapon mesh: 3rd person view */
 UPROPERTY(Replicated,VisibleDefaultsOnly, Category = Mesh)
  USkeletalMeshComponent* Mesh3P;

public:

 //nom de l'objet
 UPROPERTY(BluePrintReadWrite, EditAnywhere, Category = Items)
  FName ItemName;

 // Thumbnail for this item used in buymenu and hud
 /*UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = Items)
  UTexture2D * ItemThumbnail;*/


 //Socket pour accrocher l'item en vue FPS
 UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Mesh)
  FTransform FpsSocket;


 //Socket pour accrocher l'item en TPS
 UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Mesh)
  FTransform TpsSocket;

public:

 //Socket pour accrocher l'item dans le dos
 UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Mesh)
  FTransform PrimarySocket;

 //Socket pour accrocher l'item dans le dos
 UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Mesh)
  FTransform SecondarySocket;


 UPROPERTY(EditDefaultsOnly, Category = Items)
  FPickableAnim EquipAnim;


 UPROPERTY(BluePrintReadWrite, VisibleDefaultsOnly, Category = Pickable)
 bool IsPickable;

 float Weight;

 UPROPERTY(Replicated,BluePrintReadWrite, VisibleDefaultsOnly, Category = Pickable)
 EWeaponSlot CurrentSlot;

 //EWeaponSlot GetWeaponSlot();

 void SetWeaponSlot(EWeaponSlot NewCurrentSlot);

protected:

 /** pawn owner */
 UPROPERTY(Transient, ReplicatedUsing = OnRep_MyPawn)
  class ABaseCharacter* MyPawn;

 //////////////////////////////////////////////////////////////////////////
 // Weapon usage helpers
public:

 /** play weapon sounds */
 UAudioComponent* PlayWeaponSound(USoundCue* Sound);

 /** play weapon animations */
 float PlayWeaponAnimation(const FPickableAnim& Animation);

 /** stop playing weapon animations */
 void StopWeaponAnimation(const FPickableAnim& Animation);



 //////////////////////////////////////////////////////////////////////////
 // Replication & effects

 UFUNCTION()
  void OnRep_MyPawn();


 //////////////////////////////////////////////////////////////////////////
 // Inventory

 void OnEquip(const APickable* LastWeapon);

 void OnEquipFinished();


 void OnDesequip(const APickable* LastWeapon);

 /** Handle for efficient management of OnEquipFinished timer */
 FTimerHandle TimerHandle_OnEquipFinished;

 /** [server] weapon was added to pawn's inventory */
 virtual void OnEnterInventory(ABaseCharacter* NewOwner);

 /** [server] weapon was removed from pawn's inventory */
 virtual void OnLeaveInventory();

 /** set the weapon's owning pawn */
 void SetOwningPawn(ABaseCharacter* AShooterCharacter);

 /** check if mesh is already attached */
 bool IsAttachedToPawn() const;

 UFUNCTION(BluePrintCallable)
 void AttachMeshToPawn(EWeaponSlot Pickableslot);

 void DetachMeshFromPawn();

 /** weapon is holstered by owner pawn */
 virtual void OnUnEquip();



 protected:
 /** is equip animation playing? */
 uint32 bPendingEquip : 1;

 /** is weapon currently equipped? */
 uint32 bIsEquipped : 1;

 //is weapon attach hands
 bool bIsinHands;

public :
 bool GetIsEquiped() const { return bIsEquipped; };

 bool GetIsInHand() const { return bIsinHands; };

 /** equip sound */
 UPROPERTY(EditDefaultsOnly, Category = Sound)
  USoundCue* EquipSound;

 /** unequip sound */
 UPROPERTY(EditDefaultsOnly, Category = Sound)
  USoundCue* UnEquipSound;

 /** last time when this weapon was switched to */
 float EquipStartedTime;

 /** how much time weapon needs to be equipped */
 float EquipDuration;

 public:
  UPROPERTY(EditDefaultsOnly, Category = Animation)
 FPickableAnim PawnEquipAnim;



private:
 UPROPERTY(ReplicatedUsing = OnRep_ReplicatedLocation)
  FVector ReplicatedLocation;

 UFUNCTION()
  void OnRep_ReplicatedLocation();

 public:
  void OnRep_Instigator() override;
};





// Fill out your copyright notice in the Description page of Project Settings.

#include "Pickable.h"
#include "TacticalOps.h"
#include "Player/BaseCharacter.h"

// Sets default values
APickable::APickable(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
 Mesh1P = ObjectInitializer.CreateDefaultSubobject(this, TEXT("WeaponMesh1P"));
 Mesh1P->VisibilityBasedAnimTickOption = EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered;
 Mesh1P->bReceivesDecals = false;
 Mesh1P->CastShadow = false;
 Mesh1P->SetCollisionObjectType(ECC_WorldDynamic);
 Mesh1P->SetCollisionEnabled(ECollisionEnabled::NoCollision);
 Mesh1P->SetCollisionResponseToAllChannels(ECR_Ignore);
 RootComponent = Mesh1P;

 Mesh3P = ObjectInitializer.CreateDefaultSubobject(this, TEXT("WeaponMesh3P"));
 Mesh3P->VisibilityBasedAnimTickOption = EVisibilityBasedAnimTickOption::OnlyTickPoseWhenRendered;
 Mesh3P->bReceivesDecals = false;
 Mesh3P->CastShadow = true;
 Mesh3P->SetCollisionObjectType(ECC_WorldDynamic);
 Mesh3P->SetCollisionEnabled(ECollisionEnabled::NoCollision);
 Mesh3P->SetCollisionResponseToAllChannels(ECR_Ignore);
 //Mesh3P->SetCollisionResponseToChannel(COLLISION_WEAPON, ECR_Block);
 Mesh3P->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
 //Mesh3P->SetCollisionResponseToChannel(COLLISION_PROJECTILE, ECR_Block);
 Mesh3P->SetupAttachment(Mesh1P);

 IsPickable = true;
 bPendingEquip = false;
 bIsEquipped = false;
 bIsinHands = false;


 PrimaryActorTick.bCanEverTick = true;
 PrimaryActorTick.TickGroup = TG_PrePhysics;
 SetRemoteRoleForBackwardsCompat(ROLE_SimulatedProxy);
 bReplicates = true;
 bAlwaysRelevant = true;
 bNetUseOwnerRelevancy = false;

}

// Called when the game starts or when spawned
void APickable::BeginPlay()
{
 Super::BeginPlay();

}

void APickable::Tick(float DeltaTime)
{
 // Tick will only execute when dropped
 if (Instigator)
 {
  SetActorTickEnabled(false);
  return;
 }

 if (GetNetMode() == NM_Client)
 {
  // Update location on clients
  if ((Mesh3P->GetComponentLocation() - ReplicatedLocation).SizeSquared() > 400.f)
  {
   Mesh3P->SetAllPhysicsPosition(ReplicatedLocation);//(Mesh->GetComponentLocation() + ReplicatedLocation) * 0.5f);
  }
 }
 else
 {
  // Set replicated location so clients will receive it
  ReplicatedLocation = Mesh3P->GetComponentLocation();
 }
}




//////////////////////////////////////////////////////////////////////////
// Weapon usage helpers

UAudioComponent* APickable::PlayWeaponSound(USoundCue* Sound)
{
 UAudioComponent* AC = NULL;
 if (Sound && MyPawn)
 {
  AC = UGameplayStatics::SpawnSoundAttached(Sound, MyPawn->GetRootComponent());
 }

 return AC;
}

float APickable::PlayWeaponAnimation(const FPickableAnim& Animation)
{
 float Duration = 0.0f;
 if (MyPawn)
 {
  UAnimMontage* UseAnim = MyPawn->IsFirstPerson() ? Animation.Pawn1P : Animation.Pawn3P;
  if (UseAnim)
  {
   Duration = MyPawn->PlayAnimMontage(UseAnim);
  }
 }

 return Duration;
}

void APickable::StopWeaponAnimation(const FPickableAnim& Animation)
{
 if (MyPawn)
 {
  UAnimMontage* UseAnim = MyPawn->IsFirstPerson() ? Animation.Pawn1P : Animation.Pawn3P;
  if (UseAnim)
  {
   MyPawn->StopAnimMontage(UseAnim);
  }
 }
}

///////////////////////////////////////////////////
//Inventory


void APickable::OnEquip(const APickable* LastWeapon)
{
 bPendingEquip = true;
 AttachMeshToPawn(EWeaponSlot::InHand);


 //DetermineWeaponState();

 // Only play animation if last weapon is valid
 if (LastWeapon)
 {
  float Duration = PlayWeaponAnimation(EquipAnim);
  if (Duration GetTimeSeconds();
  EquipDuration = Duration;

  GetWorldTimerManager().SetTimer(TimerHandle_OnEquipFinished, this, &APickable::OnEquipFinished, Duration, false);
  PlayWeaponSound(EquipSound);
 }
 else
 {
  OnEquipFinished();
 }

 if (MyPawn && MyPawn->IsLocallyControlled())
 {
  PlayWeaponSound(EquipSound);
 }

 ABaseCharacter::NotifyEquipWeapon.Broadcast(MyPawn, this);
}

void APickable::OnEquipFinished()
{
 //AttachMeshToPawn();

 bIsEquipped = true;
 bPendingEquip = false;


}


void APickable::OnDesequip(const APickable* LastWeapon)
{

 AttachMeshToPawn(CurrentSlot);
 bIsEquipped = false;
 bIsinHands = false;
 PlayWeaponSound(UnEquipSound);
}

void APickable::OnEnterInventory(ABaseCharacter* NewOwner)
{
 SetOwningPawn(NewOwner);
}

void APickable::OnLeaveInventory()
{
 if (IsAttachedToPawn())
 {
  OnUnEquip();
 }

 if (Role == ROLE_Authority)
 {
  SetOwningPawn(NULL);
 }
}

void APickable::SetOwningPawn(ABaseCharacter* NewOwner)
{
 if (MyPawn != NewOwner)
 {
  Instigator = NewOwner;
  MyPawn = NewOwner;
  // net owner for RPC calls
  SetOwner(NewOwner);
 }
}

bool APickable::IsAttachedToPawn() const
{
 return bIsEquipped || bPendingEquip;
}



void APickable::AttachMeshToPawn(EWeaponSlot Pickableslot)
{

 switch (Pickableslot)
 {
 case(EWeaponSlot::InHand):
  if (MyPawn)
  {
   FName AttachPoint = MyPawn->GetWeaponAttachPoint();
   if (MyPawn->IsLocallyControlled() == true)
   {
    USkeletalMeshComponent* PawnMesh1p = MyPawn->GetSpecifcPawnMesh(true);
    USkeletalMeshComponent* PawnMesh3p = MyPawn->GetSpecifcPawnMesh(false);
    Mesh1P->SetHiddenInGame(false);
    Mesh3P->SetHiddenInGame(false);
    Mesh1P->AttachToComponent(PawnMesh1p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
    Mesh3P->AttachToComponent(PawnMesh3p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
    FVector NewLocation;
    FRotator NewRotation; // = TpsSocket.GetRotation;


    SetActorLocationAndRotation(NewLocation, NewRotation, false, 0, ETeleportType::None);
    PlayWeaponSound(EquipSound);
    bIsinHands = true;
    //GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("in hands"));
   }


  }
  break;

 case (EWeaponSlot::Primary):
  if (MyPawn)
  {
   FName AttachPoint = MyPawn->PrimaryAttachPoint;
   USkeletalMeshComponent* PawnMesh3p = MyPawn->GetSpecifcPawnMesh(false);
   Mesh1P->SetHiddenInGame(false);
   Mesh3P->AttachToComponent(PawnMesh3p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
   PlayWeaponSound(EquipSound);


   FVector NewLocation= TpsSocket.GetLocation();
   FRotator NewRotation;// = TpsSocket.Rotation();
   SetActorLocationAndRotation(NewLocation, NewRotation, false, 0, ETeleportType::None);

   //GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, TEXT("in primary"));
  }

  break;

 case (EWeaponSlot::Secondary):
  if (MyPawn)
  {
   FName AttachPoint = MyPawn->SecondaryAttachPoint;
   USkeletalMeshComponent* PawnMesh3p = MyPawn->GetSpecifcPawnMesh(false);
   Mesh1P->SetHiddenInGame(false);
   Mesh3P->AttachToComponent(PawnMesh3p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
   PlayWeaponSound(EquipSound);

   FVector NewLocation;
   FRotator NewRotation; // = TpsSocket.GetRotation;
   SetActorLocationAndRotation(NewLocation, NewRotation, false, 0, ETeleportType::None);
  }

  break;


 case (EWeaponSlot::SideGun):
  if (MyPawn)
  {
   FName AttachPoint = MyPawn->SideGunAttachPoint;
   USkeletalMeshComponent* PawnMesh3p = MyPawn->GetSpecifcPawnMesh(false);
   Mesh1P->SetHiddenInGame(false);
   Mesh3P->AttachToComponent(PawnMesh3p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
   PlayWeaponSound(EquipSound);
  }
  break;
 }
}

void APickable::DetachMeshFromPawn()
{

 Mesh1P->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform);
 Mesh1P->SetHiddenInGame(true);
 Mesh3P->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform);
 Mesh3P->SetHiddenInGame(true);
 PlayWeaponSound(UnEquipSound);
}



void APickable::OnUnEquip()

{
 DetachMeshFromPawn();
 bIsEquipped = false;
 AttachMeshToPawn(CurrentSlot);
 PlayWeaponSound(UnEquipSound);
}





void APickable::SetWeaponSlot(EWeaponSlot NewCurrentSlot)
{
 CurrentSlot = NewCurrentSlot;
}

//////////////////////////////////////////////////////////////////////////
// Replication & effects

void APickable::OnRep_MyPawn()
{
 if (MyPawn)
 {
  OnEnterInventory(MyPawn);
 }
 else
 {
  OnLeaveInventory();
 }
}




void APickable::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
 Super::GetLifetimeReplicatedProps(OutLifetimeProps);

 DOREPLIFETIME(APickable, MyPawn);
 DOREPLIFETIME(APickable, ReplicatedLocation);
 DOREPLIFETIME(APickable, CurrentSlot);
 DOREPLIFETIME(APickable, Mesh3P);
 DOREPLIFETIME(APickable, Mesh1P);



}


void APickable::OnRep_ReplicatedLocation()
{
 if (!Instigator)
 {
  // Move mesh to replicated ragdoll location
  Mesh3P->SetAllPhysicsPosition(ReplicatedLocation);
 }
}

void APickable::OnRep_Instigator()
{
 Super::OnRep_Instigator();

}


Here is the code of the weapon with the property replicated.
I even replicate the property of Mesh1P even if I still Don’t use it correctly.

Your weapon’s OnEquip() is only called on the server (or so it seems for a quick glance). This means the attachment code will only occur on the server. While CurrentWeapon is replicated (and I suspect properly updated) that just get’s the reference to the actor. You’ll still need to perform the attachment on both sides of the pond. What you need to do is use the “ReplicatedUsing” modifier in the UPROPERTY() statement to cause a function to get called when CurrentWeapon changes. And when it does, call AttachMeshToPawn() or update OnEquip() to be client/server friendly (if needed, didn’t really look).

Thank you so much for your help.

Things are much more complicated than I tought but with your help I have been able to find a way tomake it works even if it’s not completely good.
Ihad to remove ther server call because it wasn’t working at first even with the"function replicatedusing".

i know this is completely off topic but this is top google result lol

if your getting this compile error


cannot convert from EVisibilityBasedAnimTickOption to uint8

then your Mesh must use Mesh->VisibilityBasedAnimTickOption instead of Mesh->MeshComponentUpdateFlag