Hello everybody! As some of you might know, I am actually working on a class system to allow easy object oriented programming (that I called [B]Looa[/B]). I've worked on it for two weeks and now I have something apparently stable, but I can't convince myself it's good enough, so I'm looking for opinions and insights to know if I can finally say "It is good, I can keep going on with the rest of my project". I'll describe how the system works for the ones that don't want to read the code. If you just want to check out the code, go at the end of the post.
[U][B]Creating a class[/B][/U]
Creating a class is rather easy, the [B][I]class[/I][/B] function will return a table ready to be used as a class, so one would create a class like this:
[CODE]myClass = class();
function myClass:DoSomething()
print('myClass did something');
end[/CODE]
The [B][I]class[/I][/B] function can also take two [I]named arguments[/I], as such:
[CODE]secondClass = class{networked = true, parent = myClass}[/CODE]
The [I]networked[/I] argument will allow the class to network between a server side object and a client side object (we will see that later).
The [I]parent[/I] argument makes the current class a child of the given class. The parent can also be accessed by using [I]self.parent[/I].
[U][B]"Magic" methods[/B][/U]
Classes can have two "magic" methods:
- [I][B]__construct[/B][/I], that is called when an instance of a class is created (the variables of the class should be declared in this function):
[CODE]function character:__construct(name, surname)
self.name = name;
self.surname = surname;
end[/CODE]
- [B][I]__synced[/I][/B], that is [U][B]client side only[/B][/U], it's called when the object has been successfully synced with it's server side self (we'll see that later).
You can also use all Lua's metatable functions as "magic" methods.
[B][U]Instantiating a class (Creating an object)[/U][/B]
It's rather easy to instantiate a class:
[CODE]mark = character('Mark', 'Reeves');[/CODE]
[I][B]character[/B][/I] being a class. The arguments will be passed to [I][B]__construct[/B][/I].
[B][U]Networking[/U][/B]
Objects can be networked if their classes have been marked as "networked" (the named argument). This means that a server side object can set the variable of its client side self.
Networked class are little bit harder to create than normal classes, as they have one more magic function ([B][I]__synced[/I][/B]) and one more method [I][B]NetworkVar[/B][/I].
The [B][I]NetworkVar[/I][/B] method will mark a variable of a class as "networked", this means that when a server side object changes the value of a networked variable, its client side self will also have its variable changed.
This method takes two parameters, the first one being a string of the name of the variable, the second one being the type of the variable, which is optional.
Example:
[CODE]myNetworkedClass = class{networked = true}
function myNetworkedClass:__construct(value)
self:NetworkVar('value', 'number') -- Here, we mark the variable value which must be a number to be networked.
self.value = value;
end[/CODE]
Another feature of the networked classes are the [B][I]__synced[/I][/B] "magic" method as said earlier, to understand when this function is called, let's see how the networking works:
1) We create our object server side;
2) Later, our client side object is created, this object will send a request to the server, asking to sync itself with its server side self;
3) The server receives the request and sends all the networked variables to the client side object;
4) The client side object receives the variables and sets them, then, [B][I]__synced[/I][/B] is called [B][U]CLIENT SIDE ONLY[/U][/B].
Exemple:
[CODE]if (CLIENT) then
function myNetworkedClass:__synced()
print('myNetworkedClass got successfully synced!');
end
end[/CODE]
Now that our class is ready, we need to create instances of it, to do so, we must give each instances of a networked class a [I]unique ID[/I], allowing the server and client to identify the objects when networking:
[CODE]NWedObject = myNetworkedClass('SomeUniqueID'); -- Other arguments for the __construct method can be put after the unique ID.[/CODE]
If you want two instances of the same class to network, they must have the same unique ID server side and client side.
[B][U]Utility functions[/U][/B]
[I][B]instanceOf[/B][/I](object, class) Checks if an object is an instance of the given class.
[B][I]childOf[/I][/B](object, class) Checks if the class of the object is a child of the given class.
[B][U]The code[/U][/B]
Don't use the code yet, as it might be modified:
[CODE]--[[
Looa: Object Oriented Programmation with easy networking for Garry's Mod.
Description: Class system to allow nice Object Oriented coding.
Classes accepts basic inheritence and objects are automaticaly networked.
Special thanks to rejax, Acecool, Willox and everyone that helped me with
the networking on the Facepunch forum! :D
]]--
rawtype = rawtype || type; -- Will return the type of any data ignoring metatables.
--[[
Description: New type function, allowing metatable to change the type
of the tables with __type.
Arguments: var any Any data to check the type of.
Returns: string The type of the given data.
]]--
function type(var)
local type = rawtype(var);
if (type == 'table') then
local meta = getmetatable(var);
if (meta && meta.__type) then
return meta.__type;
end
end
return type;
end
looa = looa || {};
looa.net = looa.net || {};
looa.net.objects = looa.net.objects || {};
if (SERVER) then
util.AddNetworkString('Looa_ObjNW_Sync'); -- Used to sync an object between the server and clients.
util.AddNetworkString('Looa_ObjNW_Vars'); -- Used to network vars between server side and client side objects.
--[[
Description: Writes a variable of a networked object.
Arguments: obj object Object with the variable.
var string Name of the variable.
Returns: boolean True if the var could be written, false overwise.
]]--
function looa.net.WriteVar(obj, var)
local t = obj.vars[var];
if (obj[var] && t == (type(obj[var]) || true)) then
net.WriteString(var);
net.WriteType(obj[var]);
return true;
end
return false;
end
--[[
Description: Synchronizes an object with its client side self.
Arguments: obj object The object to sync.
]]--
function looa.net.SyncObject(obj)
net.Start('Looa_ObjNW_Sync');
net.WriteString(obj.uid);
for var in pairs(obj.vars) do
looa.net.WriteVar(obj, var);
end
net.Broadcast();
end
--[[
Description: Updates a variable of an object's client side self,
will fail if the object isn't synced and if the type of the variable isn't right.
Arguments: obj object The object.
var string The name of the variable to update.
]]--
function looa.net.UpdateVar(obj, var)
if (obj.synced) then
net.Start('Looa_ObjNW_Vars')
net.WriteString(obj.uid);
if (!looa.net.WriteVar(obj, var)) then return end
net.Broadcast();
end
end
--[[
Description: Called when a client requests to sync an object,
sends the currently networked vars from a server side object to its client self.
]]--
net.Receive('Looa_ObjNW_Sync', function()
local uid = net.ReadString();
local obj = looa.net.objects[uid];
if (obj) then
looa.net.SyncObject(obj);
end
end)
else -- CLIENT
looa.net.AllowSync = false; -- Sync is allowed only after InitPostEntity was called.
--[[
Description: Synchronize the object with the given unique ID with its server side self.
Arguments: uid string The unique ID of the object.
]]--
function looa.net.Sync(uid)
if (looa.net.AllowSync) then
net.Start('Looa_ObjNW_Sync');
net.WriteString(uid);
net.SendToServer();
end
end
-- Synchronizing all objects crated before they could.
hook.Add('InitPostEntity', 'syncObjects', function()
are you trying to overflow the network
[QUOTE=MeepDarknessM;47898556]are you trying to overflow the network[/QUOTE]
The networking doesn't send a lot of information at a time, the only time something "big" is sent is when when the server sends all the variables of an objects to allow the client side object to be synced. In the other cases, the only things sent per message are the unique ID, the name of the variable and the value.
To make it more clear:
- The client sends its object unique ID only ONCE (syncing request);
- The server sends its object unique ID and all the networked variables to the client ONCE, only when a client side object does a syncing request;
- The server sends its object unique ID and a variable to the client when the variable is changed server side;
I'm sorry to up the thread, but it's drowning in all the other ones and I didn't get any truly useful/interesting replies after 24 hours. I won't spam ups but I hope I will get more insights and opinion about Looa. Thank you in advance.
Sorry, you need to Log In to post a reply to this thread.