I am making a building game and I need users in my game to undo and redo the items they insert onto their plot. I do not know how to do this. I was thinking to make a table of everything inserted. But I am still not sure and I don’t know how to insert things in tables.
Tables would be my go to in regards to something like this, here’s a dev hub article Tables | Documentation - Roblox Creator Hub
Some useful things to note
table.insert(table_name, item) --inserting items
#table_name --total number of items in the table
What you can do
local playerObjects = {playerName ={}}
function revert(player)
if playerObjects[player.Name] ~= nil then
playerObjects[player.Name][#playerObjects[player.Name]]:Destroy()
end
end
How can I support redo?
The best way to do this would be using stacks
I just stumbled across this topic attempting to do the exact same thing. I know it’s over 4 years old, however, I have a solution that works really well.
Using the limited information @cjjdawg provided, I have created something that supports undo and redo using Stacks.
(Information on Stacks can be found here)
First, you need to create a ModuleScript
. Inside of there, you need to paste the following code:
local Stack = {}
Stack.__index = Stack
function Stack.new()
local self = setmetatable({}, Stack)
self.UndoStack = {}
self.RedoStack = {}
return self
end
-- Check if the stack is empty
function Stack:IsEmpty(stack: {})
return stack == 0
end
-- Create a new value in the stack
function Stack:Push(value)
table.insert(self.UndoStack, value)
end
-- Remove the newest value in the stack
function Stack:Undo()
if self:IsEmpty(self.UndoStack) then
return nil
end
local object = table.remove(self.UndoStack, #self.UndoStack)
table.insert(self.RedoStack, object)
return object
end
-- Add the last value in the redo stack
function Stack:Redo()
if self:IsEmpty(self.RedoStack) then
return nil
end
local object = table.remove(self.RedoStack, #self.RedoStack)
table.insert(self.UndoStack, object)
return object
end
return Stack
The link I provided to the documentation only uses 1 table, which is great for undoing things, however, in order to redo things there needs to be a place to store all of the values we might want to redo, which is where the second table comes in.
I have 2 tables, self.UndoStack
and self.RedoStack
. The self.UndoStack
table contains all of the pushed values that are initially pushed to the stack, using Stack:Push()
. The self.RedoStack
table contains all of the undone values.
Stack.new()
- Creates a new Stack object
Stack:Push()
- Inserts the given value into self.UndoStack
Stack:IsEmpty()
- Checks if the given stack is empty. Returns either true or false
Stack:Undo()
- Removes the last value from self.UndoStack
and inserts it into self.RedoStack
Stack:Redo()
- Removes the last value from self.RedoStack
and inserts it back into self.UndoStack
If this is being ran on the server and is per-player (Like in my case) you can use the following process:
Server Script
local Stack = require(modules.Stacks)
local stacks = {}
-- Get or create a stack for the player (Ensures only 1 stack is used)
local function GetStack(player: Player)
local stack = stacks[player.Name]
if stack == nil then
stack = Stack.new()
stacks[player.Name] = stack
end
return stacks[player.Name]
end
-- Push the placed object to the stack on placement
remotes.Build.OnServerEvent:Connect(function(player, object)
local stack = GetStack(player)
stack:Push(object)
end)
-- Get the last object the player placed and parent it in ReplicatedStorage
remotes.Undo.OnServerEvent:Connect(function(player)
local stack = GetStack(player)
local object = stack:Undo()
if object ~= nil then object.Parent = ReplicatedStorage.OldItems end
end)
-- Get the last object that was undone and parent it back to the plot
remotes.Redo.OnServerEvent:Connect(function(player)
local stack = GetStack(player)
local object = stack:Redo()
if object ~= nil then object.Parent = Workspace.Plot.PlotObjects end
end)
This post is meant for anyone who is just now finding this topic. Hopefully it will help you!