Help with tables and loops?

I’m thinking I would have to create some sort of loop and a table but I’m not 100% sure.

My situation:

Loading a specific StarterCharacter based on a StringValue.

I have a set of values in StarterPlayerScripts that control a number of configurations. One being that of a string value, the players “ShipType”. The ShipType is their Selected StarterCharacter in the game, their Spaceship.

In Replicated Storage I have a folder full of different ShipTypes each consisting of different properties and configuration values.

To simplify things I’ll use a ShipTemplate to show an example of the hierarchy below.

PlayerValues - Selected ShipType
image

Replicated Storage - Folder of different Ships
image

My overall goal is to load a specific Ship based on what the Player’s ShipType is.

How would I go about doing this? It’s easy to do it for just one default ship as I can just clone a specific object, but I’m having difficulty selecting an object based on another. I don’t quite understand loops or tables well enough just yet.

 
-- Called when the character is added
local function LoadCharacter(player)
	
	player:LoadCharacter()
	
	local character = player.Character
	
	print(character.Name, "has spawned")
	
	for i, v in pairs(character:GetChildren()) do
		if v:IsA("BaseScript") then
			v:Destroy()
		end
	end
	
	local rootPart = character:WaitForChild("HumanoidRootPart")
 
	-- Wait until rootPart is part of the workspace		
	while not rootPart:IsDescendantOf(workspace) do
		wait()
	end
	-- Gives control of the ship to the player
	rootPart:SetNetworkOwner(game.Players:GetPlayerFromCharacter(character))
		
	character:WaitForChild("Humanoid").Died:Connect(function()
	
	   		print(character.Name, "has died")
			
			local Player = game.Players:GetPlayerFromCharacter(character)
			
			LoadCharacter(Player)
	
	end)
	
end
 
-- Called when a player is added to the game
local function onPlayerAdded(player)
	
	-- Player Descendants
local PlayerValues = player:WaitForChild("PlayerScripts"):WaitForChild("PlayerValues")


	local ShipType = PlayerValues.ShipType.Value
	local Ship = game.ReplicatedStorage:WaitForChild("Ships"):FindFirstChild(ShipType)
 
	player.Character = Ship:WaitForChild("StarterCharacter"):Clone()
	
	LoadCharacter(player)
	
end
 
-- Connect onPlayerAdded() to the PlayerAdded event.
game.Players.PlayerAdded:Connect(onPlayerAdded)
2 Likes

I tried that out based on that advice but no luck. Here is a small snippet of code in a script that’s in ServerScriptService

local function onPlayerAdded(player)
	
	-- Player Descendants
local PlayerValues = player.PlayerScripts:WaitForChild("PlayerValues")


	local ShipType = PlayerValues.ShipType.Value
	local Ship = game.ReplicatedStorage:WaitForChild("Ships"):FindFirstChild(ShipType)
 
	player.Character = Ship.StarterCharacter:Clone()
	
	LoadCharacter(player)
	
end
 
-- Connect onPlayerAdded() to the PlayerAdded event.
game.Players.PlayerAdded:Connect(onPlayerAdded)
1 Like

Checked the following and here’s what I know.

  • Is Ship a non-nil value? Yes.
  • Is everything in Ship loaded when you access it? I’ve added a :WaitForChild(“StarterClone”)

player.Character = Ship:WaitForChild("StarterCharacter"):Clone()

  • Is the player’s character set to the cloned StarterCharacter , or does the assignment not work for some odd reason? The Player’s character is nil.

  • What is the clone’s parent? Should be the Character according to this line.

player.Character = Ship:WaitForChild("StarterCharacter"):Clone()

I’ve found that I received this error. I don’t understand though, as the entity, PlayerScripts exists. However, it could be an issue with referencing the player as a whole. (I’ve added my entire player handling script in the original post.)

21:54:27.646 - Infinite yield possible on ‘Players.IntellectualBeing:WaitForChild("PlayerScripts")’

21:54:27.647 - Stack Begin

21:54:27.647 - Script ‘ServerScriptService.PlayerShipHandler’, Line 43

21:54:27.647 - Stack End

1 Like

The PlayerScripts folder is created locally so you will have to use some other place where local scripts run, such as the backpack.

1 Like

Makes sense, though, a backpack doesn’t load for my player. Do I need a character for that in the first place? If so I’m not sure if I could use that if I don’t have the character loaded.

Or is there a certain ROBLOX default script for this? I removed all scripts pertaining to the roblox default character.

Localscripts in backpack only run after your character spawns. You can use PlayerScripts or PlayerGui to store the local script to load on start (even without a character.)

1 Like

StarterCharacter is not necessarily for this purpose. StarterCharacter is intended to define a character model which is used in place of default characters. What you’re seeking to apply is a custom character loader. PlayerScripts is also inaccessible to the server.

1 Like

Due to that I tried going to remote functions, here is my current code. Server → Client

Server script in Server Script Service.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 
local RespawnFunction = Instance.new("RemoteFunction")
RespawnFunction.Name = "RespawnFunction"
RespawnFunction.Parent = ReplicatedStorage
Players.CharacterAutoLoads = true
 
local function onPlayerAdded(player)
	RespawnFunction:InvokeClient(player)
	player:LoadCharacter()
end
 
Players.PlayerAdded:Connect(onPlayerAdded)
Local Script in Player Scripts
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 
local player = Players.LocalPlayer

local RespawnFunction = ReplicatedStorage:WaitForChild("RespawnFunction")
 

-- Respawn Event Function
local function Respawned()
	local Character = player.Character
	
	print(Character.Name, "has spawned")
	
	for i, v in pairs(Character:GetChildren()) do
		if v:IsA("BaseScript") then
			v:Destroy()
			
			local PlayerValues = player:WaitForChild("BackPack"):WaitForChild("PlayerValues")
			local ShipType = PlayerValues.ShipType.Value
			local Ship = game.ReplicatedStorage:WaitForChild("Ships"):FindFirstChild(ShipType)
		 
			player.Character = Ship:WaitForChild("CustomCharacter"):Clone()
			
		end
	end
end
 
RespawnFunction.OnClientInvoke = Respawned

I’m not sure what’s the issue here, all the syntax and variables seem right.
Once a player is added it should fire the function. However, the player’s character isn’t loading at all.

I`m sure BackPack is spelled Backpack.

1 Like

You are never going to want to allow the client to invoke a remote in this manner. What you’re looking for seems to be a RemoteEvent, not a RemoteFunction. With a RemoteFunction, if the server is invoking the client, the server will expect a return value and the thread will yield until one is received. Exploiters can overwrite the invocation callback for a RemoteFunction and permanently hang the server. This current code will permanently hang as it is, because a return value is not being sent.

Furthermore, for replication and security purposes, you should not be having the client set their own character. The server should be setting the character up, passing ownership and informing the client that their character is ready so that the client may hook up their own functionality as necessary.

3 Likes