#Server Authoritative Shooting

79 messages · Page 1 of 1 (latest)

fast coral
#

@icy seal Are you running client server prediction on the clients?

#

I'll just assume you're not running csp for now... I'd so something like this

  // play particle
  // spawn offline projectile
  // Init offline projectile with clientTick
  if(isServer)ObserversFire(clientTick, spawnPosition);
}

void ObserversFire(uint client tick, Vector3 spawnPosition){
  Fire(tick,spawnPosition);
}

Then i'd use something like this example https://fish-networking.gitbook.io/docs/manual/guides/lag-compensation/projectiles to set the tick offset / timings on the offline projectile so they're in roughly the same position

#

But if you're wanting to enforce server position then you'll need to use servers Transform.position (or something for spawn position) rather then sending it via RPC.

#

Pseudo code wise you want...

Player does vfx locally
Player requests bullet spawn

So your vfx will be instant but the actual hitscan will be delayed by Ping. Similar setup to most fps like csgo etc

A way to send the player's direction at the moment of the shot in the second approach In terms of this you'll either need to use the rollback manager serverside (to check clients position at fire frame). Or just use the servers position at the time it gets the RPC

upper geyserBOT
#

Berg received thanks.

fathom stump
#

hi, @icy seal , @fast coral
sorry, I'll jump on this topic a bit.
I had an issue with [ServerRPC] approach, which could be basically described as following:

  • first bulles shoots, client passes
    startBulletTime=TimeManager.Tick
    to server as a time when it was fired.

TimeManager.Time is a predicted timestamp on server, so it, technically, could be off couple ticks.
So the client thinks that the next bullet would be available when, say:
TimeManager.Time >= startBulletTime + 5 ticks
While the server time is actually, let's say 1 ms off from the client-predicted TimeManager.Time; so server, next bullet is available 1 ms later):
TimeManager.Time - 1 >= startBulletTime + 5 ticks

in 5 ms Client thinks that it could fire another bullet, passes it to server
and server is like "nah-ah, I refuse this action, because I have 1 more ms of the previous bullet to go"

how do you guys to avoid syncing issues like this?
From the read of this question, I see that @icy seal in Approach 1 hints on the problem which appears cause the server does not checks if the second bullet is valid (hence the possibility of cheating).
But if you are checking whether the bullet is valid the problem I described above arises?

fathom stump
#

Well, that is what I referring to:
The way to avoid it is to introduce “cooldown” to firing.

But then the client will say:
Hey, according to my TimeManager.Time, I could fire the bullet right now, I am gonna play animation on my side and call ServerRPC “ScheduleFire”

But the server will say: well, your TimeManager.Time is just a prediction of my time; according to my real time, you still need 2 ticks before the cooldown will allow you to fire
And hence, in ServerRPC the server checks whether client could fire - he cannot; and disallows firing.

In result, client plays useless animation for RTT until he realizes that the bullet was disallowed on server

rose mango
#

I use margin of error myself

rose mango
#

I think FPS land might do it

fathom stump
#

@rose mango do you think there's any value in wrapping these 'cooldown checks' into csp loop?
so that at least 'I am in the middle of cd with these much time left till next one' would always be kinda in sync?

rose mango
#

not really

#

if the cooldown changes a state just pass back the state so if it failed client could fix

fathom stump
#

ah, I see
thank you @rose mango
and thanks @icy seal for starting the topic

upper geyserBOT
#

FirstGearGames, pixl received thanks.

fathom stump
#

did you tried with sudden spikes in latency?

#

right, in this case this indeed should not be an issue: cause if you added extra latency, your predictions should always be spot on, cause it is not really changes?
this is just per my understanding, I may be wrong here

#

sorry, was not quite clear:
if you just add +100ms latency, consistently, your predictions of client "I am 100 ms behind on latency"
would always enable your client to make the predictions spot on
if you are adding 100+-50ms (randomly) per each message, things suppose to change?

#

I could be also wrong here, I am newbie to Fishnets 🙂

fathom stump
#

ah, I see
yeah, my comment was related to: what if between 1st and 2nd client packet, latency suddenly changes from 50ms to 48ms
that what I was mainly concerned about

but this is really only related to actions with kinda 0.1-0.2s timing
everything smaller - you probably could ignore the second packet and user won't notice (cause supposedly, there's would be next action fired in 2ms later on)
everythiong larger - and you could wait for ack from a server that 'hey, yes - I fired an event, the cooldown will go away in <x> seconds'

sinful harbor
#

I've noticed the issue -- with the way it's done in the FPS Land example -- is if you have a weapon with a high rate of fire, the server wont count some shots, so the player is firing blanks at that point. You'll see it on the Client, but the server will skip right over it cause it failed to meet the check that it was okay to fire again. Which sucks in an FPS or any PVP game. This is something I've been meaning to tackle at some point though. My current system is set up like the FPS Land Example. This was on localhost with a weapon that had a fire rate of 0.11f. Client of course got all 30, but Server missed on each 30 round mag.

fast coral
sinful harbor
#

The client I run as editor, but I build out as a headless for the server

fast coral
#

Do it the other way around i think. I have alot of desync issues with client in editor

sinful harbor
#

let me build a client and try it again

fast coral
#

From my experience in fps games we would also generally have all cooldowns based on ticks not timings

#

because like you said you can skip or even double up on shots

sinful harbor
#

yeah its something I havent really messed with, its been on the to-do list.

fast coral
#

I'm slowly converting away from MS timings also as i find anything < 100 ms can skip

sinful harbor
#

I just saw this thread, and was like "I am in the same spot, what is a good way to do this"

fast coral
#

But it turned out it was because i was running the wrong getTick inside the csp loop

sinful harbor
#

I was gonna try doing something like this

fast coral
#

FPS tick timing / firing isn't really as straight forward as it sounds. Our team struggled with it a bit but we used photon bolt for our fps at the time

sinful harbor
#
        protected override void CmdFireExample(PreciseTick preciseTick, Vector3 pos, Vector3 forward)
        {
            double timePassed = base.TimeManager.TimePassed(base.TimeManager.Tick, lastTick);
            if(timePassed >= _weaponData.ShotTime)
            {
                //FireWeapon
            }

            lastTick = preciseTick.Tick;
        }```
#

just some pseudo code

fast coral
#

I'd suggest maybe running off Base.Owner.LocalTIck. Mines a little different as i run through the CSP loop

#

So i need to send two types of ticks... local clients & servers then calculate dif

#

But mines again a little differnt as im basically delaying the start of the "knocback" so both client/server are in sync. Which will feel terrible with a gun

sinful harbor
#

the method I posted, just from running a test seems to work perfectly for me now. If the client hacks the shot time to be zero

#

the server is like "Nah dude, nice try"

fast coral
#

Yeah it should work fine. There might be a scenario where it stacks two bullets in a single frame but idk if its worth trying ot fix that

sinful harbor
#

I'll need to test it a bit more to see if that happens

#

but if that ends up coming up, I'll be back in this thread 🙂

fast coral
#

We had some double stacking and we just mostly hid it by making sure the audio / vfx only fire within timings

#

But thats also probably because our bullet shot time was less then our tick timing so we could end up with 2 bullets in 1 frame

sinful harbor
#

I have one weapon that has an insane rate of fire

#

Im gonna test that now

fast coral
#

I guess thats why most fps run 60hz min. Which is 16.6ms~ a tick

sinful harbor
#

alright, so it actually doesnt work hehe.

sinful harbor
#

Gonna try something to what you've suggested here Berg. But yeah, this seems to be a tricky one. I notice that I have my shot time set to 0.125f for this one weapon, but if I do time passed based on the last tick it was fired vs current tick (Both Server/Client) if I go full auto, I get 0.133333333 (repeating of course) and 0.116666666666667. So yeah this seems a bit tricky.

fast coral
#

I'd honestly do everything off tick. So maybe a ak has bullet CD of 3 ticks

sinful harbor
#

yeah Im thinking something similar

fast coral
#

We did try a struct like...

Bool Firing
Int FireStartTick
Int FireRate (tick)

#

so if Firing = true. send shot on every fireRate tick

sinful harbor
#

gonna give this a quick go, then call it a night and hit the gym.

#

Results are promising. I'll pick this back up tomorrow morning. There is still about a 1-2 tick discrepancy on the server from time to time, but this seems more consistent than doing it the other way. Thanks @fast coral

upper geyserBOT
#

Berg received thanks.

fast coral
#

Algood man best of luck out there 🙂

sinful harbor
#

I'll post my results here if I am able to get it working well. Appreciate the help.

sinful harbor
#

SO, I got something working

#

it's simple

#
    private bool IsAbleToFire => base.TimeManager.Tick >= _lastFireTick + _weaponData.ShotTimeTicks;

    private void FireWeapon()
    {
        if (!IsAbleToFire)
            return;

        //Do Fire Stuff
        ServerRpcFireWeapon();
        _lastFireTick = base.TimeManager.Tick;
    }

    [ServerRpc]
    private void ServerRpcFireWeapon()
    {
        if (!IsAbleToFire)
            return;

        //Do Fire Stuff
        _lastFireTick = base.TimeManager.Tick - 1;
    }```
#

This works way better than the example in FPS land

#

FPS Land's example can miss lots of shots on the server, this still MAY miss a shot or two on server, but I tested on my MG-42 which has a fire rate of 3 ticks (0.05f) and it didn't miss a single shot in the 100 rounds it had.

#

where as doing it the old way, out of the 100 shots I missed 16

#

the server taking 1 tick off is similar to the FPS land where it gives some leeway

fast coral
#

This will work but say if you're running 30hz and only allowing 1 tick leeway you'll end up with high desyncs on anyone above 33.3 ms

#

Its round trip so technically anyone on 66+ ms would desync

#

its not really "desync" though in the csp sense... I think this should work fine mostly

sinful harbor
#

I tested with high ping and dropped packets and it still held up

#

overall, its more effective than the previous way I was doing it, haha.

fast coral
#

I guess the main thing is making sure your fire rate is correctly enforced server side which seems like it will be

#

I'd maybe put some logs in here to confirm that fire rate value is playing nice

    private void ServerRpcFireWeapon()
    {
        if (!IsAbleToFire)
            Debug.LogError("Client Fired incorrectly")
            return;
#

and then see how fast you can go before you hit limits 🤓 I think you might run into issue with guns that have 1 tick fire rates as you're comparing serverside tick-1

sinful harbor
#

Oh yeah I got logs on mine

#

I do the same thing you did up there, I check, and if it cant I log and return

sinful harbor
#

might not work for all

#

but I tested with lowering the Fire Rate on the client, and it blocked shots on the server, and the other clients see them firing at normal rate.