How to load NPCs individually in clients?

I assume the title isn’t very self-explanatory so I’ll give a brief explanation of what I’m trying to achieve.

In my game, I need a system where parts are loaded inside a specific building only when the player walks in, and are seen by only the player who entered. This is needed to make sure too many models do not lag players when they aren’t seeing/interacting with them. The nearest example to this I see in any game is Restaurant Tycoon 2, where NPCs are loaded only when a player walks inside someone’s restaurant (the players inside the building can see them, while other players can’t).

I know that I’ll need to use localscripts and remote events to some extent, but I can’t build a framework for the scripts or the system itself and I can’t find a relevant devforum post either.

Would someone explain to me how this can be done?

Maybe what you could do is have the server handle the NPCs so that they are handled equally on every player in terms of what they are doing/their locations, but when a player LEAVES the building a local script moves the NPCs to ReplicatedStorage or something. Then when the player returns, you can move the NPCs back to the workspace locally, and then invoke the server to get necessary information on NPCs such as where they should be (I assume they are moving NPCs, so you want them to be put into the correct position when the player enters the building).

@roblox_user_54556995 Is this what you’re talking about?

Code inside a script inside building:

-- Code detecting whether player  is inside the building or not
-- A player has entered the building
FireRemote (player)

Code inside localscript that fires when the remote event is fired:

local objects = game.ReplicatedSotrage.Objects:Clone
objects.Parent = game.Workspace

I’ve tried to create a system based on what you suggested but I got stuck on the part where the server tells the localscript to fire the code. I’m sure there’s a way around this but I can’t find it cuz I’m not adept at using remotes. What would be a good solution?

Hello, I have had to do similar things where I had to duplicate something to the client, and I have a basic script(s) that I can give to you. It is not complete, but is easy to improve. All you need to do is the following:

Create a remote event in ReplicatedStorage called “CSRBridge”
Pretty simple. You can change the name, but you must also change the name in the scripts.

Put the following code in a localscript called “CSRReceiver”
Put this in local player scripts. This changes everything on the client

-- Services
local Players = game:GetService("Players");
local ReplicatedStorage = game:GetService("ReplicatedStorage");

-- Remotes
local CSRBridge = ReplicatedStorage:WaitForChild("CSRBridge");

-- Variables
local localPlayer = Players.LocalPlayer;

-- Events
CSRBridge.OnClientEvent:Connect(function(_variation, ...)
	local xArgs = {...};
	
	if(_variation == "DUPLICATE") then
		local object = xArgs[1];
		local name = xArgs[2] or object.Name;
		local parent = xArgs[3] or object.Parent;
		
		local clientObject = object:Clone();
			clientObject.Name = name;
			clientObject.Parent = parent;
	
	elseif(_variation == "PROPERTY") then
		local object = xArgs[1];
		local propertyName = xArgs[2];
		local newValue = xArgs[3];
	
		object[propertyName] = newValue;	
		
	end
	
end)

Use this module script to easily communicate with the client. Use this on a server script
This module script abstracts the local script and allows you to easily work with little risk of error

-- Services
local ReplicatedStorage = game:GetService("ReplicatedStorage");

-- Remotes
local CSRBridge = ReplicatedStorage:WaitForChild("CSRBridge");

-- Variables
local replicator = {};
local mt = {__index = replicator};

-- Events
function replicator.new(_player) -- Create a new replicator instance
	local self = setmetatable(replicator, mt);
		self.player = _player;
	
	return self;
	
end

function replicator:Duplicate(_object, _name, _parent) -- Duplicate the object on the client
	CSRBridge:FireClient(self.player, "DUPLICATE", _object, _name, _parent);
	
end

function replicator:ChangeProperty(_object, _propertyName, _newValue)
	CSRBridge:FireClient(self.player, "PROPERTY", _object, _propertyName, _newValue);
	
end

return replicator; -- Return

Hopefully I understood what you needed to do, and that this helps. Obviously this only a basic template, but is easily expandable. Feel free to edit it

Edit:
In the case you don’t understand how to use it, here is an example server script that uses the module script. It should show the syntax of the module

-- Services
local Players = game:GetService("Players");

-- Modules
local ClientSideReplicator = require(script.ClientSideReplicator);

-- Variables
local testPart = script.ref.Value;
local dump = script.dump.Value;

-- Events
Players.PlayerAdded:Connect(function(_localPlayer)
	local csr = ClientSideReplicator.new(_localPlayer);
	
	csr:ChangeProperty(testPart, "Transparency", 0.5);
	csr:Duplicate(testPart, "Did it work?", dump);
	
end)

2 Likes

@SuchASaltyLemon TY (Post must be at least 30 chars)

1 Like