Hey everyone, I have a question for anyone who knows a thing or two about scripting. I need a really fast, quick, neat, and efficient way of handling player states or tags.
To be more specific, I am talking about states or tags that get added to a player if they are doing something or being affected by something.
For example, if a player is blocking, they could get tagged with “Blocking” so that you can check if the player is blocking or not from another script.
I handled this specifically with tables and modules. This worked, for the most part, until I found out it wasn’t possible to get these tags within the client even after using invoke server methods.
I personally had the idea of creating a Configuration for each player when they join which could store attributes that I could handle with a ModuleScript, but I am unsure if this method is fast, quick, neat, and efficient, as knowing Roblox, almost anything is a memory leak.
If anyone has any ideas of how to handle a state or tag system, or if my Configuration idea will work perfectly fine, please let me know.
----------------------------------------------------
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TeleportService = game:GetService("TeleportService")
local Debris = game:GetService("Debris")
----------------------------------------------------
local Modules = ReplicatedStorage.Modules
local Assets = ReplicatedStorage.Assets
----------------------------------------------------
local Services = require(Modules.Services)
----------------------------------------------------
local DataService = Services:GetService("DataService")
local Network = Services:GetService("Network")
----------------------------------------------------
local Shutdown = require(script.Shutdown)
----------------------------------------------------
local PlayersLoaded = {}
local DataLoaded = {}
local PlayerLoader = {}
----------------------------------------------------
PlayerLoader.CanLoad = function(Player)
if PlayersLoaded[Player] then
return
end
return true
end
PlayerLoader.GetPlayerData = function(Player)
if DataLoaded[Player] then
return
end
return DataService:GetPlayerData(Player)
end
PlayerLoader.CharacterLoaded = function(Player)
local PlayerData = DataService:GetPlayerData(Player)
local Character = Player.Character or Player.CharacterAdded:Wait()
local Head = Character.Head
end
PlayerLoader.Load = function(Player)
if not PlayerLoader.CanLoad(Player) then
return
end
local PlayerData = DataService:GetPlayerData(Player)
PlayerLoader.CharacterLoaded(Player)
Player.CharacterAdded:Connect(function()
PlayerLoader.CharacterLoaded(Player)
end)
local Cache_Folder = Instance.new("Folder")
Cache_Folder.Parent = workspace.Cache
Cache_Folder.Name = Player.Name
local States_Folder = Instance.new("Folder")
States_Folder.Parent = Assets.States
States_Folder.Name = Player.Name
end
PlayerLoader.Disconnect = function(Player)
PlayersLoaded[Player] = nil
DataLoaded[Player] = nil
local Cache = workspace.Cache:FindFirstChild(Player.Name)
local States = Assets.States:FindFirstChild(Player.Name)
if not Cache then
return
end
if not States then
return
end
Debris:AddItem(Cache, 0)
Debris:AddItem(States, 0)
end
Players.PlayerRemoving:Connect(PlayerLoader.Disconnect)
return PlayerLoader
I had this SAME exact issue bro, I figured out a way in which you can do it. Let me share.
You have 2 module scripts. Framework and Manager
Framework contains the actual Statuses and Manager just retrieves status or adds and removes characters. Here’s mine.
Store whatever values, combat data, whatever you need in there
Secondly you put a module script inside of that module. MANAGER
function characterStatusManager.new(character)
local self = setmetatable({}, characterStatusManager)
self.Character = character
return self
end
function characterStatusManager:AddCharacter(character)
local player = PS:GetPlayerFromCharacter(character)
if player ~= nil then
local playerStatus = framework.new(character)
Characters[player.UserId] = playerStatus
laststun[player.UserId] = os.clock()
aircombo[player.UserId] = os.clock()
else
local playerStatus = framework.new(character)
Characters[character] = playerStatus
laststun[character] = os.clock()
aircombo[character] = os.clock()
end
end
function characterStatusManager:RemoveCharacter(character)
local player = PS:GetPlayerFromCharacter(character)
if player ~= nil then
Characters[player.UserId] = nil
else
Characters[character] = nil
end
end
function characterStatusManager:RetriveStatus(character)
local player = PS:GetPlayerFromCharacter(character)
if player ~= nil then
return Characters[player.UserId].StatusList
else
return Characters[character].StatusList
end
end
It is VERY messy, but you should be able to get the jist of it. I’m using this for both NPC’s and players so it may be a little funky. But a little cleaning up should help.
In the state in which you wanna call something. Just require the MANAGER script. And call on the StatusList or Whatever you need to call on. Put that in a RemoteFunction InvokeServer thing and it should work. Works for me at least.
I think this is for sure a cool method, although, the way it’s set up, you would need to create a new Manager instance in each script where you want to get a player’s tags which isn’t something I want to be doing especially when I need to be getting the tags from the same player in many different scripts all at the same time.
The module I was using before is different from the one attached now, since, the module attached isn’t handling tags but rather an early draft of the Configurations method I mentioned. Whenever I tried to print out the large table that handled each player’s tags from the Tags module, it would return an empty table. Also, when I used InvokeServer, the table wouldn’t update when data changed. I’m considering adding a DataChangedEvent, but I’m not sure if it’s even worth it overall. On top of that, everything I’ve read on this forum advises against using Attributes and CollectionService, suggesting I use a table method instead. So, I’m really confused about which approach to take.
What you could do instead is run a heartbeat like this.
RunService.RenderStepped:Connect(function()
local blah = RFunc:InvokeServer()
task.wait()
end)
it whatever script you put it in it’ll have the players status at ALL time EVERY moment.
For server scripts on the otherhand you can simply just call on the module.
But at the end of the day it is personal preference. I just prefer to use this cuz my monkey brain can understand it.