I am modifying a queueing module I found to use the Signal Module by sleitnick.
Before this, the script used bindable events instanced by the script and worked perfectly fine. I saw that HitboxClass used Signal and I wanted to be able to use that too (since it’s also way easier to work with plus i will be able to :Destroy() connections)
The script worked fine when using BindableEvents, but after using Signal.new() it throws a cyclic table error.
Something interesting to note is that roblox only throws the cyclic table error when I put the queue inside of a table. I was testing stuff out and found this out (My main system put a queue in a table for organization purposes lol)
My question now is, how can I prevent this? The obvious solution is to take the queue out of the table, but i would like to keep it inside the table lmao
Should I be using a different signal module? Anything will help. Thanks
Also I might publish the modified version when its finished but we’ll see ig
--uQueueService--
--Services--
local teleportService = game:GetService("TeleportService")
local runService = game:GetService("RunService")
local players = game:GetService("Players")
--Modules--
local Janitor = require(script:WaitForChild("Janitor"))
local Signal = require(script:WaitForChild("Signal"))
--Private--
export type QueueParams = {
MinimumPlayers: number,
MaximumPlayers: number,
PlaceId: number,
Countdown: number,
TeleportData:any
}
local newJanitor = Janitor.new()
local tpOptions = Instance.new("TeleportOptions")
tpOptions.ShouldReserveServer = true
local function teleportQueue(queue,placeId,tpData)
local success, err = pcall(function()
table.insert(tpData["PlayerAmt"],#queue)
tpOptions:SetTeleportData(tpData)
local result:TeleportAsyncResult = teleportService:TeleportAsync(placeId,queue,tpOptions)
return result.PrivateServerId
end)
if success then
return true
else
return false
end
end
local function getWholeNum(num)
if num % 10 == 0 then
return num / 10
end
end
--Public--
local methods = {}
function methods:AddPlayer(plr:Player)
local queued = self.queued
if plr then
if not table.find(queued,plr) then
if #queued < self.maxPlayers then
print("Inserting player..")
table.insert(queued,plr)
print(queued)
self.PlayerAdded:Fire(plr)
else
warn("Queue is full!","Amount of players queued:",#queued,"Maximum players:",self.maxPlayers)
end
else
warn("Player is already in queue!")
end
else
warn("Attempt to add player to queue but player was nil!")
end
end
function methods:RemovePlayer(plr)
local queued = self.queued
if plr then
local plrIndex = table.find(queued,plr)
if plrIndex and not self.finished then
table.remove(queued,plrIndex)
self.PlayerRemoved:Fire(plr)
end
else
warn("Attempt to remove player from queue but player was nil")
end
end
function methods:Teleport()
if self.placeId then
local success = teleportQueue(self.queued,self.placeId, self.tpData)
if not success then
warn("Players could not be teleported")
end
end
end
function methods:Destroy()
newJanitor:Cleanup()
setmetatable(self,nil)
table.clear(self)
end
function methods:Reset()
self.minPlayers = nil
self.maxPlayers = nil
self.placeId = nil
self.countdown = nil
self.tpData = nil
end
local QueueService = {}
function QueueService.new(queueParams:QueueParams)
local object = {
--Events--
PlayerAdded = Signal.new(),
PlayerRemoved = Signal.new(),
Initiated = Signal.new(),
CountTick = Signal.new(),
--Properties--
minPlayers = queueParams["MinimumPlayers"],
maxPlayers = queueParams["MaximumPlayers"],
placeId = queueParams["PlaceId"],
countdown = queueParams["Countdown"],
tpData = queueParams["TeleportData"],
ticking = false,
queued = {},
connections = {}
}
newJanitor:Add(object.PlayerAdded,"Destroy")
newJanitor:Add(object.PlayerRemoved,"Destroy")
newJanitor:Add(object.Initiated,"Destroy")
newJanitor:Add(object.CountTick,"Destroy")
if object.maxPlayers == nil then
object.maxPlayers = 999
end
if object.countdown == nil then
object.countdown = 5
end
assert(object.minPlayers,"Need to provide minimum amount of players!")
local left = players.PlayerRemoving:Connect(function(plr)
local index = table.find(object.queued,plr)
if index then
object.PlayerRemoved:Fire(plr)
table.remove(object.queued,index)
else
warn("Could not remove player from queue: Player not found in queue!")
end
end)
local heartbeat = runService.Heartbeat:Connect(function()
--print(#object.queued < object.minPlayers, #object.queued, object.minPlayers)
if #object.queued < object.minPlayers then
object.ticking = false
end
if #object.queued >= object.minPlayers and not object.ticking then
task.spawn(function()
object.ticking = true
print("firing tickStarted",object.ticking)
for i = object.countdown * 10,0,-1 do
wait(0.1)
--print(object.ticking,i)
if not object.ticking then break end
local num = getWholeNum(i)
if num then
object.CountTick:Fire(num)
end
end
if not object.ticking then return end
object.Initiated:Fire()
--print(object.placeId)
if runService:IsStudio() then
warn("Running Studio. Player will not be teleported")
else
if object.placeId then
teleportQueue(object.queued,object.placeId, object.tpData)
end
end
end)
end
end)
heartbeat = newJanitor:Add(heartbeat,"Disconnect")
left = newJanitor:Add(left,"Disconnect")
return setmetatable(object,{
__index = methods,
__tostring = function() return "Queue" end
})
end
return QueueService
-- A snippet of code in the main queueing system --
local QueueParams:QueueService.QueueParams = {
MinimumPlayers = params["Players"],
PlaceId = placeId,
TeleportData = {
Params = params
}
}
local newQueue = QueueService.new(QueueParams)
Queue = {
["Params"] = params,
["Queue"] = newQueue,
["Host"] = firstPlr,
}