Hi,
I've just finished making some sword models and code. The way they work is by tracing in a different arc depending on a random number, and then playing that animation. However, there is a horrible amount of lag to the point that if one or both players are moving in multiplayer, the smaller swords won't hit even when you can see blood and hear a "shink" noise. This is when both players have 30 ping.
Any thoughts?
-TFA
Edit:
I'm not actually tracing an arc. I feel it would be better described as sending a series of tracelines in an arc of angles.
Final edit: Solved. Needed Player:LagCompensation(true) before trace and Player:LagCompensation(false) after.
Enable [img]http://wiki.garrysmod.com/favicon.ico[/img] [url=http://wiki.garrysmod.com/page/Player/LagCompensation]Player:LagCompensation[/url] before doing the trace, there's an example in the page.
Also you should use [img]http://wiki.garrysmod.com/favicon.ico[/img] [url=http://wiki.garrysmod.com/page/util/SharedRandom]util.SharedRandom[/url] instead of the math random, because this one can be predicted properly ( gives the same results on client and server ).
Wow, that is SUPER freaking useful. Thank you so much! I'll pretty much consider this solved then.
When was SharedRandom added? I thought you had to manually seed it
[QUOTE=Jvs;46718370]Enable [img]http://wiki.garrysmod.com/favicon.ico[/img] [url=http://wiki.garrysmod.com/page/Player/LagCompensation]Player:LagCompensation[/url] before doing the trace, there's an example in the page.
Also you should use [img]http://wiki.garrysmod.com/favicon.ico[/img] [url=http://wiki.garrysmod.com/page/util/SharedRandom]util.SharedRandom[/url] instead of the math random, because this one can be predicted properly ( gives the same results on client and server ).[/QUOTE]
willox made me and/or cake do some tests from linux client/server and windows client/server on different machines to see if math.random() can be predicted properly; the results showed that they are accurate to the bit.
[QUOTE=MeepDarknessM;46718749]willox made me and/or cake do some tests from linux client/server and windows client/server on different machines to see if math.random() can be predicted properly; the results showed that they are accurate to the bit.[/QUOTE]
Fair enough, forgot about that.
[QUOTE=GreyGeist;46718391]Wow, that is SUPER freaking useful. Thank you so much! I'll pretty much consider this solved then.[/QUOTE]
Also, just to future proof your weapons, don't use timers for weapons logic, ever, if you need to do the swing, do it in the think hook of the weapon.
If you're not using a serverside only variable, use [URL="http://wiki.garrysmod.com/page/Entity/NetworkVar"]network vars[/URL], they can be predicted properly and restored when the player lags and all that shit.
[QUOTE=MeepDarknessM;46718749]willox made me and/or cake do some tests from linux client/server and windows client/server on different machines to see if math.random() can be predicted properly; the results showed that they are accurate to the bit.[/QUOTE]
You can't guarantee that though. If any lua code outside your controlled environment calls math.random on only client or server they get desynced.
You could call math.randomseed before every math.random call, but it violates DRY unless you write a wrapper for it, in which case you could have just used util.SharedRandom in the first place.
[QUOTE=Wyozi;46718870]You can't guarantee that though. If any lua code outside your controlled environment calls math.random on only client or server they get desynced.
You could call math.randomseed before every math.random call, but it violates DRY unless you write a wrapper for it, in which case you could have just used util.SharedRandom in the first place.[/QUOTE]
it won't be called since lua is async - you have full control of what runs when and how. if you write a function that does
[code]
math.randomseed(2);
print(math.random() * 12)
[/code]
and another piece of code that is in for example a swep
[code]
math.randomseed(1111111)
math.random() * spread
[/code]
it will always output the right values
[QUOTE=MeepDarknessM;46718930]it won't be called since lua is async - you have full control of what runs when and how. if you write a function that does
[code]
math.randomseed(2);
print(math.random() * 12)
[/code]
and another piece of code that is in for example a swep
[code]
math.randomseed(1111111)
math.random() * spread
[/code]
it will always output the right values[/QUOTE]
Yes, but what I mean is that using code with magic constants (and repeating code if you have one file for server and one for client) is worse than using util.SharedRandom, which wraps both "math.randomseed" and "math.random" into an utility function, which I think is also easier to understand.
I would much rather see
[CODE]
local spread = util.SharedRandom("spread", 0, 1)
...
local cone = util.SharedRandom("cone", 0, 1)
[/CODE]
than
[CODE]
math.randomseed(12312213)
local spread = math.random()
...
math.randomseed(4324123)
local cone = math.random()
[/CODE]
if for no other reason than just to have string literals rather than magic constants.
[QUOTE=Jvs;46718785]Fair enough, forgot about that.
Also, just to future proof your weapons, don't use timers for weapons logic, ever, if you need to do the swing, do it in the think hook of the weapon.
If you're not using a serverside only variable, use [URL="http://wiki.garrysmod.com/page/Entity/NetworkVar"]network vars[/URL], they can be predicted properly and restored when the player lags and all that shit.[/QUOTE]
Why not? A timer seems to work fine for the delay between swinging and the actual hit. Should I instead do something weird in the think event with a "is_swinging" network variable and a "time_of_swing"?
[QUOTE=GreyGeist;46719184]Why not? A timer seems to work fine for the delay between swinging and the actual hit. Should I instead do something weird in the think event with a "is_swinging" network variable and a "time_of_swing"?[/QUOTE]
While timers may be ok for serverside only stuff, they fuck up with prediction.
And no, IsSwinging and NextSwing is not as weird as you might think, it's how valve does it internally for weapons.
Hell, weapon:SetNextPrimaryFire works under the same principle.
[QUOTE=GreyGeist;46719184]Why not? A timer seems to work fine for the delay between swinging and the actual hit. Should I instead do something weird in the think event with a "is_swinging" network variable and a "time_of_swing"?[/QUOTE]
Yes
Fair enough, lol. Last thing, and slightly off topic: Any quick guides for making a weapon base? I'd like to convert my weapon code into a base, since I plan on adding more weapons similar to it.
[QUOTE=GreyGeist;46719792]Fair enough, lol. Last thing, and slightly off topic: Any quick guides for making a weapon base? I'd like to convert my weapon code into a base, since I plan on adding more weapons similar to it.[/QUOTE]
I don't have any guides, but I recommend against using self.BaseClass when accessing a parent's methods. Use similar to below.
[code]
DEFINE_BASECLASS("weapon_base_name")
function SWEP:Initialize()
self:DoThings()
BaseClass.Initialize(self)
end
[/code]
[editline]1418674896[/editline]
Here's why. Imagine the following setup.
[code]
-- my_weapon_base
function SWEP:Initialize()
-- Init shit
end
[/code]
[code]
-- my_weapon_grenade_base
SWEP.Base = "my_weapon_base"
function SWEP:Initialize()
-- Init grenade shit
self.BaseClass.Initialize(self)
end
[/code]
[code]
-- my_weapon_frag_grenade
SWEP.Base = "my_weapon_grenade_base"
function SWEP:Initialize()
-- Init frag shit
self.BaseClass.Initialize(self)
end
[/code]
When a frag grenade is initialized, we'll hit an infinite loop as "self.BaseClass" will be equal to my_weapon_grenade_base's table, which will then be calling itself.
Now, changing those files to the following will solve this.
[code]
-- my_weapon_base
function SWEP:Initialize()
-- Init shit
end
[/code]
[code]
-- my_weapon_grenade_base
DEFINE_BASECLASS "my_weapon_base"
function SWEP:Initialize()
-- Init grenade shit
BaseClass.Initialize(self)
end
[/code]
[code]
-- my_weapon_frag_grenade
DEFINE_BASECLASS "my_weapon_grenade_base"
function SWEP:Initialize()
-- Init frag shit
BaseClass.Initialize(self)
end
[/code]
Now when a frag grenade is created, all the initialize methods can safely be called as the BaseClass variable is stored local to each separate Initialize function, rather then within the weapon itself.
Sorry, you need to Log In to post a reply to this thread.