WackoMcGoose

WackoMcGoose's Roblox Terrain Poking Script

Apr 10th, 2016
561
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.66 KB | None | 0 0
  1. --WackoMcGoose's Roblox Terrain Poking Script
  2. --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.
  3. --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).
  4.  
  5.  
  6.  
  7. local LibMath = {} --Slight edit, this is normally an external module. I added the two required functions here to make this standalone ;)
  8.  
  9. --Make sure the Vector3 is a Vector3, and floor it for node-ing.
  10. LibMath.verifyAndFloorVector3 = function(pos)
  11.     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
  12.     local pos = Vector3.new(math.floor(pos.x), math.floor(pos.y), math.floor(pos.z)) --Idiotproofing, position must be integers.
  13.     return pos
  14. end
  15.  
  16. --Weighted random: Pass in a table of key-value pairs, where the keys can be either ints or strings, and values are ints >= 1.
  17. --Will return one of the keys randomly (based on weights), or nil if the table be invalid.
  18. --Params: Table (format: {Integer/String key = Integer value, ...})
  19. --Returns: Integer/String key, or nil if you did tables wrong
  20. LibMath.weightedRandom = function(values)
  21.     result = nil
  22.     pcall(function()
  23.         local index = 1
  24.         local weighttable = {}
  25.         --Set up table, eith 'value' copies of 'key'
  26.         for key, value in pairs(values) do
  27.             if value < 0 then value = 0 end
  28.             for i = 1, value do
  29.                 weighttable[index] = key
  30.                 index = index + 1
  31.             end
  32.         end
  33.         result = weighttable[math.random(1, #weighttable)]
  34.     end)
  35.     return result
  36. end
  37.  
  38. local module = {}
  39.  
  40. local VOXEL_SIZE = 4
  41. local COORD_SCALAR = Vector3.new(VOXEL_SIZE, VOXEL_SIZE, VOXEL_SIZE)
  42.  
  43. local terrainMaterials = { Enum.Material.Air, Enum.Material.Grass, Enum.Material.WoodPlanks, Enum.Material.Glacier, Enum.Material.Mud, Enum.Material.CrackedLava,
  44.     Enum.Material.Concrete, Enum.Material.Sand, Enum.Material.Rock, Enum.Material.Sandstone, Enum.Material.Ground, Enum.Material.Slate, Enum.Material.Brick,
  45.     Enum.Material.Water, Enum.Material.Snow, Enum.Material.Basalt }
  46.  
  47.  
  48. local function checkVector3Pair(startPos, endPos)
  49.     startPos = LibMath.verifyAndFloorVector3(startPos)
  50.     endPos = LibMath.verifyAndFloorVector3(endPos)
  51.     if not startPos or not endPos then return nil end
  52.     return LibMath.minMaxVector3Pair(startPos, endPos)
  53. end
  54.  
  55. local function vector3ToVoxelRegion(startPos, endPos)
  56.     startPos, endPos = checkVector3Pair(startPos, endPos)
  57.     if not startPos or not endPos then return nil end
  58.     return Region3.new(startPos * COORD_SCALAR, (endPos + Vector3.new(1, 1, 1)) * COORD_SCALAR)
  59. end
  60.  
  61. local function region3ToVoxelRegion(region)
  62.     local startPos, endPos = LibMath.getVector3sFromRegion3(region)
  63.     if not startPos or not endPos then return nil end
  64.     return vector3ToVoxelRegion(startPos, endPos)
  65. end
  66.  
  67. local function isValidMaterial(material)
  68.     for _, mat in pairs(terrainMaterials) do if mat == material then return true end end return false
  69. end
  70.  
  71.  
  72. module.make3dArray = function(startPos, endPos, prepopulatedValue, ...)
  73.     startPos, endPos = checkVector3Pair(startPos, endPos)
  74.     if not startPos or not endPos then return nil end
  75.     local array = {}
  76.     for x = 1, endPos.x - startPos.x + 1 do
  77.         array[x] = {}
  78.         for y = 1, endPos.y - startPos.y + 1 do
  79.             array[x][y] = {}
  80.             for z = 1, endPos.z - startPos.z + 1 do
  81.                 if prepopulatedValue then
  82.                     if type(prepopulatedValue) == "function" then
  83.                         array[x][y][z] = prepopulatedValue(...) --Oh please be pcall'd...
  84.                     else
  85.                         array[x][y][z] = prepopulatedValue
  86.                     end
  87.                 end
  88.             end
  89.         end
  90.     end
  91.     --/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!
  92.     array.Start = startPos
  93.     array.End = endPos
  94.     array.Size = endPos - startPos
  95.     return array
  96. end
  97.  
  98. module.getRandomMaterial = function() return terrainMaterials[math.random(1, #terrainMaterials)] end
  99.  
  100. module.getWeightedRandomMaterial = function(weightTable)
  101.     if not type(weightTable) == "table" then return module.getRandomMaterial() end --Sure why not
  102.     local weightTable2 = {}
  103.     for _, v in pairs(terrainMaterials) do
  104.         weightTable2[v] = weightTable[v] or 1; --Use weight from table if entry is present, or default of 1
  105.         weightTable2[v] = math.max(0, math.floor(weightTable2[v])) --Ensure the weight is >= 0 and an integer
  106.     end
  107.     return LibMath.weightedRandom(weightTable2)
  108. end
  109.  
  110. module.getDataAtPoint = function(point)
  111.     point = LibMath.verifyAndFloorVector3(point)
  112.     if not point then return nil end
  113.     local mat, occup = workspace.Terrain:ReadVoxels(vector3ToVoxelRegion(point, point), VOXEL_SIZE)
  114.     return mat[1][1][1], occup[1][1][1]
  115. end
  116.  
  117. module.getMaterialAtPoint = function(point) local mat, _ = module.getDataAtPoint(point) return mat end
  118. module.getOccupancyAtPoint = function(point) local _, occup = module.getDataAtPoint(point) return occup end
  119.  
  120. module.getDataForRegion = function(startPos, endPos)
  121.     startPos, endPos = checkVector3Pair(startPos, endPos)
  122.     if not startPos or not endPos then return nil end
  123.     local mat, occup = workspace.Terrain:ReadVoxels(vector3ToVoxelRegion(startPos, endPos), VOXEL_SIZE)
  124.     mat.Start = startPos mat.End = endPos occup.Start = startPos occup.End = endPos
  125.     return mat, occup
  126. end
  127.  
  128. module.getMaterialForRegion = function(startPos, endPos) local mat, _ = module.getDataForRegion(startPos, endPos) return mat end
  129. module.getOccupancyForRegion = function(startPos, endPos) local _, occup = module.getDataForRegion(startPos, endPos) return occup end
  130.  
  131. module.setDataAtPoint = function(point, material, occupancy)
  132.     point = LibMath.verifyAndFloorVector3(point)
  133.     if not point then return nil end
  134.     if type(occupancy) ~= "number" then return nil end
  135.     if not isValidMaterial(material) then return nil end
  136.     workspace.Terrain:WriteVoxels(vector3ToVoxelRegion(point, point), VOXEL_SIZE,
  137.         module.make3dArray(point, point, material), module.make3dArray(point, point, occupancy))
  138.     return true --it worked
  139. end
  140.  
  141. module.setMaterialAtPoint = function(point, material) module.setDataAtPoint(point, material, module.getOccupancyAtPoint(point)) end
  142. module.setOccupancyAtPoint = function(point, occupancy) module.setDataAtPoint(point, module.getMaterialAtPoint(point), occupancy) end
  143.  
  144. module.setDataForRegion = function(startPos, endPos, material, occupancy)
  145.     startPos, endPos = checkVector3Pair(startPos, endPos)
  146.     if not startPos or not endPos then return nil end
  147.     local mat, occup
  148.     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
  149.     elseif isValidMaterial(material) then mat = module.make3dArray(startPos, endPos, material) else return nil
  150.     end
  151.     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
  152.     elseif type(occupancy) == "number" then occup = module.make3dArray(startPos, endPos, occupancy) else return nil
  153.     end
  154.     workspace.Terrain:WriteVoxels(vector3ToVoxelRegion(startPos, endPos), VOXEL_SIZE, mat, occup)
  155.     return true
  156. end
  157.  
  158. module.setMaterialForRegion = function(startPos, endPos, material)
  159.     module.setDataForRegion(startPos, endPos, material, module.getOccupancyForRegion(startPos, endPos)) end
  160. module.setOccupancyForRegion = function(startPos, endPos, occupancy)
  161.     module.setDataForRegion(startPos, endPos, module.getMaterialForRegion(startPos, endPos), occupancy) end
  162.  
  163. return module
Advertisement
Add Comment
Please, Sign In to add comment