Adding variables to player entity

is there a way to add variables to the player entity? I’ve tried something like this :



local meta = FindMetaTable( "Player" )
local flags = {}

function meta:GetFlag(_var, _valdefault, _local)
    if !self:IsValid() then return end

    if !IsValid(flags[self:SteamID()]) then
        flags[self:SteamID()] = {}
    end

    if !IsValid(flags[self:SteamID()][_var]) then
        self:SetFlag(_var, _valdefault, _local)
    end

    return flags[self:SteamID()][_var]
end

function meta:SetFlag(_var, _val, _local)
    if !self:IsValid() then return end
    if !IsValid(flags[self:SteamID()]) then
        flags[self:SteamID()] = {}
    end
    if _local then
        flags[self:SteamID()][_var] = _val
    else
        if SERVER then
            net.Start( "UserData" )
            net.WriteTable({var = _var, val = _val})
            net.Send(self)
        end
        if CLIENT then
            net.Start( "UserData" )
            net.WriteTable({var = _var, val = _val})
            net.SendToServer()
        end
    end
end

if SERVER then
    util.AddNetworkString("UserData")
    net.Receive( "UserData", function( len, pl)
        local data =  net.ReadTable()
        flags[pl:SteamID()][data.var] = data.val
    end )
end

if CLIENT then
    net.Receive( "UserData", function(len)
        local data =  net.ReadTable()
        flags[LocalPlayer():SteamID()][data.var] = data.val
    end )
end

if done it with self.flags a global var called flags and a local var named flags, to test it I used


 if input.IsKeyDown( KEY_G ) && !table.HasValue( keys, KEY_G ) then

        if(pl:GetFlag("test", false, true)) then
            pl:SetFlag("test", false, true)
        else
            pl:SetFlag("test", true, true)
        end

        print( pl:GetFlag("test", "It didn't work...", true) )
        pl:ChatPrint("'KEY_G' pressed")
        table.insert( keys, KEY_G )
    end

    if !input.IsKeyDown( KEY_G ) && table.HasValue( keys, KEY_G ) then
        table.RemoveByValue( keys, KEY_G )
    end

but the output is always “It didn’t work…” where is should toggle true and false (meaning its not saving the var) does anyone see anything I’m doing wrong??

I believe you try to reproduce what already exists with Get/SetNW functions

No that’s not what I’m looking for, the functionality is different and I’m trying to simplify it, calling Get/SetNWAngle, Get/SetNWBool, Get/SetNWEntity, Get/SetNWFloat, Get/SetNWInt, Get/SetNWString, Get/SetNWVector can get confusing on lager scripts. I’m trying to make it one function that supports all variable types including tables along with whether it is local or not. Local meaning if server calls it, it’s a server var, if client calls its a client var, on the flip side it its not local it sends the var to the server and client.

I tried your code, indeed it’s not working but the fix is easy, remove the IsValid checks for the table



function meta:GetFlag(_var, _valdefault, _local)
    if !IsValid(self) then return end // better this way

    if !flags[self:SteamID()] then
        flags[self:SteamID()] = {}
    end

    if !flags[self:SteamID()][_var] then
        self:SetFlag(_var, _valdefault, _local)
    end

    return flags[self:SteamID()][_var]
end


with this code, your test will print “true”

IsValid will only return true if the table has a method IsValid and this method return true



local t = {}
print( IsValid( t ) ) -- false

local t = { IsValid = function() return true end }
print( IsValid( t ) ) -- true


[editline]23rd October 2014[/editline]

but there are others problems, here are more fixes



function meta:GetFlag(_var, _valdefault, _local)
    if !IsValid(self) then return end

    if flags[self:SteamID()] == nil then
        flags[self:SteamID()] = {}
    end
	
    if flags[self:SteamID()][_var] == nil then
        self:SetFlag(_var, _valdefault, _local or false)
    end
	
    return flags[self:SteamID()][_var]
end

function meta:SetFlag(_var, _val, _local)
    if !IsValid(self) then return end
	
    if flags[self:SteamID()] == nil then
        flags[self:SteamID()] = {}
    end
	
    if _local == true then
        flags[self:SteamID()][_var] = _val
    else
        if SERVER then
            net.Start( "UserData" )
            net.WriteTable({var = _var, val = _val})
            net.Send(self)
        end
        if CLIENT then
            net.Start( "UserData" )
            net.WriteTable({var = _var, val = _val})
            net.SendToServer()
        end
    end
end


Only tested locally, with



if LocalPlayer():GetFlag("test", false, true) == false then
	LocalPlayer():SetFlag("test", true, true)
else
	LocalPlayer():SetFlag("test", false, true)
end
			
print( LocalPlayer():GetFlag("test", "It didn't work...", true) )


Seems to work fine…

Who gave that code to you? I would’ve pmed you, but you have it disabled. There was a guy that stole some of my code and was leaking it on this forum, so I’d like to know if he’s still doing it. The version you posted is partially rewritten, but it is an old version of my cache ( when the guy in question was last on my server over a year ago ).

thought you might find that post interesting, I got the idea from you in this post

That explain the weird underscore prefixes… :stuck_out_tongue:

Also, why are those functions called Flag? A flag should be a boolean value, not a vector, a table or whatever

I was just testing out the idea with the code for the third person posted, it was just for convenience.

Ah, that is why. Just re-creating the functions I had listed.

I’ll be releasing that system soon ( The new version uses the data meta-table to store data ), but I use EntIndex ( via GetID ) instead and store the data in a global table. I do it this way so that data from players that have disconnected can still be grabbed and stored before being removed.

Here’s the front-end to mine ( with meta-entity link; the driver functions used to be GM based but now they’re data based )


//
// - Josh 'Acecool' Moser
//
NET_DEFAULT_FLAG_REFRESH_RATE = 1;
function META_ENTITY:GetFlag( _flag, _default, _private, _delay )
	local _data = data:GetFlag( self, _flag, _default, _private );

	// If the client isn't linked
	if ( CLIENT && _private && self != LocalPlayer( ) ) then
		local _bLinked = data:IsLinked( LocalPlayer( ), self );

		// Requests data from the server based on an interval if we don't have a linked data connection.
		if ( !_bLinked ) then
			networking:RequestFlag( _delay || NET_DEFAULT_FLAG_REFRESH_RATE, self, _flag, _data, _default );
		end
	end

	return _data;
end


//
// - Josh 'Acecool' Moser
//
function META_ENTITY:GetID( )
	local _index = ( ( self:EntIndex( ) + 128 ) - game.MaxPlayers( ) );

	// Prevents World Data from being removed by "physics_entity_solver" reporting 0.
	if ( IsValid( self ) && _index == 0 && self != game.GetWorld( ) ) then
		Log( self, self:GetClass( ) .. " is posing as world entity 0" );
		_index = nil;
	end

	return _index || -1;
end


//
//  - Josh 'Acecool' Moser
//
function META_ENTITY:ResetFlags( )
	local _flags = data:ResetFlags( self:GetID( ) );
	-- local _pflags = data:ResetFlags( self:GetID( ), true );
	return _flags, _pflags;
end


//
//  - Josh 'Acecool' Moser
//
function META_ENTITY:SetFlag( _flag, _value, _private )
	return data:SetFlag( self, _flag, _value, _private );
end
	

So, the way the current system works allows the client to request private data from the server at a delay refresh rate ( built in temp caching ), etc…

GetFlag returns the flag from the entity ( where non-private flags are synced to all clients ). For private flags, the local player gets their own, but for non localplayer entities the requester can ask the server to provide the information.

BUT, there is another feature because each vehicle has private-flags too… when the a player gets in to a vehicle, they become “linked” so private data from the vehicle is sent to the driver / passengers and is synced only when values change. When the player exits the vehicle, the link is destroyed. Private data for vehicles can be anything from speed ( because of the CurTime issue ), fuel, battery, etc…

RequestFlag is built to cache existing vars, so the 1 second / delay is specific to each flag needed, otherwise it could continue just grabbing the first one in the code and never grabbing anything else.

I’d recommend NOT setting a flag that doesn’t exist inside of GetFlag. Just return the default value if it doesn’t exist which is a quick check. Also, I’d highly recommend NOT networking client data TO the server ( this would allow potential exploits through such as overriding money and other values ). Never trust client data; if the client sets a flag on something then let it be private ( regardless of if it is or is not set to private; just have it not known to the server ). The other thing that can happen, is if you SetFlag on the server, then the client receives it and calls SetFlag,** it’ll cause an infinite loop!**

Good guess on the structure, damn near identical to the first version ( which initially only supported players, then grew )!

Look for this system that’ll be released very soon with the data system, and networking system ( still need to do a quick test to see if UMSG integration is worth it when sending huge streams of data such as screenshots where net refuses to send other messages until the screenshot has been fully sent; need to see if umsg will still send, if so then it’ll be integrated ). Maybe I’ll run those tests now and release the flag system in a few days.

Thanks for the tips :smiley: I’m glad I close to your structure :stuck_out_tongue: I started learning “gmod lua” a about 2 weeks ago, its good to hear that I’m getting somewhere. :stuck_out_tongue:

Yeah, I saw it and thought… wait a minute… is that guy still leaking my code ( clientside/shared ) and claiming it is his, or what. But yeah, it is good to see that you’ve got a good understanding of how things should work.

If you’re interested, I do tutor quite a few people, if you need help from time to time you can send me a Steam message ( Steam Icon under my name ) and I’ll respond when I’m around.

I just updated my dev-base to have some of the functions in; and I finally got around to testing the new net queuing system ( just a basic console command to test data sending while other data is being sent ) to see if it was even feasible by looking to see if net/umsg can be used together ( when sending large packets via net message, it sends in order so it doesn’t always allow other packets in while the larger ones are sending )… Turns out umsg and net messages work the same; no benefit adding a queuing system… which means I’ll be releasing the net system essentially as it is very soon!

They are both “blocked” while receiving other data, so I’ll be releasing my networking system, and with it the data system, within the next few days ( over the weekend ).

Awesome :smiley: I’ll be sure to check it out

Here’s links to everything – The full data / networking system will be up most-likely this weekend / end of – Additionally, I’ll be creating an “addon” out of this code for those that don’t want to create a new game-mode to get the features… basically it’ll act as an add-on library when I get most of the stuff released. There’ll be a ton of hooks added to control when things should load, etc…:

Hey, welcome to FacePunch.
I have written over 400 tutorials and completed “systems” in Lua for Garry’s Mod. I tutor and answer questions for free; feel free to add me on Steam if you need some guidance. This forum is for devs that need help working on things. Here are some resources to help you get started:

Generalized Lua Help ( Links to Wikis, Answers the question of “Where do I post a simple question or DarkRP Specific question”, links to other resources compiled by forum members )
https://dl.dropboxusercontent.com/u/26074909/tutoring/___welcome_docs/_welcome_general_lua_learning.lua.html

Useful Programs ( SteamCMD, Autosizer, Desktops, Process Explorer ) and Notepad++ Upgrades
https://dl.dropboxusercontent.com/u/26074909/tutoring/___welcome_docs/_welcome_useful_programs_and_notepadpp_upgrades.lua.html

AcecoolDev_Base Skeletonized Dev Base Game-Mode ( Never worry about Include or AddCSLuaFile ever again; comes with New Hooks, Console Commands, Meta-Table Objects, Helper Functions, Extended Functionality, and more! )
https://dl.dropboxusercontent.com/u/26074909/tutoring/___welcome_docs/_welcome_acecooldev_base_gamemode_info.lua.html