Skip to content

Instantly share code, notes, and snippets.

@cxmeel
Last active September 8, 2020 08:39
Show Gist options
  • Save cxmeel/e016c1f852bf72c01099d1859179a76e to your computer and use it in GitHub Desktop.
Save cxmeel/e016c1f852bf72c01099d1859179a76e to your computer and use it in GitHub Desktop.
A really simple state management solution for Roblox.

Heads up!

This is now a fully-maintained project with a dedicated repo. You can find it at https://github.com/ClockworkSquirrel/BasicState.

This is the original v0.0.1 of BasicState. This code is still subject to the MIT license as per the official repository.


Documentation

BasicState.new()

Creates a new state object. Accepts an optional InitialState parameter, for defining the state before it is returned.

Syntax

BasicState.new([ InitialState: Dictionary<any, any> ]): State

State:Set()

Sets the value of a given key in the state, and then fires off any Changed signals. You should always use this when you need to change the state. Never modify state directly!

Syntax

State:Set(Key: any, Value: any): void

State:Get()

Retrieves a value stored in the state. If DefaultValue is specified, it will return that if the entry does not exist (or is equal to nil).

Syntax

State:Get(Key: any[, DefaultValue: any]): any

State:GetState()

Returns the full state object. A new table is returned, rather than a reference to the internal state object. This prevents directly overwriting the state. You should always use the :Set() method if you wish to mutate state.

Syntax

State:GetState(): Dictionary<any, any>

State:GetChangedSignal()

Returns an RBXScriptSignal which is only fired when the value of the specified key is updated. The Event fires with the following values (in order):

Name Type Description
NewValue any The new value of the requested entry.
OldValue any The value of the entry prior to mutation.
OldState Dictionary<any, any> The entire state object prior to mutation.

Syntax

State:GetChangedSignal(Key: any): RBXScriptSignal

Example

local State = BasicState.new({
    Hello = "World"
})

State:GetChangedSignal("Hello"):Connect(function(NewValue, OldValue, OldState)
    print(OldValue) --> "World"
    print(NewValue) --> "Roblox"
end)

State:Set("Hello", "Roblox")

State:Destroy()

Destroys the current state and any RBXScriptConnections.

Syntax

State:Destroy(): void

State.Changed

An RBXScriptSignal which is fired any time the state mutates. The Event fires with the following values (in order):

Name Type Description
OldState Dictionary<any, any> The entire state object prior to mutation.
Key any The key of the entry which has mutated.

Syntax

State.Changed: RBXScriptSignal

Example

local State = BasicState.new({
    Hello = "World"
})

State.Changed:Connect(function(OldState, Key)
    print(Key) --> "Hello"
    print(OldState[Key]) --> "World"
    print(State:Get(Key)) --> "Roblox"
end)

State:Set("Hello", "Roblox")
local State = {}
local function JoinDictionary(...)
local NewDictionary = {}
for _, Dictionary in next, { ... } do
for Key, Value in next, Dictionary do
NewDictionary[Key] = Value
end
end
return NewDictionary
end
State.__index = State
function State.new(InitialState)
local self = setmetatable({}, State)
self.__state = type(InitialState) == "table" and InitialState or {}
self.__changeEvent = Instance.new("BindableEvent")
self.__bindables = {}
self.Changed = self.__changeEvent.Event
self.__newindex = function()
warn("Do not modify state directly!")
end
return self
end
function State:GetState()
return JoinDictionary(self.__state, {})
end
function State:Set(Key, Value)
local OldState = self:GetState()
self.__state[Key] = Value
self.__changeEvent:Fire(OldState, Key)
end
function State:Get(Key, DefaultValue)
local StateValue = self:GetState()[Key]
return type(StateValue) == "nil" and DefaultValue or StateValue
end
function State:GetChangedSignal(Key)
local Signal = Instance.new("BindableEvent")
self.Changed:Connect(function(OldState, ChangedKey)
if (Key == ChangedKey) then
Signal:Fire(self:Get(Key), OldState[Key], OldState)
end
end)
self.__bindables[#self.__bindables + 1] = Signal
return Signal.Event
end
function State:Destroy()
for _, bindable in next, self.__bindables do
bindable:Destroy()
end
self.__changeEvent:Destroy()
self = nil
end
return State
MIT License
Copyright (c) 2020 csqrl (a.k.a. ClockworkSquirrel)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software without modification.
THE SOFTWARE IS PROVIDED "AS IS" BY CSQRL, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR
(CSQRL), CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment