Networked Values in SWEPs

I’m not entirely sure how silly this is to ask, but the documentation on networking entities hasn’t helped me an incredible amount.

I currently have a SWEP that functions fine in single player, it has a few options on it that change the fire mode, the appearance, etc. Stuff we’ve all seen before really. But I’m unsure of the best way to network this to other players. I tested it with a bot in a LAN server and it causes various errors when I switch modes and draw the weapon. So, what is the best way to network values for a weapon? The wiki suggests not using the GetNWVar method as it de-syncs sometimes. And as it is a weapon, the SetupDataTables function isn’t available from a tiny bit of testing I did (might be wrong though). I just need one value networked, allowing me to change what is visible on the weapons of other players really.

Oh, and if anyone has any idea on how to stop laser drawing code (currently being rendered in the PreDrawViewModel hook) from doing this that would be much appreciated;

https://dl.dropboxusercontent.com/u/6003122/ShareX/2013-09/2013-09-11_21-12-01.jpg

SWEP:SetupDataTables is totally available in SWEPs.
And if you want us to fix something or you, you should post code. ( I am talking about the laser )

Ahh, I must not have been using it right :v: Well, the laser code is quite straightforward (unapologetically ripped from that other thread about lasers unsuprisingly, render was confusing me a bit);
[lua]
/* Load some materials for laser drawing. */
local laser = Material(“cable/redlaser”)
local laserDot = Material(“sprites/light_glow02_add”)

local function DrawLaser(startPos, hitPos, hitNormal)

local laserDotSize = 10
cam.Start3D(EyePos(), EyeAngles())
	render.SetMaterial(laser)
	render.DrawBeam(startPos, hitPos, 1, 0, 1, Color(255, 0, 0, 255), 0)
	render.SetMaterial(laserDot)
	render.DrawQuadEasy(hitPos, hitNormal, laserDotSize, laserDotSize, Color(255, 0, 0, 255), 0)
cam.End3D()

end

function SWEP:PreDrawViewModel(viewM, ply, wep)

if (!IsValid(self.Owner) or !IsValid(viewM)) then return end

if (curMode == 2 or curMode == 3) then

	local muzzleAtt = viewM:LookupAttachment("muzzle")
	
	if (muzzleAtt == 0) then muzzleAtt = 1 end
	local muzzlePos = viewM:GetAttachment(muzzleAtt).Pos
	local laserTrace = self.Owner:GetEyeTrace()
	DrawLaser(muzzlePos, laserTrace.HitPos, laserTrace.HitNormal)
end

end
[/lua]

Just for rendering the viewmodel laser, the worldmodel one renders fine. I’m not sure if I’m missing a call to render the viewmodel on top again or not. It’s a c_ model if that has any impact.

[editline]edited[/editline]

I assume to access a NetworkedVar created in SetupDataTables for a weapon I just need to get the current weapon of the player and run the GetXXX() function on that weapon?

Not sure that’s the problem but I wouldn’t recommend doing any rendering in PreDrawViewModel, since you might mess with the rendering context and therefore screw the way the view model is rendered.

ViewModelDrawn would be probably better.

Uh why don’t you just use self?

Try removing the cam.3d stuff from your hook.

I thought of that too but there’s a slight problem with that. Since the viewmodel renders at a different FOV than the world, viewmodels have an internal “hack” which causes GetAttachment to return an adjusted world position which matches the viewmodel’s attachment regardless of the viewmodel FOV. This is useful for muzzle effects for instance.

If you use GetAttachment directly in a viewmodel rendering hook, you’ll get an attachment position which is supposed to be used in world space, not viewmodel space, and it will look slightly offset. Which is why cam.Start3D is a good solution to force the rendering context to use the world FOV instead of the viewmodel FOV.

Another workaround which doesn’t require cam.Start3D would be using GetBonePosition instead of GetAttachment. However, since there’s no bone for the muzzle, you would need to find the closest bone and offset it.

I’ll have a look into using bone positions rather than the attachment, it seems like a usable workaround for the problems I’m having anyway. When I finally get the model sorted for this weapon I assume I could just stick a bone where I need the laser? Never really worked with bones before now :v:

As for the networked values, I spent a while last night tinkering with that, trying to make some progress. My current code looks like this;
[lua]
function SWEP:SetupDataTables()

self:NetworkVar("Int", 0 ,"curMode")

end

– Unrelated code

function SWEP:PreDrawViewModel(viewM, ply, wep)

if (!IsValid(self.Owner) or !IsValid(viewM)) then return end

if (self:GetCurMode() == 2 or self:GetCurMode() == 3) then

	local muzzleAtt = viewM:LookupAttachment("muzzle")
	
	if (muzzleAtt == 0) then muzzleAtt = 1 end
	local muzzlePos = viewM:GetAttachment(muzzleAtt).Pos
	local laserTrace = self.Owner:GetEyeTrace()
	DrawLaser(muzzlePos, laserTrace.HitPos, laserTrace.HitNormal)
end

end

hook.Add(“PostPlayerDraw”, “DrawMorphLaser”, function(ply)

if (!IsValid(ply)) then return end

local wep = ply:GetActiveWeapon()
if (!IsValid(wep) or !wep:IsWeapon()) then return end
if ((ply:GetActiveWeapon():GetClass() ~= "morphgun") or (wep:GetCurMode() == 1) or (wep:GetCurMode() == 4)) then return end

local muzzleAtt = wep:LookupAttachment("muzzle")
	
if (muzzleAtt == 0) then muzzleAtt = 1 end
local muzzlePos = wep:GetAttachment(muzzleAtt).Pos
local laserTrace = ply:GetEyeTrace()	
DrawLaser(muzzlePos, laserTrace.HitPos, laserTrace.HitNormal)

end)

function SWEP:ChangeMode(newMode)

newMode = math.Clamp(newMode, 1, #modes)
lastMode = self:GetCurMode()
print(self:GetCurMode())
self:SetCurMode(newMode)
print(self:GetCurMode())
curMode = newMode

self:SetWeaponHoldType(modes[curMode].holdType)
-- Set up the primary fire to match the new mode.
self.Primary.Automatic = modes[curMode].auto
self:SetClip1(modes[curMode].magazine)
self.Primary.Ammo = modes[curMode].ammoType
if (_debug) then print(modes[curMode].name) end
reloadTime = (CurTime() + 0.5)
self.Weapon:SetNextPrimaryFire(CurTime() + 0.5)
--[[
if (type(self.Owner) == "Player") then
	local tmpMode = curMode - 1
	net.Start("ModeChangeInformClient")
		net.WriteInt(tmpMode, 3)
	net.Send(self.Owner)
end
]]--
print(self:GetCurMode())

end
[/lua]

This is causing me a problem, the mode is setting correctly, the fire rate, damage, and as far as I can tell, ammo type all change correctly. The issue is that as soon as the ChangeMode function ends, the curMode value resets to 1 and the weapon fires incorrectly, whilst keeping the values for fire rate and such of other modes.

To access the networked value from the client, outside of a SWEP function, I would have to use LocalPlayer():GetActiveWeapon() from my testing, is this correct?

And finally, the way I see that is the other players will have a laser sight on if the local player has theirs on, something I don’t want to happen. I thought I mentioned this, but I might not have :v: To access these on other players, I’d need to call GetCurMode() on their weapon from what I understand.

[editline]12th September 2013[/editline]

ViewModelDrawn seems to cause the same problems, I assume this is due to how c_ models render.

[editline]12th September 2013[/editline]

Running the SetCurMode() function from the console actually sets the mode, causing ChangeMode to revert to whatever mode was set rather than 1 every time instead now. So progress. And I was right about accessing the GetCurMode() of other players, so learning!

So it looks like CurMode is never being updated server-side, only client side…
[lua]
] lua_run print(player.GetByID(1):GetActiveWeapon():GetCurMode())
> print(player.GetByID(1):GetActiveWeapon():GetCurMode())…
1
] lua_run_cl print(LocalPlayer():GetActiveWeapon():GetCurMode())
1
– Post mode change

] lua_run_cl print(LocalPlayer():GetActiveWeapon():GetCurMode())
4
] lua_run print(player.GetByID(1):GetActiveWeapon():GetCurMode())
> print(player.GetByID(1):GetActiveWeapon():GetCurMode())…
1
[/lua]

The SetXXX functions are shared right? And as long as I haven’t specified that ChangeMode runs on the server or client that should run in shared space too correct?

[editline]Edited:[/editline]

Well, that was easy, I was calling it from a client only block, such a dumbass some times :v: