Fix ClientSideAim RPC spam from observer clients
Use GetLocalRole()==ROLE_AutonomousProxy instead of GetRemoteRole()==ROLE_Authority to restrict the ClientAim/ShootRepCSA RPC path to the owning client only. Observers (SimulatedProxy) early-out instead of attempting to send Server RPCs on weapons they don't own, which was spamming "No owning connection" warnings and doing useless work. Default ClientAimUpdateFrequency raised to 60 Hz. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -14,7 +14,7 @@ void UEBBarrel::SpawnBulletEventMulticast_Implementation(FVector Start, FVector
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UEBBarrel::Shoot(bool Trigger, int nextFireID) {
|
void UEBBarrel::Shoot(bool Trigger, int nextFireID) {
|
||||||
if (ClientSideAim && GetOwner()->GetRemoteRole() == ROLE_Authority && Trigger) {
|
if (ClientSideAim && GetOwner()->GetLocalRole() == ROLE_AutonomousProxy && Trigger) {
|
||||||
Aim = GetComponentTransform().GetUnitAxis(EAxis::X);
|
Aim = GetComponentTransform().GetUnitAxis(EAxis::X);
|
||||||
Location = GetComponentTransform().GetLocation();
|
Location = GetComponentTransform().GetLocation();
|
||||||
nextFireEventID = nextFireID;
|
nextFireEventID = nextFireID;
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ void UEBBarrel::TickComponent(float DeltaTime, ELevelTick TickType, FActorCompon
|
|||||||
UpdateTransformHistory();
|
UpdateTransformHistory();
|
||||||
|
|
||||||
if (ClientSideAim){
|
if (ClientSideAim){
|
||||||
if (GetOwner()->GetRemoteRole()==ROLE_Authority){
|
const ENetRole LocalRole = GetOwner()->GetLocalRole();
|
||||||
|
if (LocalRole == ROLE_AutonomousProxy){
|
||||||
TimeSinceAimUpdate += DeltaTime;
|
TimeSinceAimUpdate += DeltaTime;
|
||||||
if (TimeSinceAimUpdate >= 1.0f / ClientAimUpdateFrequency) {
|
if (TimeSinceAimUpdate >= 1.0f / ClientAimUpdateFrequency) {
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ void UEBBarrel::TickComponent(float DeltaTime, ELevelTick TickType, FActorCompon
|
|||||||
ClientAim(UGameplayStatics::RebaseLocalOriginOntoZero(GetWorld(),Location), Aim);
|
ClientAim(UGameplayStatics::RebaseLocalOriginOntoZero(GetWorld(),Location), Aim);
|
||||||
TimeSinceAimUpdate = FMath::Fmod(TimeSinceAimUpdate, 1.0f / ClientAimUpdateFrequency);
|
TimeSinceAimUpdate = FMath::Fmod(TimeSinceAimUpdate, 1.0f / ClientAimUpdateFrequency);
|
||||||
};
|
};
|
||||||
}else{
|
}else if (LocalRole == ROLE_Authority){
|
||||||
if (!RemoteAimReceived) {
|
if (!RemoteAimReceived) {
|
||||||
ComputeAntiRecoilTransform();
|
ComputeAntiRecoilTransform();
|
||||||
}
|
}
|
||||||
@@ -74,6 +75,7 @@ void UEBBarrel::TickComponent(float DeltaTime, ELevelTick TickType, FActorCompon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ROLE_SimulatedProxy: observer, aim comes from replicated transform — nothing to do
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ComputeAntiRecoilTransform();
|
ComputeAntiRecoilTransform();
|
||||||
|
|||||||
@@ -226,8 +226,8 @@ public:
|
|||||||
bool ReplicateShotFiredEvents = true;
|
bool ReplicateShotFiredEvents = true;
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication", meta = (ToolTip = "When true, the owning client computes the barrel aim position/direction locally and sends it to the server via RPC. The server uses the client's aim to spawn the bullet. Essential for VR/tracked controllers where the server cannot know the exact barrel orientation. When false, the server uses the barrel component's replicated transform."))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication", meta = (ToolTip = "When true, the owning client computes the barrel aim position/direction locally and sends it to the server via RPC. The server uses the client's aim to spawn the bullet. Essential for VR/tracked controllers where the server cannot know the exact barrel orientation. When false, the server uses the barrel component's replicated transform."))
|
||||||
bool ClientSideAim=false;
|
bool ClientSideAim=false;
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication", meta = (ToolTip = "How often (Hz) the client sends aim updates to the server when ClientSideAim is true. Higher values = more accurate server-side aim at the cost of bandwidth. 15 Hz is a good default. Only relevant when ClientSideAim is enabled.", EditCondition = "ClientSideAim", ClampMin = "1"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication", meta = (ToolTip = "How often (Hz) the owning client sends aim updates to the server when ClientSideAim is true. Higher values = more accurate server-side aim at the cost of bandwidth. 60 Hz matches typical VR tracking rates. Only relevant when ClientSideAim is enabled. Only the owning client sends these updates (observers skip the RPC).", EditCondition = "ClientSideAim", ClampMin = "1"))
|
||||||
float ClientAimUpdateFrequency = 15.0f;
|
float ClientAimUpdateFrequency = 60.0f;
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication", meta = (ToolTip = "Maximum allowed distance (UU/cm) between the client-reported aim position and the server's barrel position. Acts as an anti-cheat clamp: if the client aim is further than this, the server clamps it. 200 = 2 meters. Set higher if the tracker has large offsets from the replicated barrel position.", EditCondition = "ClientSideAim", ClampMin = "0"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Replication", meta = (ToolTip = "Maximum allowed distance (UU/cm) between the client-reported aim position and the server's barrel position. Acts as an anti-cheat clamp: if the client aim is further than this, the server clamps it. 200 = 2 meters. Set higher if the tracker has large offsets from the replicated barrel position.", EditCondition = "ClientSideAim", ClampMin = "0"))
|
||||||
float ClientAimDistanceLimit = 200.0f;
|
float ClientAimDistanceLimit = 200.0f;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user