Melee Weapon Timing

I’m working on a melee swep for TTT and I’m having some strange timing issues, among some other things, all due to CLIENT vs SERVER stuff.
Unfortunately I can’t test it for a few days since I can’t port forward where I am, and I don’t have a server so I’m flying a bit blind.

So all of these are from me hosting a server populated from bots:

First, My self:EmitSound() lines unintentionally emit the same sound twice, once for both CLIENT and SERVER.
Is this because I am both the Server and the Client since I’m hosting the game?
When I put this swep on TTT servers will it play two sounds or just one?

Next, I use Timers to sync up the melee with the sounds and the effects. So… Apparently it makes a Timer on both the Server and on the Client (I know because I had set the time to fire them as random just to test, there are two timers created). Is this normal, and if not, is there a way to fix it?

Also, when the weapon hits a player I run plyr:viewpunch, should this be if SERVER, if CLIENT, or both?
Finally, I have a line to push objects. phys:ApplyForce() - should this be if SERVER, if CLIENT, or both?

Thanks a million guys, this is driving me nuts!

Without knowing what your code is, all I can do is guess. For the first one, try wrapping your EmitSound method in a client condition, to force it to only emit the sound once, for the client.

if( CLIENT ) then
self:EmitSound( )

As for your other questions, I’d like to know the answers to these too.

Hey don’t mark it as dumb… any help is appreciated. I tried that earlier today just for kicks and while it fixed the dual-sounds, no sound was played to people around the player (the server didn’t play it).

Also a new thing: I got a hold of a server, and it seems that the timing for the meleeing is all off - the animations always play out of sync, like I’ll click, hear the attack sound, see the attack effect, but no swinging of weapon.

Do if SERVER instead

Then it doesn’t play on the client’s game, if I’m not mistaken

well logic says that if removing the serverside part solved the double sound glitch, then it should be playing on the client’s game, no?

You are using timers, that’s your problem. Weapons are really particular because they use a mechanic called “prediction” to make them appear more responsive on the user’s side. When you press your left mouse button, it takes some time for the command to arrive to the server, and some more time for the server to send the new state of the weapon to the client. Without prediction, this would cause a notable delay between the moment you press your left mouse button and the moment you see the weapon actually fire. Prediction fixes that by causing the weapon to fire immediately on your client, so you have the illusion that there is no delay. It’s purely a visual trick of course, but it is quite convincing.

Also, because the server and the client don’t run at the same rate, clientside prediction needs to be run several times until the current time on the client matches the current time on the server. When you fire your weapon once, it will call PrimaryAttack once on the server, and several times on the client. Some functions such as EmitSound or SendWeaponAnim have special behaviour when called clientside in such situations, this is why you normally don’t see animations playing several times in a row. However some functions are not meant to be used during clientside prediction, this is when you need to use IsFirstTimePredicted to run tasks that should be done only once on the client.
As I previously said, firing your weapon causes PrimaryAttack to be called several times on the client due to prediction. IsFirstTimePredicted will return true on the first of those calls, and false on the others.

Now back to your problem.
By using timers, you are playing sounds outside of your weapon hooks. Which means that there is no prediction involved and EmitSound will do what it generally does. So it’s completely normal to hear the sound twice.
The only way to fix that is to play your sound inside of one of your weapon hooks. The most suitable one would be SWEP:Think. All you need to do is store the time at which the sound should be played in a network variable, and then play the sound in SWEP:Think if the current time is greater than the time stored in that variable.

So something like this:

function SWEP:SetupDataTables()
self:NetworkVar(“Float”, 0, “NextMeleeAttack”)

function SWEP:PrimaryAttack()
self:SetNextMeleeAttack(CurTime() + 0.3)

function SWEP:Think()
local nextMeleeAttack = self:GetNextMeleeAttack()
if nextMeleeAttack > 0 and CurTime() >= nextMeleeAttack then

function SWEP:DoMeleeAttack()
– you should do your melee trace attack here as well



Should be server only since the player on the receiving end isn’t the owner of the weapon, they don’t care about weapon prediction.

Server. Anything that has an effect on something that other players can see and interact with should be serverside only.

Thanks! After I got it setup into a server, the synchronization for the animation was all out of whack, probably due -like you said- to the timer implementation.
I’ll throw together one using CurTime() then. Thanks man!

[editline]2nd January 2014[/editline]

It’s working beauuuuuuuuuuuuuuuuuuuuuutifully - thanks!

When I hit breakable props with it, they disappear now. I think the code is being called multiple times like you said, but print statements say only one client call and one server call. Any ideas?

Wait, what method are you using? Tracehull, then sending damage to the entity?

Ah yeah I had the exact same problem. For some reason applying damage to a prop inside a weapon’s Think hook causes them to break without spawning gibs and I’ve yet to figure why.
As a dirty workaround, I had to use timer.Simple with a delay of 0 to apply the damage. It’s not very pretty but it works, and since you are doing this serverside only, there’s nothing wrong with it.

Really? For me it was just a matter of setting the damage enum to bullet.