Explanation on Serverside vs Clientside vs Shared

Background Info: I have about 3 years coding Experience(2 Years C++, and 1 AP Course in Java) and Lua Appears to be easy for me to pick up so far

My Problem:
I’m not quite sure about When to use or call Serverside/Clientside Functions(Methods)
Can Serverside Functions be called in a shared.Lua File?

Also I’d appreciate a good link to a tutorial

Serverside is controlled by the server (srcds per say), client-side would be controlled by a player, and shared is the combination of both.

Server is usual the important data and sometimes if not always is the content that you don’t want the client to modify. Client never sees the server content as it resided on the server.
[lua]

function _R.Player:RegisterUser(user, pass, email, group, regdate)
local salt, hash, key
if self.Registered then
umsg.Start(“cl_error”, self)
umsg.String(“Registeration Error;Your already registered.”)
umsg.End()
return
end
if !user or !pass or !email then
umsg.Start(“cl_register”, self)
umsg.End()
umsg.Start(“cl_error”, self)
umsg.String(“Registeration Error;You left a entry blank.”)
umsg.End()
return
end
if !group then group = Group or 0 end
if !regdate then regdate = os.time() end
if Forum == “smf” then
if TMySQL then
tmysql.query("SELECT member_name FROM " … Prefix … “_members WHERE member_name=’” … user … “’”, function( Args )
if Args && Args[1] then
umsg.Start(“cl_register”, self)
umsg.End()
umsg.Start(“cl_error”, self)
umsg.String(“Registeration Error;This username is taken.”)
umsg.End()
return
end
end)
hash= string.lower(crypto.sha1(string.lower(user) … pass))
tmysql.query(“INSERT INTO " … Prefix … “_members (member_name, passwd, date_registered, id_group, real_name, email_address, member_ip, member_ip2) VALUES(’” … escape(user) … “’, '” … escape(hash) … “’, '” … regdate … “’, '” … group … “’, '” … escape(user) … “’, '” … email … “’, '” … self:IPAddress() … “’, '” … self:IPAddress() … “’ )”, SQLHandle )
self:ChatPrint(”[SMF] Successfully registered user, " … user)
self:LinkUser(user, pass)
self.Registered = true
else
local query1 = database:query("SELECT member_name FROM " … Prefix … “_members WHERE member_name=’” … user … “’”)
query1.onSuccess = function( query )
local Args = query:getData()[1] or nil
if Args then
umsg.Start(“cl_register”, self)
umsg.End()
umsg.Start(“cl_error”, self)
umsg.String(“Registeration Error;This username is taken.”)
umsg.End()
return
end
end
query1:start()
hash = string.lower(crypto.sha1(string.lower(user) … pass))
local query2 = database:query(“INSERT INTO " … Prefix … “_members (member_name, passwd, date_registered, id_group, real_name, email_address, member_ip, member_ip2) VALUES(’” … escape(user) … “’, '” … escape(hash) … “’, '” … regdate … “’, '” … group … “’, '” … escape(user) … “’, '” … email … “’, '” … self:IPAddress() … “’, '” … self:IPAddress() … “’ )” )
query2.onSuccess = function( query )
self:ChatPrint(”[SMF] Successfully registered user, " … user)
self:LinkUser(user, pass)
self.Registered = true
end
query2:start()
end
elseif Forum == “mybb” then
if TMySQL then
tmysql.query(“SELECT username FROM " … Prefix … “_users WHERE username=’” … user … “’”, function( Args )
if Args && Args[1] then
umsg.Start(“cl_register”, self)
umsg.End()
umsg.Start(“cl_error”, self)
umsg.String(“Registeration Error;This username is taken.”)
umsg.End()
return
end
end)
salt = self:Salt(8)
hash = string.lower(tostring(pass))
hash = string.lower(crypto.md5(salt) … crypto.md5(hash))
hash = string.lower(crypto.md5(hash))
tmysql.query(“INSERT INTO " … Prefix … “_users (username, password, salt, regdate, usergroup, usertitle, email, regip, lastip) VALUES(’” … escape(user) … “’, '” … escape(hash) … “’, '” … escape(salt) … “’, '” … regdate … “’, '” … group … “’, '” … escape(user) … “’, '” … email … “’, '” … self:IPAddress() … “’, '” … self:IPAddress() … “’ )”, SQLHandle )
self:ChatPrint(”[MyBB] Successfully registered user, " … user)
self:LinkUser(user, pass)
self.Registered = true
else
local query1 = database:query(“SELECT username FROM " … Prefix … “_users WHERE username=’” … user … “’”)
query1.onSuccess = function( query )
local Args = query:getData()[1] or nil
if Args then
umsg.Start(“cl_register”, self)
umsg.End()
umsg.Start(“cl_error”, self)
umsg.String(“Registeration Error;This username is taken.”)
umsg.End()
return
end
end
query1:start()
salt = self:Salt(8)
hash = string.lower(tostring(pass))
hash = string.lower(crypto.md5(salt) … crypto.md5(hash))
hash = string.lower(crypto.md5(hash))
local query2 = database:query(“INSERT INTO " … Prefix … “_users (username, password, salt, regdate, usergroup, usertitle, email, regip, lastip) VALUES(’” … escape(user) … “’, '” … escape(hash) … “’, '” … escape(salt) … “’, '” … regdate … “’, '” … group … “’, '” … escape(user) … “’, '” … email … “’, '” … self:IPAddress() … “’, '” … self:IPAddress() … “’ )”)
query2.onSuccess = function( query )
self:ChatPrint(”[MyBB] Successfully registered user, " … user)
self:LinkUser(user, pass)
self.Registered = true
end
query2:start()
end
elseif Forum == “vb” then
if TMySQL then
tmysql.query(“SELECT username FROM " … Prefix … “_user WHERE username=’” … user … “’”, function( Args )
if Args && Args[1] then
umsg.Start(“cl_register”, self)
umsg.End()
umsg.Start(“cl_error”, self)
umsg.String(“Registeration Error;This username is taken.”)
umsg.End()
return
end
end)
salt = self:Salt(30)
hash = string.lower(tostring(pass))
hash = string.lower(crypto.md5(salt) … crypto.md5(hash))
hash = string.lower(crypto.md5(hash))
tmysql.query(“INSERT INTO " … Prefix … “_user (username, password, salt, joindate, usergroupid, usertitle, email, ipaddress) VALUES(’” … escape(user) … “’, '” … escape(hash) … “’, '” … escape(salt) … “’, '” … regdate … “’, '” … group … “’, '” … escape(user) … “’, '” … escape(email) … “’, '” … self:IPAddress() … “’)”, SQLHandle )
self:ChatPrint(”[vB] Successfully registered user, " … user)
timer.Simple(1, function()
self:LinkUser(user, pass)
self.Registered = true
end)
else
local query1 = database:query(“SELECT username FROM " … Prefix … “_user WHERE username=’” … user … “’”)
query1.onSuccess = function( query )
local Args = query:getData()[1] or nil
if Args then
umsg.Start(“cl_register”, self)
umsg.End()
umsg.Start(“cl_error”, self)
umsg.String(“Registeration Error;This username is taken.”)
umsg.End()
return
end
end
query1:start()
salt = self:Salt(8)
hash = string.lower(tostring(pass))
hash = string.lower(crypto.md5(salt) … crypto.md5(hash))
hash = string.lower(crypto.md5(hash))
local query2 = database:query(“INSERT INTO " … Prefix … “_user (username, password, salt, joindate, usergroupid, usertitle, email, ipaddress) VALUES(’” … escape(user) … “’, '” … escape(hash) … “’, '” … escape(salt) … “’, '” … regdate … “’, '” … group … “’, '” … escape(user) … “’, '” … email … “’, '” … self:IPAddress() … “’)”)
query2.onSuccess = function( query )
self:ChatPrint(”[vB] Successfully registered user, " … user)
self:LinkUser(user, pass)
self.Registered = true
end
query2:start()
end
else
if TMySQL then
tmysql.query(“SELECT username FROM " … Prefix … “_user WHERE username=’” … user … “’”, function( Args )
if Args && Args[1] then
umsg.Start(“cl_register”, self)
umsg.End()
umsg.Start(“cl_error”, self)
umsg.String(“Registeration Error;This username is taken.”)
umsg.End()
return
end
end)
salt = self:Salt(64)
key = self:Salt(40)
hash = string.lower(tostring(pass))
hash = string.lower(crypto.sha256(pass))
hash = string.lower(crypto.sha256(pass … salt))
hash = tostring('a:3:{s:4:“hash”;s:64:”’ … hash … '”;s:4:“salt”;s:64:”’ … salt … '”;s:8:“hashFunc”;s:6:“sha256”;}’)
tmysql.query(“INSERT INTO " … Prefix … “_user (username, email, user_group_id, register_date, user_state) VALUES(’” … escape(user) … “’, '” … escape(email) … “’, '” … group … “’, '” … regdate … “’, '” … escape(‘valid’) … “’)”, SQLHandle )
timer.Simple(1, function()
tmysql.query(“SELECT user_id FROM " … Prefix … “_user WHERE username=’” … user … “’”, function( _Args )
if _Args then
local auth = “XenForo_Authentication_Core”
tmysql.query(“INSERT INTO " … Prefix … “_user_authenticate (user_id, scheme_class, data, remember_key) VALUES(’” … _Args[1][1] … “’, '” … escape(auth) … “’, '” … escape(hash) … “’, '” … escape(key) … “’)”, SQLHandle )
self:ChatPrint(”[XF] Successfully registered user, " … user)
self:LinkUser(user, pass)
self.Registered = true
end
end)
end)
else
local query1 = database:query(“SELECT username FROM " … Prefix … “_user WHERE username=’” … user … “’”)
query1.onSuccess = function( query )
local Arg = query:getData()[1] or nil
if Arg then
umsg.Start(“cl_register”, self)
umsg.End()
umsg.Start(“cl_error”, self)
umsg.String(“Registeration Error;This username is taken.”)
umsg.End()
return
end
end
query1:start()
salt = self:Salt(64)
key = self:Salt(40)
hash = string.lower(tostring(pass))
hash = string.lower(crypto.sha256(pass))
hash = string.lower(crypto.sha256(pass … salt))
hash = tostring('a:3:{s:4:“hash”;s:64:”’ … hash … '”;s:4:“salt”;s:64:”’ … salt … '”;s:8:“hashFunc”;s:6:“sha256”;}’)
local query2 = database:query(“INSERT INTO " … Prefix … “_user (username, email, user_group_id, register_date, user_state) VALUES(’” … escape(user) … “’, '” … escape(email) … “’, '” … group … “’, '” … regdate … “’, '” … escape(‘valid’) … “’)”)
query2.onSuccess = function( _query )
print(“1”)
local query3 = database:query(“SELECT user_id FROM " … Prefix … “_user WHERE username=’” … user … “’” )
query3.onSuccess = function( __query )
local _Args = __query:getData()[1] or nil
print(“2”)
if _Args then
print(“3”)
local auth = “XenForo_Authentication_Core”
local query4 = database:query(“INSERT INTO " … Prefix … “_user_authenticate (user_id, scheme_class, data, remember_key) VALUES(’” … _Args[‘user_id’] … “’, '” … escape(auth) … “’, '” … escape(hash) … “’, '” … escape(key) …”’)”)
query4.onSuccess = function( ___query )
print(“4”)
self:ChatPrint(”[XF] Successfully registered user, " … user)
self:LinkUser(user, pass)
self.Registered = true
end
query4:start()
end
end
query3:start()
end
query2:start()
end
end
end
[/lua]
Client’s shouldn’t be allowed to or trusted with important information.

Shared is content you wish to call or will call on both client and server. Such as the following below.
[lua]

function _R.Player:IsRunner()
return self:Team() == TEAM_RUNNER
end

function _R.Player:IsDeath()
return self:Team() == TEAM_DEATH
end

function _R.Player:IsDead()
return self:Team() == TEAM_RUNNER_DEAD or self:Team() == TEAM_DEATH_DEAD
end
[/lua]
The above can be called either by a client or the server.

Client is content that you want the client to have and see. Such as HUDs and Menus. These are usually visual content as the server never draws any visual like that stated.

[lua]
local function OpenStore()
if Store.StoreMenu and Store.StoreMenu:IsValid() then
Store.StoreMenu:SetVisible( true )
end

local MAIN = vgui.Create( "DFrame" )
MAIN:SetTitle( "Global Store ($" .. LocalPlayer():GetNWInt("dollars") .. ")"  )
MAIN:SetSize( ScrW() * 0.6, ScrH() * 0.7 )
MAIN:Center()
MAIN:SetDraggable( false )

MAIN:MakePopup()
MAIN.Close = function()
	MAIN:SetVisible( false )
end
local SHEET = vgui.Create( "DPropertySheet", MAIN )
SHEET:SetPos( 5, 30 )
SHEET:SetSize( MAIN:GetWide() - 10, MAIN:GetTall() - 40 )

local TRAILS = vgui.Create( "DPanel", SHEET )
TRAILS:SetSize( SHEET:GetWide() - 10, SHEET:GetTall() - 10 )

local TrailColumn1, TrailColumn2 = CreateColumns( TRAILS )

TRAILS.Refresh = function()
	for k, v in pairs( Store.TrailsTable ) do
		local BUTTON = vgui.Create( "DButton" )
		BUTTON:SetSize( 64, 64 )
		BUTTON:SetText( "" )
		
		local id = surface.GetTextureID( v[1] )
		BUTTON.Paint = function()
			if v[1] == LocalPlayer():GetNWString('Trail') then
				surface.SetTexture( id )
				surface.SetDrawColor( 0, 255, 0, 255 )
				surface.DrawOutlinedRect( 0, 0, 65, 65 )
				surface.SetDrawColor( 255, 255, 255, 255 )
				surface.DrawTexturedRect( 0, 0, 64, 64 )
			else
				surface.SetTexture( id )
				surface.SetDrawColor( 255, 255, 255, 255 )
				surface.DrawTexturedRect( 0, 0, 64, 64 )
				surface.DrawOutlinedRect( 0, 0, 64, 64 )
			end
		end
		
		if table.HasValue( Store.PersonalTrails, k ) then
			BUTTON:SetToolTip( v[3] )
			BUTTON.DoClick = function( BUTTON )
				surface.PlaySound( "ui/buttonclick.wav" )
				RunConsoleCommand( "settrail", Store.TrailsTable[k][1], k )
			end
			
			TrailColumn1:AddItem( BUTTON )
		else
			BUTTON.DoClick = function()
				surface.PlaySound( "ui/buttonclickrelease.wav" )
				RunConsoleCommand( "buytrail", k )
				MAIN:Close()
			end
			
			TrailColumn2:AddItem( BUTTON )
		end
	end
end
TRAILS:Refresh()

local MASKS = vgui.Create( "DPanel", SHEET )
MASKS:SetSize( SHEET:GetWide() - 10, SHEET:GetTall() - 10 )

local MaskColumn1, MaskColumn2 = CreateColumns( MASKS )

MASKS.Refresh = function()
	for k, v in pairs( Store.MasksTable ) do
		local BUTTON = vgui.Create( "DButton" )
		BUTTON:SetSize( 64, 64 )
		BUTTON:SetText( "" )
		local id = surface.GetTextureID( v[1] )
		BUTTON.Paint = function()
			if v[1] == LocalPlayer():GetNWString('Mask') then
				surface.SetTexture( id )
				surface.SetDrawColor( 0, 255, 0, 255 )
				surface.DrawOutlinedRect( 0, 0, 65, 65 )
				surface.SetDrawColor( 255, 255, 255, 255 )
				surface.DrawTexturedRect( 0, 0, 64, 64 )
			else
				surface.SetTexture( id )
				surface.SetDrawColor( 255, 255, 255, 255 )
				surface.DrawOutlinedRect( 0, 0, 64, 64 )
				surface.DrawTexturedRect( 0, 0, 64, 64 )
			end
		end
		
		if table.HasValue( Store.PersonalMasks, k ) then
			BUTTON:SetToolTip( v[3] )
			BUTTON.DoClick = function( BUTTON )
				surface.PlaySound( "ui/buttonclick.wav" )
				RunConsoleCommand( "setmask", Store.MasksTable[k][1], k )
			end
			
			MaskColumn1:AddItem( BUTTON )
		else
			BUTTON.DoClick = function()
				surface.PlaySound( "ui/buttonclickrelease.wav" )
				RunConsoleCommand( "buymask", k )
				MAIN:Close()
			end
			
			MaskColumn2:AddItem( BUTTON )
		end
	end
end
MASKS:Refresh()

local HATS = vgui.Create( "DPanel", SHEET )
HATS:SetSize( SHEET:GetWide() - 10, SHEET:GetTall() - 10 )

local HatColumn1, HatColumn2 = CreateColumns( HATS )

HATS.Refresh = function()
	for k, v in pairs( Store.HatsTable ) do
		local BUTTON = vgui.Create( "SpawnIcon" )
		BUTTON:SetSize( 64, 64 )
		BUTTON:SetModel( v[1] .. ".mdl" )
		if table.HasValue( Store.PersonalHats, k ) then
			BUTTON:SetToolTip( v[3] )
			BUTTON.DoClick = function( BUTTON )
			surface.PlaySound( "ui/buttonclick.wav" )
			if v[4] != nil then
				print(v[4])
				RunConsoleCommand( "sethat", Store.HatsTable[k][1], k, v[4] )
			else
				RunConsoleCommand( "sethat", Store.HatsTable[k][1], k )
			end
			BUTTON.Paint = function()
				if v[1] == LocalPlayer():GetNWString('HatModel') then
					surface.SetDrawColor( 0, 255, 0, 255 )
					surface.DrawOutlinedRect( 0, 0, 64, 64 )
				else
					surface.SetDrawColor( 255, 255, 255, 255 )
					surface.DrawOutlinedRect( 0, 0, 64, 64 )
				end
			end
		end

		HatColumn1:AddItem( BUTTON )
	else
		BUTTON:SetToolTip( v[3] .. "

$" … v[2] )
BUTTON.DoClick = function()
surface.PlaySound( “ui/buttonclickrelease.wav” )
RunConsoleCommand( “buyhat”, k )
MAIN:Close()
end

		HatColumn2:AddItem( BUTTON )
		end
	end
end
HATS:Refresh()

SHEET:AddSheet( "Trails", TRAILS, "gui/silkicons/world", false, false, "A selection of trails that follow you around." )
SHEET:AddSheet( "Masks", MASKS, "gui/silkicons/group", false, false, "A selection of masks you can use in front of your face." )
SHEET:AddSheet( "Headwear", HATS, "gui/silkicons/user", false, false, "A selection of items you can use on your head." )

local setvis = MAIN.SetVisible
MAIN.SetVisible = function( b )
	if b then
		TRAILS:Refresh()
		MASKS:Refresh()
		HATS:Refresh()
	end
	setvis( b )
end

Store.StoreVGUI = MAIN

end
concommand.Add( “store”, OpenStore )
[/lua]
The above is a menu that the client can buy and set their mask, trail, and/or model.

I’ve given you 3 different pieces of code from separate projects. I’ve surely left some stuff out. And I’m sure that someone will come along and correct and explain further the differences.

How Often Do You need to call Serverside Functions then? Assuming Your Only Really Creating Sweps/Stools/Entities Etc.

And Also Where oh Where is a Sleep Method? hehe

Server side data is totally disconnected from client side data (they’re not directly linked/related). The only way to manage that is through net/usermessages and the only thing that does is sending data. It is up to you do manipulate the data you receive. After GMod 13 is released, both server to client and client to server data sending will be possible without using “hacky” ways (that is already implemented on GMod 13 but it is on a “closed” beta).

EDIT: There is no “Sleep” methods. Lua here is used through hooks and stuff like that. Basically called at major events.

Well, Currently I’m Creating a Bunch of Random Sweps to get the basics down. And my current swep is a Poison Dart Rifle, that deals Damage over Time but I found the Timer So I believe this is all I need
Not Quite Sure if I’m Using the Timer Function Right But Time for Trial and Error. haha ahh I love Coding

[lua]
function SWEP:PrimaryAttack()

local tr = self.Owner:GetEyeTrace()

self:EmitSound(ShootSound)//play sound
self.BaseClass.ShootEffects(self)

if (!SERVER) then return end//check serverside

local ph = tr.Entity:GetPhysicsObject()//getObject

if ( tr.Entity:IsNPC() or tr.Entity:IsPlayer() ) then//Check if Object is NPC or Player

ent = tr.Entity
timer.Create("timer1", 2, 5,SWEP:Poison,ent)//Loop Poison 5 Times on Entity

end
[/lua]

[lua]function SWEP:Poison(ent2)

ent2.SetHealth(ent2.Health() - 10)

end
[/lua]

Use [.lua.][./lua.] tags without the .'s.

[lua]
function SWEP:PrimaryAttack()

local tr = self.Owner:GetEyeTrace()

self:EmitSound(ShootSound)//play sound
self.BaseClass.ShootEffects(self)

if (!SERVER) then return end//check serverside

local ph = tr.Entity:GetPhysicsObject()//getObject

if ( tr.Entity:IsNPC() or tr.Entity:IsPlayer() ) then//Check if Object is NPC or Player

ent = tr.Entity
timer.Create("timer1", 2, 5, function() SWEP:Poison(ent) end)//Loop Poison 5 Times on Entity

end
[/lua]