Помогите пожалуйста со скриптам
Предоставлю вам свои скрипты связанные с проблемой применения одежды на персонажа, у меня следующая задумка: Игрок подходит к примеру к нпс и зажимает E, открывается интерфейса магазина одежда, камера приближает немного скин игрока и смотрит как бы спереди на него, чтоб при выборе одежды к примеру тип одежды: Shirt, при его выборе чтоб футболка на игроке удалялась и одевалась выбранная из Scrolling Frame, правее от него кнопки категории (AccessoriesButton, PantsButton, ShirtsButton) в этом же порядке вертикально, при сохранении выбранная одежда сохраняется на игроке при всех последующих заходах в игру, при закрытии интерфейса, если была выбрана какая-то одежда, то она становится прежней, также я использую DataStore2, так как собираюсь делать сложную игру, пожалуйста помогите буду очень вам благодарен
Структура Gui:
StarterGui
└── ClothingShopGUI
├── ShopMenu
│ ├── CategoryPanel
│ │ ├── ShirtButton
│ │ ├── PantsButton
│ │ ├── AccessoriesButton
│ └── ClothesPanel
└── Templates
└── TemplateButton (ImageButton)
Клиентский скрипт:
local player = game.Players.LocalPlayer
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local shopGui = player.PlayerGui.ClothingShopGui
local shopMenu = shopGui.ShopMenu
local clothesPanel = shopMenu.ClothesPanel
local categoryPanel = shopMenu.CategoryPanel
local templateButton = shopGui.Templates.TemplateButton
local createdButtons = {}
-- Список всех доступных предметов
local outfits = {
["Shirt"] = {
["Los California"] = {
AssetId = 128196044584927,
},
},
["Pants"] = {
["Black Jeans"] = {
AssetId = 382537568,
},
},
["Accessories"] = {
["T-Shirt-Black"] = {
AssetId = 6964007640,
},
["Glasses"] = {
AssetId = 6968110631,
},
},
}
-- Текущая категория
local currentCategory = "Shirt"
-- RemoteEvents
local wearItemEvent = ReplicatedStorage:FindFirstChild("WearItem")
if not wearItemEvent then
warn("RemoteEvent 'WearItem' не найден в ReplicatedStorage!")
end
-- Функция очистки GUI
function clearGUI()
for _, btn in ipairs(createdButtons) do
btn:Destroy()
end
table.clear(createdButtons)
end
-- Функция создания кнопок для выбранной категории
function generateButtonsForCategory(category)
clearGUI()
local items = outfits[category]
if not items then return end
for name, data in pairs(items) do
local btn = templateButton:Clone()
btn.Name = name
btn.Image = "rbxassetid://116862680140339" -- дефолтное изображение
btn:SetAttribute("AssetId", data.AssetId)
btn:SetAttribute("Kind", category:lower()) -- shirt / pants / accessory
btn.Visible = true
btn.Parent = clothesPanel
table.insert(createdButtons, btn)
btn.MouseButton1Click:Connect(function()
if wearItemEvent and data and data.AssetId then
local kind = string.lower("kind")
print("Надеваем:", kind, data.AssetId)
wearItemEvent:FireServer(data.AssetId, kind:sub(1,1):upper()..kind:sub(2))
else
warn("Ошибка: RemoteEvent не найден или отсутствует data.AssetId")
end
end)
end
end
-- Обработчик клика на категории
function onCategoryButtonClick(category)
currentCategory = category
generateButtonsForCategory(category)
end
-- Подключаем события для кнопок категорий
categoryPanel.ShirtButton.MouseButton1Click:Connect(function()
onCategoryButtonClick("Shirt")
end)
categoryPanel.PantsButton.MouseButton1Click:Connect(function()
onCategoryButtonClick("Pants")
end)
categoryPanel.AccessoriesButton.MouseButton1Click:Connect(function()
onCategoryButtonClick("Accessory")
end)
-- Инициализация при открытии магазина
generateButtonsForCategory(currentCategory)Серверный скрипт:
print("Серверный скрипт запущен!")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Http = game:GetService("HttpService")
local Players = game:GetService("Players")
-- === Создаём RemoteEvent'ы ===
local wearEv = Instance.new("RemoteEvent", ReplicatedStorage); wearEv.Name = "WearItem"
local quitEv = Instance.new("RemoteEvent", ReplicatedStorage); quitEv.Name = "QuitCustom"
local saveEv = Instance.new("RemoteEvent", ReplicatedStorage); saveEv.Name = "SaveCustom"
print("RemoteEvents созданы")
-- Подключаем DataStore2
local success, DataStore2 = pcall(require, game.ServerScriptService:FindFirstChild("DataStore2"))
if success then
print("DataStore2 подключен")
else
warn("Ошибка подключения DataStore2:", DataStore2)
end
local originals = {} -- оригинальные описания для отката
-- === WearItem: одеваем штаны/майки/аксессуары ===
wearEv.OnServerEvent:Connect(function(plr, assetId, kind)
print("Тип assetId:", typeof(assetId))
print("Значение assetId:", assetId)
print("Получено событие:", plr.Name, kind, assetId)
local char = plr.Character or plr.CharacterAdded:Wait()
local hum = char:FindFirstChildOfClass("Humanoid")
if not hum then return warn("Humanoid не найден у игрока", plr.Name) end
originals[plr] = originals[plr] or hum:GetAppliedDescription()
-- Удаляем старую одежду
for _, child in pairs(char:GetChildren()) do
if kind == "shirt" and child:IsA("Shirt") then
child:Destroy()
elseif kind == "pants" and child:IsA("Pants") then
child:Destroy()
elseif kind == "shirtgraphic" and child:IsA("ShirtGraphic") then
child:Destroy()
elseif kind == "accessory" and (child:IsA("Accessory") or child:IsA("Model")) then
child:Destroy()
end
end
local desc = hum:GetAppliedDescription()
if kind == "shirt" then
desc.Shirt = tonumber(assetId)
elseif kind == "pants" then
desc.Pants = tonumber(assetId)
elseif kind == "shirtgraphic" then
desc.Graphic = tonumber(assetId) -- ✅ Правильное поле
elseif kind == "accessory" then
desc.HatAccessory = tostring(assetId)
end
hum:ApplyDescription(desc)
-- Диагностика
print("Shirt:", desc.Shirt)
print("Pants:", desc.Pants)
print("Graphic:", desc.Graphic or "нет графики") -- ✅ Исправленный вывод
print("HatAccessory:", desc.HatAccessory or "нет аксессуара")
end)
-- === QuitCustom: отмена кастомизации ===
quitEv.OnServerEvent:Connect(function(plr)
local char = plr.Character
if char and originals[plr] then
local hum = char:FindFirstChildOfClass("Humanoid")
if hum then
hum:ApplyDescription(originals[plr])
end
end
end)
-- === SaveCustom: сохранение гардероба через DataStore2 ===
local saveDebounce = {}
local function scheduleSave(plr)
if saveDebounce[plr] then return end
saveDebounce[plr] = true
delay(3, function()
local char = plr.Character
if not char then return end
local hum = char:FindFirstChildOfClass("Humanoid")
if not hum then return end
local data = hum:GetAppliedDescription()
local serializableData = {
Shirt = data.Shirt,
Pants = data.Pants,
ShirtGraphic = data.Graphic,
HatAccessory = data.HatAccessory,
FaceAccessory = data.FaceAccessory,
HairAccessory = data.HairAccessory,
HeadColor = (data.HeadColor and data.HeadColor:ToHex()) or BrickColor.new("White"):ToHex(),
TorsoColor = (data.TorsoColor and data.TorsoColor:ToHex()) or BrickColor.new("White"):ToHex(),
}
local blob = Http:JSONEncode(serializableData)
local store = DataStore2("AvatarData", plr)
local success, err = pcall(function()
store:Set(blob)
end)
if not success then
warn("Не удалось сохранить данные игрока " .. plr.Name, err)
else
print("Данные игрока " .. plr.Name .. " успешно сохранены")
end
saveDebounce[plr] = false
end)
end
saveEv.OnServerEvent:Connect(function(plr)
if originals[plr] then
scheduleSave(plr)
else
warn("Нет данных для сохранения у игрока", plr.Name)
end
end)
-- === Загрузка при входе ===
Players.PlayerAdded:Connect(function(plr)
local store = DataStore2("AvatarData", plr)
local savedBlob = store:Get(nil)
if savedBlob then
local success, savedData = pcall(Http.JSONDecode, Http, savedBlob)
if success and savedData then
plr.CharacterAppearanceLoaded:Wait()
local char = plr.Character or plr.CharacterAdded:Wait()
local hum = char:FindFirstChildOfClass("Humanoid") or char:WaitForChild("Humanoid", 10)
if hum then
local desc = Instance.new("HumanoidDescription")
for propertyName, value in pairs(savedData) do
if string.find(propertyName, "Color") then
local color = BrickColor.new("White")
pcall(function()
color = BrickColor.new(Color3.fromHex(value))
end)
desc[propertyName] = color
elseif desc[propertyName] ~= nil then
desc[propertyName] = value
end
end
hum:ApplyDescription(desc)
end
end
end
end)