Injecting LocalScript into clients from server

I feel this topic is fuzzy and although I found many related questions with answers such as this and this, I still don’t have a good grasp on how to pull this off. So in the interest of keeping my sanity, here is my attempt at formulating a set of questions that pinpoint exactly how I can write a server script that will inject code to be run on the clients.

So my attemt at a preise problem formulation:

Given a Script called game.ServerScriptService.MyScript containing the following code:

print("Server running")
local function injectLocalScript(player:Player, localScript:LocalScript)
	-- TODO: What should I put here to inject the local script into the player?
end

local localScript = game.ServerStorage:FindFirstChild("MyLocalScript")

game.Players.PlayerAdded:Connect(function(player:Player)
	injectLocalScript(player, localScript)
end)

and given a LocalScript called game.ServerStorage.MyLocalScript containing the following code:

print(script:GetFullName(), "successfully injected to client")

while true do
	task.wait(1)
	print("client injected script still here")
end

I want to know what statements should I put in injectLocalScript() function so that a copy of MyLocalScript is inserted into every player at the point when they join the game and run uninterrupted until they leave.

I almost made this work by inserting it into the character of the player, but the problem is then the script is removed every time the player dies.

NOTES:

I know I can put stuff into game.StarterPlayer.StarterPlayerScripts to accomplish this but I have good reasons for avoiding this mechanism. For one I want my script to be self contained and portable as a package.

1 Like

You can parent it to player.PlayerScripts and it will stay there until player leaves the game

1 Like

To inject a LocalScript into the player when they join the game, you can use the Player/LoadLocalScript() function. The code in injectLocalScript() should look like this:

local function injectLocalScript(player:Player, localScript:LocalScript)
   player:LoadLocalScript(localScript)
end

This will cause a copy of the LocalScript to be inserted into the player’s character, which will start running immediately and persist until the player leaves the game.

Do you have a reference to this method? I don’t see it documented anywhere.

2 Likes

My question to you is… why? Injecting local scripts creates unnecessary steps and can create more problems than it solves.

If this is about Dex or related method on preventing localscripts bring spoofed by saveinstance() then it wouldnt work, clients can still read objects inserted on other players. But if you really wanna do it, here it is.

print("Server running")
local function injectLocalScript(player:Player, localScript:LocalScript)   
      local __LS = localscript:Clone()
      __LS.Parent = player.PlayerScripts.StarterPlayerScripts -- IDK
end

local localScript = game.ServerStorage:FindFirstChild("MyLocalScript")

game.Players.PlayerAdded:Connect(function(player:Player)
	injectLocalScript(player, localScript)
end)

This is not the solution to whatever you need this for. There’s no reason to not use StarterPlayerScripts. If this is to combat dex, then you are taking the wrong approach.

They can also use FireClient(), if it’s about specific players, but i highly doubt it’ll do much. That is if you fired the event to ANY Player, meaning the dex user can still spoof your script regardless.

So, I’m assuming you want to place the LocalScript into the player but have it execute too. I made a script for BaseAdmin’s LocalDeploy feature, which allows a command to be “deployed” to the client.

However, there’s no point of listing that script here since for the most part the code isn’t relevant except for this line here:

cmdmod.Parent = plr.Backpack

This line will parent the script to the player’s backpack, where it will run.


PlayerScripts, a member of Player, does not exist on the server, which brings me to my next thought:

--Add to localscript, this *might* actually work!
local player = game.Players.LocalPlayer
if script.Parent ~= player.PlayerScripts then script.Parent = player.PlayerScripts end

The question remains, why? Why would you put the effort for parenting this local script into the player’s backpack and doing all this work?

It sounds like you’re trying to make SoundService:PlayLocalSound for local scripts. StarterPlayerScripts exists and RemoteEvent exists.

Additionally, with the release of RunContext, you will be able to perform the action which is centered around the point you made here:


I have tested this before, it seemed to work, but it also appears you can parent the LocalScript to StarterCharacterScripts in a Script. If this works for StarterCharacterScripts, it might also work for StarterPlayerScripts.

1 Like

Unfortunately player.PlayerScripts is only accessible from the client, trying to parent my local script there from the server fails.

That is a fair question. The answer is that I have an NPC system that I use in a lot of my games. I want to drop in as few files as possible, having it be a stand alone piece of code. The way it works now, I need two components, one is running on the server side and one should be put into each player on join and run there until the player leaves. The communications between the two parts is all events etc.

If having to install the NPC system consists of copying a bunch of files to the correct folders, it becomes a hazzle to maintain. When there is a new version I have to remember all the little bits and what folders they go into.

I solved this by making one “main” module that has the components as children. I drop that into the right place and then the npc system should work.

I disagree, I definitely have a reason to avoid StarterPlayerScripts. For one, the script has to be in that folder BEFORE the player joins the game, but really I don’t know if I want the script on the player until a certain point in time.

But if I add it at a certain point in time, it will only be put on players that join after that time, the already joined players will not receive it.

So then I could make a “loader script” that is tasked with taking events and loading other scripts on command. But that just becomes a mess, and I still need to remember to put something under StarterPlayerScripts for it to work. In other words my code will be spread all over the place and will be unecessarily complex.

This will put it in StarterPlayerScripts, which means the script wlil not run on current clients, right? Only players that join AFTER this will work, which kind of defeats the purpose.

Can’t you solve this with the usage of packages?


That aside, your code should be centered around script instances, nor should the script instances themselves be located in weird places (such as anywhere in workspace, including characters or models). A lot of your code should be in modules and scripts should simply be running those modules.

When you modularize your code, you can decide what modules/methods would even run to begin with, removing the need to create odd script replication behaviors.

I read up on the RunContext stuff you mentioned and tried it out. It worked just like that™!

For whomever wants to know how this works, here is a short summary:

  1. Create a normal Script (not a LocalScript) called MyLocalScript. It does not matter where it is parented, as long as it is accessible from your main server script.
  2. Set the RunContext property of MyLocalScript to Client and the Enabled to false in the Roblox Studio Property editor.
  3. From your main Script, when you feel like running MyLocalScript for a player, clone it and parent the clone to anywhere inside the player and set Enabled = true on the clone.
  4. At this pointMyLocalScript will run like a normal LocalScript would for that player, and it will run until the player exits.

Important notes:

  1. It needs to be a normal Script and not a LocalScript. By setting the RunContext to “Client” it stops behaving like a server side script and starts working like a LocalScript.
  2. It will NOT play nice with the “starter folders”, so please don’t try to put it in places like StarterPlayerScripts etc. (it might be started twice which creates trouble).
  3. The script will not really be copied, but rather the bytecode compiled on the server will be streamed to the client which actually provides some extra security/elegance/speed benefits.

For more details please see this article, this property reference and this enum reference.

Just to be clear, RunContext isn’t released in live games yet but it works in studio.

1 Like

Thanks for the heads’up. I guess I will have to launch later

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.