Storing values - Script instead of physical

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.

Is this possible?

This is currently how it is set up:
image

You could use DataStores to store the values and just call them using GetAsync() in the scripts, no?

1 Like

Wouldn’t this method cause drainage across the server though? :confused:

You could use _G. I know it’s a bad practice but that’s what i know.

1 Like

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?

So far liking this method;

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

_G.Configuartion = {CurrentStatus = ..., isDoor = ..., isOwner = ...}

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.

1 Like

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. :slight_smile:

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)
2 Likes

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:

@waterrunner

Code:
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