#Server Authoritative Shooting
79 messages · Page 1 of 1 (latest)
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
Berg received thanks.
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?
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
I use margin of error myself
I think FPS land might do it
@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?
not really
if the cooldown changes a state just pass back the state so if it failed client could fix
ah, I see
thank you @rose mango
and thanks @icy seal for starting the topic
FirstGearGames, pixl received thanks.
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 🙂
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'
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.
Are you running fps land in editor? I've noticed in editor client side i can sometimes skip ticks. But its only in editor & only if i tab out more then once
The client I run as editor, but I build out as a headless for the server
Do it the other way around i think. I have alot of desync issues with client in editor
let me build a client and try it again
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
yeah its something I havent really messed with, its been on the to-do list.
I'm slowly converting away from MS timings also as i find anything < 100 ms can skip
I just saw this thread, and was like "I am in the same spot, what is a good way to do this"
https://discord.com/channels/424284635074134018/1091114409344118914 I had a similarish issue with Tick timing the other day (different scenario, pushing players)
But it turned out it was because i was running the wrong getTick inside the csp loop
I was gonna try doing something like this
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
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
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
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"
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
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 🙂
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
I guess thats why most fps run 60hz min. Which is 16.6ms~ a tick
alright, so it actually doesnt work hehe.
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.
I'd honestly do everything off tick. So maybe a ak has bullet CD of 3 ticks
yeah Im thinking something similar
We did try a struct like...
Bool Firing
Int FireStartTick
Int FireRate (tick)
so if Firing = true. send shot on every fireRate tick
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
Berg received thanks.
Algood man best of luck out there 🙂
I'll post my results here if I am able to get it working well. Appreciate the help.
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
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
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.
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
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
also none of my weapons have 1 tick. 3 is the lowest. So I guess ultimately the solution I posted is perfect for me
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.