mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
728
lua/pac3/editor/client/saved_parts.lua
Normal file
728
lua/pac3/editor/client/saved_parts.lua
Normal file
@@ -0,0 +1,728 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local L = pace.LanguageString
|
||||
|
||||
-- load only when hovered above
|
||||
local function add_expensive_submenu_load(pnl, callback)
|
||||
local old = pnl.OnCursorEntered
|
||||
pnl.OnCursorEntered = function(...)
|
||||
callback()
|
||||
pnl.OnCursorEntered = old
|
||||
return old(...)
|
||||
end
|
||||
end
|
||||
|
||||
file.CreateDir("pac3")
|
||||
file.CreateDir("pac3/__backup/")
|
||||
file.CreateDir("pac3/__backup_save/")
|
||||
|
||||
function pace.SaveParts(name, prompt_name, override_part, overrideAsUsual)
|
||||
if not name or prompt_name then
|
||||
Derma_StringRequest(
|
||||
L"save parts",
|
||||
L"filename:",
|
||||
prompt_name or pace.LastSaveName or "autoload",
|
||||
|
||||
function(name)
|
||||
pace.LastSaveName = name
|
||||
pace.SaveParts(name, nil, override_part, overrideAsUsual)
|
||||
|
||||
pace.RefreshFiles()
|
||||
end
|
||||
)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
pac.dprint("saving parts %s", name)
|
||||
|
||||
local data = {}
|
||||
|
||||
if not overrideAsUsual then
|
||||
if pace.use_current_part_for_saveload and pace.current_part:IsValid() then
|
||||
override_part = pace.current_part
|
||||
end
|
||||
|
||||
if override_part then
|
||||
data = override_part:ToSaveTable()
|
||||
end
|
||||
elseif override_part then
|
||||
table.insert(data, override_part:ToSaveTable())
|
||||
override_part = nil
|
||||
end
|
||||
|
||||
if #data == 0 then
|
||||
for key, part in pairs(pac.GetLocalParts()) do
|
||||
if not part:HasParent() and part:GetShowInEditor() then
|
||||
table.insert(data, part:ToSaveTable())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
data = hook.Run("pac_pace.SaveParts", data) or data
|
||||
|
||||
if not override_part and #file.Find("pac3/sessions/*", "DATA") > 0 and not name:find("/") then
|
||||
pace.luadata.WriteFile("pac3/sessions/" .. name .. ".txt", data)
|
||||
else
|
||||
if file.Exists("pac3/" .. name .. ".txt", "DATA") then
|
||||
local date = os.date("%y-%m-%d-%H_%M_%S")
|
||||
local read = file.Read("pac3/" .. name .. ".txt", "DATA")
|
||||
file.Write("pac3/__backup_save/" .. name .. "_" .. date .. ".txt", read)
|
||||
|
||||
local files, folders = file.Find("pac3/__backup_save/*", "DATA")
|
||||
|
||||
if #files > 30 then
|
||||
local targetFiles = {}
|
||||
|
||||
for i, filename in ipairs(files) do
|
||||
local time = file.Time("pac3/__backup_save/" .. filename, "DATA")
|
||||
table.insert(targetFiles, {"pac3/__backup_save/" .. filename, time})
|
||||
end
|
||||
|
||||
table.sort(targetFiles, function(a, b)
|
||||
return a[2] > b[2]
|
||||
end)
|
||||
|
||||
for i = 31, #files do
|
||||
file.Delete(targetFiles[i][1])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
pace.luadata.WriteFile("pac3/" .. name .. ".txt", data)
|
||||
end
|
||||
|
||||
pace.Backup(data, name)
|
||||
end
|
||||
|
||||
local last_backup
|
||||
local maxBackups = CreateConVar("pac_backup_limit", "100", {FCVAR_ARCHIVE}, "Maximal amount of backups")
|
||||
|
||||
function pace.Backup(data, name)
|
||||
name = name or ""
|
||||
|
||||
if not data then
|
||||
data = {}
|
||||
for key, part in pairs(pac.GetLocalParts()) do
|
||||
if not part:HasParent() and part:GetShowInEditor() then
|
||||
table.insert(data, part:ToSaveTable())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #data > 0 then
|
||||
|
||||
local files, folders = file.Find("pac3/__backup/*", "DATA")
|
||||
|
||||
if #files > maxBackups:GetInt() then
|
||||
local temp = {}
|
||||
for key, name in pairs(files) do
|
||||
local time = file.Time("pac3/__backup/" .. name, "DATA")
|
||||
table.insert(temp, {path = "pac3/__backup/" .. name, time = time})
|
||||
end
|
||||
|
||||
table.sort(temp, function(a, b)
|
||||
return a.time > b.time
|
||||
end)
|
||||
|
||||
for i = maxBackups:GetInt() + 1, #files do
|
||||
file.Delete(temp[i].path, "DATA")
|
||||
end
|
||||
end
|
||||
|
||||
local date = os.date("%y-%m-%d-%H_%M_%S")
|
||||
local str = pace.luadata.Encode(data)
|
||||
|
||||
if str ~= last_backup then
|
||||
file.Write("pac3/__backup/" .. (name=="" and name or (name..'_')) .. date .. ".txt", str)
|
||||
last_backup = str
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pace.LoadParts(name, clear, override_part)
|
||||
if not name then
|
||||
local frm = vgui.Create("DFrame")
|
||||
frm:SetTitle(L"parts")
|
||||
local pnl = pace.CreatePanel("browser", frm)
|
||||
|
||||
pnl.OnLoad = function(node)
|
||||
pace.LoadParts(node.FileName, clear, override_part)
|
||||
end
|
||||
|
||||
if #file.Find("pac3/sessions/*", "DATA") > 0 then
|
||||
pnl:SetDir("sessions/")
|
||||
else
|
||||
pnl:SetDir("")
|
||||
end
|
||||
|
||||
pnl:Dock(FILL)
|
||||
|
||||
frm:SetSize(300, 500)
|
||||
frm:MakePopup()
|
||||
frm:Center()
|
||||
|
||||
local btn = vgui.Create("DButton", frm)
|
||||
btn:Dock(BOTTOM)
|
||||
btn:SetText(L"load from url")
|
||||
btn.DoClick = function()
|
||||
Derma_StringRequest(
|
||||
L"load part",
|
||||
L"pastebin urls also work!",
|
||||
"",
|
||||
function(name)
|
||||
pace.LoadParts(name, clear, override_part)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
else
|
||||
if hook.Run("PrePACLoadOutfit", name) == false then
|
||||
return
|
||||
end
|
||||
|
||||
pac.dprint("loading Parts %s", name)
|
||||
|
||||
if name:find("https?://") then
|
||||
local function callback(str)
|
||||
if string.find( str, "<!DOCTYPE html>" ) then
|
||||
pace.MessagePrompt("Invalid URL, the website returned a HTML file. If you're using Github then use the RAW option.", "URL Failed", "OK")
|
||||
return
|
||||
end
|
||||
|
||||
local data, err = pace.luadata.Decode(str)
|
||||
if not data then
|
||||
local message = string.format("URL fail: %s : %s\n", name, err)
|
||||
pace.MessagePrompt(message, "URL Failed", "OK")
|
||||
return
|
||||
end
|
||||
|
||||
pace.LoadPartsFromTable(data, clear, override_part)
|
||||
end
|
||||
|
||||
pac.HTTPGet(name, callback, function(err)
|
||||
pace.MessagePrompt(err, "HTTP Request Failed for " .. name, "OK")
|
||||
end)
|
||||
else
|
||||
name = name:gsub("%.txt", "")
|
||||
|
||||
local data,err = pace.luadata.ReadFile("pac3/" .. name .. ".txt")
|
||||
|
||||
if name == "autoload" and (not data or not next(data)) then
|
||||
local err
|
||||
data,err = pace.luadata.ReadFile("pac3/sessions/" .. name .. ".txt",nil,true)
|
||||
if not data then
|
||||
if err then
|
||||
ErrorNoHalt(("Autoload failed: %s\n"):format(err))
|
||||
end
|
||||
return
|
||||
end
|
||||
elseif not data then
|
||||
ErrorNoHalt(("Decoding %s failed: %s\n"):format(name,err))
|
||||
return
|
||||
end
|
||||
|
||||
pace.LoadPartsFromTable(data, clear, override_part)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
concommand.Add('pac_load_url', function(ply, cmd, args)
|
||||
if not args[1] then return print('[PAC3] No URL specified') end
|
||||
local url = args[1]:Trim()
|
||||
if not url:find("https?://") then return print('[PAC3] Invalid URL specified') end
|
||||
pac.Message('Loading specified URL')
|
||||
if args[2] == nil then args[2] = '1' end
|
||||
pace.LoadParts(url, tobool(args[2]))
|
||||
end)
|
||||
|
||||
function pace.LoadPartsFromTable(data, clear, override_part)
|
||||
if pace.use_current_part_for_saveload and pace.current_part:IsValid() then
|
||||
override_part = pace.current_part
|
||||
end
|
||||
|
||||
if clear then
|
||||
pace.ClearParts()
|
||||
pace.ClearUndo()
|
||||
else
|
||||
--pace.RecordUndoHistory()
|
||||
end
|
||||
|
||||
local partsLoaded = {}
|
||||
|
||||
local copy_id = tostring(data)
|
||||
|
||||
if data.self then
|
||||
local part
|
||||
|
||||
if override_part then
|
||||
part = override_part
|
||||
part:SetTable(data)
|
||||
else
|
||||
part = override_part or pac.CreatePart(data.self.ClassName, nil, data, pac.GetPartFromUniqueID(pac.Hash(pac.LocalPlayer), data.self.UniqueID):IsValid() and copy_id)
|
||||
end
|
||||
|
||||
table.insert(partsLoaded, part)
|
||||
else
|
||||
data = pace.FixBadGrouping(data)
|
||||
data = pace.FixUniqueIDs(data)
|
||||
|
||||
for key, tbl in pairs(data) do
|
||||
local part = pac.CreatePart(tbl.self.ClassName, nil, tbl, pac.GetPartFromUniqueID(pac.Hash(pac.LocalPlayer), tbl.self.UniqueID):IsValid() and copy_id)
|
||||
table.insert(partsLoaded, part)
|
||||
end
|
||||
end
|
||||
|
||||
pace.RefreshTree(true)
|
||||
|
||||
for i, part in ipairs(partsLoaded) do
|
||||
part:CallRecursive('OnOutfitLoaded')
|
||||
part:CallRecursive('PostApplyFixes')
|
||||
end
|
||||
|
||||
pac.LocalPlayer.pac_fix_show_from_render = SysTime() + 1
|
||||
|
||||
pace.RecordUndoHistory()
|
||||
end
|
||||
|
||||
local function add_files(tbl, dir)
|
||||
local files, folders = file.Find("pac3/" .. dir .. "/*", "DATA")
|
||||
|
||||
if folders then
|
||||
for key, folder in pairs(folders) do
|
||||
if folder == "__backup" or folder == "objcache" or folder == "__animations" or folder == "__backup_save" then goto CONTINUE end
|
||||
tbl[folder] = {}
|
||||
add_files(tbl[folder], dir .. "/" .. folder)
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
if files then
|
||||
for i, name in pairs(files) do
|
||||
if name:find("%.txt") then
|
||||
local path = "pac3/" .. dir .. "/" .. name
|
||||
|
||||
if file.Exists(path, "DATA") then
|
||||
local data = {}
|
||||
data.Name = name:gsub("%.txt", "")
|
||||
data.FileName = name
|
||||
data.Size = string.NiceSize(file.Size(path, "DATA"))
|
||||
local time = file.Time(path, "DATA")
|
||||
data.LastModified = os.date("%m/%d/%Y %H:%M", time)
|
||||
data.Time = file.Time(path, "DATA")
|
||||
data.Path = path
|
||||
data.RelativePath = (dir .. "/" .. data.Name):sub(2)
|
||||
|
||||
local dat,err=pace.luadata.ReadFile(path)
|
||||
data.Content = dat
|
||||
|
||||
if dat then
|
||||
table.insert(tbl, data)
|
||||
else
|
||||
pac.dprint(("Decoding %s failed: %s\n"):format(path,err))
|
||||
chat.AddText(("Could not load: %s\n"):format(path))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(tbl, function(a,b)
|
||||
if a.Time and b.Time then
|
||||
return a.Name < b.Name
|
||||
end
|
||||
|
||||
return true
|
||||
end)
|
||||
end
|
||||
|
||||
function pace.GetSavedParts(dir)
|
||||
if pace.CachedFiles then
|
||||
return pace.CachedFiles
|
||||
end
|
||||
|
||||
local out = {}
|
||||
|
||||
add_files(out, dir or "")
|
||||
|
||||
pace.CachedFiles = out
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
local function populate_part(menu, part, override_part, clear)
|
||||
local name = part.self.Name or ""
|
||||
|
||||
if name == "" then
|
||||
name = part.self.ClassName .. " (no name)"
|
||||
end
|
||||
|
||||
if #part.children > 0 then
|
||||
local menu, pnl = menu:AddSubMenu(name, function()
|
||||
pace.LoadPartsFromTable(part, nil, override_part)
|
||||
end)
|
||||
pnl:SetImage(part.self.Icon)
|
||||
menu.GetDeleteSelf = function() return false end
|
||||
local old = menu.Open
|
||||
menu.Open = function(...)
|
||||
if not menu.pac_opened then
|
||||
for key, part in pairs(part.children) do
|
||||
populate_part(menu, part, override_part, clear)
|
||||
end
|
||||
menu.pac_opened = true
|
||||
end
|
||||
|
||||
return old(...)
|
||||
end
|
||||
else
|
||||
menu:AddOption(name, function()
|
||||
pace.LoadPartsFromTable(part, clear, override_part)
|
||||
end):SetImage(part.self.Icon)
|
||||
end
|
||||
end
|
||||
|
||||
local function populate_parts(menu, tbl, override_part, clear)
|
||||
for key, data in pairs(tbl) do
|
||||
if not data.Path then
|
||||
local menu, pnl = menu:AddSubMenu(key, function()end, data)
|
||||
pnl:SetImage(pace.MiscIcons.load)
|
||||
menu.GetDeleteSelf = function() return false end
|
||||
local old = menu.Open
|
||||
menu.Open = function(...)
|
||||
if not menu.pac_opened then
|
||||
populate_parts(menu, data, override_part, clear)
|
||||
menu.pac_opened = true
|
||||
end
|
||||
|
||||
return old(...)
|
||||
end
|
||||
else
|
||||
local icon = pace.MiscIcons.outfit
|
||||
local parts = data.Content
|
||||
|
||||
if parts.self then
|
||||
icon = parts.self.Icon
|
||||
parts = {parts}
|
||||
end
|
||||
|
||||
local outfit, pnl = menu:AddSubMenu(data.Name, function()
|
||||
pace.LoadParts(data.RelativePath, clear, override_part)
|
||||
end)
|
||||
pnl:SetImage(icon)
|
||||
outfit.GetDeleteSelf = function() return false end
|
||||
|
||||
local old = outfit.Open
|
||||
outfit.Open = function(...)
|
||||
if not outfit.pac_opened then
|
||||
for key, part in pairs(parts) do
|
||||
populate_part(outfit, part, override_part, clear)
|
||||
end
|
||||
outfit.pac_opened = true
|
||||
end
|
||||
|
||||
return old(...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pace.AddSavedPartsToMenu(menu, clear, override_part)
|
||||
menu.GetDeleteSelf = function() return false end
|
||||
|
||||
menu:AddOption(L"load from url", function()
|
||||
Derma_StringRequest(
|
||||
L"load parts",
|
||||
L"Some indirect urls from on pastebin, dropbox, github, etc are handled automatically. Pasting the outfit's file contents into the input field will also work.",
|
||||
"",
|
||||
|
||||
function(name)
|
||||
pace.LoadParts(name, clear, override_part)
|
||||
end
|
||||
)
|
||||
end):SetImage(pace.MiscIcons.url)
|
||||
|
||||
menu:AddOption(L"load from clipboard", function()
|
||||
pace.MultilineStringRequest(
|
||||
L"load parts from clipboard",
|
||||
L"Paste the outfits content here.",
|
||||
"",
|
||||
|
||||
function(name)
|
||||
local data,err = pace.luadata.Decode(name)
|
||||
if data then
|
||||
pace.LoadPartsFromTable(data, clear, override_part)
|
||||
end
|
||||
end
|
||||
)
|
||||
end):SetImage(pace.MiscIcons.paste)
|
||||
|
||||
if not override_part and pace.example_outfits then
|
||||
local examples, pnl = menu:AddSubMenu(L"examples")
|
||||
pnl:SetImage(pace.MiscIcons.help)
|
||||
examples.GetDeleteSelf = function() return false end
|
||||
|
||||
local sorted = {}
|
||||
for k,v in pairs(pace.example_outfits) do sorted[#sorted + 1] = {k = k, v = v} end
|
||||
table.sort(sorted, function(a, b) return a.k < b.k end)
|
||||
|
||||
for _, data in pairs(sorted) do
|
||||
examples:AddOption(data.k, function() pace.LoadPartsFromTable(data.v) end)
|
||||
:SetImage(pace.MiscIcons.outfit)
|
||||
end
|
||||
end
|
||||
|
||||
menu:AddSpacer()
|
||||
|
||||
local tbl = pace.GetSavedParts()
|
||||
populate_parts(menu, tbl, override_part, clear)
|
||||
|
||||
menu:AddSpacer()
|
||||
|
||||
local backups, pnl = menu:AddSubMenu(L"backups")
|
||||
pnl:SetImage(pace.MiscIcons.clone)
|
||||
backups.GetDeleteSelf = function() return false end
|
||||
|
||||
add_expensive_submenu_load(pnl, function()
|
||||
local files = file.Find("pac3/__backup/*", "DATA")
|
||||
local files2 = {}
|
||||
|
||||
for i, filename in ipairs(files) do
|
||||
table.insert(files2, {filename, file.Time("pac3/__backup/" .. filename, "DATA")})
|
||||
end
|
||||
|
||||
table.sort(files2, function(a, b)
|
||||
return a[2] > b[2]
|
||||
end)
|
||||
|
||||
for _, data in pairs(files2) do
|
||||
local name = data[1]
|
||||
local full_path = "pac3/__backup/" .. name
|
||||
local friendly_name = os.date("%m/%d/%Y %H:%M:%S ", file.Time(full_path, "DATA")) .. string.NiceSize(file.Size(full_path, "DATA"))
|
||||
backups:AddOption(friendly_name, function() pace.LoadParts("__backup/" .. name, true) end)
|
||||
:SetImage(pace.MiscIcons.outfit)
|
||||
end
|
||||
end)
|
||||
|
||||
local backups, pnl = menu:AddSubMenu(L"outfit backups")
|
||||
pnl:SetImage(pace.MiscIcons.clone)
|
||||
backups.GetDeleteSelf = function() return false end
|
||||
|
||||
add_expensive_submenu_load(pnl, function()
|
||||
local files = file.Find("pac3/__backup_save/*", "DATA")
|
||||
local files2 = {}
|
||||
|
||||
for i, filename in ipairs(files) do
|
||||
table.insert(files2, {filename, file.Time("pac3/__backup_save/" .. filename, "DATA")})
|
||||
end
|
||||
|
||||
table.sort(files2, function(a, b)
|
||||
return a[2] > b[2]
|
||||
end)
|
||||
|
||||
for _, data in pairs(files2) do
|
||||
local name = data[1]
|
||||
local stamp = data[2]
|
||||
local nicename = name
|
||||
local date = os.date("_%y-%m-%d-%H_%M_%S", stamp)
|
||||
|
||||
if nicename:find(date, 1, true) then
|
||||
nicename = nicename:Replace(date, os.date(" %m/%d/%Y %H:%M:%S", stamp))
|
||||
end
|
||||
|
||||
backups:AddOption(nicename:Replace(".txt", "") .. " (" .. string.NiceSize(file.Size("pac3/__backup_save/" .. name, "DATA")) .. ")",
|
||||
function()
|
||||
pace.LoadParts("__backup_save/" .. name, true)
|
||||
end)
|
||||
:SetImage(pace.MiscIcons.outfit)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local function populate_parts(menu, tbl, dir, override_part)
|
||||
dir = dir or ""
|
||||
menu:AddOption(L"new file", function() pace.SaveParts(nil, dir .. "/", override_part) end)
|
||||
:SetImage("icon16/page_add.png")
|
||||
|
||||
menu:AddOption(L"new directory", function()
|
||||
Derma_StringRequest(
|
||||
L"new directory",
|
||||
L"name:",
|
||||
"",
|
||||
|
||||
function(name)
|
||||
file.CreateDir("pac3/" .. dir .. "/" .. name)
|
||||
pace.RefreshFiles()
|
||||
end
|
||||
)
|
||||
end)
|
||||
:SetImage("icon16/folder_add.png")
|
||||
|
||||
menu:AddOption(L"to clipboard", function()
|
||||
local data = {}
|
||||
for key, part in pairs(pac.GetLocalParts()) do
|
||||
if not part:HasParent() and part:GetShowInEditor() then
|
||||
table.insert(data, part:ToSaveTable())
|
||||
end
|
||||
end
|
||||
SetClipboardText(pace.luadata.Encode(data):sub(1, -1))
|
||||
end)
|
||||
:SetImage(pace.MiscIcons.copy)
|
||||
|
||||
menu:AddSpacer()
|
||||
for key, data in pairs(tbl) do
|
||||
if not data.Path then
|
||||
local menu, pnl = menu:AddSubMenu(key, function()end, data)
|
||||
pnl:SetImage(pace.MiscIcons.load)
|
||||
menu.GetDeleteSelf = function() return false end
|
||||
populate_parts(menu, data, dir .. "/" .. key, override_part)
|
||||
else
|
||||
local parts = data.Content
|
||||
|
||||
if parts[1] then
|
||||
local menu, pnl = menu:AddSubMenu(data.Name, function() pace.SaveParts(nil, data.RelativePath, override_part) end)
|
||||
menu.GetDeleteSelf = function() return false end
|
||||
pnl:SetImage(pace.MiscIcons.outfit)
|
||||
|
||||
menu:AddOption(L"delete", function()
|
||||
file.Delete("pac3/" .. data.RelativePath .. ".txt", "DATA")
|
||||
pace.RefreshFiles()
|
||||
end):SetImage(pace.MiscIcons.clear)
|
||||
|
||||
pnl:SetImage(pace.MiscIcons.outfit)
|
||||
elseif parts.self then
|
||||
menu:AddOption(data.Name, function() pace.SaveParts(nil, data.RelativePath, override_part) end)
|
||||
:SetImage(parts.self.Icon)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if dir ~= "" then
|
||||
menu:AddSpacer()
|
||||
|
||||
menu:AddOption(L"delete directory", function()
|
||||
Derma_Query(
|
||||
L"Are you sure you want to delete data/pac3" .. dir .. "/* and all its files?\nThis cannot be undone!",
|
||||
L"delete directory",
|
||||
|
||||
L"yes", function()
|
||||
local function delete_directory(dir)
|
||||
local files, folders = file.Find(dir .. "*", "DATA")
|
||||
|
||||
for k,v in ipairs(files) do
|
||||
file.Delete(dir .. v)
|
||||
end
|
||||
|
||||
for k,v in ipairs(folders) do
|
||||
delete_directory(dir .. v .. "/")
|
||||
end
|
||||
|
||||
if file.Find(dir .. "*", "DATA")[1] then
|
||||
Derma_Message("Cannot remove the directory.\nMaybe it contains hidden files?", "unable to remove directory", L"ok")
|
||||
else
|
||||
file.Delete(dir)
|
||||
end
|
||||
end
|
||||
delete_directory("pac3/" .. dir .. "/")
|
||||
pace.RefreshFiles()
|
||||
end,
|
||||
|
||||
L"no", function()
|
||||
|
||||
end
|
||||
)
|
||||
end):SetImage("icon16/folder_delete.png")
|
||||
end
|
||||
end
|
||||
|
||||
function pace.AddSaveMenuToMenu(menu, override_part)
|
||||
menu.GetDeleteSelf = function() return false end
|
||||
|
||||
if not override_part then
|
||||
menu:AddOption(L"auto load (your spawn outfit)", function()
|
||||
pace.SaveParts("autoload", nil, override_part)
|
||||
pace.RefreshFiles()
|
||||
end)
|
||||
:SetImage(pace.MiscIcons.autoload)
|
||||
menu:AddSpacer()
|
||||
end
|
||||
|
||||
local tbl = pace.GetSavedParts()
|
||||
populate_parts(menu, tbl, nil, override_part)
|
||||
end
|
||||
|
||||
-- this fixes parts that are using the same uniqueid as other parts because of some bugs in older versions
|
||||
function pace.FixUniqueIDs(data)
|
||||
local ids = {}
|
||||
|
||||
local function iterate(part)
|
||||
ids[part.self.UniqueID] = ids[part.self.UniqueID] or {}
|
||||
|
||||
table.insert(ids[part.self.UniqueID], part)
|
||||
|
||||
for key, part in pairs(part.children) do
|
||||
iterate(part)
|
||||
end
|
||||
end
|
||||
|
||||
for key, part in pairs(data) do
|
||||
iterate(part)
|
||||
end
|
||||
|
||||
for key, val in pairs(ids) do
|
||||
if #val > 1 then
|
||||
for key, part in pairs(val) do
|
||||
pac.dprint("Part (%s using model %s) named %q has %i other parts with the same unique id. Fixing!", part.self.ClassName, part.self.Name, part.self.Model or "", #val)
|
||||
part.self.UniqueID = pac.Hash()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
-- this is for fixing parts that are not in a group
|
||||
|
||||
function pace.FixBadGrouping(data)
|
||||
local parts = {}
|
||||
local other = {}
|
||||
|
||||
for key, part in pairs(data) do
|
||||
if part.self.ClassName ~= "group" then
|
||||
table.insert(parts, part)
|
||||
else
|
||||
table.insert(other, part)
|
||||
end
|
||||
end
|
||||
|
||||
if #parts > 0 then
|
||||
local out = {
|
||||
{
|
||||
["self"] = {
|
||||
["EditorExpand"] = true,
|
||||
["ClassName"] = "group",
|
||||
["UniqueID"] = pac.Hash(),
|
||||
["Name"] = "automatic group",
|
||||
},
|
||||
|
||||
["children"] = parts,
|
||||
},
|
||||
}
|
||||
|
||||
for k,v in pairs(other) do
|
||||
table.insert(out, v)
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
Reference in New Issue
Block a user