--[[ TAVERN TOWN INSPECTOR AIO Version: 0.2.0 UI: WindUI 1.6.66 Runtime implementation: - Workspace folder discovery - Recursive model inspection - Wildlife discovery - Model hierarchy reporting - Local highlights and labels - Runtime diagnostics - Event logging - Cleanup and unload Target: Roblox Player ]] --================================================== -- INITIALIZATION --================================================== local VERSION = "0.2.0" local WINDUI_VERSION = "1.6.66" local startedAt = os.clock() local WindUI = nil local Window = nil local Connections = {} local Visuals = {} local CONFIG = { Version = VERSION, WindUIVersion = WINDUI_VERSION, MaxLogs = 60, AutoRefresh = false, Notifications = true, CompactMode = false, RefreshInterval = 3, } local State = { Running = true, VisualizerEnabled = false, LabelsEnabled = true, Logs = {}, TotalDetected = 0, TotalRemoved = 0, LastScan = "Never", WildlifeFolder = nil, WorldFolder = nil, } --================================================== -- LOGGING --================================================== local function log(message) print(("[Tavern Inspector][%s] %s"):format( os.date("%H:%M:%S"), tostring(message) )) end local function addLog(message) local entry = { Time = os.date("%H:%M:%S"), Message = tostring(message), } table.insert(State.Logs, entry) while #State.Logs > CONFIG.MaxLogs do table.remove(State.Logs, 1) end log(message) end --================================================== -- NOTIFICATIONS --================================================== local function notify(title, content, duration) if not WindUI then warn("[Tavern Inspector] WindUI unavailable.") return end local ok, err = pcall(function() WindUI:Notify({ Title = title, Content = content, Duration = duration or 3, }) end) if not ok then warn("[Tavern Inspector] Notification error: " .. tostring(err)) end end local function safeNotify(title, content, duration) if CONFIG.Notifications then notify(title, content, duration) end end --================================================== -- CONNECTION MANAGEMENT --================================================== local function trackConnection(connection) table.insert(Connections, connection) return connection end local function disconnectAll() for _, connection in ipairs(Connections) do pcall(function() connection:Disconnect() end) end table.clear(Connections) end --================================================== -- WINDUI LOADER --================================================== local function loadWindUI() if type(loadstring) ~= "function" then error("Executor does not expose loadstring.") end local sourceUrl = "https://github.com/Footagesus/WindUI/releases/download/" .. WINDUI_VERSION .. "/main.lua" local response = game:HttpGet(sourceUrl) if type(response) ~= "string" or #response < 1000 then error("Invalid WindUI download response.") end local chunk, compileError = loadstring(response) if not chunk then error("WindUI compilation failed: " .. tostring(compileError)) end local ok, result = pcall(chunk) if not ok then error("WindUI initialization failed: " .. tostring(result)) end if type(result) ~= "table" or type(result.CreateWindow) ~= "function" then error("WindUI CreateWindow API unavailable.") end return result end local loadOK, loadResult = pcall(loadWindUI) if not loadOK then warn("[Tavern Inspector] INITIALIZATION FAILED") warn(tostring(loadResult)) return end WindUI = loadResult log("WindUI " .. WINDUI_VERSION .. " loaded.") --================================================== -- SERVICES --================================================== local Players = game:GetService("Players") local Workspace = game:GetService("Workspace") local RunService = game:GetService("RunService") local LocalPlayer = Players.LocalPlayer --================================================== -- GENERAL HELPERS --================================================== local function findFolder(name) return Workspace:FindFirstChild(name) end local function getFirstPart(model) if not model then return nil end if model.PrimaryPart then return model.PrimaryPart end for _, object in ipairs(model:GetDescendants()) do if object:IsA("BasePart") then return object end end return nil end local function getModels(folder) local results = {} if not folder then return results end for _, object in ipairs(folder:GetDescendants()) do if object:IsA("Model") then table.insert(results, object) end end return results end local function countParts(model) local count = 0 for _, object in ipairs(model:GetDescendants()) do if object:IsA("BasePart") then count += 1 end end return count end --================================================== -- VISUAL CLEANUP --================================================== local function removeVisual(model) local objects = Visuals[model] if not objects then return end for _, object in ipairs(objects) do pcall(function() object:Destroy() end) end Visuals[model] = nil end local function clearVisuals() for model in pairs(Visuals) do removeVisual(model) end table.clear(Visuals) end --================================================== -- LOCAL MODEL VISUALS --================================================== local function createVisual(model) if not model or not model:IsA("Model") then return end if not model:IsDescendantOf(Workspace) then return end local part = getFirstPart(model) if not part then return end if Visuals[model] then return end local objects = {} if State.VisualizerEnabled then local highlight = Instance.new("Highlight") highlight.Name = "TavernInspectorHighlight" highlight.Adornee = model highlight.FillColor = Color3.fromRGB(25, 178, 205) highlight.OutlineColor = Color3.fromRGB(249, 201, 70) highlight.FillTransparency = 0.65 highlight.OutlineTransparency = 0 highlight.DepthMode = Enum.HighlightDepthMode.AlwaysOnTop highlight.Parent = model table.insert(objects, highlight) end if State.LabelsEnabled then local billboard = Instance.new("BillboardGui") billboard.Name = "TavernInspectorLabel" billboard.Adornee = part billboard.Size = UDim2.fromOffset(150, 35) billboard.StudsOffset = Vector3.new(0, 3, 0) billboard.AlwaysOnTop = true billboard.Parent = part local label = Instance.new("TextLabel") label.Size = UDim2.fromScale(1, 1) label.BackgroundTransparency = 1 label.Text = model.Name label.TextColor3 = Color3.fromRGB(255, 255, 255) label.TextStrokeTransparency = 0.2 label.TextScaled = true label.Font = Enum.Font.GothamBold label.Parent = billboard table.insert(objects, billboard) end if #objects > 0 then Visuals[model] = objects end end --================================================== -- WILDLIFE DISCOVERY --================================================== local function refreshWildlife() local folder = findFolder("Wildlife") State.WildlifeFolder = folder if not folder then State.TotalDetected = 0 State.LastScan = os.date("%H:%M:%S") addLog("Workspace.Wildlife not found.") return false end local models = getModels(folder) local validCount = 0 for _, model in ipairs(models) do if model:IsDescendantOf(Workspace) then validCount += 1 if State.VisualizerEnabled or State.LabelsEnabled then createVisual(model) end end end State.TotalDetected = validCount State.LastScan = os.date("%H:%M:%S") -- Remove visuals belonging to models that disappeared. for model in pairs(Visuals) do if not model:IsDescendantOf(Workspace) or not model:IsDescendantOf(folder) then removeVisual(model) State.TotalRemoved += 1 end end addLog("Wildlife refresh completed. Models: " .. validCount) return true end --================================================== -- WILDLIFE VISUAL SETTINGS --================================================== local function updateVisuals() clearVisuals() if State.VisualizerEnabled or State.LabelsEnabled then refreshWildlife() end end --================================================== -- FOLDER INSPECTION --================================================== local function inspectFolder(folderName) local folder = findFolder(folderName) print("\n========== " .. folderName .. " INSPECTION ==========") if not folder then print("Folder not found in Workspace.") addLog(folderName .. " folder not found.") return end local descendants = folder:GetDescendants() local models = 0 local parts = 0 local folders = 0 print("Folder:", folder:GetFullName()) print("Direct children:", #folder:GetChildren()) print("Total descendants:", #descendants) for _, object in ipairs(descendants) do if object:IsA("Model") then models += 1 elseif object:IsA("BasePart") then parts += 1 elseif object:IsA("Folder") then folders += 1 end end print("Models:", models) print("BaseParts:", parts) print("Folders:", folders) print("\nDirect children:") for _, child in ipairs(folder:GetChildren()) do print( child.Name, child.ClassName, "Children:", #child:GetChildren() ) end print("==========================================\n") addLog(folderName .. " inspection completed.") end --================================================== -- MODEL STRUCTURE INSPECTION --================================================== local function inspectModel(model) if not model or not model:IsA("Model") then return end print("\n========== MODEL STRUCTURE ==========") print("Name:", model.Name) print("FullName:", model:GetFullName()) print("PrimaryPart:", model.PrimaryPart and model.PrimaryPart.Name or "None") print("Direct children:", #model:GetChildren()) print("Total descendants:", #model:GetDescendants()) print("BaseParts:", countParts(model)) local function printHierarchy(parent, depth) if depth > 8 then print(string.rep(" ", depth), "... depth limit") return end for _, child in ipairs(parent:GetChildren()) do print( string.rep(" ", depth) .. child.Name, "[" .. child.ClassName .. "]" ) printHierarchy(child, depth + 1) end end print("\nHierarchy:") printHierarchy(model, 0) print("=====================================\n") end local function inspectAllWildlifeModels() local folder = findFolder("Wildlife") if not folder then addLog("Cannot inspect wildlife models: folder missing.") return end local models = getModels(folder) print("\n========== WILDLIFE MODEL REPORT ==========") print("Models discovered:", #models) for index, model in ipairs(models) do print( index, model.Name, "Parts:", countParts(model), "PrimaryPart:", model.PrimaryPart and model.PrimaryPart.Name or "None" ) end print("===========================================\n") addLog("Wildlife model report generated: " .. #models) end --================================================== -- EVENT LOGS --================================================== local function printLogs() print("\n========== TAVERN INSPECTOR LOGS ==========") if #State.Logs == 0 then print("No events recorded.") end for _, entry in ipairs(State.Logs) do print("[" .. entry.Time .. "] " .. entry.Message) end print("===========================================\n") end --================================================== -- WINDOW --================================================== Window = WindUI:CreateWindow({ Title = "Tavern Town | Inspector AIO", Author = "AIO v" .. VERSION, Icon = "paw-print", Theme = "Dark", Size = UDim2.fromOffset(680, 500), MinSize = Vector2.new(560, 400), ToggleKey = Enum.KeyCode.RightControl, Resizable = true, HideSearchBar = false, Folder = "TavernTownInspector", }) pcall(function() Window:Tag({ Title = "v" .. VERSION, Color = "Success", }) end) local Dashboard = Window:Tab({ Title = "Dashboard", Icon = "layout-dashboard", }) local WildlifeTab = Window:Tab({ Title = "Wildlife", Icon = "paw-print", }) local DiagnosticsTab = Window:Tab({ Title = "Diagnostics", Icon = "scan-search", }) local SettingsTab = Window:Tab({ Title = "Settings", Icon = "settings", }) --================================================== -- DASHBOARD --================================================== Dashboard:Paragraph({ Title = "Tavern Town Inspector AIO", Desc = "Version " .. VERSION .. " | WindUI " .. WINDUI_VERSION, }) Dashboard:Paragraph({ Title = "Runtime", Desc = "Roblox Player runtime initialization completed.", }) Dashboard:Button({ Title = "Run Interface Check", Icon = "activity", Callback = function() local elapsed = math.floor((os.clock() - startedAt) * 1000) addLog("Interface check completed.") safeNotify( "Interface Check", "WindUI responsive. " .. elapsed .. " ms." ) end, }) Dashboard:Button({ Title = "Refresh Wildlife", Icon = "refresh-cw", Callback = function() local ok = refreshWildlife() safeNotify( "Wildlife Refresh", ok and "Wildlife discovery completed." or "Wildlife folder not found." ) end, }) Dashboard:Button({ Title = "Print Full Report", Icon = "file-text", Callback = function() print("\n========== INSPECTOR REPORT ==========") print("Version:", VERSION) print("WindUI:", WINDUI_VERSION) print("Player:", LocalPlayer and LocalPlayer.Name or "Unavailable") print("PlaceId:", game.PlaceId) print("GameId:", game.GameId) print("Wildlife detected:", State.TotalDetected) print("Visuals tracked:", #Visuals) print("Total removed:", State.TotalRemoved) print("Last scan:", State.LastScan) print("======================================\n") safeNotify("Report", "Report printed to console.") end, }) Dashboard:Button({ Title = "Show Event Logs", Icon = "scroll-text", Callback = printLogs, }) --================================================== -- WILDLIFE --================================================== WildlifeTab:Paragraph({ Title = "Animal Visualizer", Desc = "Runtime wildlife discovery and local visual controls.", }) WildlifeTab:Toggle({ Title = "Enable Highlights", Value = false, Callback = function(value) State.VisualizerEnabled = value updateVisuals() addLog("Highlights: " .. tostring(value)) safeNotify( "Visualizer", value and "Highlights enabled." or "Highlights disabled." ) end, }) WildlifeTab:Toggle({ Title = "Enable Animal Labels", Value = true, Callback = function(value) State.LabelsEnabled = value updateVisuals() addLog("Animal labels: " .. tostring(value)) safeNotify( "Animal Labels", value and "Labels enabled." or "Labels disabled." ) end, }) WildlifeTab:Button({ Title = "Refresh Wildlife", Icon = "refresh-cw", Callback = function() refreshWildlife() safeNotify( "Wildlife", "Detected models: " .. State.TotalDetected ) end, }) WildlifeTab:Button({ Title = "Clear Visuals", Icon = "eye-off", Callback = function() clearVisuals() State.VisualizerEnabled = false State.LabelsEnabled = false addLog("All local visuals cleared.") safeNotify("Visuals", "Local visuals cleared.") end, }) WildlifeTab:Button({ Title = "Inspect Wildlife Models", Icon = "search", Callback = inspectAllWildlifeModels, }) --================================================== -- DIAGNOSTICS --================================================== DiagnosticsTab:Paragraph({ Title = "Runtime Diagnostics", Desc = "Inspect accessible runtime services and Workspace folders.", }) DiagnosticsTab:Button({ Title = "Run Environment Diagnostics", Icon = "scan", Callback = function() local checks = { {"WindUI loaded", WindUI ~= nil}, {"CreateWindow available", type(WindUI.CreateWindow) == "function"}, {"LocalPlayer available", LocalPlayer ~= nil}, {"Workspace available", Workspace ~= nil}, {"RunService available", RunService ~= nil}, {"Wildlife folder available", findFolder("Wildlife") ~= nil}, {"World folder available", findFolder("World") ~= nil}, } print("\n========== ENVIRONMENT DIAGNOSTICS ==========") for _, check in ipairs(checks) do print( check[1] .. ":", check[2] and "PASS" or "FAIL" ) end print("PlaceId:", game.PlaceId) print("GameId:", game.GameId) print("==============================================\n") addLog("Environment diagnostics completed.") safeNotify("Diagnostics", "Diagnostics printed to console.") end, }) DiagnosticsTab:Button({ Title = "Inspect Wildlife Folder", Icon = "folder-search", Callback = function() inspectFolder("Wildlife") end, }) DiagnosticsTab:Button({ Title = "Inspect World Folder", Icon = "globe", Callback = function() inspectFolder("World") end, }) DiagnosticsTab:Button({ Title = "Inspect Model Structure", Icon = "boxes", Callback = function() local folder = findFolder("Wildlife") if not folder then addLog("Wildlife folder not found.") return end local models = getModels(folder) if #models == 0 then addLog("No wildlife models found.") return end inspectModel(models[1]) end, }) DiagnosticsTab:Button({ Title = "Print Runtime Information", Icon = "terminal", Callback = function() print("\n========== RUNTIME INFORMATION ==========") print("Version:", VERSION) print("WindUI:", WINDUI_VERSION) print("Player:", LocalPlayer and LocalPlayer.Name or "Unavailable") print("PlaceId:", game.PlaceId) print("GameId:", game.GameId) print("Elapsed:", os.clock() - startedAt) print("==========================================\n") addLog("Runtime information printed.") end, }) DiagnosticsTab:Button({ Title = "Show Event Logs", Icon = "scroll-text", Callback = printLogs, }) --================================================== -- SETTINGS --================================================== SettingsTab:Paragraph({ Title = "General Settings", Desc = "Configure local interface behavior.", }) SettingsTab:Toggle({ Title = "Notifications", Value = CONFIG.Notifications, Callback = function(value) CONFIG.Notifications = value addLog("Notifications: " .. tostring(value)) if value then notify("Settings", "Notifications enabled.") end end, }) SettingsTab:Toggle({ Title = "Auto Refresh Preference", Value = CONFIG.AutoRefresh, Callback = function(value) CONFIG.AutoRefresh = value addLog("Auto refresh: " .. tostring(value)) safeNotify( "Settings", value and "Automatic refresh enabled." or "Automatic refresh disabled." ) end, }) SettingsTab:Toggle({ Title = "Compact Mode Preference", Value = CONFIG.CompactMode, Callback = function(value) CONFIG.CompactMode = value addLog("Compact mode: " .. tostring(value)) safeNotify("Settings", "Compact mode preference updated.") end, }) SettingsTab:Button({ Title = "Force Full Refresh", Icon = "refresh-ccw", Callback = function() local ok, err = pcall(function() refreshWildlife() end) if not ok then addLog("Refresh failed: " .. tostring(err)) end safeNotify( "Refresh", ok and "Refresh completed." or "Refresh failed." ) end, }) SettingsTab:Button({ Title = "Clear Event Logs", Icon = "trash-2", Callback = function() table.clear(State.Logs) log("Event logs cleared.") safeNotify("Logs", "Event logs cleared.") end, }) SettingsTab:Button({ Title = "Print Configuration", Icon = "settings-2", Callback = function() print("\n========== CONFIGURATION ==========") for key, value in pairs(CONFIG) do print(key, value) end print("===================================\n") end, }) --================================================== -- AUTOMATIC REFRESH --================================================== task.spawn(function() while State.Running do if CONFIG.AutoRefresh then local ok, err = pcall(refreshWildlife) if not ok then addLog("Automatic refresh error: " .. tostring(err)) end end task.wait(CONFIG.RefreshInterval) end end) --================================================== -- CLEANUP / UNLOAD --================================================== local function unload() if not State.Running then return end State.Running = false clearVisuals() disconnectAll() addLog("Inspector unloading.") local destroyed = false for _, methodName in ipairs({"Destroy", "Close"}) do local method = Window and Window[methodName] if type(method) == "function" then local ok = pcall(function() method(Window) end) if ok then destroyed = true break end end end if not destroyed then warn("[Tavern Inspector] Window cleanup method unavailable.") end print("[Tavern Inspector] Unload completed.") end SettingsTab:Button({ Title = "Unload UI", Icon = "power", Callback = unload, }) --================================================== -- READY --================================================== addLog("Tavern Town Inspector AIO v" .. VERSION .. " initialized.") safeNotify( "Tavern Inspector", "AIO v" .. VERSION .. " loaded successfully.", 5 ) print("[Tavern Inspector] AIO v" .. VERSION .. " loaded.") print("[Tavern Inspector] Runtime diagnostics initialized.")