I was wondering which is a more efficient leveling system.
currently I have it so the client listens to their EXP values checks when they are able to level up, they use a Remote Event to tell the server they can level up. The server checks to make sure this is true. if so then level up.
or
would it be better to just have the server listening to everyone’s EXP values to check if they have a level up if so level them up?
I don’t really know if having a bunch of listeners is taxing or not, if it is taxing is it worth the bandwidth to have the client do the listening and then the server just doing the checks?
perform checks on the client before firing a remote instead of the server checking everyone’s stats constantly
[quote from below]
but it’s better not to fire a remote at all in the first place unless necessary measures have been taken, sticking to the server for everything or for the sake of organization will not tend to equate to better performance though
To answer your question, most people do it on the server, but doing the first option wouldn’t hurt. But I’d stick to the server for organization purposes.
--client
function GatherAllStats()
local EXP={}
local LEVELS={}
for i,v in pairs(Data.Levels:GetChildren()) do
for o, Values in pairs(v:GetChildren()) do
LEVELS[Values.Name] = Values
end
end
for i,v in pairs(Data.Experience:GetChildren()) do
for o, Values in pairs(v:GetChildren()) do
EXP[Values.Name] = Values
end
end
return EXP, LEVELS
end
function GatherCertainStats(Target)
local EXP={}
local LEVELS={}
Par.Stats.StatsFrame:ClearAllChildren()
for i,v in pairs(Data.Levels[Target]:GetChildren()) do
LEVELS[v.Name] = v
end
for i,v in pairs(Data.Experience[Target]:GetChildren()) do
EXP[v.Name] = v
end
return EXP, LEVELS
end
function SetUpStats(Target)
local EXP,LEVELS
if Target == "All" then
EXP, LEVELS = GatherAllStats()
else
EXP, LEVELS = GatherCertainStats(Target)
end
for i,v in pairs(LEVELS) do
local Example = Par.ExampleStats.Example:Clone()
Example.Parent = Par.Stats.StatsFrame
Example.PreviousLevel.Text = v.Value
Example.NextLevel.Text = v.Value+1
Example.LableName.Text = v.Name
local exper = EXP[v.Name]
Example.Visible = true
local Math = tonumber(exper.Value)/(RS.GameConfigs.NextEXP.Value*v.Value)
Example.OuterBar.InnerBar.Size = UDim2.new(Math,0,1,0)
Example.Position = UDim2.new(0,0,0,(#Par.Stats.StatsFrame:GetChildren()*50)-50)
Par.Stats.StatsFrame.CanvasSize = UDim2.new(0,0,0,(#Par.Stats.StatsFrame:GetChildren()*50))
exper.Changed:Connect(function()
local Math = tonumber(exper.Value)/(RS.GameConfigs.NextEXP.Value*v.Value)
if Math >= 1 then
GCE:FireServer("LevelUp", exper)
Math = 0
end
Example.OuterBar.InnerBar:TweenSize(UDim2.new(Math,0,1,0))
end)
v.Changed:Connect(function()
Example.NextLevel.Text = v.Value+1
Example.PreviousLevel.Text = v.Value
end)
end
end
--Server
GCE.OnServerEvent:Connect(function(Player, ...)
local param = {...}
local Data = RS:FindFirstChild(Player.UserId)
if Data == nil then
return
end
if param[1] == "LevelUp" then
local Experience = Data.Experience[param[2].Parent.Name][param[2].Name]
local Level = Data.Levels[param[2].Parent.Name][param[2].Name]
if Experience ~= nil then
if tonumber(Experience.Value) >= RS.GameConfigs.NextEXP.Value*tonumber(Level.Value) then
Experience.Value = 0
Level.Value = tonumber(Level.Value)+1
end
end
end
end)
If the server is the one granting the xp in the first place (which it should be), add a check for leveling up there. Than, if something happens, tell the client through a remote event.
While the first option would work, it ends up being less optimized since the server updates xp, the client checks the new stuff and makes the determination, and then tells the server to check.
Unless there is user input involved (clicking buy), keep all calculations on the server, and send info to the client to display.
Why would you do that? It’s inefficient to let the server handle checking every single client’s values each time their changed.
On the other hand, don’t spam remotes either as you’ve only got a 50 KB/sec limit, verify separately for each client locally so that there isn’t too much unnecessary strain on the server, and then tell the server about the new level and let it save it or perform necessary actions;
unless you’re talking about awarding exp or something here, in that case just fire for the client instead to display new information etc.
The issue with this is that the server still has to verify the client. In this scenario, you end up doing the calculation on both the client and server, which doesn’t make sense for the use case. The server has much more power than the clients to process things, and it makes sense to use the server in that way.
In different cases; You would be right. I.E. a client makes a purchase, which both the server and client would check: The client for visual purposes and the server for validity purposes.
Your doing the calculations less though. on one hand the server will check if you leveled up every time your exp changes. if the clients doing the calculating the server will only check when the client says that it has leveled up
Both ways will work. I’m simply pointing out that the server is built for handling calculations, while the client is built more for displaying things. In the end, it won’t be that significant of a difference.
However, your method will have a added delay due to the two remote events that need to be sent: client to server, server to client. The server-only method will only use one remote event: server to client. That delay may be noticable, it may not be. It depends on the client’s connection.
At the end of the day, choose the one that fits into your organization layout the best. If you want to optimize ping / delay or server performance. Server sided calculations or server and client sided calculations.