How to define vgui?

Hello!

I am trying to make a gmod deathmatch gamemode. I have 3 classes and two teams, which you can switch between using console commands.

I would like to have it so that when you type in the command to change class, a window comes up with a button for each class, and then the same to select a primary and secondary weapon for that class (from a selection).

Currently I have (in shared.lua):


function ChangeMyClass(ply, cmd,input)
	local Frame = vgui.Create( "DFrame" )
	Frame:SetPos( 5, 5 )
	Frame:SetSize( 300, 150 )
	Frame:SetTitle( "loadout window" )
	Frame:SetVisible( false )
	Frame:SetDraggable( false )
	Frame:ShowCloseButton( true )
		if(input[1]=="1" )then
			Frame:SetVisible(true)
			Frame:MakePopup()

			local Button1 = vgui.Create("DButton",Frame)
			Button1:SetText( "M1A1" )
			Button:SetTextColor( Color( 255, 255, 255 ) )
			
			Button:SetPos( 100, 100 )
			Button:SetSize( 100, 30 )

			Button.Paint = function( self, w, h )
				draw.RoundedBox( 0, 0, 0, w, h, Color( 41, 128, 185, 250 ) )
			end

			print("assault")
			player_manager.SetPlayerClass(ply,"player_assault")
			ply:Spawn()
		end

		if(input[1]=="2")then
			print("sniper")
			player_manager.SetPlayerClass(ply,"player_sniper")
			ply:Spawn()
		end

		if(input[1]=="3")then
			print("heavy")
			player_manager.SetPlayerClass(ply,"player_heavy")
			ply:Spawn()
		end
end
concommand.Add("set_class",ChangeMyClass)

I’ve only set it up for one class for now, just to determine how to make it work.

However, when I type “set_class 1” into the console I get an error message: “attempt to index global ‘vgui’ (a nil value)”

I know that vgui is undefined, and that I need to define it in order to use it, but I have no idea how. The gmod wiki hasn’t helped at all, and neither has google. The only cause for this problem that ive found so far is either vgui is being called before its being defined (I’m not defining it at all), or that it has been undefined by an addon, and that gmod will normally have vgui automatically defined.

Any help would be greatly appreciated.



if CLIENT then 
--your code here
end

I assume you mean like this:



if CLIENT then
function ChangeMyClass(ply, cmd,input)
	local Frame = vgui.Create( "DFrame" )
	Frame:SetPos( 5, 5 )
	Frame:SetSize( 300, 150 )
	Frame:SetTitle( "loadout window" )
	Frame:SetVisible( false )
	Frame:SetDraggable( false )
	Frame:ShowCloseButton( true )
		if(input[1]=="1" )then
			Frame:SetVisible(true)
			Frame:MakePopup()

			local Button1 = vgui.Create("DButton",Frame)
			Button1:SetText( "M1A1" )
			Button:SetTextColor( Color( 255, 255, 255 ) )
			
			Button:SetPos( 100, 100 )
			Button:SetSize( 100, 30 )

			Button.Paint = function( self, w, h )
				draw.RoundedBox( 0, 0, 0, w, h, Color( 41, 128, 185, 250 ) )
			end

			print("assault")
			player_manager.SetPlayerClass(ply,"player_assault")
			ply:Spawn()
		end

		if(input[1]=="2")then
			print("sniper")
			player_manager.SetPlayerClass(ply,"player_sniper")
			ply:Spawn()
		end

		if(input[1]=="3")then
			print("heavy")
			player_manager.SetPlayerClass(ply,"player_heavy")
			ply:Spawn()
		end
end
end
concommand.Add("set_class",ChangeMyClass)

That doesn’t work. I get the same error

if it helps, the full error message is

[ERROR] gamemodes/pvp/gamemode/shared.lua:42: attempt to index global ‘vgui’ (a nil value)

  1. unknown - gamemodes/pvp/gamemode/shared.lua:42
  2. unknown - lua/includes/modules/concommand.lua:54

concommand.Add is always serverside when on singleplayer
test your gamemode on a dedicated server, or use game.SinglePlayer() and the net library to create the vgui

edit:
you also need to use the net library for serverside functions on client

Sorry, didn’t read through all of your code. I was assuming it was all client-side. Silly me. :s:

https://wiki.garrysmod.com/page/Net_Library_Usage

Make the menu client-side. When the player selects a team, send a message to the server. Now, on a server-side only lua file, the server will then spawn them based on the message it received.

This is good practice anyways, as the client was trying to use server-side functions - you shouldn’t mix them up like that.

Aha, this helps! Thank you both!

I shall try to fix it tomorrow morning :slight_smile:

Okay, so I’m confused. You’re saying I should have my menu client-side, which makes sense - front end stuff is meant to be client-side, backend should be server-side.

However, you also said that vgui is a server-side funcion/library, so how do I draw the window client-side?
GbrosMC says that I need to use the net library to access serverside functions clientside (vgui is one of these, I gather). How would I do that? Do I just make a function server-side which then gets called by the client? That wouldn’t seem right to me.

Also what’s this about concommand being serverside only? You mean I have to get input from the console server-side, send it to the client which then draws the corresponding window, and then send the button-click result back to the server, which then sets the player’s team? That seems way too convoluted.

P.S. I’ve only just started using Lua, although I’ve been working in Java for quite some time, so despite my knowing how to code, I don’t know everything about how lua works yet. I’m still getting used to some libraries being restricted to either severside or clientside.

VGUI is clientside, since it gets drawn. everything hud/menu wise is always clientside. Concommand.Add is a serverside function, wich can only be called by the server, so instead of drawing the vgui there, use the net library to send a signal to the client, wich then opens the vgui.

Aaaah, okay, thanks for clearing that up!

[editline]21st October 2016[/editline]

Right, currently I’m trying to do this (serverside)



	local rf = RecipientFilter()
	rf:AddPlayer(ply)
	net.Start("set_team",false)
	net.Send(rf)
	print("It didnt crash!")

However it is telling me that RecipientFilter() is nil. I don’t know why. It doesn’t need any parameters, and I’ve spelt it right (I copy-pasted it off the gmod wiki just to make sure). I checked and you can only call it serverside. I have no idea what I could be doing wrong here :stuck_out_tongue:

just instead of the RF, use the player argument from concommand, and send it to that player.

What player argument from concommand? Do you mean Player:ConCommand()? I had a look on the gmod wiki and I’m not sure what you mean.

concommand.Add() got a ‘ply’ argument in the function callback. Thats what you use to send the net message.

How? :stuck_out_tongue:
Sorry, I feel like this is fairly simple and I just don’t get it.

So looking at the documentation on the gmod wiki I can see what you’re talking about, but I can’t figure out how to use it. net.Send() needs a list of players in the brackets, and RecipientFilter seems to be how you’re meant to make one. The ply in the function callback is a Player, not a list containing the player.

Thanks for your help btw!

net.Send() accepts 1 entity too, eg the player. simply put the ‘ply’ argument in there.

I’ve already tried that:



concommand.Add( "set_team", function (ply,cmd,args)
	net.Start("set_team",false)
	net.Send(ply)
	print("Sever has sent a set_team command to client")
end)

I still get this error:
[ERROR] gamemodes/pvp/gamemode/shared.lua:36: attempt to call field ‘Send’ (a nil value)

  1. unknown - gamemodes/pvp/gamemode/shared.lua:36
  2. unknown - lua/includes/modules/concommand.lua:54

Hey, your original code wasn’t actually technically wrong, concommand.Add can be used on both server and client as the entire concommand library is shared.

This part of your code is wrong however, you switch from Button1 to Button halfway through. After fixing that, placing it in a client-side lua file (cl_init.lua of sandbox in this case), and typing set_class 1 in console, I was able to draw this:
Imgur

I also recommend you drop the input check and do something like this instead

Put in Client-side lua file(cl_init.lua for example):


function ChangeMyClass(ply, cmd, input )
	local Frame = vgui.Create( "DFrame" )
	Frame:SetSize( 300, 150 )
	Frame:Center()
	Frame:SetTitle( "loadout window" )
	Frame:SetVisible( true )
	Frame:SetDraggable( false )
	Frame:ShowCloseButton( true )
	Frame:MakePopup()

	local Button1 = vgui.Create("DButton", Frame)
	Button1:SetText( "M1A1" )
	Button1:SetTextColor( Color( 255, 255, 255 ) )
			
	Button1:SetPos( 20, 100 )
	Button1:SetSize( 80, 30 )

	Button1.Paint = function( self, w, h )
		draw.RoundedBox( 0, 0, 0, w, h, Color( 41, 128, 185, 250 ) )
	end
	
	Button1.DoClick = function()
		LocalPlayer():ConCommand( "select_m1a1" )
		Frame:Remove()
	end
	
	local Button2 = vgui.Create("DButton", Frame)
	Button2:SetText( "SNIPER" )
	Button2:SetTextColor( Color( 255, 255, 255 ) )
			
	Button2:SetPos( 110, 100 )
	Button2:SetSize( 80, 30 )

	Button2.Paint = function( self, w, h )
		draw.RoundedBox( 0, 0, 0, w, h, Color( 41, 128, 185, 250 ) )
	end
	
	Button2.DoClick = function()
		LocalPlayer():ConCommand( "select_sniper" )
		Frame:Remove()
	end

	local Button3 = vgui.Create("DButton", Frame)
	Button3:SetText( "HEAVY" )
	Button3:SetTextColor( Color( 255, 255, 255 ) )
			
	Button3:SetPos( 200, 100 )
	Button3:SetSize( 80, 30 )

	Button3.Paint = function( self, w, h )
		draw.RoundedBox( 0, 0, 0, w, h, Color( 41, 128, 185, 250 ) )
	end
	
	Button3.DoClick = function()
		LocalPlayer():ConCommand( "select_heavy" )
		Frame:Remove()
	end
end
concommand.Add("set_class",ChangeMyClass)

Put in Server-side lua file(init.lua for example):


concommand.Add( "select_sniper", function( ply )
	print("sniper")
	player_manager.SetPlayerClass(ply,"player_sniper")
	ply:Spawn()
end )

Good luck on your gamemode, gamemode-maker man.

also i’ve never posted here before because you all scare the shit out of me

concommand.Add is shared.

What a helpfull off-topic reply.

I don’t see how it’s not on topic. You told him something that isn’t true and I corrected you. concommand.Add is not serverside only. If he wants to open his menu with a concommand, he can do that completely on the client.

Feel free to report my post if you feel it is off topic.

Ah, okay, thanks.

[editline]25th October 2016[/editline]

Thank you! Sorry for the late reply :stuck_out_tongue:

This looks like it will help, still not sure about vgui? Will I not still get this problem with vgui not being initialised, or was it simply because I was trying to use a button I hadn’t made yet? Can’t believe I didn’t notice that :stuck_out_tongue:

Thanks once again!