--Made by Stickmasterluke local storage = game:GetService('ServerStorage') local sharedStorage = game:GetService('ReplicatedStorage') local event = sharedStorage:WaitForChild('Event') event.OnServerEvent:connect(function(player, eventName, ...) print(player,eventName,...) local tuple = {...} if eventName == 'Respawn' then end end) --Made By Stickmasterluke local userInputService = game:GetService('UserInputService') local ContextActionService = game:GetService('ContextActionService') local sharedStorage = game:GetService('ReplicatedStorage') local runService = game:GetService('RunService') local terrain = game.Workspace.Terrain local debris = game:GetService('Debris') local camera = game.Workspace.CurrentCamera local player = game.Players.LocalPlayer local materialsTable = require(script.MaterialsList) local playerGui = player:WaitForChild('PlayerGui') local tools = { {name = 'Add', usesMaterials = true, color = BrickColor.new('Toothpaste'), swapWith = 2 }, {name = 'Subtract', color = BrickColor.new('Really red'), swapWith = 1, }, {name = 'Grow', usesMaterials = true, color = BrickColor.new('Lime green'), swapWith = 4, }, {name = 'Erode', color = BrickColor.new('Br. yellowish orange'), swapWith = 3, }, {name = 'Paint', usesMaterials = true, color = BrickColor.new('Institutional white') }, } local scale = 30 local strength = 0 local resolution = 4 --grid resolution (4x4x4 voxels) local maxSelectionSize = 7 local selectionSize = 3 local materialSelection = materialsTable[1] local toolNumber = 1 local currentTool = tools[toolNumber] local brushShape = 'Sphere' local snapToGrid = false ----Variables---- local forceSnapToGrid = false local forceIgnoreWater = false local forceIgnoreWaterTo = true local isIgnoreWater = true local lastCursorDistance = 300 local one256th = 1/256 --This should later be replaced with 0 once smooth terrain doesn't aproximate 1/256 to 0. This is causing small occupancies to become air local materialAir = Enum.Material.Air local materialWater = Enum.Material.Water local ceil = math.ceil local floor = math.floor local abs = math.abs local min = math.min local max = math.max local sqrt = math.sqrt local sin = math.sin local cos = math.cos local pi = math.pi --------------- local touchPadTemplate = game:GetService('ReplicatedStorage'):WaitForChild('TouchPadTemplate') local touchPadVisual1 = touchPadTemplate:clone() touchPadVisual1.Parent = playerGui local touchPadVisual2 = touchPadTemplate:clone() touchPadVisual2.Parent = playerGui local linePart = game:GetService('ReplicatedStorage'):WaitForChild('LinePart'):clone() local palettePanel = game:GetService('ReplicatedStorage'):WaitForChild('PalettePanel'):clone() palettePanel.Parent = playerGui for i,materialSubTable in pairs(materialsTable) do local newMaterialLabel = Instance.new('ImageLabel') newMaterialLabel.Name = 'MaterialButton' .. materialSubTable.enum.Name newMaterialLabel.BorderSizePixel = 2 newMaterialLabel.BorderColor3 = Color3.new(223/255, 223/255, 223/255)--Color3.new(.2, 1, 1) newMaterialLabel.BackgroundColor3 = Color3.new(.2, 1, 1) newMaterialLabel.BackgroundTransparency = 0 newMaterialLabel.Image = materialSubTable.image newMaterialLabel.Size = UDim2.new(0, 160, 0, 160) newMaterialLabel.Position = UDim2.new(0, 33 + ((i-1) % 5) * 193, 0, 33 + (ceil(i/5)-1) * 193) newMaterialLabel.ZIndex = 2 newMaterialLabel.Parent = palettePanel.SurfaceGui.Background materialSubTable.button = newMaterialLabel end local selectionPart = nil local selectionObject = nil function updateSelection() if not selectionPart then selectionPart = Instance.new('Part') selectionPart.Name = 'SelectionPart' selectionPart.Transparency = 1 selectionPart.TopSurface = 'Smooth' selectionPart.BottomSurface = 'Smooth' selectionPart.Anchored = true selectionPart.CanCollide = false selectionPart.formFactor = 'Custom' selectionPart.Parent = playerGui end if not selectionObject then selectionObject = Instance.new('SelectionSphere') selectionObject.Name = 'SelectionObject' selectionObject.Adornee = selectionPart selectionObject.Parent = selectionPart end if palettePanel.SurfaceGui.Enabled then selectionObject.Color = BrickColor.new('Institutional white') selectionObject.SurfaceTransparency = 0 selectionObject.SurfaceColor = BrickColor.new('Institutional white') selectionPart.Size = Vector3.new(1, 1, 1) else selectionObject.Color = currentTool.color or BrickColor.new('Toothpaste') selectionObject.SurfaceTransparency = .95 - strength * .3 selectionObject.SurfaceColor = currentTool.color or BrickColor.new('Toothpaste') selectionPart.Size = Vector3.new(1, 1, 1) * selectionSize * resolution + Vector3.new(.1, .1, .1) end end updateSelection() local abs = math.abs local max = math.max local min = math.min local tau = math.pi*2 local pi = math.pi local halfpi = math.pi*.5 local random = math.random local leftThumbstickMotion = Vector3.new(0,0,0) local rightThumbstickMotion = Vector3.new(0,0,0) local mainCFrame1 = CFrame.new(0,0,0) local mainCFrame2 = CFrame.new(0,0,0) camera.CameraType = Enum.CameraType.Scriptable camera.CoordinateFrame = CFrame.new(0,60,0) camera.HeadScale = scale --userInputService.MouseIconEnabled = false game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Chat, false) game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Health, false) game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false) local function fastSpawn(func) coroutine.resume(coroutine.create(func)) end function deepCast(origin, endPoint, ignoreList, filterFunction, cubeTerrain) local ray = Ray.new(origin, endPoint - origin) local hit, pos, normal, material = game.Workspace:FindPartOnRayWithIgnoreList(ray, ignoreList, cubeTerrain) if hit and filterFunction(hit) then table.insert(ignoreList, hit) return deepCast(pos, endPoint, ignoreList, filterFunction, cubeTerrain) else return hit, pos, normal, material end end local bulletFireFilter = function(hit) return hit.Name == 'Effect' end local newCFrame = CFrame.new() runService.Heartbeat:connect(function() end) local function getCell(list, x, y, z, materialList) -- only include materialsList if you want to ignore water return (materialList and materialList[x] and materialList[x][y] and materialList[x][y][z]) == materialWater and 0 or list and list[x] and list[x][y] and list[x][y][z] end local function getNeighborOccupancies(list, x, y, z, materialsList, includeSelf) --only include materialsList if you want to ignore water local fullNeighbor = false local emptyNeighbor = false local neighborOccupancies = includeSelf and getCell(list, x, y, z, materialsList) or 0 local totalNeighbors = includeSelf and 1 or 0 local nearMaterial = materialSelection.enum for axis = 1, 3 do for offset = -1, 1, 2 do local neighbor = nil local neighborMaterial = nil if axis == 1 then neighbor = list[x + offset] and list[x + offset][y][z] elseif axis == 2 then neighbor = list[x][y + offset] and list[x][y + offset][z] elseif axis == 3 then neighbor = list[x][y][z + offset] end if neighbor then if materialsList then if axis == 1 then neighborMaterial = materialsList[x + offset] and materialsList[x + offset][y][z] elseif axis == 2 then neighborMaterial = materialsList[x][y + offset] and materialsList[x][y + offset][z] elseif axis == 3 then neighborMaterial = materialsList[x][y][z + offset] end if neighborMaterial == materialWater then neighbor = 0 end end if neighbor >= 1 then fullNeighbor = true end if neighbor <= 0 then emptyNeighbor = true end totalNeighbors = totalNeighbors + 1 neighborOccupancies = neighborOccupancies + neighbor end end end return neighborOccupancies / (totalNeighbors ~= 0 and totalNeighbors or getCell(list, x, y, z, materialsList)), fullNeighbor, emptyNeighbor end function operation(centerPoint) local desiredMaterial = materialSelection.enum local radius = selectionSize * .5 * resolution local minBounds = Vector3.new( floor((centerPoint.x - radius) / resolution) * resolution, floor((centerPoint.y - radius) / resolution) * resolution, floor((centerPoint.z - radius) / resolution) * resolution) local maxBounds = Vector3.new( ceil((centerPoint.x + radius) / resolution) * resolution, ceil((centerPoint.y + radius) / resolution) * resolution, ceil((centerPoint.z + radius) / resolution) * resolution) local region = Region3.new(minBounds, maxBounds) local materials, occupancies = terrain:ReadVoxels(region, resolution) local airFillerMaterial = materialAir local waterHeight = 0 if isIgnoreWater and (currentTool.name == 'Erode' or currentTool.name == 'Subtract') then for ix,vx in ipairs(materials) do for iy,vy in ipairs(vx) do for iz, vz in ipairs(vy) do if vz == materialWater then airFillerMaterial = materialWater if iy > waterHeight then waterHeight = iy end end end end end end for ix, vx in ipairs(occupancies) do local cellVectorX = minBounds.x + (ix - .5) * resolution - centerPoint.x for iy, vy in pairs(vx) do local cellVectorY = minBounds.y + (iy - .5) * resolution - centerPoint.y for iz, cellOccupancy in pairs(vy) do local cellVectorZ = minBounds.z + (iz - .5) * resolution - centerPoint.z local cellMaterial = materials[ix][iy][iz] local distance = sqrt(cellVectorX * cellVectorX + cellVectorY * cellVectorY + cellVectorZ * cellVectorZ) local magnitudePercent = 1 local brushOccupancy = 1 if brushShape == 'Sphere' then magnitudePercent = cos(min(1, distance / (radius + resolution * .5)) * pi * .5) brushOccupancy = max(0, min(1, (radius + .5 * resolution - distance) / resolution)) elseif brushShape == 'Box' then if not (snapToGrid or forceSnapToGrid) then local xOutside = 1 - max(0, abs(cellVectorX / resolution) + .5 - selectionSize * .5) local yOutside = 1 - max(0, abs(cellVectorY / resolution) + .5 - selectionSize * .5) local zOutside = 1 - max(0, abs(cellVectorZ / resolution) + .5 - selectionSize * .5) brushOccupancy = xOutside * yOutside * zOutside end end if isIgnoreWater and cellMaterial == materialWater then cellMaterial = materialAir cellOccupancy = 0 end local airFillerMaterial = waterHeight >= iy and airFillerMaterial or materialAir if currentTool.name == 'Add' then if selectionSize <= 2 then if brushOccupancy >= .5 then if cellMaterial == materialAir or cellOccupancy <= 0 then materials[ix][iy][iz] = desiredMaterial end occupancies[ix][iy][iz] = 1 end else if brushOccupancy > cellOccupancy then occupancies[ix][iy][iz] = brushOccupancy end if brushOccupancy >= .5 and cellMaterial == materialAir then materials[ix][iy][iz] = desiredMaterial end end elseif currentTool.name == 'Subtract' then if cellMaterial ~= materialAir then if selectionSize <= 2 then if brushOccupancy >= .5 then occupancies[ix][iy][iz] = airFillerMaterial == materialWater and 1 or 0 materials[ix][iy][iz] = airFillerMaterial end else local desiredOccupancy = max(0,1 - brushOccupancy) if desiredOccupancy < cellOccupancy then if desiredOccupancy <= one256th then occupancies[ix][iy][iz] = airFillerMaterial == materialWater and 1 or 0 materials[ix][iy][iz] = airFillerMaterial else occupancies[ix][iy][iz] = min(cellOccupancy, desiredOccupancy) end end end end elseif currentTool.name == 'Grow' then if brushOccupancy >= .5 then --working on local desiredOccupancy = cellOccupancy local neighborOccupancies, fullNeighbor, emptyNeighbor = getNeighborOccupancies(occupancies, ix, iy, iz, isIgnoreWater and materials) if cellOccupancy > 0 or fullNeighbor then --problem if selection size is small. desiredOccupancy = desiredOccupancy + neighborOccupancies * (strength + .1) * .25 * brushOccupancy * magnitudePercent end if cellMaterial == materialAir and desiredOccupancy > 0 then materials[ix][iy][iz] = desiredMaterial end if desiredOccupancy ~= cellOccupancy then occupancies[ix][iy][iz] = desiredOccupancy end end elseif currentTool.name == 'Erode' then if cellMaterial ~= materialAir then local flippedBrushOccupancy = 1 - brushOccupancy if flippedBrushOccupancy <= .5 then local desiredOccupancy = cellOccupancy local emptyNeighbor = false local neighborOccupancies = 6 for axis = 1, 3 do for offset = -1, 1, 2 do local neighbor = nil local neighborMaterial = nil if axis == 1 then neighbor = occupancies[ix + offset] and occupancies[ix + offset][iy][iz] neighborMaterial = materials[ix + offset] and materials[ix + offset][iy][iz] elseif axis == 2 then neighbor = occupancies[ix][iy + offset] and occupancies[ix][iy + offset][iz] neighborMaterial = materials[ix][iy + offset] and materials[ix][iy + offset][iz] elseif axis == 3 then neighbor = occupancies[ix][iy][iz + offset] neighborMaterial = materials[ix][iy][iz + offset] end if neighbor then if isIgnoreWater and neighborMaterial == materialWater then neighbor = 0 end if neighbor <= 0 then emptyNeighbor = true end neighborOccupancies = neighborOccupancies - neighbor end end end if cellOccupancy < 1 or emptyNeighbor then desiredOccupancy = max(0,desiredOccupancy - (neighborOccupancies / 6) * (strength + .1) * .25 * brushOccupancy * magnitudePercent) end if desiredOccupancy <= one256th then occupancies[ix][iy][iz] = airFillerMaterial == materialWater and 1 or 0 materials[ix][iy][iz] = airFillerMaterial else occupancies[ix][iy][iz] = desiredOccupancy end end end elseif currentTool.name == 'Paint' then if brushOccupancy > 0 and cellOccupancy > 0 then materials[ix][iy][iz] = desiredMaterial end end end end end terrain:WriteVoxels(region, resolution, materials, occupancies) end local downKeys = {} local function handleInput(input,soaked) if input.KeyCode == Enum.KeyCode.Thumbstick1 then leftThumbstickMotion = Vector3.new(input.Position.x,0,-input.Position.y) end if input.KeyCode == Enum.KeyCode.Thumbstick2 then rightThumbstickMotion = Vector3.new(input.Position.x,0,-input.Position.y) end if input.KeyCode == Enum.KeyCode.ButtonR2 then strength = min(1,max(0,(input.Position.z-.1)*1.11)) updateSelection() end if input.UserInputState == Enum.UserInputState.Begin then if input.KeyCode then downKeys[input.KeyCode] = tick() end if input.KeyCode == Enum.KeyCode.ButtonR1 then local swapWith = currentTool.swapWith if swapWith then currentTool = tools[swapWith] updateSelection() end elseif input.KeyCode == Enum.KeyCode.ButtonL1 then palettePanel.SurfaceGui.Enabled = not palettePanel.SurfaceGui.Enabled updateSelection() elseif input.KeyCode == Enum.KeyCode.ButtonA then if abs(rightThumbstickMotion.x) > abs(rightThumbstickMotion.z) then if rightThumbstickMotion.x < 0 then toolNumber = ((toolNumber - 2)%#tools) + 1 currentTool = tools[toolNumber] else toolNumber = (toolNumber%#tools) + 1 currentTool = tools[toolNumber] end else if rightThumbstickMotion.z < 0 then selectionSize = min(maxSelectionSize,selectionSize + 1) else selectionSize = max(1,selectionSize - 1) end end updateSelection() elseif input.KeyCode == Enum.KeyCode.ButtonB then local controllerCFrame = camera.CoordinateFrame*userInputService:GetUserCFrame(Enum.UserCFrame.LeftHand) local positionChange = (controllerCFrame * CFrame.new(leftThumbstickMotion*scale)).p - controllerCFrame.p camera.CoordinateFrame = CFrame.new(positionChange) * camera.CoordinateFrame end elseif input.UserInputState == Enum.UserInputState.End then elseif input.UserInputState == Enum.UserInputState.Change then end end userInputService.InputBegan:connect(handleInput) userInputService.InputEnded:connect(handleInput) userInputService.InputChanged:connect(handleInput) runService.Heartbeat:connect(function() if strength > 0 and not palettePanel.SurfaceGui.Enabled then operation(mainCFrame1.p) end end) local lastTick = tick() local camerax = 0 local cameray = 0 runService:BindToRenderStep('Pizza', Enum.RenderPriority.Camera.Value, function() local thisTick = tick() local delta = thisTick - lastTick lastTick = thisTick local renderCamera = camera:GetRenderCFrame() local userHeadCFrame = userInputService:GetUserCFrame(Enum.UserCFrame.Head) local userLeftHandCFrame = userInputService:GetUserCFrame(Enum.UserCFrame.LeftHand) local userRightHandCFrame = userInputService:GetUserCFrame(Enum.UserCFrame.RightHand) local scaledLeftHandCFrame = CFrame.new(userLeftHandCFrame.p*(scale-1))*userLeftHandCFrame local scaledRightHandCFrame = CFrame.new(userRightHandCFrame.p*(scale-1))*userRightHandCFrame mainCFrame1 = camera.CoordinateFrame * scaledRightHandCFrame mainCFrame2 = camera.CoordinateFrame * scaledLeftHandCFrame touchPadVisual1.SurfaceGui.Enabled = (rightThumbstickMotion ~= Vector3.new(0,0,0)) if touchPadVisual1.SurfaceGui.Enabled then touchPadVisual1.Size = Vector3.new(1,0,1) * scale * .15 touchPadVisual1.CFrame = camera.CoordinateFrame * scaledRightHandCFrame * CFrame.new(0,0,.15*scale) * CFrame.Angles(0,-halfpi,0) touchPadVisual1.SurfaceGui.TouchIcon.Position = UDim2.new(rightThumbstickMotion.x*.5+.5,0,rightThumbstickMotion.z*.5+.5,0) end touchPadVisual2.SurfaceGui.Enabled = (leftThumbstickMotion ~= Vector3.new(0,0,0)) if touchPadVisual2.SurfaceGui.Enabled then touchPadVisual2.Size = Vector3.new(1,0,1) * scale * .15 touchPadVisual2.CFrame = camera.CoordinateFrame * scaledLeftHandCFrame * CFrame.new(0,0,.15*scale) * CFrame.Angles(0,-halfpi,0) touchPadVisual2.SurfaceGui.TouchIcon.Position = UDim2.new(leftThumbstickMotion.x*.5+.5,0,leftThumbstickMotion.z*.5+.5,0) end linePart.Parent = touchPadVisual2.SurfaceGui.Enabled and game.Workspace or nil if linePart.Parent then local startCFrame = camera.CoordinateFrame * scaledLeftHandCFrame * CFrame.new(0,0,.15*scale) local point1 = startCFrame.p local point2 = (startCFrame * CFrame.new(leftThumbstickMotion*scale)).p local distance = (point1-point2).magnitude linePart.Size = Vector3.new(.01*scale,.01*scale,distance) linePart.CFrame = CFrame.new(point1,point2) * CFrame.new(0,0,-distance*.5) end if palettePanel.SurfaceGui.Enabled then palettePanel.Size = Vector3.new(1,0,1) * scale * 1 palettePanel.CFrame = camera.CoordinateFrame * scaledLeftHandCFrame * CFrame.new(.75*scale,0,.15*scale) * CFrame.Angles(0,-halfpi,0) end if not userInputService.VREnabled then if leftThumbstickMotion.magnitude > .2 then local positionChange = (renderCamera * CFrame.new(leftThumbstickMotion*delta*scale*2)).p - renderCamera.p camera.CoordinateFrame = CFrame.new(positionChange) * camera.CoordinateFrame -- * CFrame.new(leftThumbstickMotion*delta*scale*2) end end if rightThumbstickMotion.magnitude > .2 then if not userInputService.VREnabled then camerax = camerax - delta*rightThumbstickMotion.x cameray = cameray - delta*rightThumbstickMotion.z camera.CoordinateFrame = CFrame.new(camera.CoordinateFrame.p) * CFrame.Angles(0,camerax,0) * CFrame.Angles(cameray,0,0) end end if palettePanel.SurfaceGui.Enabled then local localEndpoint = palettePanel:GetRenderCFrame():pointToObjectSpace(mainCFrame1.p) local scaleX = .5 - (localEndpoint.Z / palettePanel.Size.Z) local scaleY = .5 + (localEndpoint.X / palettePanel.Size.X) local scaleDepth = (localEndpoint.Y+palettePanel.Size.Y*.5) / palettePanel.Size.X if abs(scaleDepth) < .05 then if scaleX >= 0 and scaleX <= 1 and scaleY >= 0 and scaleY <= 1 then --some sanity checks to lower computation when not near palette local offsetX = scaleX * palettePanel.SurfaceGui.AbsoluteSize.X local offsetY = scaleY * palettePanel.SurfaceGui.AbsoluteSize.Y local touchingMaterial = nil for i,v in pairs(materialsTable) do local button = v.button if button then if offsetX >= button.AbsolutePosition.X and offsetX <= button.AbsolutePosition.X + button.AbsoluteSize.X and offsetY >= button.AbsolutePosition.Y and offsetY <= button.AbsolutePosition.Y + button.AbsoluteSize.Y then touchingMaterial = v break end end end if touchingMaterial and touchingMaterial ~= materialSelection then materialSelection = touchingMaterial for i,v in pairs(materialsTable) do local button = v.button if button then button.BorderSizePixel = (touchingMaterial == v) and 20 or 2 end end end end end end selectionPart.CFrame = mainCFrame1 end) -- local materialsTable = { --Interface order is defined by order here {enum = Enum.Material.Grass, image = 'http://www.roblox.com/asset/?id=225314676'}, {enum = Enum.Material.Sand, image = 'http://www.roblox.com/asset/?id=225315607'}, {enum = Enum.Material.Rock, image = 'http://www.roblox.com/asset/?id=225315178'}, {enum = Enum.Material.Water, image = 'http://www.roblox.com/asset/?id=225315529', forceIgnoreWater = true, forceIgnoreWaterTo = false}, {enum = Enum.Material.Ground, image = 'http://www.roblox.com/asset/?id=254542189'}, {enum = Enum.Material.Sandstone, image = 'http://www.roblox.com/asset/?id=254541350'}, {enum = Enum.Material.Slate, image = 'http://www.roblox.com/asset/?id=225315290'}, {enum = Enum.Material.Snow, image = 'http://www.roblox.com/asset/?id=254541898'}, {enum = Enum.Material.Mud, image = 'http://www.roblox.com/asset/?id=254541862'}, {enum = Enum.Material.Brick, image = 'http://www.roblox.com/asset/?id=225315419', forceSnapToGrid = true}, {enum = Enum.Material.Concrete, image = 'http://www.roblox.com/asset/?id=225314983'}, {enum = Enum.Material.Glacier, image = 'http://www.roblox.com/asset/?id=254541572'}, {enum = Enum.Material.WoodPlanks, image = 'http://www.roblox.com/asset/?id=225315705', forceSnapToGrid = true}, {enum = Enum.Material.CrackedLava, image = 'http://www.roblox.com/asset/?id=254541726'}, {enum = Enum.Material.Basalt, image = 'http://www.roblox.com/asset/?id=254542066'}, } return materialsTable