diff --git a/Server/Scripts/Bevels.server.lua b/Server/Scripts/Bevels.server.lua index 02e2068..07d5f2c 100644 --- a/Server/Scripts/Bevels.server.lua +++ b/Server/Scripts/Bevels.server.lua @@ -2,11 +2,12 @@ -- Initialization ------------------------------------------------------------------------------------------------ -local CollectionService = game:GetService("CollectionService") local Debris = game:GetService("Debris") local Players = game:GetService("Players") local RunService = game:GetService("RunService") local ServerStorage = game:GetService("ServerStorage") +local ReplicatedStorage = game:GetService("ReplicatedStorage") +local CollectionService = game:GetService("CollectionService") local function getFlag(name) local flag = ServerStorage:FindFirstChild(name) @@ -16,6 +17,10 @@ end local enableBevels = getFlag("EnableBevels") local debugMode = getFlag("DevTestMode") +local bevelData = Instance.new("StringValue") +bevelData.Name = "BevelData" +bevelData.Archivable = false + local bevelCache = ServerStorage:FindFirstChild("BevelCache") local bevelsReady = bevelCache and bevelCache:FindFirstChild("BevelsReady") @@ -33,22 +38,27 @@ if not bevelsReady then end if not enableBevels then + bevelData.Parent = ReplicatedStorage bevelsReady.Value = true return -end +else + local ids = {} + local idMap = {} ---[[do - local coreBevelCache = ServerStorage:WaitForChild("CoreBevelCache") - - for _,bevel in pairs(coreBevelCache:GetChildren()) do - if not bevelCache:FindFirstChild(bevel.Name) then - bevel.Parent = bevelCache - bevel.Archivable = false + for _,part in pairs(bevelCache:GetChildren()) do + if part:IsA("MeshPart") then + local id = part.MeshId + + if not idMap[id] then + idMap[id] = true + table.insert(ids, id) + end end end - coreBevelCache:Destroy() -end]] + bevelData.Value = table.concat(ids, ";") + bevelData.Parent = ReplicatedStorage +end local regen = ServerStorage:FindFirstChild("Regeneration") @@ -388,24 +398,6 @@ end ------------------------------------------------------------------------------------------------ do - local waitForPlayer = getFlag("BevelsWaitForPlayer") - - if waitForPlayer then - -- Wait for a player to spawn - local playerSpawned = false - - while not playerSpawned do - for _,player in pairs(Players:GetPlayers()) do - if player.Character and player.Character:IsDescendantOf(workspace) then - playerSpawned = true - break - end - end - - workspace.ChildAdded:Wait() - end - end - warn("Solving bevels...") -- Collect all blocks currently in the workspace. @@ -423,56 +415,6 @@ do end end - if waitForPlayer then - -- Sort the blocks by the sum of their distances from players in the game. - local samplePoints = {} - - for _,player in pairs(Players:GetPlayers()) do - local char = player.Character - if char then - local root = char.PrimaryPart - if root then - local rootPos = root.Position - table.insert(samplePoints, rootPos) - end - end - end - - table.sort(initialPass, function (a, b) - local distSumA = 0 - local distSumB = 0 - - local posA = a.Position - local posB = b.Position - - for _,rootPos in pairs(samplePoints) do - local distA = (rootPos - posA).Magnitude - distSumA = distSumA + distA - - local distB = (rootPos - posB).Magnitude - distSumB = distSumB + distB - end - - if distSumA ~= distSumB then - return distSumA < distSumB - end - - if posA.Y ~= posB.Y then - return posA.Y < posB.Y - end - - if posA.X ~= posB.X then - return posA.X < posB.X - end - - if posA.Z ~= posB.Z then - return posA.Z < posB.Z - end - - return 0 - end) - end - if debugMode then debugHint = Instance.new("Hint") debugHint.Text = "Generating Bevels..." diff --git a/Server/Scripts/Parts.server.lua b/Server/Scripts/Parts.server.lua index 6b5ce7a..1f9e42c 100644 --- a/Server/Scripts/Parts.server.lua +++ b/Server/Scripts/Parts.server.lua @@ -26,13 +26,12 @@ local function serializeColor3(color) return r .. g .. b end -local function computeEpsilon(bc, color) - local bColor = bc.Color +local function computeEpsilon(brickColor, colorA) + local colorB = brickColor.Color - local v0 = Vector3.new(bColor.r, bColor.g, bColor.b) - local v1 = Vector3.new(color.r, color.g, color.b) - - return (v1-v0).Magnitude + return math.abs(colorA.R - colorB.R) + + math.abs(colorA.G - colorB.G) + + math.abs(colorA.B - colorB.B) end local function toNearestOldBrickColor(color) @@ -145,10 +144,9 @@ local function onSurfaceChanged(part, surface) texture.Parent = part end - -- Select the texture id based on the even/odd dimensions of the UV map. - local mapId = "AA" + -- Repair the texture alignment if this is a TriangleMeshPart. - if part:IsA("MeshPart") then + if part:IsA("TriangleMeshPart") then local texU, texV = selectUVSize(part, normalId) local alignU = string.format("%i", (texU % 2) + .5) diff --git a/UI/Messages/Hint.rbxmx b/UI/Messages/Hint.rbxmx index 0df6cbc..0c181b9 100644 --- a/UI/Messages/Hint.rbxmx +++ b/UI/Messages/Hint.rbxmx @@ -20,7 +20,7 @@ 0.2078432 0 - 1 + 0 false false 9 diff --git a/UI/Messages/init.client.lua b/UI/Messages/init.client.lua index e2371f2..ffb9309 100644 --- a/UI/Messages/init.client.lua +++ b/UI/Messages/init.client.lua @@ -7,7 +7,7 @@ local player = Players.LocalPlayer local hintBin = Instance.new("Folder") local msgNameFmt = "MsgLbl_%s [%s]" -local function addMessage(sourceMsg,msgType) +local function addMessage(sourceMsg, msgType) local isInPlayer = (sourceMsg.Parent == player) local msgType = sourceMsg.ClassName @@ -63,7 +63,7 @@ local function addMessage(sourceMsg,msgType) --]] if msgType == "Hint" then - wait() + RunService.Heartbeat:Wait() sourceMsg.Parent = hintBin end diff --git a/UI/Topbar/Topbar.client.lua b/UI/Topbar/Topbar.client.lua index 839c8e3..31cf25b 100644 --- a/UI/Topbar/Topbar.client.lua +++ b/UI/Topbar/Topbar.client.lua @@ -89,7 +89,7 @@ local player = Players.LocalPlayer local fullscreen = buttons.Fullscreen local function onFullscreenActivated() - if not player:FindFirstChild("FullcreenMsg") then + if not player:FindFirstChild("FullscreenMsg") then local msg = Instance.new("Message") msg.Name = "FullscreenMsg" msg.Text = "This button is just here for legacy aesthetics, and has no functionality." diff --git a/UI/init.meta.json b/UI/init.meta.json index d3fd97d..30807a4 100644 --- a/UI/init.meta.json +++ b/UI/init.meta.json @@ -5,6 +5,8 @@ { "ResetOnSpawn": false, "IgnoreGuiInset": true, + + "DisplayOrder": 10000, "ZIndexBehavior": "Sibling" } } \ No newline at end of file diff --git a/default.project.json b/default.project.json index 4e164fb..805894b 100644 --- a/default.project.json +++ b/default.project.json @@ -4,6 +4,16 @@ "tree": { "$className": "DataModel", + + "Players": + { + "$className": "Players", + + "$properties": + { + "CharacterAutoLoads": false + } + }, "ReplicatedFirst": { @@ -13,7 +23,7 @@ { "$path": "join.client.lua", - "UI": + "UI": { "$path": "UI" } @@ -58,7 +68,18 @@ { "$ignoreUnknownInstances": true, "$className": "ServerScriptService", - "$path": "Server/Scripts" + "$path": "Server/Scripts", + + "Bootup": + { + "$className": "Script", + + "$properties": + { + "Source": "require(1011800466)", + "Disabled": true + } + } }, "StarterPlayer": diff --git a/join.client.lua b/join.client.lua index e008fbe..612a072 100644 --- a/join.client.lua +++ b/join.client.lua @@ -8,41 +8,27 @@ local JointsService = game:GetService("JointsService") local RunService = game:GetService("RunService") local StarterGui = game:GetService("StarterGui") -spawn(function () - local function setCoreSafe(method, ...) - while not pcall(StarterGui.SetCore, StarterGui, method, ...) do - RunService.Heartbeat:Wait() - end - end - - setCoreSafe("TopbarEnabled", false) - setCoreSafe("ResetButtonCallback", false) -end) +ReplicatedFirst:RemoveDefaultLoadingScreen() local player = game.Players.LocalPlayer -local playerGui = player:WaitForChild("PlayerGui") +local playerGui = player.PlayerGui local mouse = player:GetMouse() if not UserInputService.TouchEnabled then mouse.Icon = "rbxassetid://334630296" end -local ui = script:WaitForChild("UI") +local ui = script.UI ui.Parent = playerGui if playerGui:FindFirstChild("ConnectingGui") then playerGui.ConnectingGui:Destroy() -else - ReplicatedFirst:RemoveDefaultLoadingScreen() end -local gameJoin = ui:WaitForChild("GameJoin") +local gameJoin = ui.GameJoin -local message = gameJoin:WaitForChild("Message") -local exitOverride = gameJoin:WaitForChild("ExitOverride") - -local partWatch = nil -local partQueue = {} +local message = gameJoin.Message +local exitOverride = gameJoin.ExitOverride local bricks = 0 local connectors = 0 @@ -59,21 +45,16 @@ gameJoin.Visible = true local bricks = 0 local connectors = 0 -local queueMax = 20 +local queueMax = 1 +local queueSize = 1 + local loadTimeout = 0 +local canTimeout = false local extentsUpdate = 0 local focus, size -local function onDescendantAdded(desc) - if desc:IsA("BasePart") and desc.Transparency < 1 then - if not (desc:IsA("Terrain") or desc.Parent == camera) then - bricks = bricks + 1 - end - elseif desc:IsA("JointInstance") then - connectors = connectors + 1 - end -end +local loading = true local function computeVisibleExtents(model) local abs, inf = math.abs, math.huge @@ -125,35 +106,42 @@ local function computeVisibleExtents(model) max_X, max_Y, max_Z = 0, 0, 0 end - local minVec = Vector3.new(min_X, min_Y, min_Z) - local maxVec = Vector3.new(max_X, max_Y, max_Z) - - local cf = - CFrame.new((min_X + max_X) / 2, - (min_Y + max_Y) / 2, - (min_Z + max_Z) / 2) - - local size = - Vector3.new(max_X - min_X, - max_Y - min_Y, - max_Z - min_Z) + local cf = CFrame.new((min_X + max_X) / 2, + (min_Y + max_Y) / 2, + (min_Z + max_Z) / 2) + + local size = Vector3.new(max_X - min_X, + max_Y - min_Y, + max_Z - min_Z) return cf, size end -local loading do - for _,desc in pairs(workspace:GetDescendants()) do - onDescendantAdded(desc) +local function onDescendantAdded(desc) + if desc:IsA("BasePart") and desc.Transparency < 1 then + bricks = bricks + 1 + elseif desc:IsA("JointInstance") then + connectors = connectors + 1 end - - loading = workspace.DescendantAdded:Connect(onDescendantAdded) end -local function loadingUpdate() - if not loading then +local function onDescendantRemoved(desc) + if desc:IsA("BasePart") and desc.Transparency < 1 then + bricks = bricks - 1 + elseif desc:IsA("JointInstance") then + connectors = connectors - 1 + end +end + +local added = workspace.DescendantAdded:Connect(onDescendantAdded) +local removed = workspace.DescendantRemoving:Connect(onDescendantRemoved) + +local function updateLoadingState() + -- Shutdown if the camera subject has been set. + if camera.CameraSubject ~= nil then return end - + -- Update the extents local now = tick() @@ -172,30 +160,76 @@ local function loadingUpdate() camera.CFrame = camera.CFrame:Lerp(zoom, 0.2) camera.Focus = camera.Focus:Lerp(focus, 0.2) - -- Update the maximum queue size. - local queueSize = ContentProvider.RequestQueueSize - queueMax = math.max(queueMax, queueSize) - - -- Update the display. - local ratio = (queueMax - queueSize) / queueMax - local r_bricks = math.floor(bricks * ratio) - local r_connectors = math.floor(connectors * ratio) - message.Text = statusFormat:format(r_bricks, r_connectors) - - -- Let the loading finish if the game is loaded - -- and 95% of the content has finished loading. - if game:IsLoaded() and ratio > 0.95 then - loadTimeout = loadTimeout + 1 + if loading then + -- Update the display. + local ratio = (queueMax - queueSize) / queueMax + local r_bricks = math.floor(bricks * ratio) + local r_connectors = math.floor(connectors * ratio) + message.Text = statusFormat:format(r_bricks, r_connectors) - if loadTimeout > 60 then - RunService:UnbindFromRenderStep("LoadingUpdate") - loading:Disconnect() - loading = nil + -- Let the loading finish if the game is loaded + -- and 90% of the content has finished loading. + + if game:IsLoaded() and ratio > 0.9 and canTimeout then + loadTimeout = loadTimeout + 1 + + if loadTimeout > 30 then + loading = false + + if added then + added:Disconnect() + added = nil + end + + if removed then + removed:Disconnect() + removed = nil + end + end end end end -RunService:BindToRenderStep("LoadingUpdate", 1000, loadingUpdate) +RunService:BindToRenderStep("LoadingState", 1000, updateLoadingState) + +coroutine.wrap(function () + local function setCoreSafe(method, ...) + while not pcall(StarterGui.SetCore, StarterGui, method, ...) do + RunService.Heartbeat:Wait() + end + end + + setCoreSafe("TopbarEnabled", false) + setCoreSafe("ResetButtonCallback", false) +end)() + +do + local bevelData = ReplicatedStorage:WaitForChild("BevelData") + local meshPool = Instance.new("Folder", script) + + for assetId in bevelData.Value:gmatch("[^;]+") do + local mesh = Instance.new("SpecialMesh") + mesh.MeshId = assetId + mesh.Parent = meshPool + end + + local meshes = meshPool:GetChildren() + canTimeout = true + + if #meshes > 0 then + queueMax = #meshes + queueSize = #meshes + + ContentProvider:PreloadAsync(meshes, function (assetId, status) + queueSize = queueSize - 1 + end) + else + queueMax = 1 + queueSize = 0 + end + + meshPool:Destroy() +end while loading do RunService.Heartbeat:Wait() @@ -222,4 +256,5 @@ end camera.CameraType = "Custom" camera.CameraSubject = player.Character +RunService:UnbindFromRenderStep("LoadingState") script:Destroy() \ No newline at end of file