Hi, I’m currently working on a coding project - Currently, the way my values work is in physical form; they are stored within a folder inside the script.
I was wondering if there were a way I could counter this by storing Values within the lines of code itself; keeping in mind I am using ModuleScripts and the Values will need to be changed across all scripts when present.
So ideally, I wish to keep the Values within the ‘System’ ModuleScript & if they’re altered / changed within another script then it affects all.
I’m not even sure why you need to change the values across all scripts? Can’t you just hook it to a changed event or reference the ValueObject itself rather than referencing the value?
As I’m going to have several of these systems within the place (Ideally one per player that joins) - Will changing the values effect ALL across the server?
Ideally I want to drift away from using the physical values and instead store all changes within the script itself; my issue is that when carrying arguments across ModuleScripts, if a value were to change in one, then it wouldn’t change in the others.
No. You might have to use messaging service for that.
Don’t. Use BindableEvents and maybe metatables, something like this:
local module = {}
module.isDoor = setmetatable({
Value = false -- boolean?
_Event = Instance.new("BindableEvent") -- private field?
Changed = self._Event.Event
}, {
__newindex = function(self, index, value)
if index == "Value" then
rawset(self, index, value) -- rawset so this metatable doesn't fire
self._Event:Fire(value)
end
end
})
return module
It would be quite a bit easier to use classes, I’d recommend OOP for the custom ValueObjects.
Example:
-- value class module
local Value = {}
Value.__index = Value
function Value.new(value)
assert(value, "Value doesn't exist")
local self = setmetatable({}, Value)
self.Value = value
self._Event = Instance.new("Event")
self.Changed = self._Event.Event -- Value.Changed:Connect()
return self
end
function Value:__newindex(index, value)
if index == "Value" then
assert(typeof(value) == typeof(self[index]), "You must use a value which is the type " .. typeof(self[index]))
rawset(self, index, value)
self._Event:Fire(value)
end
end
return Value
-- module
local Value = require(Path.To.Module)
local module = {}
module.isDoor = Value.new(true) -- requires value field.
return module
DataStores are a highly inefficient way to accomplish this. Making calls to an already unstable API can wreak havoc on your game. You can use the _G global to store values. An example would be
If you need to detect changes across servers use the MessagingService. Don’t use this for communication between scripts in a single game instance as it’s an inefficient way of working around RemoteEvents / BindableEvents.
If the values are supposed to change across all scripts, they really just need to stem from the module script. The easiest solution for that is metatables, where you connect the behaviour to value objects which you don’t want to use.
Other than that, I can only think of _G which everyone else has suggested. I believe it is mainly used for organisation of multiple modules?
Please don’t use data stores to store values in this specific case because this is a hacky workaround. You will end up hitting your data store limits very quickly if you aren’t careful causing data loss. Data stores should only really be used for saving players data.
_G isn’t a bad practice as long as you don’t incorrectly use it. The only reason why people say not to use it is because we have ModuleScrips as a better alternative. ModuleScrips allow you to split up code into smaller, more readable chunks. With _G this isn’t possible because it is just one big table.
I think this issue has been over-complicated because couldn’t you just store your values as variables in your ModuleScript. Variables in modules are shared as direct references between each script that requires it. This means if a script changes the variable in the ModuleScript then all the other scripts requiring that module will see the change. From my knowledge I think it is then possible to create a custom changed event to listen for the variable changes.
I do believe I have overcomplicated it myself; having read this, I went back and did simple argument transfering & turns out I can change a value in one script & have it affect another.
Yep, it is. The Lua Chat System does this as well actually! You can either implement this as a custom Signal class or allow the engine to handle it with a BindableEvent.
For every change, you would fire off the BindableEvent/signal manually (you’d probably need a newproxy to reasonably act as a medium to do this). You can then connect to that same signal like a normal listener so long as you return the items back out.
Not a changed event but a simple example of creating signals for a custom class using BindableEvents anyway:
-- From your class
myClass = {}
myClass.eTableAdded = Instance.new("BindableEvent")
myClass.TableAdded = myClass.eTableAdded.Event
setmetatable(myClass, {
__newindex = function(self, ...)
myClass.eTableAdded:Fire(...)
end
})
-- From somewhere else
local class = require(myClass)
class.TableAdded:Connect(function (...)
print(...)
end)
Adding to this, it would seem that I’m unable to transfer the values - Even as a read only - via RemoteEvents; as the actual script is ran server-side, the piloting is managed via Client. I’m unable to send my Configuration argument to the Client to be read. Instead I am met with this error:
function System.FlightControl(Transfer, FlightUI)
System = Transfer
PilotSeat = System.Interior["PilotSeat"]
CurrentPilot = game:GetService("Players").LocalPlayer
local TiltY, TiltZ = System.Exterior:WaitForChild("Root").Orientation.Y, 0
while PilotSeat.Occupant do wait()
if System.Configuration.isWarping.Value == false then
if PilotSeat.Throttle == -1 then
System.BodyMovers["BodyVelocity"].Velocity
= System.Exterior["Root"].CFrame.LookVector * -50/2
elseif PilotSeat.Throttle == 0 then
System.BodyMovers["BodyVelocity"].Velocity
= System.Exterior["Root"].CFrame.LookVector * 0
elseif PilotSeat.Throttle == 1 then
System.BodyMovers["BodyVelocity"].Velocity
= System.Exterior["Root"].CFrame.LookVector * 50
end
if PilotSeat.Steer == -1 then
TiltY = TiltY + 1
if TiltZ == 25 then
else
TiltZ = TiltZ + 1
end
elseif PilotSeat.Steer == 0 then
if TiltZ == 0 then
elseif TiltZ > 0 then TiltZ = TiltZ - 1
elseif TiltZ < 0 then TiltZ = TiltZ + 1
end
elseif PilotSeat.Steer == 1 then
TiltY = TiltY - 1
if TiltZ == -25 then
else
TiltZ = TiltZ - 1
end
System.BodyMovers.BodyGyro.CFrame = CFrame.Angles(0, math.rad(TiltY), 0) * CFrame.Angles(0, 0, math.rad(TiltZ))
end
else
end
end
end