Minecraft-like Roblox block game rblx.games/135624152691584
roblox roblox-game rojo

core: impovements

+174 -66
-14
src/ReplicatedStorage/Shared/ChunkManager/Chunk.lua
··· 158 158 end 159 159 160 160 function Chunk:RemoveBlock(x, y, z) 161 - print("[DEBUG] Chunk:RemoveBlock called - Chunk:", self.pos, "Block coords:", x, y, z) 162 161 local blockKey = keyFromCoords(x, y, z) 163 - local existingBlock = self.data[blockKey] 164 - if existingBlock then 165 - print("[DEBUG] Removing existing block with ID:", existingBlock.id) 166 - else 167 - print("[DEBUG] No block found at coords", x, y, z) 168 - end 169 162 self.data[blockKey] = nil 170 163 self:PropogateChanges(x,y,z,0) 171 164 end 172 165 173 166 function Chunk:RemoveBlockSmooth(x, y, z) 174 - print("[DEBUG] Chunk:RemoveBlockSmooth called - Chunk:", self.pos, "Block coords:", x, y, z) 175 167 local blockKey = keyFromCoords(x, y, z) 176 - local existingBlock = self.data[blockKey] 177 - if existingBlock then 178 - print("[DEBUG] Smooth removing existing block with ID:", existingBlock.id) 179 - else 180 - print("[DEBUG] Smooth remove: no block found at coords", x, y, z) 181 - end 182 168 self.data[blockKey] = nil 183 169 self.delayedRemoval[blockKey] = true 184 170 self:PropogateChanges(x,y,z,0)
+105 -40
src/ReplicatedStorage/Shared/PlacementManager.lua
··· 5 5 6 6 local ChunkManager = require("./ChunkManager") 7 7 local Util = require("./Util") 8 - local RunService = game:GetService("RunService") 9 8 10 9 PlacementManager.ChunkFolder = ChunkManager.ChunkFolder 11 10 ··· 33 32 34 33 local Mouse: Mouse = nil 35 34 local lastNormalId: Enum.NormalId? = nil 36 - local pendingBreakResync = {} 35 + local BREAK_ROLLBACK_TIMEOUT = 0.6 36 + local pendingBreaks = {} 37 + 38 + local function makeChunkKey(cx: number, cy: number, cz: number): string 39 + return `{cx},{cy},{cz}` 40 + end 41 + 42 + local function makeBlockKey(x: number, y: number, z: number): string 43 + return `{x},{y},{z}` 44 + end 45 + 46 + local function getPendingBreak(chunkKey: string, blockKey: string) 47 + local chunkMap = pendingBreaks[chunkKey] 48 + if not chunkMap then 49 + return nil 50 + end 51 + return chunkMap[blockKey] 52 + end 53 + 54 + local function clearPendingBreak(chunkKey: string, blockKey: string) 55 + local chunkMap = pendingBreaks[chunkKey] 56 + if not chunkMap then 57 + return 58 + end 59 + chunkMap[blockKey] = nil 60 + if not next(chunkMap) then 61 + pendingBreaks[chunkKey] = nil 62 + end 63 + end 64 + 65 + local function clearPendingBreaksForChunk(chunkKey: string) 66 + pendingBreaks[chunkKey] = nil 67 + end 68 + 69 + local function scheduleBreakRollback(cx: number, cy: number, cz: number, x: number, y: number, z: number) 70 + task.delay(BREAK_ROLLBACK_TIMEOUT, function() 71 + local chunkKey = makeChunkKey(cx, cy, cz) 72 + local blockKey = makeBlockKey(x, y, z) 73 + local pending = getPendingBreak(chunkKey, blockKey) 74 + if not pending then 75 + return 76 + end 77 + clearPendingBreak(chunkKey, blockKey) 78 + local chunk = ChunkManager:GetChunk(cx, cy, cz) 79 + if pending.data and chunk then 80 + chunk:CreateBlock(x, y, z, pending.data) 81 + end 82 + ChunkManager:RefreshChunk(cx, cy, cz) 83 + end) 84 + end 37 85 38 86 local function normalIdToOffset(normal: Enum.NormalId): Vector3 39 87 if normal == Enum.NormalId.Top then ··· 83 131 return Vector3.new(cx, cy, cz), Vector3.new(bx, by, bz) 84 132 end 85 133 134 + local function getPlayerPosition(): Vector3? 135 + local player = game:GetService("Players").LocalPlayer 136 + local character = player and player.Character 137 + if not character then 138 + return nil 139 + end 140 + local root = character:FindFirstChild("HumanoidRootPart") 141 + return root and root.Position or nil 142 + end 143 + 144 + local function isWithinReach(cx: number, cy: number, cz: number, x: number, y: number, z: number): boolean 145 + local playerPos = getPlayerPosition() 146 + if not playerPos then 147 + return false 148 + end 149 + local blockPos = Util.ChunkPosToCFrame(Vector3.new(cx, cy, cz), Vector3.new(x, y, z)).Position 150 + return (blockPos - playerPos).Magnitude <= 24 151 + end 152 + 86 153 -- Gets the block and normalid of the block (and surface) the player is looking at 87 154 function PlacementManager:Raycast() 88 155 if not Mouse then ··· 133 200 134 201 -- FIRES REMOTE 135 202 function PlacementManager:BreakBlock(cx, cy, cz, x, y, z) 136 - print("[DEBUG] PlacementManager:BreakBlock called - Chunk:", cx, cy, cz, "Block:", x, y, z) 203 + if typeof(cx) ~= "number" or typeof(cy) ~= "number" or typeof(cz) ~= "number" then 204 + return 205 + end 206 + if typeof(x) ~= "number" or typeof(y) ~= "number" or typeof(z) ~= "number" then 207 + return 208 + end 209 + if x < 1 or x > 8 or y < 1 or y > 8 or z < 1 or z > 8 then 210 + return 211 + end 212 + if not isWithinReach(cx, cy, cz, x, y, z) then 213 + return 214 + end 215 + 137 216 local chunk = ChunkManager:GetChunk(cx, cy, cz) 138 - if chunk and not chunk:GetBlockAt(x, y, z) then 139 - print("[DEBUG] Client missing block; resyncing nearby chunks") 140 - ChunkManager:ResyncAroundChunk(cx, cy, cz, 1) 141 - task.defer(function() 142 - task.synchronize() 143 - RunService.RenderStepped:Wait() 144 - task.desynchronize() 145 - local refreshed = ChunkManager:GetChunk(cx, cy, cz) 146 - if refreshed and refreshed:GetBlockAt(x, y, z) then 147 - task.synchronize() 148 - breakRemote:FireServer(cx, cy, cz, x, y, z) 149 - task.desynchronize() 150 - print("[DEBUG] BreakBlock remote fired to server after resync") 151 - end 152 - end) 217 + local blockData = chunk and chunk:GetBlockAt(x, y, z) or nil 218 + local chunkKey = makeChunkKey(cx, cy, cz) 219 + local blockKey = makeBlockKey(x, y, z) 220 + if getPendingBreak(chunkKey, blockKey) then 153 221 return 154 222 end 223 + pendingBreaks[chunkKey] = pendingBreaks[chunkKey] or {} 224 + pendingBreaks[chunkKey][blockKey] = { 225 + data = blockData, 226 + time = tick(), 227 + } 228 + if blockData then 229 + chunk:RemoveBlock(x, y, z) 230 + end 231 + scheduleBreakRollback(cx, cy, cz, x, y, z) 155 232 task.synchronize() 156 233 breakRemote:FireServer(cx, cy, cz, x, y, z) 157 234 task.desynchronize() 158 - print("[DEBUG] BreakBlock remote fired to server") 159 235 end 160 236 161 237 -- CLIENTSIDED: only apply server-validated changes ··· 166 242 167 243 -- CLIENTSIDED: only apply server-validated changes 168 244 local function applyBreakBlockLocal(cx, cy, cz, x, y, z) 169 - print("[DEBUG] PlacementManager:BreakBlockLocal called - Chunk:", cx, cy, cz, "Block:", x, y, z) 170 245 local chunk = ChunkManager:GetChunk(cx, cy, cz) 171 - if chunk then 172 - print("[DEBUG] Found chunk, calling RemoveBlock") 173 - if chunk.RemoveBlockSmooth then 174 - chunk:RemoveBlockSmooth(x, y, z) 175 - else 176 - chunk:RemoveBlock(x, y, z) 177 - end 178 - else 179 - print("[DEBUG] Chunk not found at coords:", cx, cy, cz) 246 + if not chunk then 247 + return 248 + end 249 + local chunkKey = makeChunkKey(cx, cy, cz) 250 + local blockKey = makeBlockKey(x, y, z) 251 + if getPendingBreak(chunkKey, blockKey) then 252 + clearPendingBreak(chunkKey, blockKey) 253 + return 180 254 end 255 + chunk:RemoveBlock(x, y, z) 181 256 end 182 257 183 258 function PlacementManager:GetBlockAtMouse(): nil | {chunk:Vector3, block: Vector3} ··· 250 325 end 251 326 if m == "B_D" then 252 327 applyBreakBlockLocal(cx, cy, cz, x, y ,z) 253 - local key = `{cx},{cy},{cz}` 254 - if not pendingBreakResync[key] then 255 - pendingBreakResync[key] = true 256 - task.defer(function() 257 - task.synchronize() 258 - RunService.RenderStepped:Wait() 259 - task.desynchronize() 260 - pendingBreakResync[key] = nil 261 - ChunkManager:ResyncAroundChunk(cx, cy, cz, 1) 262 - end) 263 - end 264 328 end 265 329 if m == "C_R" then 330 + clearPendingBreaksForChunk(makeChunkKey(cx, cy, cz)) 266 331 ChunkManager:RefreshChunk(cx, cy, cz) 267 332 end 268 333 end)
+47
src/ServerScriptService/Actor/PlayerScale.server.lua
··· 1 + --!native 2 + --!optimize 2 3 + 4 + local Players = game:GetService("Players") 5 + 6 + local SCALE = 1.4 7 + 8 + local function applyScale(character: Model) 9 + if character.ScaleTo then 10 + pcall(function() 11 + character:ScaleTo(SCALE) 12 + end) 13 + return 14 + end 15 + 16 + local humanoid = character:FindFirstChildOfClass("Humanoid") 17 + if not humanoid then 18 + return 19 + end 20 + 21 + if humanoid.RigType == Enum.HumanoidRigType.R15 then 22 + for _, name in ipairs({"BodyHeightScale", "BodyWidthScale", "BodyDepthScale", "HeadScale"}) do 23 + local scaleValue = humanoid:FindFirstChild(name) 24 + if scaleValue then 25 + scaleValue.Value = SCALE 26 + end 27 + end 28 + end 29 + end 30 + 31 + local function onCharacterAdded(character: Model) 32 + character:WaitForChild("Humanoid", 5) 33 + applyScale(character) 34 + end 35 + 36 + local function onPlayerAdded(player: Player) 37 + player.CharacterAdded:Connect(onCharacterAdded) 38 + if player.Character then 39 + onCharacterAdded(player.Character) 40 + end 41 + end 42 + 43 + for _, player in ipairs(Players:GetPlayers()) do 44 + onPlayerAdded(player) 45 + end 46 + 47 + Players.PlayerAdded:Connect(onPlayerAdded)
+22 -12
src/ServerScriptService/Actor/ServerChunkManager/init.server.lua
··· 1 1 --!native 2 2 --!optimize 2 3 3 4 - print("Hello world!") 5 - 6 4 task.synchronize() 7 5 8 6 local ReplicatedStorage = game:GetService("ReplicatedStorage") ··· 13 11 14 12 local Util = require(Shared.Util) 15 13 local TG = require("./ServerChunkManager/TerrainGen") 14 + local Players = game:GetService("Players") 16 15 17 16 do 18 17 local workspaceModFolder = game:GetService("Workspace"):WaitForChild("mods") ··· 127 126 return chunk 128 127 end 129 128 129 + local function isBlockInsidePlayer(blockPos: Vector3): boolean 130 + for _, player in ipairs(Players:GetPlayers()) do 131 + local character = player.Character 132 + if character then 133 + local cf, size = character:GetBoundingBox() 134 + local localPos = cf:PointToObjectSpace(blockPos) 135 + if math.abs(localPos.X) <= size.X * 0.5 136 + and math.abs(localPos.Y) <= size.Y * 0.5 137 + and math.abs(localPos.Z) <= size.Z * 0.5 then 138 + return true 139 + end 140 + end 141 + end 142 + return false 143 + end 144 + 130 145 placeRemote.OnServerEvent:Connect(function(player, cx, cy, cz, x, y, z, blockId) 131 146 --print("place",player, cx, cy, cz, x, y, z, blockData) 132 147 ··· 150 165 return 151 166 end 152 167 168 + local blockPos = Util.ChunkPosToCFrame(Vector3.new(cx, cy, cz), Vector3.new(x, y, z)).Position 169 + if isBlockInsidePlayer(blockPos) then 170 + return 171 + end 172 + 153 173 local chunk = getServerChunk(cx, cy, cz) 154 174 if chunk:GetBlockAt(x, y, z) then 155 175 return ··· 163 183 end) 164 184 165 185 breakRemote.OnServerEvent:Connect(function(player, cx, cy, cz, x, y, z) 166 - print("[DEBUG] Server breakRemote received - Player:", player.Name, "Chunk:", cx, cy, cz, "Block:", x, y, z) 167 - 168 186 if typeof(cx) ~= "number" or typeof(cy) ~= "number" or typeof(cz) ~= "number" then 169 - print("[DEBUG] Invalid chunk coordinate types") 170 187 return 171 188 end 172 189 if typeof(x) ~= "number" or typeof(y) ~= "number" or typeof(z) ~= "number" then 173 - print("[DEBUG] Invalid block coordinate types") 174 190 return 175 191 end 176 192 if x < 1 or x > 8 or y < 1 or y > 8 or z < 1 or z > 8 then 177 - print("[DEBUG] Block coordinates out of range:", x, y, z) 178 193 return 179 194 end 180 195 if math.abs(cx) > MAX_CHUNK_DIST or math.abs(cy) > MAX_CHUNK_DIST or math.abs(cz) > MAX_CHUNK_DIST then 181 - print("[DEBUG] Chunk coordinates out of range:", cx, cy, cz) 182 196 return 183 197 end 184 198 if not isWithinReach(player, cx, cy, cz, x, y, z) then 185 - print("[DEBUG] Block not within player reach") 186 199 return 187 200 end 188 201 189 202 local chunk = getServerChunk(cx, cy, cz) 190 203 if not chunk:GetBlockAt(x, y, z) then 191 - print("[DEBUG] No block found at specified location") 192 204 task.synchronize() 193 205 tickRemote:FireClient(player, "C_R", cx, cy, cz, 0, 0, 0, 0) 194 206 task.desynchronize() 195 207 return 196 208 end 197 - print("[DEBUG] All validations passed, removing block") 198 209 chunk:RemoveBlock(x, y, z) 199 210 propogate("B_D", cx, cy, cz, x, y, z, 0) 200 - print("[DEBUG] Block removal propagated to clients") 201 211 end) 202 212 203 213 task.desynchronize()