I have a method that, on button input, checks value on PlayerState and, if check successful, sends RPC back:
void UAbilityController::OnSpellUpgradeButtonClicked(USpellWidget* SpellWidget)
{
ATBCPlayerState* TBCPlayerState{StaticCast<ATBCPlayerState*>(PlayerState)};
if (TBCPlayerState->GetSpellPoints() <= 0u) return;
....
TBCPlayerState->Server_AddSpellPoints(-1);
The problem is that when on a client, replication is not immediate, and replicated value is often faulty, i.e. i can spam button fast and bypass check. How can i fix this situation? I tried adding lock guards to both AbilityController and PlayerState, didn’t help. I can’t make OnSpellUpgradeButtonClicked a Server RPC, because it resides on HUD.
The way I handle it right now is just invoke AddSpellPoints on client:
if (PlayerController->IsNetMode(NM_Client))
{
GEngine->AddOnScreenDebugMessage(
-1, 3.f, FColor::Orange, TEXT("Client net mode"));
// Replication takes time, so change client value too, to ensure upgrade cannot be spammed
TBCPlayerState->AddSpellPoints(-1);
}
This way, on next button spam, value will be updated, and replication will validate that.