Как одевать одежду через кнопку интерфейса в Roblox Studio
Друзья, прошу помогите, я уже весь на нервах от этих скриптов, 3 день не могу понять в чем проблема. Я хочу реализовать применение одежды с помощью интерфейса ScreenGui, я использую ImageButton, чтоб была сама картинка одежды и использовал MeshId, не получается, может у меня есть ошибки в коде, я не знаю, также пытался брать Id из каталога Роблокс. У меня есть скрипт что на Серверной части, что на Клиентской, я его внёс в сам Frame который находится в ScreenGui моем, также я использую Scrolling Frame, чтоб там делать кнопки с одеждой. Моя цель такая: Игрок подходит к NPC зажимает кнопку Е и открывается интерфейс с Scrolling Frame в котором находится одежда, я ещё отсортировал по категориям(Pants, Shirts и Accessories) с камерой я тоже разобрался, я хочу чтоб когда игрок нажимал на одежду(ImageButton) она применялась на него, и были кнопки Выйти и Сохранить, при выходе одежда возвращалась к начальной, а при сохранении - сохранялась выбранная одежда.

Архитектура скриптов
1. RemoteEvents (ReplicatedStorage)
local RS = game:GetService("ReplicatedStorage")
local wear = Instance.new("RemoteEvent", RS); wear.Name = "WearItem"
local quit = Instance.new("RemoteEvent", RS); quit.Name = "QuitCustom"
local save = Instance.new("RemoteEvent", RS); save.Name = "SaveCustom"
2. Кнопки в ScrollingFrame (LocalScript)
local wearEv = RS:WaitForChild("WearItem")
for _,btn in pairs(script.Parent:GetDescendants()) do
if btn:IsA("ImageButton") then
btn.MouseButton1Click:Connect(function()
local id = btn:GetAttribute("AssetId")
local kind = btn:GetAttribute("Kind") -- "Shirt","Pants","Accessory"
wearEv:FireServer(id, kind)
end)
end
end
3. Серверный скрипт
local DS = game:GetService("DataStoreService"):GetDataStore("AvatarSaves")
local IS = game:GetService("InsertService")
local RS = game:GetService("ReplicatedStorage")
local originals = {} -- таблица «оригиналов» HumanoidDescription
RS.WearItem.OnServerEvent:Connect(function(plr, assetId, kind)
local char = plr.Character
if not char then return end
local hum = char:FindFirstChildOfClass("Humanoid")
if not hum then return end
-- сохраним первое состояние
originals[plr] = originals[plr] or hum:GetAppliedDescription() :contentReference[oaicite:6]{index=6}
local desc = hum:GetAppliedDescription()
if kind == "Shirt" or kind == "Pants" then
local mdl = IS:LoadAsset(assetId)
local clothing = mdl:FindFirstChildOfClass(kind)
if clothing then
desc[kind] = clothing[kind.."Template"] -- TemplateId! :contentReference[oaicite:7]{index=7}
end
mdl:Destroy()
elseif kind == "Accessory" then
desc.Accessory = tostring(assetId)
end
hum:ApplyDescription(desc) -- сработает без респавна :contentReference[oaicite:8]{index=8}
end)
RS.QuitCustom.OnServerEvent:Connect(function(plr)
local char = plr.Character
if char and originals[plr] then
char:FindFirstChildOfClass("Humanoid"):ApplyDescription(originals[plr])
end
end)
RS.SaveCustom.OnServerEvent:Connect(function(plr)
local char = plr.Character
if not char then return end
local hum = char:FindFirstChildOfClass("Humanoid")
local data = hum:GetAppliedDescription()
-- превращаем HumanoidDescription в таблицу / JSON
local blob = game:GetService("HttpService"):JSONEncode(data)
DS:SetAsync(plr.UserId, blob) -- в DataStore можно хранить только строки или таблицы :contentReference[oaicite:9]{index=9}
end)
game.Players.PlayerAdded:Connect(function(plr)
local saved = DS:GetAsync(plr.UserId)
if saved then
local hd = game:GetService("HttpService"):JSONDecode(saved)
plr.CharacterAppearanceLoaded:Wait()
plr.Character:WaitForChild("Humanoid"):ApplyDescription(hd)
end
end)