-- // VARIABLES // -- -- | Services | -- local CollectionService = game:GetService("CollectionService") local RunService = game:GetService("RunService") local Players = game:GetService("Players") -- | Forward Declarations & Module Table | -- local Core = {} local Utilities: {DELETED_MARKER: {}} -- | Internal Configuration Constants | -- local REMOTE_FOLDER_NAME = "DataReplicator_InternalRemotes" local UPDATE_EVENT_NAME = "DR_Internal_Update" local REQUEST_FUNC_NAME = "DR_Internal_Request" local PENDING_BATCH_TAG = "DataReplicator_PendingBatch" -- | Remote Instances | -- local internalUpdateEvent: RemoteEvent local internalRequestFunc: RemoteFunction -- // SERVER-SIDE IMPLEMENTATION // -- if RunService:IsServer() then -- | Security Configuration Constants | -- local REQUIRE_AUTHORIZATION_CALLBACK = false local RATE_LIMIT_MAX_REQUESTS_IN_WINDOW = 100 local RATE_LIMIT_WINDOW_SECONDS = 60 local RATE_LIMIT_SUB_WINDOWS_COUNT = 6 -- | Primary Data Storage on Server | -- local replicatedDataStore: { [string]: any } = {} -- | Mapping for Client Listeners & Obfuscation | -- local clientKeyMaps: { [Player]: { [string]: string } } = {} local clientRealToObfuscated: { [Player]: { [string]: string } } = {} -- | Callback for Client Access Authorization | -- local authorizationCallback: ((player: Player, realKey: string) -> boolean)? = nil -- | Rate Limiting Tracker | -- local playerRequestTracker: { [Player]: { [number]: number } } = {} local SUB_WINDOW_DURATION = RATE_LIMIT_WINDOW_SECONDS / RATE_LIMIT_SUB_WINDOWS_COUNT -- | Batching System Variables | -- local playerUpdateBatchQueue: { [Player]: { [string]: any } } = {} local isBatchProcessingScheduled = false -- // FUNCTIONS // -- local function getOrCreateObfuscatedKey(player: Player, realKey: string): string if not clientRealToObfuscated[player] then clientRealToObfuscated[player] = {} clientKeyMaps[player] = {} end local existingObfuscatedKey = clientRealToObfuscated[player][realKey] if existingObfuscatedKey then return existingObfuscatedKey end local newObfuscatedKey = Utilities.GenerateObfuscatedKey() while clientKeyMaps[player][newObfuscatedKey] do newObfuscatedKey = Utilities.GenerateObfuscatedKey() end clientKeyMaps[player][newObfuscatedKey] = realKey clientRealToObfuscated[player][realKey] = newObfuscatedKey return newObfuscatedKey end local function checkAndUpdateRateLimit(player: Player): boolean local currentTime = tick() if not playerRequestTracker[player] then playerRequestTracker[player] = {} end local playerLogs = playerRequestTracker[player] local oldestValidSubWindowTime = currentTime - RATE_LIMIT_WINDOW_SECONDS for subWindowTimestamp, _ in pairs(playerLogs) do if subWindowTimestamp < oldestValidSubWindowTime then playerLogs[subWindowTimestamp] = nil end end local currentRequestsInWindow = 0 for _, count in pairs(playerLogs) do currentRequestsInWindow += count end if currentRequestsInWindow >= RATE_LIMIT_MAX_REQUESTS_IN_WINDOW then return false end local currentSubWindowKey = math.floor(currentTime / SUB_WINDOW_DURATION) * SUB_WINDOW_DURATION playerLogs[currentSubWindowKey] = (playerLogs[currentSubWindowKey] or 0) + 1 return true end local function addToPlayerBatch(player: Player, obfuscatedKey: string, data: any) if not playerUpdateBatchQueue[player] then playerUpdateBatchQueue[player] = {} end playerUpdateBatchQueue[player][obfuscatedKey] = data if not CollectionService:HasTag(player, PENDING_BATCH_TAG) then CollectionService:AddTag(player, PENDING_BATCH_TAG) end if not isBatchProcessingScheduled then isBatchProcessingScheduled = true task.defer(function() isBatchProcessingScheduled = false local playersWithPendingBatches = CollectionService:GetTagged(PENDING_BATCH_TAG) for _, p in ipairs(playersWithPendingBatches) do if typeof(p) == "Instance" and p:IsA("Player") and playerUpdateBatchQueue[p] then local batchToSend = playerUpdateBatchQueue[p] playerUpdateBatchQueue[p] = nil CollectionService:RemoveTag(p, PENDING_BATCH_TAG) if next(batchToSend) then internalUpdateEvent:FireClient(p, batchToSend, nil, "batch_update") end end end end) end end function Core.SetAuthorizationCallback(callback: ((player: Player, realKey: string) -> boolean)?) if callback == nil then authorizationCallback = nil elseif typeof(callback) == "function" then authorizationCallback = callback else warn("[DataReplicator | Core | SetAuthorizationCallback] Failed - Provided value is not a function or nil.") end end function Core.Create(realKey: string, data: any): boolean if typeof(realKey) ~= "string" or realKey == "" or replicatedDataStore[realKey] ~= nil then warn(`[DataReplicator | Core | Create] Failed - Invalid or duplicate key: '{realKey}'`) return false end replicatedDataStore[realKey] = data return true end function Core.Update(realKey: string, data: any, target: Player | {Player} | "All" | "AllExcept" | nil, exceptTarget: Player | {Player} | nil): boolean if typeof(realKey) ~= "string" or realKey == "" or replicatedDataStore[realKey] == nil then warn(`[DataReplicator | Core | Update] Failed - Key not found or invalid: '{realKey}'`) return false end replicatedDataStore[realKey] = data local targetPlayers: { Player } = {} local targetType = typeof(target) if target == nil then for player, realToObfuscatedMap in pairs(clientRealToObfuscated) do if realToObfuscatedMap[realKey] and player.Parent then table.insert(targetPlayers, player) end end elseif targetType == "Instance" and target:IsA("Player") then if target.Parent and clientRealToObfuscated[target :: Player] and clientRealToObfuscated[target :: Player][realKey] then table.insert(targetPlayers, target :: Player) end elseif targetType == "string" and target == "All" then for _, player in ipairs(Players:GetPlayers()) do if clientRealToObfuscated[player] and clientRealToObfuscated[player][realKey] then table.insert(targetPlayers, player) end end elseif targetType == "string" and target == "AllExcept" then local exclusions = {} local exceptType = typeof(exceptTarget) if exceptType == "Instance" and exceptTarget:IsA("Player") then exclusions[exceptTarget :: Player] = true elseif exceptType == "table" then for _, p in ipairs(exceptTarget :: { Player }) do if typeof(p) == "Instance" and p:IsA("Player") then exclusions[p] = true end end end for _, player in ipairs(Players:GetPlayers()) do if not exclusions[player] and clientRealToObfuscated[player] and clientRealToObfuscated[player][realKey] then table.insert(targetPlayers, player) end end elseif targetType == "table" then for _, player in ipairs(target :: { Player }) do if typeof(player) == "Instance" and player:IsA("Player") and player.Parent then if clientRealToObfuscated[player] and clientRealToObfuscated[player][realKey] then table.insert(targetPlayers, player) end end end else warn(`[DataReplicator | Core | Update] Invalid target type for key '{realKey}': {targetType}`) return true end if #targetPlayers > 0 then for _, player in ipairs(targetPlayers) do if player.Parent and clientRealToObfuscated[player] and clientRealToObfuscated[player][realKey] then local obfuscatedKey = clientRealToObfuscated[player][realKey] addToPlayerBatch(player, obfuscatedKey, data) end end end return true end function Core.Delete(realKey: string): boolean if typeof(realKey) ~= "string" or realKey == "" or replicatedDataStore[realKey] == nil then warn(`[DataReplicator | Core | Delete] Failed - Key not found or invalid: '{realKey}'`) return false end replicatedDataStore[realKey] = nil for player, realToObfuscatedMap in pairs(clientRealToObfuscated) do local obfuscatedKey = realToObfuscatedMap[realKey] if obfuscatedKey then if player.Parent then addToPlayerBatch(player, obfuscatedKey, Utilities.DELETED_MARKER) end local obfuscatedToRealMap = clientKeyMaps[player] if obfuscatedToRealMap then obfuscatedToRealMap[obfuscatedKey] = nil end realToObfuscatedMap[realKey] = nil end end return true end function Core.GetServerData(realKey: string): any | nil if typeof(realKey) ~= "string" then warn(`[DataReplicator | Core | GetServerData] Failed - Invalid key type: {typeof(realKey)}`) return nil end return replicatedDataStore[realKey] end local function handleServerInvoke(player: Player, action: string, realKey: string) -- / Rate Limiting / -- if not checkAndUpdateRateLimit(player) then warn(`[DataReplicator | Core | RateLimit] Player {player.Name} exceeded rate limit ({RATE_LIMIT_MAX_REQUESTS_IN_WINDOW} reqs in {RATE_LIMIT_WINDOW_SECONDS}s). Action: {action}, Key: {realKey}`) return nil end if typeof(realKey) ~= "string" or realKey == "" then warn(`[DataReplicator | Core | OnServerInvoke] Received invalid realKey '{realKey}' from {player.Name} (Action: {action})`) return nil end -- / Authorization and Action Handling / -- if action == "request_listen" or action == "request_data" then local isAuthorized = false if authorizationCallback then local successAuth, resultAuth = pcall(authorizationCallback, player, realKey) if successAuth then isAuthorized = resultAuth else warn(`[DataReplicator | Core | OnServerInvoke] Authorization callback errored for player {player.Name}, key '{realKey}': {resultAuth}. Denying access.`) isAuthorized = false end else if REQUIRE_AUTHORIZATION_CALLBACK then warn(`[DataReplicator | Core | OnServerInvoke] DENIED: Access requires an authorization callback for key '{realKey}', but none is set. Player: {player.Name}.`) isAuthorized = false else isAuthorized = true end end if not isAuthorized then return nil end local data = replicatedDataStore[realKey] if data == nil and action == "request_data" then return nil end local obfuscatedKey = getOrCreateObfuscatedKey(player, realKey) if action == "request_listen" then if data ~= nil then task.spawn(internalUpdateEvent.FireClient, internalUpdateEvent, player, obfuscatedKey, data, "update") else task.spawn(internalUpdateEvent.FireClient, internalUpdateEvent, player, obfuscatedKey, nil, "delete") end return obfuscatedKey elseif action == "request_data" then return { ObfuscatedKey = obfuscatedKey, Data = data } end return nil elseif action == "stop_listening" then if clientRealToObfuscated[player] then local obfuscatedKey = clientRealToObfuscated[player][realKey] if obfuscatedKey then local obfuscatedToRealMap = clientKeyMaps[player] if obfuscatedToRealMap then obfuscatedToRealMap[obfuscatedKey] = nil end clientRealToObfuscated[player][realKey] = nil end end return true else warn(`[DataReplicator | Core | OnServerInvoke] Received unknown action '{action}' for key '{realKey}' from {player.Name}`) return nil end end local function onPlayerRemoving(player: Player) if clientKeyMaps[player] then clientKeyMaps[player] = nil end if clientRealToObfuscated[player] then clientRealToObfuscated[player] = nil end if playerRequestTracker[player] then playerRequestTracker[player] = nil end if playerUpdateBatchQueue[player] then playerUpdateBatchQueue[player] = nil end if CollectionService:HasTag(player, PENDING_BATCH_TAG) then CollectionService:RemoveTag(player, PENDING_BATCH_TAG) end end Core.ServerInit = function() internalRequestFunc.OnServerInvoke = handleServerInvoke Players.PlayerRemoving:Connect(onPlayerRemoving) end -- // CLIENT-SIDE IMPLEMENTATION // -- elseif RunService:IsClient() then -- | Data Cache Storage on Client | -- local localDataCache: { [string]: any } = {} -- | Signal for Local Notifications | -- local updateSignals: { [string]: BindableEvent } = {} -- | Active and Pending Mappings in Client | -- local activeListeners: { [string]: string } = {} local pendingSignals: { [string]: BindableEvent } = {} -- // FUNCTIONS // -- function Core.Request(realKey: string): any | nil if typeof(realKey) ~= "string" or realKey == "" then warn(`[DataReplicator | Core | Request] Invalid realKey provided: '{realKey}'`) return nil end local responseData: { ObfuscatedKey: string, Data: any } | nil local success, result = pcall(function() responseData = internalRequestFunc:InvokeServer("request_data", realKey) end) if not success then warn(`[DataReplicator | Core | Request] InvokeServer failed for '{realKey}': {result}`) return nil end if responseData and typeof(responseData) == "table" and typeof(responseData.ObfuscatedKey) == "string" and responseData.Data ~= nil then local obsKey = responseData.ObfuscatedKey local data = responseData.Data localDataCache[obsKey] = data activeListeners[realKey] = obsKey return data else return nil end end function Core.GetCached(realKey: string): any | nil if typeof(realKey) ~= "string" then return nil end local obfuscatedKey = activeListeners[realKey] return if obfuscatedKey then localDataCache[obfuscatedKey] else nil end function Core.WaitForData(realKey: string, timeout: number?): (any?, boolean) if typeof(realKey) ~= "string" or realKey == "" then warn(`[DataReplicator | Core | WaitForData] Invalid realKey provided: '{realKey}'`) return nil, false end local cachedData = Core.GetCached(realKey) if cachedData ~= nil then return cachedData, true end local timeoutDuration = if typeof(timeout) == "number" and timeout > 0 then timeout else 5 local receivedData: any = nil local didSucceed = false local didTimeout = false local eventConnection: RBXScriptConnection = nil local signalToWaitOn = Core.Listen(realKey) local function onDataReceivedFromSignal(newData: any) if not didSucceed and not didTimeout then receivedData = newData didSucceed = true end end if signalToWaitOn and typeof(signalToWaitOn.Event) == "RBXScriptSignal" then eventConnection = signalToWaitOn.Event:Connect(onDataReceivedFromSignal) end local startTime = os.clock() while not didSucceed and not didTimeout do if (os.clock() - startTime) >= timeoutDuration then didTimeout = true end if not didSucceed then cachedData = Core.GetCached(realKey) if cachedData ~= nil then receivedData = cachedData didSucceed = true end end if not didSucceed and not didTimeout then RunService.Heartbeat:Wait() end end if eventConnection then eventConnection:Disconnect() eventConnection = nil end if didSucceed then return receivedData, true else return nil, false end end function Core.Listen(realKey: string): BindableEvent if typeof(realKey) ~= "string" or realKey == "" then warn(`[DataReplicator | Core | Listen] Invalid realKey provided: '{realKey}'`) local dummySignal = Instance.new("BindableEvent") task.defer(dummySignal.Destroy, dummySignal) return dummySignal end local existingObfuscatedKey = activeListeners[realKey] if existingObfuscatedKey and updateSignals[existingObfuscatedKey] then local signal = updateSignals[existingObfuscatedKey] local cachedData = localDataCache[existingObfuscatedKey] if cachedData ~= nil then task.spawn(signal.Fire, signal, cachedData) end return signal end if pendingSignals[realKey] then return pendingSignals[realKey] end local newSignal = Instance.new("BindableEvent") pendingSignals[realKey] = newSignal task.spawn(function() local returnedObfuscatedKey: string? local success, result = pcall(function() returnedObfuscatedKey = internalRequestFunc:InvokeServer("request_listen", realKey) end) local currentSignalForRealKey = pendingSignals[realKey] or (activeListeners[realKey] and updateSignals[activeListeners[realKey]]) if success and typeof(returnedObfuscatedKey) == "string" and returnedObfuscatedKey ~= "" then activeListeners[realKey] = returnedObfuscatedKey if pendingSignals[realKey] == newSignal then if updateSignals[returnedObfuscatedKey] and updateSignals[returnedObfuscatedKey] ~= newSignal then updateSignals[returnedObfuscatedKey]:Destroy() end updateSignals[returnedObfuscatedKey] = newSignal pendingSignals[realKey] = nil elseif currentSignalForRealKey and currentSignalForRealKey ~= newSignal then newSignal:Destroy() end else warn(`[DataReplicator | Core | Listen] Failed to establish listener for '{realKey}': {result or returnedObfuscatedKey or "Unknown error"}`) if pendingSignals[realKey] == newSignal then pendingSignals[realKey] = nil end end end) return newSignal end function Core.StopListening(realKey: string) if typeof(realKey) ~= "string" or realKey == "" then return end local obfuscatedKey = activeListeners[realKey] activeListeners[realKey] = nil if pendingSignals[realKey] then pendingSignals[realKey]:Destroy() pendingSignals[realKey] = nil end if obfuscatedKey then if updateSignals[obfuscatedKey] then updateSignals[obfuscatedKey]:Destroy() updateSignals[obfuscatedKey] = nil end localDataCache[obfuscatedKey] = nil pcall(internalRequestFunc.InvokeServer, internalRequestFunc, "stop_listening", realKey) end end local function handleClientUpdate(batchOrObfuscatedKey: string | {[string]: any}, newDataOrNil: any, actionType: string) if actionType == "batch_update" then local batchData = batchOrObfuscatedKey :: {[string]: any} if typeof(batchData) ~= "table" then warn(`[DataReplicator | Core | OnClientEvent] Received invalid batch data type: {typeof(batchData)}`) return end for obfuscatedKeyInBatch, dataInBatch in pairs(batchData) do if typeof(obfuscatedKeyInBatch) ~= "string" then warn(`[DataReplicator | Core | OnClientEvent] Invalid obfuscatedKey in batch: {obfuscatedKeyInBatch}`) continue end local effectiveAction = if dataInBatch == Utilities.DELETED_MARKER then "delete" else "update" local effectiveData = if effectiveAction == "delete" then nil else dataInBatch local targetSignal = updateSignals[obfuscatedKeyInBatch] if not targetSignal then for rKey, sig in pairs(pendingSignals) do if activeListeners[rKey] == obfuscatedKeyInBatch then targetSignal = sig updateSignals[obfuscatedKeyInBatch] = targetSignal pendingSignals[rKey] = nil; break end end end if not targetSignal then if effectiveAction == "update" then localDataCache[obfuscatedKeyInBatch] = effectiveData elseif effectiveAction == "delete" then localDataCache[obfuscatedKeyInBatch] = nil end continue end if effectiveAction == "update" then localDataCache[obfuscatedKeyInBatch] = effectiveData task.spawn(targetSignal.Fire, targetSignal, effectiveData) elseif effectiveAction == "delete" then localDataCache[obfuscatedKeyInBatch] = nil task.spawn(targetSignal.Fire, targetSignal, nil) for rk, obk in pairs(activeListeners) do if obk == obfuscatedKeyInBatch then activeListeners[rk] = nil end end if updateSignals[obfuscatedKeyInBatch] == targetSignal then updateSignals[obfuscatedKeyInBatch]:Destroy() updateSignals[obfuscatedKeyInBatch] = nil end end end elseif actionType == "update" or actionType == "delete" then local obfuscatedKey = batchOrObfuscatedKey :: string local newData = newDataOrNil if typeof(obfuscatedKey) ~= "string" then return end local targetSignal = updateSignals[obfuscatedKey] if not targetSignal then for rk, pendingSignal in pairs(pendingSignals) do if activeListeners[rk] == obfuscatedKey then targetSignal = pendingSignal updateSignals[obfuscatedKey] = targetSignal pendingSignals[rk] = nil; break end end end if not targetSignal then if actionType == "update" then localDataCache[obfuscatedKey] = newData elseif actionType == "delete" then localDataCache[obfuscatedKey] = nil end return end if actionType == "update" then localDataCache[obfuscatedKey] = newData task.spawn(targetSignal.Fire, targetSignal, newData) elseif actionType == "delete" then localDataCache[obfuscatedKey] = nil task.spawn(targetSignal.Fire, targetSignal, nil) for rk, obk in pairs(activeListeners) do if obk == obfuscatedKey then activeListeners[rk] = nil end end if updateSignals[obfuscatedKey] == targetSignal then updateSignals[obfuscatedKey]:Destroy() updateSignals[obfuscatedKey] = nil end end else warn(`[DataReplicator | Core | OnClientEvent] Received unknown action type '{actionType}' for ObsKey '{batchOrObfuscatedKey :: string}'`) end end Core.ClientInit = function() internalUpdateEvent.OnClientEvent:Connect(handleClientUpdate) end end -- // INITIALIZATION // -- function Core.Init(utils: {}, mainScriptInstance: Instance) Utilities = utils if RunService:IsServer() then local remoteFolder = Utilities.GetOrCreateRemote(mainScriptInstance, "Folder", REMOTE_FOLDER_NAME) internalUpdateEvent = Utilities.GetOrCreateRemote(remoteFolder, "RemoteEvent", UPDATE_EVENT_NAME) :: RemoteEvent internalRequestFunc = Utilities.GetOrCreateRemote(remoteFolder, "RemoteFunction", REQUEST_FUNC_NAME) :: RemoteFunction Core.ServerInit() elseif RunService:IsClient() then local remoteFolder = mainScriptInstance:WaitForChild(REMOTE_FOLDER_NAME, 20) if not remoteFolder then error("[DataReplicator | Core | Init] Failed to find Remote Folder under Init.lua after 20 seconds.") end local eventChild = remoteFolder:WaitForChild(UPDATE_EVENT_NAME, 15) if not eventChild then error(`[DataReplicator | Core | Init] Failed to find RemoteEvent '{UPDATE_EVENT_NAME}' after 15 seconds.`) end internalUpdateEvent = eventChild :: RemoteEvent local funcChild = remoteFolder:WaitForChild(REQUEST_FUNC_NAME, 15) if not funcChild then error(`[DataReplicator | Core | Init] Failed to find RemoteFunction '{REQUEST_FUNC_NAME}' after 15 seconds.`) end internalRequestFunc = funcChild :: RemoteFunction Core.ClientInit() end end return Core