Dodo12wScripts

Hidden Devs Scripter Application

Aug 2nd, 2025 (edited)
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.40 KB | Source Code | 0 0
  1. --[[
  2.     SignalNet
  3.     Version: 1.0.0
  4.     Author: dodo12w
  5.     License: MIT
  6.    
  7.     A robust signal messaging system built on top of Sleitnick's Signal module.
  8.     Provides named event and function-style signals with automatic queuing,
  9.     order-independent fire/connect behavior, and deferred call support.
  10. --]]
  11.  
  12.  
  13. local module = {}
  14.  
  15. --- Loaded Modules ---
  16.  
  17. -- Sleitnick's Signal Module
  18. local Signal = require(script.Signal)
  19.  
  20. --- Private Variables ---
  21.  
  22. --[[
  23. Signals[SignalName] = SignalTable
  24. ]]
  25.  
  26. -- Stores All Signal Tables
  27. local Signals = {}
  28. -- Stores names of function signals
  29. local FunctionSignals = {}
  30. -- Stores names of event signals
  31. local EventSignals = {}
  32.  
  33. --- Private Functions ---
  34.  
  35. -- Throws an error if using duplicate signal name
  36. local function assertSignalName(signalName)
  37.     if EventSignals[signalName] then
  38.         assert(false, "You have used : "..signalName.." as a signal event name already. Please use a different name.")
  39.     end
  40.     if FunctionSignals[signalName] then
  41.         assert(false, "You have used : "..signalName.." as a signal function name already. Please use a different name.")
  42.     end
  43. end
  44.  
  45. --[[
  46. Event Signal: {
  47.     ["Signal"] = Signal.new(), -- Signal that's fired to by :Fire() calls
  48.     ["Que"] = {}, -- Holds params to fire calls before connection. Example: {{...}, {...}, {...}}
  49. }
  50. ]]
  51.  
  52. --[[
  53. Returns event signal table
  54. ]]
  55.  
  56. -- Creates event signal table and tracks name
  57. local function newEventSignal(signalName)
  58.     assertSignalName(signalName)
  59.     EventSignals[signalName] = true
  60.     return {
  61.         ["Signal"] = Signal.new(),
  62.         ["Que"] = {},
  63.     }
  64. end
  65.  
  66. --[[
  67. Function Signal: {
  68.     ["Signal"] = Signal.new(), -- Signal that's waited on for by :Wait() calls
  69.     ["Signal_Receive"] = Signal.new(), -- Signal that's fired to by :Fire() calls
  70.     ["Que"] = {}, -- Holds params to fire calls before connection. Example: {{...}, {...}, {...}}
  71. }
  72. ]]
  73.  
  74. --[[
  75. Returns function signal table
  76. ]]
  77.  
  78. -- Creates function signal table and tracks name
  79. local function newFunctionSignal(signalName)
  80.     assertSignalName(signalName)
  81.     FunctionSignals[signalName] = true
  82.     return {
  83.         ["Signal"] = Signal.new(), -- Signal that's waited on for by :Wait() calls
  84.         ["Signal_Receive"] = Signal.new(), -- Signal that's fired to by :Fire() calls
  85.         ["Que"] = {}, -- Holds params to fire calls before connection. Example: {{...}, {...}, {...}}
  86.     }
  87. end
  88.  
  89. -- Fires the fire function inside of the parameters metatable
  90. local function fireQueuedCalls(signalName, Que)
  91.     for _, parameters in ipairs(Que) do
  92.         local metatable = getmetatable(parameters)
  93.         -- Metatable used in order to fire regardless of signal type (Event or Function and Regular or Deferred)
  94.         metatable.FireFunction(signalName, parameters)
  95.     end
  96. end
  97.  
  98. --- Public Functions ---
  99.  
  100. --[[
  101. Returns signal connection returned from Sleitnick's Signal:Connect()
  102. ]]
  103.  
  104. -- Creates function signal table if it doesn't exist, creates new connection, then fires any queued calls
  105. module.ConnectFunction = function(signalName, signalFunction)
  106.     if not Signals[signalName] then
  107.         Signals[signalName] = newFunctionSignal(signalName)
  108.     end
  109.  
  110.     local SignalReceive = Signals[signalName].Signal_Receive
  111.     local wasConnected = #SignalReceive:GetConnections() ~= 0
  112.  
  113.     local connection = SignalReceive:Connect(function(...)
  114.         Signals[signalName].Signal:Fire(signalFunction(table.unpack({...})))
  115.     end)
  116.  
  117.     if not wasConnected then
  118.         fireQueuedCalls(signalName, Signals[signalName].Que)
  119.     end
  120.  
  121.     return connection
  122. end
  123.  
  124. --[[
  125. Returns connected function results
  126. ]]
  127.  
  128. -- Creates event signal table if it doesn't exist, if no connection then add params to que, if signal table and connected then :Fire()
  129. module.FireFunction = function(signalName, ...)
  130.     -- Creates metatable that holds fire function to fire signal
  131.     local metatable = {
  132.         FireFunction = function(signalName, parameters)
  133.             -- Does not fire deferred because :Wait() already called
  134.             Signals[signalName].Signal_Receive:Fire(table.unpack(parameters))
  135.         end
  136.     }
  137.    
  138.     local parameters = setmetatable({...}, metatable)
  139.  
  140.     if not Signals[signalName] then
  141.         Signals[signalName] = newFunctionSignal(signalName)
  142.         table.insert(Signals[signalName].Que, parameters)
  143.     elseif #Signals[signalName].Signal_Receive:GetConnections() == 0 then
  144.         table.insert(Signals[signalName].Que, parameters)
  145.     else
  146.         -- By default this fires deferred in order to prevent a race condition with the :Wait()
  147.         Signals[signalName].Signal_Receive:FireDeferred(table.unpack(parameters))
  148.     end
  149.    
  150.     -- Returns unpacked results of the connected function received from :Wait()
  151.     return table.unpack({Signals[signalName].Signal:Wait()})
  152. end
  153.  
  154. --[[
  155. Returns signal connection returned from Sleitnick's Signal:Once()
  156. ]]
  157.  
  158. -- Creates function signal table if it doesn't exist, creates new connection, then fires any queued calls
  159. -- By using :Once() from sleitnick's module, this function will only fire once, and then disconnects itself
  160. module.ConnectOnceFunction = function(signalName, signalFunction)
  161.     if not Signals[signalName] then
  162.         Signals[signalName] = newFunctionSignal(signalName)
  163.     end
  164.  
  165.     local SignalReceive = Signals[signalName].Signal_Receive
  166.     local wasConnected = #SignalReceive:GetConnections() ~= 0
  167.  
  168.     local connection = SignalReceive:Once(function(...)
  169.         Signals[signalName].Signal:Fire(signalFunction(table.unpack({...})))
  170.     end)
  171.  
  172.     if not wasConnected then
  173.         fireQueuedCalls(signalName, Signals[signalName].Que)
  174.     end
  175.  
  176.     return connection
  177. end
  178.  
  179. --[[
  180. Returns signal connection returned from Sleitnick's Signal:Connect()
  181. ]]
  182.  
  183. -- Creates event signal table if it doesn't exist, creates new connection, then fires any queued calls
  184. module.ConnectEvent = function(signalName, signalFunction) 
  185.     if not Signals[signalName] then
  186.         Signals[signalName] = newEventSignal(signalName)
  187.     end
  188.  
  189.     local Signal = Signals[signalName].Signal
  190.     local wasConnected = #Signal:GetConnections() ~= 0
  191.  
  192.     local connection = Signal:Connect(signalFunction)
  193.  
  194.     if not wasConnected then
  195.         fireQueuedCalls(signalName, Signals[signalName].Que)
  196.     end
  197.  
  198.     return connection
  199. end
  200.  
  201. -- Creates event signal table if it doesn't exist, if no connection then add params to que, if signal table and connected then :Fire()
  202. module.FireEvent = function(signalName, ...)
  203.     -- Creates metatable that holds fire function to fire signal
  204.     local metatable = {
  205.         FireFunction = function(signalName, parameters)
  206.             Signals[signalName].Signal:Fire(table.unpack(parameters))
  207.         end
  208.     }
  209.  
  210.     local parameters = setmetatable({...}, metatable)
  211.  
  212.     if not Signals[signalName] then
  213.         Signals[signalName] = newEventSignal(signalName)
  214.         table.insert(Signals[signalName].Que, parameters)
  215.     elseif #Signals[signalName].Signal:GetConnections() == 0 then
  216.         table.insert(Signals[signalName].Que, parameters)
  217.     else
  218.         Signals[signalName].Signal:Fire(table.unpack(parameters))
  219.     end
  220. end
  221.  
  222. -- Creates event signal table if it doesn't exist, if no connection then add params to que, if signal table and connected then :FireDeferred()
  223. module.FireDeferredEvent = function(signalName, ...)
  224.     -- Creates metatable that holds fire function to fire signal
  225.     local metatable = {
  226.         FireFunction = function(signalName, parameters)
  227.             Signals[signalName].Signal:FireDeferred(table.unpack(parameters))
  228.         end
  229.     }
  230.  
  231.     local parameters = setmetatable({...}, metatable)
  232.  
  233.     if not Signals[signalName] then
  234.         Signals[signalName] = newEventSignal(signalName)
  235.         table.insert(Signals[signalName].Que, parameters)
  236.     elseif #Signals[signalName].Signal:GetConnections() == 0 then
  237.         table.insert(Signals[signalName].Que, parameters)
  238.     else
  239.         Signals[signalName].Signal:FireDeferred(table.unpack(parameters))
  240.     end
  241. end
  242.  
  243. --[[
  244. Returns signal connection returned from Sleitnick's Signal:Once()
  245. ]]
  246.  
  247. -- Creates event signal table if it doesn't exist, creates new connection, then fires any queued calls
  248. -- By using :Once() from sleitnick's module, this event will only fire once, and then disconnects itself
  249. module.ConnectOnceEvent = function(signalName, signalFunction) 
  250.     if not Signals[signalName] then
  251.         Signals[signalName] = newEventSignal(signalName)
  252.     end
  253.  
  254.     local Signal = Signals[signalName].Signal
  255.     local wasConnected = #Signal:GetConnections() ~= 0
  256.  
  257.     local connection = Signal:Once(signalFunction)
  258.  
  259.     if not wasConnected then
  260.         fireQueuedCalls(signalName, Signals[signalName].Que)
  261.     end
  262.  
  263.     return connection
  264. end
  265.  
  266. --[[
  267. Returns the arguments fired from the Signal
  268. ]]
  269.  
  270. -- Wrapper for Sleitnick's Signal:Wait()
  271. module.Wait = function(signalName)
  272.     if Signals[signalName] then
  273.         return Signals[signalName].Signal:Wait()
  274.     end
  275. end
  276.  
  277. --[[
  278. Returns a signal
  279. ]]
  280.  
  281. -- Wrapper for Sleitnick's Signal.Wrap()
  282. module.Wrap = function(event)
  283.     return Signal.Wrap(event)
  284. end
  285.  
  286. -- Disconnects all connections from the signal using Sleitnick's :DisconnectAll()
  287. module.DisconnectAll = function(signalName)
  288.     if Signals[signalName] then
  289.         if Signals[signalName].Signal_Receive then
  290.             Signals[signalName].Signal_Receive:DisconnectAll()
  291.         end
  292.         Signals[signalName].Signal:DisconnectAll()
  293.     end
  294. end
  295.  
  296. -- Destroy a signal using Sleitnick's :Destroy() and cleans up the signal table
  297. module.Destroy = function(signalName)
  298.     if Signals[signalName] then
  299.         if Signals[signalName].Signal_Receive then
  300.             Signals[signalName].Signal_Receive:Destroy()
  301.         end
  302.         Signals[signalName].Signal:Destroy()
  303.         Signals[signalName] = nil
  304.         EventSignals[signalName] = nil
  305.         FunctionSignals[signalName] = nil
  306.     end
  307. end
  308.  
  309. -- Returns a table of all connections from a signal using Sleitnick's :GetConnections()
  310. module.GetConnections = function(signalName)
  311.     local result = {}
  312.  
  313.     if Signals[signalName] then
  314.         if Signals[signalName].Signal_Receive then
  315.             result = Signals[signalName].Signal_Receive:GetConnections()
  316.         else
  317.             result = Signals[signalName].Signal:GetConnections()
  318.         end
  319.     end
  320.  
  321.     return result
  322. end
  323.  
  324. return module
  325.  
  326.  
  327. --------------------------------------------    CHEST HANDLER THAT USES MY SIGNAL MODULE ----------------------------------------- 
  328.  
  329. local module = {}
  330.  
  331. --- Services ---
  332.  
  333. local ReplicatedStorage = game:GetService("ReplicatedStorage")
  334. local ProximityPromptService = game:GetService("ProximityPromptService")
  335.  
  336. --- Modules ---
  337.  
  338. local Shared = require(ReplicatedStorage.Shared)
  339. local LootPlan = Shared.LootPlan
  340. local SignalNet = Shared.SignalNet
  341. local Remotes = Shared.Remotes
  342.  
  343. --- Events ---
  344.  
  345. -- Event to send new item to player
  346. local NewItemEvent = Remotes.Server:Get("NewItem")
  347.  
  348. --- Private Variables ---
  349.  
  350. -- Initialize chest rarity loot plan (single type)
  351. local ChestPlan = LootPlan.new("Single")
  352.  
  353. ChestPlan:AddLoot("Mythical", 0.01)
  354. ChestPlan:AddLoot("Legendary", 0.1)
  355. ChestPlan:AddLoot("Epic", 2.5)
  356. ChestPlan:AddLoot("Rare", 10)
  357. ChestPlan:AddLoot("Uncommon", 30)
  358. ChestPlan:AddLoot("Common", 57.39)
  359.  
  360. -- Cost of opening a chest
  361. local chestCost = 50
  362. -- Table to track player debounce times
  363. local playerTimes = {}
  364. -- Debounce time in seconds
  365. local chestDebounce = 2
  366.  
  367. -- Function to get a random accessory from that rarity folder
  368. local function getRandomAccessoryFromRarity(rarity)
  369.     local folder = ReplicatedStorage:WaitForChild("ChestAccessories"):FindFirstChild(rarity)
  370.     if not folder then return nil end
  371.  
  372.     local accessories = folder:GetChildren()
  373.     if #accessories == 0 then return nil end
  374.  
  375.     return accessories[math.random(1, #accessories)].Name
  376. end
  377.  
  378. -- Returns a random item and its rarity from a chest
  379. local function giveChestReward(player)
  380.     local rarity = ChestPlan:GetRandomLoot()
  381.     local item = getRandomAccessoryFromRarity(rarity)
  382.  
  383.     return item, rarity
  384. end
  385.  
  386. -- Function to check if player needs to wait for debounce
  387. local function needToWaitDebounce(player)
  388.     local currentTime = tick()
  389.    
  390.     if playerTimes[player] then
  391.         if currentTime - playerTimes[player] < chestDebounce then
  392.             return true
  393.         end
  394.     end
  395.    
  396.     playerTimes[player] = currentTime
  397.    
  398.     return false
  399. end
  400.  
  401. -- Rewards player with chest if they have enough coins and are outside of the debounce
  402. local function iceChestPromptTriggered(player)
  403.     local playerCoins = SignalNet.FireFunction("GetPlayerCoins", player)
  404.    
  405.     if playerCoins < chestCost or needToWaitDebounce(player) then return end
  406.    
  407.     local item, rarity = giveChestReward(player)
  408.    
  409.     SignalNet.FireEvent("IncrementPlayerCoins", player, -chestCost)
  410.    
  411.     SignalNet.FireEvent("AddItem", player, item)
  412.    
  413.     NewItemEvent:SendToPlayer(player, item, rarity)
  414. end
  415.  
  416. -- Connect function when ice chest prompt triggered
  417. ProximityPromptService.PromptTriggered:Connect(function(prompt, player)
  418.     if prompt:HasTag("IceChest") then
  419.         iceChestPromptTriggered(player)
  420.     end
  421. end)
  422.  
  423.  
  424. return module
  425.  
Advertisement
Add Comment
Please, Sign In to add comment