RemoteInstance: Manage players' instances from server

RemoteInstance

Get it on Roblox!
RemoteInstance is a module that can help you manage your players' instances from server easily. You can create/modify client instances from server without manually creating RemoteEvents/Functions.

Without RemoteInstance you have to manually setup all the events:

-- Server
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local createPart = ReplicatedStorage.CreatePartEvent

Players.PlayerAdded:Connect(function(player)
    createPart.FirePlayer(player, Color3.new(1, 0, 0), "MyPart")
end

-- Client
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local createPart = ReplicatedStorage.CreatePartEvent

createPart.OnClientEvent:Connect(function(color, name)
    local part = Instance.new("Part")
    part.Name = name
    part.Color3 = color
    part.Parent = workspace
end)

With RemoteInstance you just have to require the module:

-- Server
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local RemoteInstance = require(ReplicatedStorage.RemoteInstance)

Players.PlayerAdded:Connect(function(player)
    local part = RemoteInstance.new("Part", player)
    part.Name = "MyPart"
    part.Color3 = Color3.new(1, 0, 0)
    part.Parent = workspace
end

-- Client
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local RemoteInstance = require(ReplicatedStorage.RemoteInstance)

Do you think you could post the source code within a github. Also what about tweens and animations.

3 Likes
local RemoteInstance = {}

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

local createEvent = script.CreateEvent
local createFunction = script.CreateFunction
local createInstance = script.CreateInstance
local get = script.Get
local set = script.Set

if RunService:IsServer() then
	if not _G.RemoteInstance then
		_G.RemoteInstance = {}
	end
	
	local moduleData = _G.RemoteInstance
	local isInitialized = moduleData.isInitialized
	
	if not moduleData.isInitialized then
		moduleData.isInitialized = true
	end
	
	if not moduleData.private then
		moduleData.private = {}
	end
	
	RemoteInstance.__index = RemoteInstance
	
	function RemoteInstance.new(className: string, player: Player)
		local self = setmetatable({}, RemoteInstance)
		moduleData.private[self] = {
			instanceId = createInstance:InvokeClient(player, className),
			player = player
		}
		return self
	end

	function RemoteInstance:get(index)
		local data = get:InvokeClient(moduleData.private[self].player, moduleData.private[self].instanceId, index)
		if data.value then
			return data.value
		elseif data.remoteEvent then
			return data.remoteEvent.OnServerEvent
		elseif data.remoteFunction then
			return function(...)
				return data.remoteFunction:InvokeClient(moduleData.private[self].player, ...)
			end
		end
	end

	function RemoteInstance:__newindex(index, value)
		local data
		if moduleData.private[value] then
			data = { instanceId = moduleData.private[value].instanceId }
		else
			data = { value = value }
		end
		spawn(function()
			set:InvokeClient(moduleData.private[self].player, moduleData.private[self].instanceId, index, data)
		end)
	end
	
	if not isInitialized then
		function createEvent.OnServerInvoke()
			return Instance.new("RemoteEvent", ReplicatedStorage)
		end
		
		function createFunction.OnServerInvoke()
			return Instance.new("RemoteFunction", ReplicatedStorage)
		end
	end

	export type RemoteInstance = typeof(RemoteInstance.new())
else
	local instances = {}
	
	function createInstance.OnClientInvoke(className)
		table.insert(instances, Instance.new(className))
		return #instances
	end
	
	function get.OnClientInvoke(instanceId, index)
		local instance = instances[instanceId]
		local value = instance[index]
		if typeof(value) == "RBXScriptSignal" then
			local remoteEvent = createEvent:InvokeServer()
			value:Connect(function()
				remoteEvent:FireServer()
			end)
			return { remoteEvent = remoteEvent }
		elseif typeof(value) == "function" then
			local remoteFunction = createFunction:InvokeServer()
			function remoteFunction.OnClientInvoke(...)
				value(instance, ...)
			end
			return { remoteFunction = remoteFunction }
		else
			return { value = value }
		end
	end
	
	function set.OnClientInvoke(instanceId, index, data)
		if data.value then
			instances[instanceId][index] = data.value
		elseif data.instanceId then
			instances[instanceId][index] = instances[data.instanceId]
		end
	end
end

return RemoteInstance

image

2 Likes

I think some clarification is necessary here. This module relies on RemoteFunctions to work, so pitching it as an alternative to RemoteEvents/Functions (how it comes off) isn’t accurate. I assume that what you mean to say is that developers can do server → client communication without manually configuring individual RemoteEvents/Functions - instead using this to help them do that. The phrasing makes it sound like this is a complete alternative.

1 Like

Ok, thank you. I will change the description.

I would tell the OP to remove _G usage for a reason

Why? Is it unsafe?

  1. race conditions, when you define a item, and it starts, race conditions is caused
  2. backdoors, it’s easier to put backdoors, but it has no preinstalled backdoors
  3. nothing else
1 Like