Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --WackoMcGoose's Roblox Terrain Poking Script
- --Won't help you *generate* terrain, but should make it easier for you to go "hey roblox, fill THIS region with THIS material at THIS occupancy", or "hey roblox, give me THIS region of terrain data", all using Vector3 coords instead of whatever the heck Vector3int16 is.
- --Note on that, by the way: Coordinates are Vector3s by VOXEL coordinates, not STUD coordinates. So "getDataAtPoint(Vector3.new(10, 10, 10))" will return the Enum.Material and float occupancy of the voxel located at stud coordinate (42, 42, 42).
- local LibMath = {} --Slight edit, this is normally an external module. I added the two required functions here to make this standalone ;)
- --Make sure the Vector3 is a Vector3, and floor it for node-ing.
- LibMath.verifyAndFloorVector3 = function(pos)
- if not pcall(function() return pos.x == pos.x end) then warn("Whatever you put into here, it's not a Vector3!") return nil end
- local pos = Vector3.new(math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)) --Idiotproofing, position must be integers.
- return pos
- end
- --Weighted random: Pass in a table of key-value pairs, where the keys can be either ints or strings, and values are ints >= 1.
- --Will return one of the keys randomly (based on weights), or nil if the table be invalid.
- --Params: Table (format: {Integer/String key = Integer value, ...})
- --Returns: Integer/String key, or nil if you did tables wrong
- LibMath.weightedRandom = function(values)
- result = nil
- pcall(function()
- local index = 1
- local weighttable = {}
- --Set up table, eith 'value' copies of 'key'
- for key, value in pairs(values) do
- if value < 0 then value = 0 end
- for i = 1, value do
- weighttable[index] = key
- index = index + 1
- end
- end
- result = weighttable[math.random(1, #weighttable)]
- end)
- return result
- end
- local module = {}
- local VOXEL_SIZE = 4
- local COORD_SCALAR = Vector3.new(VOXEL_SIZE, VOXEL_SIZE, VOXEL_SIZE)
- local terrainMaterials = { Enum.Material.Air, Enum.Material.Grass, Enum.Material.WoodPlanks, Enum.Material.Glacier, Enum.Material.Mud, Enum.Material.CrackedLava,
- Enum.Material.Concrete, Enum.Material.Sand, Enum.Material.Rock, Enum.Material.Sandstone, Enum.Material.Ground, Enum.Material.Slate, Enum.Material.Brick,
- Enum.Material.Water, Enum.Material.Snow, Enum.Material.Basalt }
- local function checkVector3Pair(startPos, endPos)
- startPos = LibMath.verifyAndFloorVector3(startPos)
- endPos = LibMath.verifyAndFloorVector3(endPos)
- if not startPos or not endPos then return nil end
- return LibMath.minMaxVector3Pair(startPos, endPos)
- end
- local function vector3ToVoxelRegion(startPos, endPos)
- startPos, endPos = checkVector3Pair(startPos, endPos)
- if not startPos or not endPos then return nil end
- return Region3.new(startPos * COORD_SCALAR, (endPos + Vector3.new(1, 1, 1)) * COORD_SCALAR)
- end
- local function region3ToVoxelRegion(region)
- local startPos, endPos = LibMath.getVector3sFromRegion3(region)
- if not startPos or not endPos then return nil end
- return vector3ToVoxelRegion(startPos, endPos)
- end
- local function isValidMaterial(material)
- for _, mat in pairs(terrainMaterials) do if mat == material then return true end end return false
- end
- module.make3dArray = function(startPos, endPos, prepopulatedValue, ...)
- startPos, endPos = checkVector3Pair(startPos, endPos)
- if not startPos or not endPos then return nil end
- local array = {}
- for x = 1, endPos.x - startPos.x + 1 do
- array[x] = {}
- for y = 1, endPos.y - startPos.y + 1 do
- array[x][y] = {}
- for z = 1, endPos.z - startPos.z + 1 do
- if prepopulatedValue then
- if type(prepopulatedValue) == "function" then
- array[x][y][z] = prepopulatedValue(...) --Oh please be pcall'd...
- else
- array[x][y][z] = prepopulatedValue
- end
- end
- end
- end
- end
- --/b/rotip: Use array.Start and array.End to generate the Region3 for WriteVoxels... just remember to multiply by 4 and that the second V3 needs to be one bigger!
- array.Start = startPos
- array.End = endPos
- array.Size = endPos - startPos
- return array
- end
- module.getRandomMaterial = function() return terrainMaterials[math.random(1, #terrainMaterials)] end
- module.getWeightedRandomMaterial = function(weightTable)
- if not type(weightTable) == "table" then return module.getRandomMaterial() end --Sure why not
- local weightTable2 = {}
- for _, v in pairs(terrainMaterials) do
- weightTable2[v] = weightTable[v] or 1; --Use weight from table if entry is present, or default of 1
- weightTable2[v] = math.max(0, math.floor(weightTable2[v])) --Ensure the weight is >= 0 and an integer
- end
- return LibMath.weightedRandom(weightTable2)
- end
- module.getDataAtPoint = function(point)
- point = LibMath.verifyAndFloorVector3(point)
- if not point then return nil end
- local mat, occup = workspace.Terrain:ReadVoxels(vector3ToVoxelRegion(point, point), VOXEL_SIZE)
- return mat[1][1][1], occup[1][1][1]
- end
- module.getMaterialAtPoint = function(point) local mat, _ = module.getDataAtPoint(point) return mat end
- module.getOccupancyAtPoint = function(point) local _, occup = module.getDataAtPoint(point) return occup end
- module.getDataForRegion = function(startPos, endPos)
- startPos, endPos = checkVector3Pair(startPos, endPos)
- if not startPos or not endPos then return nil end
- local mat, occup = workspace.Terrain:ReadVoxels(vector3ToVoxelRegion(startPos, endPos), VOXEL_SIZE)
- mat.Start = startPos mat.End = endPos occup.Start = startPos occup.End = endPos
- return mat, occup
- end
- module.getMaterialForRegion = function(startPos, endPos) local mat, _ = module.getDataForRegion(startPos, endPos) return mat end
- module.getOccupancyForRegion = function(startPos, endPos) local _, occup = module.getDataForRegion(startPos, endPos) return occup end
- module.setDataAtPoint = function(point, material, occupancy)
- point = LibMath.verifyAndFloorVector3(point)
- if not point then return nil end
- if type(occupancy) ~= "number" then return nil end
- if not isValidMaterial(material) then return nil end
- workspace.Terrain:WriteVoxels(vector3ToVoxelRegion(point, point), VOXEL_SIZE,
- module.make3dArray(point, point, material), module.make3dArray(point, point, occupancy))
- return true --it worked
- end
- module.setMaterialAtPoint = function(point, material) module.setDataAtPoint(point, material, module.getOccupancyAtPoint(point)) end
- module.setOccupancyAtPoint = function(point, occupancy) module.setDataAtPoint(point, module.getMaterialAtPoint(point), occupancy) end
- module.setDataForRegion = function(startPos, endPos, material, occupancy)
- startPos, endPos = checkVector3Pair(startPos, endPos)
- if not startPos or not endPos then return nil end
- local mat, occup
- if type(material) == "table" then if material.Start and material.End and material.Size then mat = material else warn("Bad material table!") return nil end
- elseif isValidMaterial(material) then mat = module.make3dArray(startPos, endPos, material) else return nil
- end
- if type(occupancy) == "table" then if occupancy.Start and occupancy.End and occupancy.Size then occup = occupancy else warn("Bad occupancy table!") return nil end
- elseif type(occupancy) == "number" then occup = module.make3dArray(startPos, endPos, occupancy) else return nil
- end
- workspace.Terrain:WriteVoxels(vector3ToVoxelRegion(startPos, endPos), VOXEL_SIZE, mat, occup)
- return true
- end
- module.setMaterialForRegion = function(startPos, endPos, material)
- module.setDataForRegion(startPos, endPos, material, module.getOccupancyForRegion(startPos, endPos)) end
- module.setOccupancyForRegion = function(startPos, endPos, occupancy)
- module.setDataForRegion(startPos, endPos, module.getMaterialForRegion(startPos, endPos), occupancy) end
- return module
Advertisement
Add Comment
Please, Sign In to add comment