[RELEASE] New NWVars

hey, im not sure if this is more efficient or better than current NWVars in any way (i havent benchmarked it yet), but i had some spare time and decided to write this.

Source:
[lua]
local _R = debug.getregistry();
local net = net;
local hook = hook;
NWVars = {};
/*
NWVars table layout:

NWVars = {
    EntityID = {
        Type = Value
    }
}

*/

function _R.Entity:GetNetworkedVariable(enum, name, default)
if (!isnumber(enum) || !istable(NWVars[self:EntIndex()]) || !istable(NWVars[self:EntIndex()][enum]) || !NWVars[self:EntIndex()][enum][name]) then
// in consistency, filter it out and shit
return default || nil;
end

return NWVars[self:EntIndex()][enum][name];

end

if (SERVER) then
util.AddNetworkString(“nwvars_spawn”);
util.AddNetworkString(“nwvar”);

function _R.Entity:SetNetworkedVariable(enumType, strName, Value)
    if (!IsValid(self)) then
        error("Attempt to use \"SetNetworkedVariable\" on invalid entity!");
    end
     
    if (!NWVars[self:EntIndex()]) then
        NWVars[self:EntIndex()] = {};
    end
     
    if (!NWVars[self:EntIndex()][enumType]) then
        NWVars[self:EntIndex()][enumType] = {};
    end
     
    if (NWVars[self:EntIndex()][enumType][strName]) then
        ErrorNoHalt("Entity already has a " .. enumType .. " with name: " .. strName .. ", over writing!");
    end
     
    NWVars[self:EntIndex()][enumType][strName] = Value;
     
    net.Start("nwvar")
        net.WriteUInt(self:EntIndex(), 32);
        net.WriteInt(enumType, 4);
        net.WriteString(strName);
        net.WriteTable({Value});
    net.Broadcast();
end
 
hook.Add("PlayerInitialSpawn", "initspawn_SendNWVars", function(p)
    net.Start("nwvars_spawn")
        net.WriteTable(NWVars);
    net.Send(p);
end)

else
NWVars = {};

net.Receive("nwvars_spawn", function(l)
    NWVars = net.ReadTable();
end)
 
net.Receive("nwvar", function(l)
    local entindex = net.ReadUInt(32);
    local enum = net.ReadInt(4);
    local name = net.ReadString();
    local val = net.ReadTable();
     
    // i didnt see how using ambiguous types will work without passing an argument.
    NWVars[entindex] = NWVars[entindex] || {};
    NWVars[entindex][enum] = NWVars[entindex][enum] || {};
    NWVars[entindex][enum][name] = val[1];
end)

end
[/lua]

Usage/Result



lua_run print(Entity(1):GetNetworkedVariable(TYPE_NUMBER, "Money"))
	nil

lua_run_cl print(Entity(1):GetNetworkedVariable(TYPE_NUMBER, "Money"))
	nil

lua_run Entity(1):SetNetworkedVariable(TYPE_NUMBER, "Money", 1337)

lua_run print(Entity(1):GetNetworkedVariable(TYPE_NUMBER, "Money"))
	1337

lua_run_cl print(Entity(1):GetNetworkedVariable(TYPE_NUMBER, "Money"))
	1337


Looks pretty classic I would say. So good enough for most things. I would just make a few suggestions for a potential future version if I may :).

  • First I didn’t yet use the net library myself so I cannot tell. But is there a max size allowed for packets from server to client ? On the wiki client to server sends are restricted to 64kb max. But how about the other way ? Here you don’t check for that at all so that might lead to a crash if there is such a restriction. Maybe if you have some large text inside of a string for example you should split it into multiple “WriteString” calls ? But still maybe one send or broadcast is restricted so it would be even safer to split it into multiple calls. Maybe sending the first packet with an int serving as the count of packets to use for the same networked variable ?

  • Next I guess that “Broadcast” must for sure compress the data before sending it but maybe it would be even better to compress them first in some cases ? Of course it would be useless to compress just an int… But here again I’m talking about large strings or tables.

  • As another improvement I was thinking of set values on specific clients if desired. This would be a nice little addition to the current system. And I guess you would just need to use “Send” instead of “Broadcast”.

  • Finally as another nice improvement maybe a “client-to-server” feature would be nice too :).

These are just thoughts of what I mean could improve it. That doesn’t mean that what you did is not good at all :). Some other more experienced lua coders may go against some things I said because I don’t know how the system works internally perosnally.

Thanks for sharing anyway :).

EDIT:

Which one should I believe lol ?

usermessages have limits, net doesnt.

net.SendToServer is used on the client to send a … net … to the server.

net.Send sends a net to a specific player, or table of players.
net.Broadcast sends the net to everyone on the server.

also a client to server would not be useful for this seeing as the client should NEVER set values, its should only get and display. (just a general rule of thumb) if you start allowing the client to set values, you introduce the possibility of ‘hacks’ and exploits.

-EDIT-
ye i kinda forgot that net has a limit of 64kb due to… well the fact that you would need to send a shitload to reach it.

Ok thanks for your reply :). About client-to-server what about making your setter send a console command ?

what would be the point of that?

What do you do if a client needs to be able to tell others about something ?

it shouldnt need to ever. you get the server to do it. the server serves the entire populous, the client serves itself.

How about GUI ? A player chooses a class in a menu for example. Other players should know which class he’s in. Or at least the server.

when you change team the server does it, just set the nwvar in there.

I mean it could be anything. What if you need to login to access some server functionalities ? There are plenty of cases where client-to-server communication would be needed.

the server processes all the info to send to the client, therefore the server needs to know. just set it on the server.

Console commands. That’s the only proper way to communicate between the client and the server. If console commands aren’t enough for what you’re doing, there’s a good chance that you’re doing it wrong.

no its not? you can use net for that aswell. -cough- datastream

Datastream no longer exists. Also it used console commands.

Note that I said that concommands were the only proper way, not the only way. You will almost never need the net library for common client to server communication.

i was kidding about datastream (just to clarify) it was a peice of shit.

and i wouldnt say its the only proper way, but its definitely the easiest, and ye you dont NEED net for common communications but i decided to with my gamemode heh :l

This is nothing unique, I’ve seen hundreds of servers use usermessages in gmod11 and 12 the way you did with the net library, I honestly believe it’s not even worth using the net library, I’m still sticking with usermessages, if you use something over a usermessage limit, you’re doing it wrong.

To the people trying to make a “gui” out of this: this is for developers, specifically lua developers, if you can’t code then I would highly suggest staying away from this type of stuff.

Also code error:

you utilize a net table twice
the table is also global
and you will get a util is nil error because you didn’t local it.


ErrorNoHalt("Entity already has a " .. enumType .. " with name: " .. strName .. ", over writing!");

I imagine this will end up very annoying

What is the point of using the enum type thing if you’re going to use net.WriteTable( {value} )?
Storing it in seperate enum type variables clientside is a bit useless.

because i dont know how to use ReadType on the receiving end with a type thats not always the same. so i just sent it as a table.

and i never said it was an improvement in anyway, just something i did.

if its bad, so be it.