What do you want to achieve? Keep it simple and clear!
I’m trying to create a system like in the game: “Beat Up Simulator”, where a player can type in another player’s name into a textbox , and an NPC’s appearance will change to the appearance of the given player.
What is the issue? Include screenshots / videos if possible!
I fired a RemoteEvent to the server when a button was clicked (RE:FireServer(TextInput.Text) – The text in the textbox. Then picked it up on a server script. I used Players:GetUserIdFromNameAsync to get the UserId of the given player’s name, (from the TextBox’s text).
I tried using HumanoidDescriptions to change the look of the NPC, (using Players:GetHumanoidDescriptionFromUserId(Id), & Humanoid:ApplyDescription(desc)). When I tested, I typed in a player’s name, pressed the button, a HumanoidDescription did get inserted into the NPC’s Humanoid, but it had no information in it, (no body colors, shirts, pants, accessories). Is there something more I need to add?
What solutions have you tried so far? Did you look for solutions on the Developer Hub?
I looked over the docs for HumanoidDescriptions, but could not find any other information on what I’m specifically trying to do other than the info I already had. I looked over the DevForum as well and couldn’t really find anyone having the same problem as me.
It sounds like what you’re doing is how you should be doing it, but instead of helping you debug code that’s not in your post, I’ll just give you this freebie:
This does exactly what you need it to, minus receiving input from a player. Instructions:
Set the PlayerSpoofUserId attribute on a Model with a Humanoid in it
Apply the PlayerSpoof CollectionService tag to the model.
How it works: The Binder object in the PlayerSpoof module will notice the tag and manage the life cycle of a PlayerSpoof object it creates via the module. The module uses evaera’s Promise library to dynamically load the appearance from the provided user ID and apply it to the Humanoid. It should all be pretty straight forward, but in case it’s not just ask about it and I can answer it.
Basically whatever that attribute changes to, the PlayerSpoof object handles the rest. Just get a valid user ID from the client to the server, and have the server set the PlayerSpoofUserId attribute!
Personally, I would use a RemoteFunction in the NPC itself, like this:
local rfSetPlayerSpoofUserId = script.Parent
local figure = rfSetPlayerSpoofUserId.Parent
local human = assert(figure:FindFirstChildWhichIsA("Humanoid"))
local function isValidUserId(userId)
return typeof(userId) == "number" and userId > 0 and math.floor(userId) == userId
end
local function setPlayerSpoofUserId(playerInvoke, userId)
assert(isValidUserId(userId), "Bad user ID: " .. tostring(userId))
-- TODO: Add some kind of debounce and limit system so a bad client can't
-- spam the server with requests!
figure:SetAttribute("PlayerSpoofUserId", userId)
end
rfSetPlayerSpoofUserId.OnServerInokve = setPlayerSpoofUserId
On the client, you’d have a number of options to get that user ID. You’d have to be more specific in your preference for me to provide any valuable advice here I think.
It does not seem to be working. I added this bit of extra code to detect when a player presses the button and run the setPlayerSpoofUserId function:
rfSetPlayerSpoofUserId.OnServerInvoke = function(PlayerName) -- The TextBox's text
local UserID = game.Players:GetUserIdFromNameAsync(PlayerName)
setPlayerSpoofUserId(UserID)
end
Remember the first parameter of OnServerInvoke is the player whose client invoked the RemoteFunction.
Also, the client should be submitting a valid user ID, not the player’s input text (as a string). You can do all that input validation on the client in whatever UI you’re making. The server’s job is to make sure it was given something that appears to be a valid user ID.
Thanks, I got the player’s UserId in the client script with Players:GetUserIdFromNameAsync(TextBox.Text), then RF:InvokeServer(UserId) and edited the code in the server script to this:
rfSetPlayerSpoofUserId.OnServerInvoke = function(Player, UserID)
setPlayerSpoofUserId(UserID)
end
I’m getting an error in the output after clicking the Enter button saying: Workspace.Dummy.SetPlayerSpoofUserId.PlayerSpoofHandler:10: Bad user ID: nil
Look closely at the parameters of the functions. The one I wrote, setPlayerSpoofUserId, expects a player and the userId, because I stuffed it into OnServerInvoke (edit: whose first value is always a Player, as you know). You’re calling that function manually in an anonymous function, without the player.
-- Running the function
rfSetPlayerSpoofUserId.OnServerInvoke = function(Player, UserID)
setPlayerSpoofUserId(Player, UserID)
end
-- setPlayerSpoofUserId function
local function setPlayerSpoofUserId(PlayerInvoke, userId)
assert(isValidUserId(userId), "Bad user ID: " .. tostring(userId))
figure:SetAttribute("PlayerSpoofUserId", userId)
end
I tested with these changes, but when I press enter, the appearance of the dummy does not change. I do not see a HumanoidDescription being added into the Humanoid of the Dummy either, and there were no errors in the output.
Did you remember to tag the Model with PlayerSpoof? The Binder won’t bind a new PlayerSpoof object unless the object’s been tagged accordingly.
Alternatively, instead of using the Binder and a CollectionService tag, you could add a script to the model like this, which constructs a PlayerSpoof object manually.
local PlayerSpoof = require(...) -- Go find it!
local model = script.Parent
local playerSpoof = PlayerSpoof.new(model)
-- The PlayerSpoof object should work automatically at this point!
You can clone the player model and add “_clone” to the name of the model.
You can do this by putting the players object in the fireserver args and get the character from Player.Character