From 4785795640ab632f77adb782352e56fa0acb94ad Mon Sep 17 00:00:00 2001 From: ocbwoy3 Date: Fri, 9 Jan 2026 17:02:35 +0200 Subject: [PATCH] core: some fixes --- .gitmodules | 3 - .../Shared/ChunkManager/init.lua | 174 +++++++++++++++--- ReplicatedStorage/Shared/PlacementManager.lua | 2 +- ReplicatedStorage/Shared/Util.lua | 5 +- ServerScriptService/Actor/ClientState.lua | 3 +- .../Actor/PlayerScale.server.lua | 47 ----- .../ServerChunkManager/TerrainGen/init.lua | 12 +- StarterGui/Hotbar/LocalScript.client.lua | 3 +- ThirdParty/Character-Realism | 1 - default.project.json | 12 +- 10 files changed, 166 insertions(+), 96 deletions(-) delete mode 100644 .gitmodules delete mode 100644 ServerScriptService/Actor/PlayerScale.server.lua delete mode 160000 ThirdParty/Character-Realism diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 69313dc..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "ThirdParty/Character-Realism"] - path = ThirdParty/Character-Realism - url = https://github.com/MaximumADHD/Character-Realism diff --git a/ReplicatedStorage/Shared/ChunkManager/init.lua b/ReplicatedStorage/Shared/ChunkManager/init.lua index db946aa..f9ff8b6 100644 --- a/ReplicatedStorage/Shared/ChunkManager/init.lua +++ b/ReplicatedStorage/Shared/ChunkManager/init.lua @@ -13,6 +13,7 @@ local Globals = require(script.Parent:WaitForChild("Globals")) local remote = game:GetService("ReplicatedStorage"):WaitForChild("RecieveChunkPacket") local tickremote = game:GetService("ReplicatedStorage"):WaitForChild("Tick") +local Players = game:GetService("Players") local ChunkFolder = Instance.new("Folder") ChunkFolder.Name = "$blockscraft_client" @@ -23,7 +24,7 @@ local CHUNK_RADIUS = Globals.RenderDistance or 5 local LOAD_BATCH = Globals.LoadBatch or 8 local RESYNC_INTERVAL = Globals.ResyncInterval or 5 local RESYNC_RADIUS = Globals.ResyncRadius or 2 -local DEBUG_RESYNC = true +local DEBUG_RESYNC = false local FORCELOAD_CHUNKS = { {0, 1, 0} } @@ -35,7 +36,11 @@ local lastChunkKey: string? = nil local lastHeavyTick = 0 local HEAVY_TICK_INTERVAL = 1.5 local lastUnloadSweep = 0 -local UNLOAD_SWEEP_INTERVAL = 1.5 +local UNLOAD_SWEEP_INTERVAL = 3 -- slower sweep cadence +local MAX_LOADED_CHUNKS = 0 +local SPAWN_CHUNK_KEY: string? = nil +local playerFrozen = false +local storedMovementState = nil local function worldToChunkCoord(v: number): number return math.floor((v + 16) / 32) @@ -53,6 +58,11 @@ do table.sort(CHUNK_OFFSETS, function(a, b) return a[4] < b[4] end) + MAX_LOADED_CHUNKS = math.max(1, math.floor(#CHUNK_OFFSETS * 2)) -- tighter cap than full render cube + if FORCELOAD_CHUNKS[1] then + local forced = FORCELOAD_CHUNKS[1] + SPAWN_CHUNK_KEY = `{forced[1]},{forced[2]},{forced[3]}` + end end function ChunkManager:UnloadAllNow() @@ -77,6 +87,126 @@ local function Swait(l) end end +local function setCharacterFrozen(shouldFreeze: boolean) + local player = Players.LocalPlayer + if not player then + return + end + local character = player.Character + if not character then + return + end + local humanoid = character:FindFirstChildOfClass("Humanoid") + local root = character:FindFirstChild("HumanoidRootPart") + if not humanoid or not root then + return + end + if shouldFreeze == playerFrozen then + return + end + if shouldFreeze then + if not storedMovementState then + storedMovementState = { + walkSpeed = humanoid.WalkSpeed, + autoRotate = humanoid.AutoRotate, + } + if humanoid.UseJumpPower then + storedMovementState.jumpPower = humanoid.JumpPower + else + storedMovementState.jumpHeight = humanoid.JumpHeight + end + end + humanoid.AutoRotate = false + humanoid.WalkSpeed = 0 + if humanoid.UseJumpPower then + humanoid.JumpPower = 0 + else + humanoid.JumpHeight = 0 + end + root.Anchored = true + else + root.Anchored = false + if storedMovementState then + humanoid.AutoRotate = storedMovementState.autoRotate + humanoid.WalkSpeed = storedMovementState.walkSpeed + if humanoid.UseJumpPower and storedMovementState.jumpPower then + humanoid.JumpPower = storedMovementState.jumpPower + elseif storedMovementState.jumpHeight then + humanoid.JumpHeight = storedMovementState.jumpHeight + end + end + storedMovementState = nil + end + playerFrozen = shouldFreeze +end + +local function getLocalPlayerChunkPos() + local player = Players.LocalPlayer + if not player then + return nil + end + local character = player.Character + if not character then + return nil + end + local root = character:FindFirstChild("HumanoidRootPart") + if not root then + return nil + end + local pos = root.Position + return { + x = worldToChunkCoord(pos.X), + y = worldToChunkCoord(pos.Y), + z = worldToChunkCoord(pos.Z) + } +end + +local function isWithinRenderDistance(chunkPos: Vector3, centerChunkPos): boolean + if not centerChunkPos then + return false + end + return math.abs(chunkPos.X - centerChunkPos.x) <= CHUNK_RADIUS + and math.abs(chunkPos.Y - centerChunkPos.y) <= CHUNK_RADIUS + and math.abs(chunkPos.Z - centerChunkPos.z) <= CHUNK_RADIUS +end + +local function shouldSkipUnload(key: string): boolean + return SPAWN_CHUNK_KEY ~= nil and key == SPAWN_CHUNK_KEY +end + +local function scheduleChunkUnload(key: string, chunk) + if not chunk or unloadingChunks[key] then + return + end + unloadingChunks[key] = true + task.defer(function() + chunk:Unload() + chunk:Destroy() + Chunk.AllChunks[key] = nil + unloadingChunks[key] = nil + end) +end + +local function evictOutOfRangeChunks(centerChunkPos) + if not centerChunkPos then + return + end + local loadedCount = 0 + for key, loadedChunk in pairs(Chunk.AllChunks) do + if loadedChunk.loaded and not shouldSkipUnload(key) then + local inRange = isWithinRenderDistance(loadedChunk.pos, centerChunkPos) + if inRange then + loadedCount += 1 + if loadedCount > MAX_LOADED_CHUNKS then + scheduleChunkUnload(key, loadedChunk) + end + else + scheduleChunkUnload(key, loadedChunk) + end + end + end +end + function ChunkManager:GetChunk(x, y, z) local key = `{x},{y},{z}` if Chunk.AllChunks[key] then @@ -112,7 +242,10 @@ local function ensureNeighboringChunksLoaded(x, y, z) for _, offset in ipairs(offsets) do local nx, ny, nz = x + offset[1], y + offset[2], z + offset[3] - ChunkManager:GetChunk(nx, ny, nz):Tick() + local neighbor = ChunkManager:GetChunk(nx, ny, nz) + if neighbor then + neighbor:Tick() + end end end @@ -136,6 +269,7 @@ function ChunkManager:LoadChunk(x, y, z) chunk.instance = instance chunk.loaded = true unloadingChunks[key] = nil + evictOutOfRangeChunks(getLocalPlayerChunkPos()) end) end @@ -251,7 +385,7 @@ end function ChunkManager:Tick() ChunkManager:ForceTick() - local player = game:GetService("Players").LocalPlayer + local player = Players.LocalPlayer if not player.Character then return end @@ -263,6 +397,7 @@ function ChunkManager:Tick() z = worldToChunkCoord(pos.Z) } local ck = `{chunkPos.x},{chunkPos.y},{chunkPos.z}` + local currentChunk = Chunk.AllChunks[ck] local now = tick() local shouldHeavyTick = (ck ~= lastChunkKey) or (now - lastHeavyTick >= HEAVY_TICK_INTERVAL) lastChunkKey = ck @@ -270,26 +405,29 @@ function ChunkManager:Tick() lastHeavyTick = now end + setCharacterFrozen(not (currentChunk and currentChunk.loaded)) + if shouldHeavyTick then task.defer(function() local processed = 0 for _, offset in ipairs(CHUNK_OFFSETS) do local cx, cy, cz = chunkPos.x + offset[1], chunkPos.y + offset[2], chunkPos.z + offset[3] local chunk = ChunkManager:GetChunk(cx, cy, cz) - chunk.inhabitedTime = now - if not chunk.loaded then - ChunkManager:LoadChunk(cx, cy, cz) - processed += 1 - if processed % LOAD_BATCH == 0 then - Swait(1) + if chunk then + chunk.inhabitedTime = now + if not chunk.loaded then + ChunkManager:LoadChunk(cx, cy, cz) + processed += 1 + if processed % LOAD_BATCH == 0 then + Swait(1) + end end end end end) else - local current = Chunk.AllChunks[ck] - if current then - current.inhabitedTime = now + if currentChunk then + currentChunk.inhabitedTime = now end end @@ -318,14 +456,8 @@ function ChunkManager:Tick() if now - lastUnloadSweep >= UNLOAD_SWEEP_INTERVAL then lastUnloadSweep = now for key, loadedChunk in pairs(Chunk.AllChunks) do - if now - loadedChunk.inhabitedTime > 15 and not unloadingChunks[key] then - unloadingChunks[key] = true - task.defer(function() - loadedChunk:Unload() - loadedChunk:Destroy() - Chunk.AllChunks[key] = nil - unloadingChunks[key] = nil - end) + if now - loadedChunk.inhabitedTime > 30 and not unloadingChunks[key] and not shouldSkipUnload(key) then -- keep chunks around longer before unloading + scheduleChunkUnload(key, loadedChunk) end end end diff --git a/ReplicatedStorage/Shared/PlacementManager.lua b/ReplicatedStorage/Shared/PlacementManager.lua index c4da335..956e0ff 100644 --- a/ReplicatedStorage/Shared/PlacementManager.lua +++ b/ReplicatedStorage/Shared/PlacementManager.lua @@ -6,7 +6,7 @@ local PlacementManager = {} local ChunkManager = require("./ChunkManager") local Util = require("./Util") -local DEBUG_PLACEMENT = true +local DEBUG_PLACEMENT = false local function debugPlacementLog(...: any) if DEBUG_PLACEMENT then Util.StudioLog(...) diff --git a/ReplicatedStorage/Shared/Util.lua b/ReplicatedStorage/Shared/Util.lua index 5ca4f8b..5e9d204 100644 --- a/ReplicatedStorage/Shared/Util.lua +++ b/ReplicatedStorage/Shared/Util.lua @@ -1,18 +1,19 @@ local RunService = game:GetService("RunService") local IS_STUDIO = RunService:IsStudio() +local ENABLE_STUDIO_LOG = false local module = {} -- Prints only when running in Studio (avoids noisy live logs) function module.StudioLog(...: any) - if not IS_STUDIO then + if not IS_STUDIO or not ENABLE_STUDIO_LOG then return end print(...) end function module.StudioWarn(...: any) - if not IS_STUDIO then + if not IS_STUDIO or not ENABLE_STUDIO_LOG then return end warn(...) diff --git a/ServerScriptService/Actor/ClientState.lua b/ServerScriptService/Actor/ClientState.lua index 378a68c..110d39d 100644 --- a/ServerScriptService/Actor/ClientState.lua +++ b/ServerScriptService/Actor/ClientState.lua @@ -43,9 +43,10 @@ local function rebuildBlockCatalog() for _, block in ipairs(blocksFolder:GetChildren()) do local id = block:GetAttribute("n") if id ~= nil then + local displayName = block:GetAttribute("name") or block:GetAttribute("displayName") or block:GetAttribute("dn") or block.Name table.insert(blockCatalog, { id = tostring(id), - name = block:GetAttribute("displayName") or block:GetAttribute("dn") or block.Name, + name = displayName, }) end end diff --git a/ServerScriptService/Actor/PlayerScale.server.lua b/ServerScriptService/Actor/PlayerScale.server.lua deleted file mode 100644 index bb009a7..0000000 --- a/ServerScriptService/Actor/PlayerScale.server.lua +++ /dev/null @@ -1,47 +0,0 @@ ---!native ---!optimize 2 - -local Players = game:GetService("Players") - -local SCALE = 1.3 - -local function applyScale(character: Model) - if character.ScaleTo then - pcall(function() - character:ScaleTo(SCALE) - end) - return - end - - local humanoid = character:FindFirstChildOfClass("Humanoid") - if not humanoid then - return - end - - if humanoid.RigType == Enum.HumanoidRigType.R15 then - for _, name in ipairs({"BodyHeightScale", "BodyWidthScale", "BodyDepthScale", "HeadScale"}) do - local scaleValue = humanoid:FindFirstChild(name) - if scaleValue then - scaleValue.Value = SCALE - end - end - end -end - -local function onCharacterAdded(character: Model) - character:WaitForChild("Humanoid", 5) - applyScale(character) -end - -local function onPlayerAdded(player: Player) - player.CharacterAdded:Connect(onCharacterAdded) - if player.Character then - onCharacterAdded(player.Character) - end -end - -for _, player in ipairs(Players:GetPlayers()) do - onPlayerAdded(player) -end - -Players.PlayerAdded:Connect(onPlayerAdded) diff --git a/ServerScriptService/Actor/ServerChunkManager/TerrainGen/init.lua b/ServerScriptService/Actor/ServerChunkManager/TerrainGen/init.lua index acc0534..8ee1031 100644 --- a/ServerScriptService/Actor/ServerChunkManager/TerrainGen/init.lua +++ b/ServerScriptService/Actor/ServerChunkManager/TerrainGen/init.lua @@ -63,9 +63,7 @@ function TerrainGen:GetChunk(x, y, z) if y == 1 then for cx = 1, 8 do for cz = 1, 8 do - --local perlin = math.noise(((x*8)+cx)/100,((z*8)+cz)/100) - chunk:CreateBlock(cx, 1, cz, { id = 1, state = {} }) - --chunk:CreateBlock(x, 2, z, { id = 1, state = {} }) + chunk:CreateBlock(cx, 1, cz, { id = "mc:grass_block", state = {} }) end end end @@ -73,9 +71,7 @@ function TerrainGen:GetChunk(x, y, z) for cx = 1, 8 do for cy = 1, 8 do for cz = 1, 8 do - --local perlin = math.noise(((x*8)+cx)/100,((z*8)+cz)/100) - chunk:CreateBlock(cx, cy, cz, { id = 2, state = {} }) - --chunk:CreateBlock(x, 2, z, { id = 1, state = {} }) + chunk:CreateBlock(cx, cy, cz, { id = "mc:dirt_block", state = {} }) end end end @@ -93,9 +89,7 @@ function TerrainGen:GetFakeChunk(x, y, z) for cy = 1,8 do for cx = 1, 8 do for cz = 1, 8 do - --local perlin = math.noise(((x*8)+cx)/100,((z*8)+cz)/100) - chunk:CreateBlock(cx, cy, cz, { id = -2, state = {} }) - --chunk:CreateBlock(x, 2, z, { id = 1, state = {} }) + chunk:CreateBlock(cx, cy, cz, { id = "invalid", state = {} }) end end end diff --git a/StarterGui/Hotbar/LocalScript.client.lua b/StarterGui/Hotbar/LocalScript.client.lua index b8dbbaf..5eab6f5 100644 --- a/StarterGui/Hotbar/LocalScript.client.lua +++ b/StarterGui/Hotbar/LocalScript.client.lua @@ -313,6 +313,7 @@ function Hotbar:render() for i = 1, HOTBAR_SIZE do local id = self.state.slots[i] or "" local isSelected = i == self.state.selected + local displayName = id ~= "" and (self.state.names and self.state.names[id] or id) or "" slotElements[`Slot{i-1}`] = Roact.createElement("TextButton", { Size = UDim2.fromOffset(50, 50), @@ -358,7 +359,7 @@ function Hotbar:render() Position = UDim2.fromOffset(4, 26), Size = UDim2.new(1, -8, 0, 18), Font = Enum.Font.GothamBold, - Text = id, + Text = displayName, TextColor3 = colors.text, TextSize = 15, TextWrapped = true, diff --git a/ThirdParty/Character-Realism b/ThirdParty/Character-Realism deleted file mode 160000 index 14021f7..0000000 --- a/ThirdParty/Character-Realism +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 14021f7c4d0c89dd99d5a5af5f64b363c903767c diff --git a/default.project.json b/default.project.json index 5a4931c..786f1ae 100644 --- a/default.project.json +++ b/default.project.json @@ -23,11 +23,7 @@ "ServerScriptService": { "$className": "ServerScriptService", "$ignoreUnknownInstances": true, - "$path": "ServerScriptService", - - "RealismServer": { - "$path": "ThirdParty/Character-Realism/Realism.server.lua" - } + "$path": "ServerScriptService" }, "StarterGui": { @@ -43,11 +39,7 @@ "StarterPlayerScripts": { "$className": "StarterPlayerScripts", "$ignoreUnknownInstances": true, - "$path": "StarterPlayer/StarterPlayerScripts", - - "RealismClient": { - "$path": "ThirdParty/Character-Realism/RealismClient" - } + "$path": "StarterPlayer/StarterPlayerScripts" } },