Advertisement
Haloformide

RbxUtility

Mar 30th, 2020
769
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 36.13 KB | None | 0 0
  1. local t = {}
  2.  
  3. ------------------------------------------------------------------------------------------------------------------------
  4. ------------------------------------------------------------------------------------------------------------------------
  5. ------------------------------------------------------------------------------------------------------------------------
  6. ------------------------------------------------JSON Functions Begin----------------------------------------------------
  7. ------------------------------------------------------------------------------------------------------------------------
  8. ------------------------------------------------------------------------------------------------------------------------
  9. ------------------------------------------------------------------------------------------------------------------------
  10.  
  11.  --JSON Encoder and Parser for Lua 5.1
  12.  --
  13.  --Copyright 2007 Shaun Brown  (http://www.chipmunkav.com)
  14.  --All Rights Reserved.
  15.  
  16.  --Permission is hereby granted, free of charge, to any person
  17.  --obtaining a copy of this software to deal in the Software without
  18.  --restriction, including without limitation the rights to use,
  19.  --copy, modify, merge, publish, distribute, sublicense, and/or
  20.  --sell copies of the Software, and to permit persons to whom the
  21.  --Software is furnished to do so, subject to the following conditions:
  22.  
  23.  --The above copyright notice and this permission notice shall be
  24.  --included in all copies or substantial portions of the Software.
  25.  --If you find this software useful please give www.chipmunkav.com a mention.
  26.  
  27.  --THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  28.  --EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  29.  --OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  30.  --IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  31.  --ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  32.  --CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  33.  --CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  34.  
  35. local string = string
  36. local math = math
  37. local table = table
  38. local error = error
  39. local tonumber = tonumber
  40. local tostring = tostring
  41. local type = type
  42. local setmetatable = setmetatable
  43. local pairs = pairs
  44. local ipairs = ipairs
  45. local assert = assert
  46.  
  47.  
  48. local StringBuilder = {
  49.     buffer = {}
  50. }
  51.  
  52. function StringBuilder:New()
  53.     local o = {}
  54.     setmetatable(o, self)
  55.     self.__index = self
  56.     o.buffer = {}
  57.     return o
  58. end
  59.  
  60. function StringBuilder:Append(s)
  61.     self.buffer[#self.buffer+1] = s
  62. end
  63.  
  64. function StringBuilder:ToString()
  65.     return table.concat(self.buffer)
  66. end
  67.  
  68. local JsonWriter = {
  69.     backslashes = {
  70.         ['\b'] = "\\b",
  71.         ['\t'] = "\\t",
  72.         ['\n'] = "\\n",
  73.         ['\f'] = "\\f",
  74.         ['\r'] = "\\r",
  75.         ['"']  = "\\\"",
  76.         ['\\'] = "\\\\",
  77.         ['/']  = "\\/"
  78.     }
  79. }
  80.  
  81. function JsonWriter:New()
  82.     local o = {}
  83.     o.writer = StringBuilder:New()
  84.     setmetatable(o, self)
  85.     self.__index = self
  86.     return o
  87. end
  88.  
  89. function JsonWriter:Append(s)
  90.     self.writer:Append(s)
  91. end
  92.  
  93. function JsonWriter:ToString()
  94.     return self.writer:ToString()
  95. end
  96.  
  97. function JsonWriter:Write(o)
  98.     local t = type(o)
  99.     if t == "nil" then
  100.         self:WriteNil()
  101.     elseif t == "boolean" then
  102.         self:WriteString(o)
  103.     elseif t == "number" then
  104.         self:WriteString(o)
  105.     elseif t == "string" then
  106.         self:ParseString(o)
  107.     elseif t == "table" then
  108.         self:WriteTable(o)
  109.     elseif t == "function" then
  110.         self:WriteFunction(o)
  111.     elseif t == "thread" then
  112.         self:WriteError(o)
  113.     elseif t == "userdata" then
  114.         self:WriteError(o)
  115.     end
  116. end
  117.  
  118. function JsonWriter:WriteNil()
  119.     self:Append("null")
  120. end
  121.  
  122. function JsonWriter:WriteString(o)
  123.     self:Append(tostring(o))
  124. end
  125.  
  126. function JsonWriter:ParseString(s)
  127.     self:Append('"')
  128.     self:Append(string.gsub(s, "[%z%c\\\"/]", function(n)
  129.         local c = self.backslashes[n]
  130.         if c then return c end
  131.         return string.format("\\u%.4X", string.byte(n))
  132.     end))
  133.     self:Append('"')
  134. end
  135.  
  136. function JsonWriter:IsArray(t)
  137.     local count = 0
  138.     local isindex = function(k)
  139.         if type(k) == "number" and k > 0 then
  140.             if math.floor(k) == k then
  141.                 return true
  142.             end
  143.         end
  144.         return false
  145.     end
  146.     for k,v in pairs(t) do
  147.         if not isindex(k) then
  148.             return false, '{', '}'
  149.         else
  150.             count = math.max(count, k)
  151.         end
  152.     end
  153.     return true, '[', ']', count
  154. end
  155.  
  156. function JsonWriter:WriteTable(t)
  157.     local ba, st, et, n = self:IsArray(t)
  158.     self:Append(st)
  159.     if ba then     
  160.         for i = 1, n do
  161.             self:Write(t[i])
  162.             if i < n then
  163.                 self:Append(',')
  164.             end
  165.         end
  166.     else
  167.         local first = true;
  168.         for k, v in pairs(t) do
  169.             if not first then
  170.                 self:Append(',')
  171.             end
  172.             first = false;         
  173.             self:ParseString(k)
  174.             self:Append(':')
  175.             self:Write(v)          
  176.         end
  177.     end
  178.     self:Append(et)
  179. end
  180.  
  181. function JsonWriter:WriteError(o)
  182.     error(string.format(
  183.         "Encoding of %s unsupported",
  184.         tostring(o)))
  185. end
  186.  
  187. function JsonWriter:WriteFunction(o)
  188.     if o == Null then
  189.         self:WriteNil()
  190.     else
  191.         self:WriteError(o)
  192.     end
  193. end
  194.  
  195. local StringReader = {
  196.     s = "",
  197.     i = 0
  198. }
  199.  
  200. function StringReader:New(s)
  201.     local o = {}
  202.     setmetatable(o, self)
  203.     self.__index = self
  204.     o.s = s or o.s
  205.     return o   
  206. end
  207.  
  208. function StringReader:Peek()
  209.     local i = self.i + 1
  210.     if i <= #self.s then
  211.         return string.sub(self.s, i, i)
  212.     end
  213.     return nil
  214. end
  215.  
  216. function StringReader:Next()
  217.     self.i = self.i+1
  218.     if self.i <= #self.s then
  219.         return string.sub(self.s, self.i, self.i)
  220.     end
  221.     return nil
  222. end
  223.  
  224. function StringReader:All()
  225.     return self.s
  226. end
  227.  
  228. local JsonReader = {
  229.     escapes = {
  230.         ['t'] = '\t',
  231.         ['n'] = '\n',
  232.         ['f'] = '\f',
  233.         ['r'] = '\r',
  234.         ['b'] = '\b',
  235.     }
  236. }
  237.  
  238. function JsonReader:New(s)
  239.     local o = {}
  240.     o.reader = StringReader:New(s)
  241.     setmetatable(o, self)
  242.     self.__index = self
  243.     return o;
  244. end
  245.  
  246. function JsonReader:Read()
  247.     self:SkipWhiteSpace()
  248.     local peek = self:Peek()
  249.     if peek == nil then
  250.         error(string.format(
  251.             "Nil string: '%s'",
  252.             self:All()))
  253.     elseif peek == '{' then
  254.         return self:ReadObject()
  255.     elseif peek == '[' then
  256.         return self:ReadArray()
  257.     elseif peek == '"' then
  258.         return self:ReadString()
  259.     elseif string.find(peek, "[%+%-%d]") then
  260.         return self:ReadNumber()
  261.     elseif peek == 't' then
  262.         return self:ReadTrue()
  263.     elseif peek == 'f' then
  264.         return self:ReadFalse()
  265.     elseif peek == 'n' then
  266.         return self:ReadNull()
  267.     elseif peek == '/' then
  268.         self:ReadComment()
  269.         return self:Read()
  270.     else
  271.         return nil
  272.     end
  273. end
  274.        
  275. function JsonReader:ReadTrue()
  276.     self:TestReservedWord{'t','r','u','e'}
  277.     return true
  278. end
  279.  
  280. function JsonReader:ReadFalse()
  281.     self:TestReservedWord{'f','a','l','s','e'}
  282.     return false
  283. end
  284.  
  285. function JsonReader:ReadNull()
  286.     self:TestReservedWord{'n','u','l','l'}
  287.     return nil
  288. end
  289.  
  290. function JsonReader:TestReservedWord(t)
  291.     for i, v in ipairs(t) do
  292.         if self:Next() ~= v then
  293.              error(string.format(
  294.                 "Error reading '%s': %s",
  295.                 table.concat(t),
  296.                 self:All()))
  297.         end
  298.     end
  299. end
  300.  
  301. function JsonReader:ReadNumber()
  302.         local result = self:Next()
  303.         local peek = self:Peek()
  304.         while peek ~= nil and string.find(
  305.         peek,
  306.         "[%+%-%d%.eE]") do
  307.             result = result .. self:Next()
  308.             peek = self:Peek()
  309.     end
  310.     result = tonumber(result)
  311.     if result == nil then
  312.             error(string.format(
  313.             "Invalid number: '%s'",
  314.             result))
  315.     else
  316.         return result
  317.     end
  318. end
  319.  
  320. function JsonReader:ReadString()
  321.     local result = ""
  322.     assert(self:Next() == '"')
  323.         while self:Peek() ~= '"' do
  324.         local ch = self:Next()
  325.         if ch == '\\' then
  326.             ch = self:Next()
  327.             if self.escapes[ch] then
  328.                 ch = self.escapes[ch]
  329.             end
  330.         end
  331.                 result = result .. ch
  332.     end
  333.         assert(self:Next() == '"')
  334.     local fromunicode = function(m)
  335.         return string.char(tonumber(m, 16))
  336.     end
  337.     return string.gsub(
  338.         result,
  339.         "u%x%x(%x%x)",
  340.         fromunicode)
  341. end
  342.  
  343. function JsonReader:ReadComment()
  344.         assert(self:Next() == '/')
  345.         local second = self:Next()
  346.         if second == '/' then
  347.             self:ReadSingleLineComment()
  348.         elseif second == '*' then
  349.             self:ReadBlockComment()
  350.         else
  351.             error(string.format(
  352.         "Invalid comment: %s",
  353.         self:All()))
  354.     end
  355. end
  356.  
  357. function JsonReader:ReadBlockComment()
  358.     local done = false
  359.     while not done do
  360.         local ch = self:Next()     
  361.         if ch == '*' and self:Peek() == '/' then
  362.             done = true
  363.                 end
  364.         if not done and
  365.             ch == '/' and
  366.             self:Peek() == "*" then
  367.                     error(string.format(
  368.             "Invalid comment: %s, '/*' illegal.",  
  369.             self:All()))
  370.         end
  371.     end
  372.     self:Next()
  373. end
  374.  
  375. function JsonReader:ReadSingleLineComment()
  376.     local ch = self:Next()
  377.     while ch ~= '\r' and ch ~= '\n' do
  378.         ch = self:Next()
  379.     end
  380. end
  381.  
  382. function JsonReader:ReadArray()
  383.     local result = {}
  384.     assert(self:Next() == '[')
  385.     local done = false
  386.     if self:Peek() == ']' then
  387.         done = true;
  388.     end
  389.     while not done do
  390.         local item = self:Read()
  391.         result[#result+1] = item
  392.         self:SkipWhiteSpace()
  393.         if self:Peek() == ']' then
  394.             done = true
  395.         end
  396.         if not done then
  397.             local ch = self:Next()
  398.             if ch ~= ',' then
  399.                 error(string.format(
  400.                     "Invalid array: '%s' due to: '%s'",
  401.                     self:All(), ch))
  402.             end
  403.         end
  404.     end
  405.     assert(']' == self:Next())
  406.     return result
  407. end
  408.  
  409. function JsonReader:ReadObject()
  410.     local result = {}
  411.     assert(self:Next() == '{')
  412.     local done = false
  413.     if self:Peek() == '}' then
  414.         done = true
  415.     end
  416.     while not done do
  417.         local key = self:Read()
  418.         if type(key) ~= "string" then
  419.             error(string.format(
  420.                 "Invalid non-string object key: %s",
  421.                 key))
  422.         end
  423.         self:SkipWhiteSpace()
  424.         local ch = self:Next()
  425.         if ch ~= ':' then
  426.             error(string.format(
  427.                 "Invalid object: '%s' due to: '%s'",
  428.                 self:All(),
  429.                 ch))
  430.         end
  431.         self:SkipWhiteSpace()
  432.         local val = self:Read()
  433.         result[key] = val
  434.         self:SkipWhiteSpace()
  435.         if self:Peek() == '}' then
  436.             done = true
  437.         end
  438.         if not done then
  439.             ch = self:Next()
  440.                     if ch ~= ',' then
  441.                 error(string.format(
  442.                     "Invalid array: '%s' near: '%s'",
  443.                     self:All(),
  444.                     ch))
  445.             end
  446.         end
  447.     end
  448.     assert(self:Next() == "}")
  449.     return result
  450. end
  451.  
  452. function JsonReader:SkipWhiteSpace()
  453.     local p = self:Peek()
  454.     while p ~= nil and string.find(p, "[%s/]") do
  455.         if p == '/' then
  456.             self:ReadComment()
  457.         else
  458.             self:Next()
  459.         end
  460.         p = self:Peek()
  461.     end
  462. end
  463.  
  464. function JsonReader:Peek()
  465.     return self.reader:Peek()
  466. end
  467.  
  468. function JsonReader:Next()
  469.     return self.reader:Next()
  470. end
  471.  
  472. function JsonReader:All()
  473.     return self.reader:All()
  474. end
  475.  
  476. function Encode(o)
  477.     local writer = JsonWriter:New()
  478.     writer:Write(o)
  479.     return writer:ToString()
  480. end
  481.  
  482. function Decode(s)
  483.     local reader = JsonReader:New(s)
  484.     return reader:Read()
  485. end
  486.  
  487. function Null()
  488.     return Null
  489. end
  490. -------------------- End JSON Parser ------------------------
  491.  
  492. t.DecodeJSON = function(jsonString)
  493.     pcall(function() warn("RbxUtility.DecodeJSON is deprecated, please use Game:GetService('HttpService'):JSONDecode() instead.") end)
  494.  
  495.     if type(jsonString) == "string" then
  496.         return Decode(jsonString)
  497.     end
  498.     print("RbxUtil.DecodeJSON expects string argument!")
  499.     return nil
  500. end
  501.  
  502. t.EncodeJSON = function(jsonTable)
  503.     pcall(function() warn("RbxUtility.EncodeJSON is deprecated, please use Game:GetService('HttpService'):JSONEncode() instead.") end)
  504.     return Encode(jsonTable)
  505. end
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514. ------------------------------------------------------------------------------------------------------------------------
  515. ------------------------------------------------------------------------------------------------------------------------
  516. ------------------------------------------------------------------------------------------------------------------------
  517. --------------------------------------------Terrain Utilities Begin-----------------------------------------------------
  518. ------------------------------------------------------------------------------------------------------------------------
  519. ------------------------------------------------------------------------------------------------------------------------
  520. ------------------------------------------------------------------------------------------------------------------------
  521. --makes a wedge at location x, y, z
  522. --sets cell x, y, z to default material if parameter is provided, if not sets cell x, y, z to be whatever material it previously w
  523. --returns true if made a wedge, false if the cell remains a block
  524. t.MakeWedge = function(x, y, z, defaultmaterial)
  525.     return game:GetService("Terrain"):AutoWedgeCell(x,y,z)
  526. end
  527.  
  528. t.SelectTerrainRegion = function(regionToSelect, color, selectEmptyCells, selectionParent)
  529.     local terrain = game:GetService("Workspace"):FindFirstChild("Terrain")
  530.     if not terrain then return end
  531.  
  532.     assert(regionToSelect)
  533.     assert(color)
  534.  
  535.     if not type(regionToSelect) == "Region3" then
  536.         error("regionToSelect (first arg), should be of type Region3, but is type",type(regionToSelect))
  537.     end
  538.     if not type(color) == "BrickColor" then
  539.         error("color (second arg), should be of type BrickColor, but is type",type(color))
  540.     end
  541.  
  542.     -- frequently used terrain calls (speeds up call, no lookup necessary)
  543.     local GetCell = terrain.GetCell
  544.     local WorldToCellPreferSolid = terrain.WorldToCellPreferSolid
  545.     local CellCenterToWorld = terrain.CellCenterToWorld
  546.     local emptyMaterial = Enum.CellMaterial.Empty
  547.  
  548.     -- container for all adornments, passed back to user
  549.     local selectionContainer = Instance.new("Model")
  550.     selectionContainer.Name = "SelectionContainer"
  551.     selectionContainer.Archivable = false
  552.     if selectionParent then
  553.         selectionContainer.Parent = selectionParent
  554.     else
  555.         selectionContainer.Parent = game:GetService("Workspace")
  556.     end
  557.  
  558.     local updateSelection = nil -- function we return to allow user to update selection
  559.     local currentKeepAliveTag = nil -- a tag that determines whether adorns should be destroyed
  560.     local aliveCounter = 0 -- helper for currentKeepAliveTag
  561.     local lastRegion = nil -- used to stop updates that do nothing
  562.     local adornments = {} -- contains all adornments
  563.     local reusableAdorns = {}
  564.  
  565.     local selectionPart = Instance.new("Part")
  566.     selectionPart.Name = "SelectionPart"
  567.     selectionPart.Transparency = 1
  568.     selectionPart.Anchored = true
  569.     selectionPart.Locked = true
  570.     selectionPart.CanCollide = false
  571.     selectionPart.Size = Vector3.new(4.2,4.2,4.2)
  572.  
  573.     local selectionBox = Instance.new("SelectionBox")
  574.  
  575.     -- srs translation from region3 to region3int16
  576.     local function Region3ToRegion3int16(region3)
  577.         local theLowVec = region3.CFrame.p - (region3.Size/2) + Vector3.new(2,2,2)
  578.         local lowCell = WorldToCellPreferSolid(terrain,theLowVec)
  579.  
  580.         local theHighVec = region3.CFrame.p + (region3.Size/2) - Vector3.new(2,2,2)
  581.         local highCell = WorldToCellPreferSolid(terrain, theHighVec)
  582.  
  583.         local highIntVec = Vector3int16.new(highCell.x,highCell.y,highCell.z)
  584.         local lowIntVec = Vector3int16.new(lowCell.x,lowCell.y,lowCell.z)
  585.  
  586.         return Region3int16.new(lowIntVec,highIntVec)
  587.     end
  588.  
  589.     -- helper function that creates the basis for a selection box
  590.     function createAdornment(theColor)
  591.         local selectionPartClone = nil
  592.         local selectionBoxClone = nil
  593.  
  594.         if #reusableAdorns > 0 then
  595.             selectionPartClone = reusableAdorns[1]["part"]
  596.             selectionBoxClone = reusableAdorns[1]["box"]
  597.             table.remove(reusableAdorns,1)
  598.  
  599.             selectionBoxClone.Visible = true
  600.         else
  601.             selectionPartClone = selectionPart:Clone()
  602.             selectionPartClone.Archivable = false
  603.  
  604.             selectionBoxClone = selectionBox:Clone()
  605.             selectionBoxClone.Archivable = false
  606.  
  607.             selectionBoxClone.Adornee = selectionPartClone
  608.             selectionBoxClone.Parent = selectionContainer
  609.  
  610.             selectionBoxClone.Adornee = selectionPartClone
  611.  
  612.             selectionBoxClone.Parent = selectionContainer
  613.         end
  614.            
  615.         if theColor then
  616.             selectionBoxClone.Color = theColor
  617.         end
  618.  
  619.         return selectionPartClone, selectionBoxClone
  620.     end
  621.  
  622.     -- iterates through all current adornments and deletes any that don't have latest tag
  623.     function cleanUpAdornments()
  624.         for cellPos, adornTable in pairs(adornments) do
  625.  
  626.             if adornTable.KeepAlive ~= currentKeepAliveTag then -- old news, we should get rid of this
  627.                 adornTable.SelectionBox.Visible = false
  628.                 table.insert(reusableAdorns,{part = adornTable.SelectionPart, box = adornTable.SelectionBox})
  629.                 adornments[cellPos] = nil
  630.             end
  631.         end
  632.     end
  633.  
  634.     -- helper function to update tag
  635.     function incrementAliveCounter()
  636.         aliveCounter = aliveCounter + 1
  637.         if aliveCounter > 1000000 then
  638.             aliveCounter = 0
  639.         end
  640.         return aliveCounter
  641.     end
  642.  
  643.     -- finds full cells in region and adorns each cell with a box, with the argument color
  644.     function adornFullCellsInRegion(region, color)
  645.         local regionBegin = region.CFrame.p - (region.Size/2) + Vector3.new(2,2,2)
  646.         local regionEnd = region.CFrame.p + (region.Size/2) - Vector3.new(2,2,2)
  647.  
  648.         local cellPosBegin = WorldToCellPreferSolid(terrain, regionBegin)
  649.         local cellPosEnd = WorldToCellPreferSolid(terrain, regionEnd)
  650.  
  651.         currentKeepAliveTag = incrementAliveCounter()
  652.         for y = cellPosBegin.y, cellPosEnd.y do
  653.             for z = cellPosBegin.z, cellPosEnd.z do
  654.                 for x = cellPosBegin.x, cellPosEnd.x do
  655.                     local cellMaterial = GetCell(terrain, x, y, z)
  656.                    
  657.                     if cellMaterial ~= emptyMaterial then
  658.                         local cframePos = CellCenterToWorld(terrain, x, y, z)
  659.                         local cellPos = Vector3int16.new(x,y,z)
  660.  
  661.                         local updated = false
  662.                         for cellPosAdorn, adornTable in pairs(adornments) do
  663.                             if cellPosAdorn == cellPos then
  664.                                 adornTable.KeepAlive = currentKeepAliveTag
  665.                                 if color then
  666.                                     adornTable.SelectionBox.Color = color
  667.                                 end
  668.                                 updated = true
  669.                                 break
  670.                             end
  671.                         end
  672.  
  673.                         if not updated then
  674.                             local selectionPart, selectionBox = createAdornment(color)
  675.                             selectionPart.Size = Vector3.new(4,4,4)
  676.                             selectionPart.CFrame = CFrame.new(cframePos)
  677.                             local adornTable = {SelectionPart = selectionPart, SelectionBox = selectionBox, KeepAlive = currentKeepAliveTag}
  678.                             adornments[cellPos] = adornTable
  679.                         end
  680.                     end
  681.                 end
  682.             end
  683.         end
  684.         cleanUpAdornments()
  685.     end
  686.  
  687.  
  688.     ------------------------------------- setup code ------------------------------
  689.     lastRegion = regionToSelect
  690.  
  691.     if selectEmptyCells then -- use one big selection to represent the area selected
  692.         local selectionPart, selectionBox = createAdornment(color)
  693.  
  694.         selectionPart.Size = regionToSelect.Size
  695.         selectionPart.CFrame = regionToSelect.CFrame
  696.  
  697.         adornments.SelectionPart = selectionPart
  698.         adornments.SelectionBox = selectionBox
  699.  
  700.         updateSelection =
  701.             function (newRegion, color)
  702.                 if newRegion and newRegion ~= lastRegion then
  703.                     lastRegion = newRegion
  704.                     selectionPart.Size = newRegion.Size
  705.                     selectionPart.CFrame = newRegion.CFrame
  706.                 end
  707.                 if color then
  708.                     selectionBox.Color = color
  709.                 end
  710.             end
  711.     else -- use individual cell adorns to represent the area selected
  712.         adornFullCellsInRegion(regionToSelect, color)
  713.         updateSelection =
  714.             function (newRegion, color)
  715.                 if newRegion and newRegion ~= lastRegion then
  716.                     lastRegion = newRegion
  717.                     adornFullCellsInRegion(newRegion, color)
  718.                 end
  719.             end
  720.  
  721.     end
  722.  
  723.     local destroyFunc = function()
  724.         updateSelection = nil
  725.         if selectionContainer then selectionContainer:Destroy() end
  726.         adornments = nil
  727.     end
  728.  
  729.     return updateSelection, destroyFunc
  730. end
  731.  
  732. -----------------------------Terrain Utilities End-----------------------------
  733.  
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740. ------------------------------------------------------------------------------------------------------------------------
  741. ------------------------------------------------------------------------------------------------------------------------
  742. ------------------------------------------------------------------------------------------------------------------------
  743. ------------------------------------------------Signal class begin------------------------------------------------------
  744. ------------------------------------------------------------------------------------------------------------------------
  745. ------------------------------------------------------------------------------------------------------------------------
  746. ------------------------------------------------------------------------------------------------------------------------
  747. --[[
  748. A 'Signal' object identical to the internal RBXScriptSignal object in it's public API and semantics. This function
  749. can be used to create "custom events" for user-made code.
  750. API:
  751. Method :connect( function handler )
  752.     Arguments:   The function to connect to.
  753.     Returns:     A new connection object which can be used to disconnect the connection
  754.     Description: Connects this signal to the function specified by |handler|. That is, when |fire( ... )| is called for
  755.                  the signal the |handler| will be called with the arguments given to |fire( ... )|. Note, the functions
  756.                  connected to a signal are called in NO PARTICULAR ORDER, so connecting one function after another does
  757.                  NOT mean that the first will be called before the second as a result of a call to |fire|.
  758.  
  759. Method :disconnect()
  760.     Arguments:   None
  761.     Returns:     None
  762.     Description: Disconnects all of the functions connected to this signal.
  763.  
  764. Method :fire( ... )
  765.     Arguments:   Any arguments are accepted
  766.     Returns:     None
  767.     Description: Calls all of the currently connected functions with the given arguments.
  768.  
  769. Method :wait()
  770.     Arguments:   None
  771.     Returns:     The arguments given to fire
  772.     Description: This call blocks until
  773. ]]
  774.  
  775. function t.CreateSignal()
  776.     local this = {}
  777.  
  778.     local mBindableEvent = Instance.new('BindableEvent')
  779.     local mAllCns = {} --all connection objects returned by mBindableEvent::connect
  780.  
  781.     --main functions
  782.     function this:connect(func)
  783.         if self ~= this then error("connect must be called with `:`, not `.`", 2) end
  784.         if type(func) ~= 'function' then
  785.             error("Argument #1 of connect must be a function, got a "..type(func), 2)
  786.         end
  787.         local cn = mBindableEvent.Event:Connect(func)
  788.         mAllCns[cn] = true
  789.         local pubCn = {}
  790.         function pubCn:disconnect()
  791.             cn:Disconnect()
  792.             mAllCns[cn] = nil
  793.         end
  794.         pubCn.Disconnect = pubCn.disconnect
  795.        
  796.         return pubCn
  797.     end
  798.    
  799.     function this:disconnect()
  800.         if self ~= this then error("disconnect must be called with `:`, not `.`", 2) end
  801.         for cn, _ in pairs(mAllCns) do
  802.             cn:Disconnect()
  803.             mAllCns[cn] = nil
  804.         end
  805.     end
  806.    
  807.     function this:wait()
  808.         if self ~= this then error("wait must be called with `:`, not `.`", 2) end
  809.         return mBindableEvent.Event:Wait()
  810.     end
  811.    
  812.     function this:fire(...)
  813.         if self ~= this then error("fire must be called with `:`, not `.`", 2) end
  814.         mBindableEvent:Fire(...)
  815.     end
  816.    
  817.     this.Connect = this.connect
  818.     this.Disconnect = this.disconnect
  819.     this.Wait = this.wait
  820.     this.Fire = this.fire
  821.  
  822.     return this
  823. end
  824.  
  825. ------------------------------------------------- Sigal class End ------------------------------------------------------
  826.  
  827.  
  828.  
  829.  
  830. ------------------------------------------------------------------------------------------------------------------------
  831. ------------------------------------------------------------------------------------------------------------------------
  832. ------------------------------------------------------------------------------------------------------------------------
  833. -----------------------------------------------Create Function Begins---------------------------------------------------
  834. ------------------------------------------------------------------------------------------------------------------------
  835. ------------------------------------------------------------------------------------------------------------------------
  836. ------------------------------------------------------------------------------------------------------------------------
  837. --[[
  838. A "Create" function for easy creation of Roblox instances. The function accepts a string which is the classname of
  839. the object to be created. The function then returns another function which either accepts accepts no arguments, in
  840. which case it simply creates an object of the given type, or a table argument that may contain several types of data,
  841. in which case it mutates the object in varying ways depending on the nature of the aggregate data. These are the
  842. type of data and what operation each will perform:
  843. 1) A string key mapping to some value:
  844.       Key-Value pairs in this form will be treated as properties of the object, and will be assigned in NO PARTICULAR
  845.       ORDER. If the order in which properties is assigned matter, then they must be assigned somewhere else than the
  846.       |Create| call's body.
  847.  
  848. 2) An integral key mapping to another Instance:
  849.       Normal numeric keys mapping to Instances will be treated as children if the object being created, and will be
  850.       parented to it. This allows nice recursive calls to Create to create a whole hierarchy of objects without a
  851.       need for temporary variables to store references to those objects.
  852.  
  853. 3) A key which is a value returned from Create.Event( eventname ), and a value which is a function function
  854.       The Create.E( string ) function provides a limited way to connect to signals inside of a Create hierarchy
  855.       for those who really want such a functionality. The name of the event whose name is passed to
  856.       Create.E( string )
  857.  
  858. 4) A key which is the Create function itself, and a value which is a function
  859.       The function will be run with the argument of the object itself after all other initialization of the object is
  860.       done by create. This provides a way to do arbitrary things involving the object from withing the create
  861.       hierarchy.
  862.       Note: This function is called SYNCHRONOUSLY, that means that you should only so initialization in
  863.       it, not stuff which requires waiting, as the Create call will block until it returns. While waiting in the
  864.       constructor callback function is possible, it is probably not a good design choice.
  865.       Note: Since the constructor function is called after all other initialization, a Create block cannot have two
  866.       constructor functions, as it would not be possible to call both of them last, also, this would be unnecessary.
  867.  
  868.  
  869. Some example usages:
  870.  
  871. A simple example which uses the Create function to create a model object and assign two of it's properties.
  872. local model = Create'Model'{
  873.     Name = 'A New model',
  874.     Parent = game.Workspace,
  875. }
  876.  
  877.  
  878. An example where a larger hierarchy of object is made. After the call the hierarchy will look like this:
  879. Model_Container
  880.  |-ObjectValue
  881.  |  |
  882.  |  `-BoolValueChild
  883.  `-IntValue
  884.  
  885. local model = Create'Model'{
  886.     Name = 'Model_Container',
  887.     Create'ObjectValue'{
  888.         Create'BoolValue'{
  889.             Name = 'BoolValueChild',
  890.         },
  891.     },
  892.     Create'IntValue'{},
  893. }
  894.  
  895.  
  896. An example using the event syntax:
  897.  
  898. local part = Create'Part'{
  899.     [Create.E'Touched'] = function(part)
  900.         print("I was touched by "..part.Name)
  901.     end,   
  902. }
  903.  
  904.  
  905. An example using the general constructor syntax:
  906.  
  907. local model = Create'Part'{
  908.     [Create] = function(this)
  909.         print("Constructor running!")
  910.         this.Name = GetGlobalFoosAndBars(this)
  911.     end,
  912. }
  913.  
  914.  
  915. Note: It is also perfectly legal to save a reference to the function returned by a call Create, this will not cause
  916.       any unexpected behavior. EG:
  917.       local partCreatingFunction = Create'Part'
  918.       local part = partCreatingFunction()
  919. ]]
  920.  
  921. --the Create function need to be created as a functor, not a function, in order to support the Create.E syntax, so it
  922. --will be created in several steps rather than as a single function declaration.
  923. local function Create_PrivImpl(objectType)
  924.     if type(objectType) ~= 'string' then
  925.         error("Argument of Create must be a string", 2)
  926.     end
  927.     --return the proxy function that gives us the nice Create'string'{data} syntax
  928.     --The first function call is a function call using Lua's single-string-argument syntax
  929.     --The second function call is using Lua's single-table-argument syntax
  930.     --Both can be chained together for the nice effect.
  931.     return function(dat)
  932.         --default to nothing, to handle the no argument given case
  933.         dat = dat or {}
  934.  
  935.         --make the object to mutate
  936.         local obj = Instance.new(objectType)
  937.         local parent = nil
  938.  
  939.         --stored constructor function to be called after other initialization
  940.         local ctor = nil
  941.  
  942.         for k, v in pairs(dat) do
  943.             --add property
  944.             if type(k) == 'string' then
  945.                 if k == 'Parent' then
  946.                     -- Parent should always be set last, setting the Parent of a new object
  947.                     -- immediately makes performance worse for all subsequent property updates.
  948.                     parent = v
  949.                 else
  950.                     obj[k] = v
  951.                 end
  952.  
  953.  
  954.             --add child
  955.             elseif type(k) == 'number' then
  956.                 if type(v) ~= 'userdata' then
  957.                     error("Bad entry in Create body: Numeric keys must be paired with children, got a: "..type(v), 2)
  958.                 end
  959.                 v.Parent = obj
  960.  
  961.  
  962.             --event connect
  963.             elseif type(k) == 'table' and k.__eventname then
  964.                 if type(v) ~= 'function' then
  965.                     error("Bad entry in Create body: Key `[Create.E\'"..k.__eventname.."\']` must have a function value\
  966.                            got: "..tostring(v), 2)
  967.                 end
  968.                 obj[k.__eventname]:connect(v)
  969.  
  970.  
  971.             --define constructor function
  972.             elseif k == t.Create then
  973.                 if type(v) ~= 'function' then
  974.                     error("Bad entry in Create body: Key `[Create]` should be paired with a constructor function, \
  975.                            got: "..tostring(v), 2)
  976.                 elseif ctor then
  977.                     --ctor already exists, only one allowed
  978.                     error("Bad entry in Create body: Only one constructor function is allowed", 2)
  979.                 end
  980.                 ctor = v
  981.  
  982.  
  983.             else
  984.                 error("Bad entry ("..tostring(k).." => "..tostring(v)..") in Create body", 2)
  985.             end
  986.         end
  987.  
  988.         --apply constructor function if it exists
  989.         if ctor then
  990.             ctor(obj)
  991.         end
  992.        
  993.         if parent then
  994.             obj.Parent = parent
  995.         end
  996.  
  997.         --return the completed object
  998.         return obj
  999.     end
  1000. end
  1001.  
  1002. --now, create the functor:
  1003. t.Create = setmetatable({}, {__call = function(tb, ...) return Create_PrivImpl(...) end})
  1004.  
  1005. --and create the "Event.E" syntax stub. Really it's just a stub to construct a table which our Create
  1006. --function can recognize as special.
  1007. t.Create.E = function(eventName)
  1008.     return {__eventname = eventName}
  1009. end
  1010.  
  1011. -------------------------------------------------Create function End----------------------------------------------------
  1012.  
  1013.  
  1014.  
  1015.  
  1016. ------------------------------------------------------------------------------------------------------------------------
  1017. ------------------------------------------------------------------------------------------------------------------------
  1018. ------------------------------------------------------------------------------------------------------------------------
  1019. ------------------------------------------------Documentation Begin-----------------------------------------------------
  1020. ------------------------------------------------------------------------------------------------------------------------
  1021. ------------------------------------------------------------------------------------------------------------------------
  1022. ------------------------------------------------------------------------------------------------------------------------
  1023.  
  1024. t.Help =
  1025.     function(funcNameOrFunc)
  1026.         --input argument can be a string or a function.  Should return a description (of arguments and expected side effects)
  1027.         if funcNameOrFunc == "DecodeJSON" or funcNameOrFunc == t.DecodeJSON then
  1028.             return "Function DecodeJSON.  " ..
  1029.                    "Arguments: (string).  " ..
  1030.                    "Side effect: returns a table with all parsed JSON values"
  1031.         end
  1032.         if funcNameOrFunc == "EncodeJSON" or funcNameOrFunc == t.EncodeJSON then
  1033.             return "Function EncodeJSON.  " ..
  1034.                    "Arguments: (table).  " ..
  1035.                    "Side effect: returns a string composed of argument table in JSON data format"
  1036.         end  
  1037.         if funcNameOrFunc == "MakeWedge" or funcNameOrFunc == t.MakeWedge then
  1038.             return "Function MakeWedge. " ..
  1039.                    "Arguments: (x, y, z, [default material]). " ..
  1040.                    "Description: Makes a wedge at location x, y, z. Sets cell x, y, z to default material if "..
  1041.                    "parameter is provided, if not sets cell x, y, z to be whatever material it previously was. "..
  1042.                    "Returns true if made a wedge, false if the cell remains a block "
  1043.         end
  1044.         if funcNameOrFunc == "SelectTerrainRegion" or funcNameOrFunc == t.SelectTerrainRegion then
  1045.             return "Function SelectTerrainRegion. " ..
  1046.                    "Arguments: (regionToSelect, color, selectEmptyCells, selectionParent). " ..
  1047.                    "Description: Selects all terrain via a series of selection boxes within the regionToSelect " ..
  1048.                    "(this should be a region3 value). The selection box color is detemined by the color argument " ..
  1049.                    "(should be a brickcolor value). SelectionParent is the parent that the selection model gets placed to (optional)." ..
  1050.                    "SelectEmptyCells is bool, when true will select all cells in the " ..
  1051.                    "region, otherwise we only select non-empty cells. Returns a function that can update the selection," ..
  1052.                    "arguments to said function are a new region3 to select, and the adornment color (color arg is optional). " ..
  1053.                    "Also returns a second function that takes no arguments and destroys the selection"
  1054.         end
  1055.         if funcNameOrFunc == "CreateSignal" or funcNameOrFunc == t.CreateSignal then
  1056.             return "Function CreateSignal. "..
  1057.                    "Arguments: None. "..
  1058.                    "Returns: The newly created Signal object. This object is identical to the RBXScriptSignal class "..
  1059.                    "used for events in Objects, but is a Lua-side object so it can be used to create custom events in"..
  1060.                    "Lua code. "..
  1061.                    "Methods of the Signal object: :connect, :wait, :fire, :disconnect. "..
  1062.                    "For more info you can pass the method name to the Help function, or view the wiki page "..
  1063.                    "for this library. EG: Help('Signal:connect')."
  1064.         end
  1065.         if funcNameOrFunc == "Signal:connect" then
  1066.             return "Method Signal:connect. "..
  1067.                    "Arguments: (function handler). "..
  1068.                    "Return: A connection object which can be used to disconnect the connection to this handler. "..
  1069.                    "Description: Connectes a handler function to this Signal, so that when |fire| is called the "..
  1070.                    "handler function will be called with the arguments passed to |fire|."
  1071.         end
  1072.         if funcNameOrFunc == "Signal:wait" then
  1073.             return "Method Signal:wait. "..
  1074.                    "Arguments: None. "..
  1075.                    "Returns: The arguments passed to the next call to |fire|. "..
  1076.                    "Description: This call does not return until the next call to |fire| is made, at which point it "..
  1077.                    "will return the values which were passed as arguments to that |fire| call."
  1078.         end
  1079.         if funcNameOrFunc == "Signal:fire" then
  1080.             return "Method Signal:fire. "..
  1081.                    "Arguments: Any number of arguments of any type. "..
  1082.                    "Returns: None. "..
  1083.                    "Description: This call will invoke any connected handler functions, and notify any waiting code "..
  1084.                    "attached to this Signal to continue, with the arguments passed to this function. Note: The calls "..
  1085.                    "to handlers are made asynchronously, so this call will return immediately regardless of how long "..
  1086.                    "it takes the connected handler functions to complete."
  1087.         end
  1088.         if funcNameOrFunc == "Signal:disconnect" then
  1089.             return "Method Signal:disconnect. "..
  1090.                    "Arguments: None. "..
  1091.                    "Returns: None. "..
  1092.                    "Description: This call disconnects all handlers attacched to this function, note however, it "..
  1093.                    "does NOT make waiting code continue, as is the behavior of normal Roblox events. This method "..
  1094.                    "can also be called on the connection object which is returned from Signal:connect to only "..
  1095.                    "disconnect a single handler, as opposed to this method, which will disconnect all handlers."
  1096.         end
  1097.         if funcNameOrFunc == "Create" then
  1098.             return "Function Create. "..
  1099.                    "Arguments: A table containing information about how to construct a collection of objects. "..
  1100.                    "Returns: The constructed objects. "..
  1101.                    "Descrition: Create is a very powerfull function, whose description is too long to fit here, and "..
  1102.                    "is best described via example, please see the wiki page for a description of how to use it."
  1103.         end
  1104.     end
  1105.    
  1106. --------------------------------------------Documentation Ends----------------------------------------------------------
  1107.  
  1108. return t
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement