Guest User

Untitled

a guest
Oct 12th, 2024
7
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.98 KB | None | 0 0
  1. -- Settings
  2.  
  3. --Bools
  4. local interpolation = true
  5. local moveByGrid = true
  6. local buildmodePlacement = true
  7.  
  8. --ints
  9. local rotationStep = 90
  10. local maxHeight = 90
  11.  
  12. --Numbers/Floats
  13.  
  14. local lerpLevel = 0.1
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35. --Other
  36. local gridTexture = "rbxassetid://2415319308"
  37.  
  38. local placement = {}
  39. placement.__index = placement
  40. local players = game:GetService("Players")
  41. local runservice = game:GetService("RunService")
  42. local contextActionService = game:GetService("ContextActionService")
  43.  
  44. local player = players.LocalPlayer
  45. local character = player.Character or player.CharacterAdded:Wait()
  46. local mouse = player:GetMouse()
  47.  
  48. -- Constructor Variables
  49. local GRID_SIZE
  50. local ITEM_LOCATION
  51. local ROTATE_KEY
  52. local TERMINATE_KEY
  53. -- activation variables
  54.  
  55.  
  56.  
  57. local object
  58. local placedObjects
  59. local plot
  60. local stackable
  61. local primary
  62. -- Variables that used in calculation
  63. local posX
  64. local posY
  65. local posZ
  66. local speed = 1
  67. local rotation = 0
  68. local rotationVal = false
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75. -- other
  76. local collided = nil
  77. local selectionbox
  78.  
  79.  
  80. local TerminateButton = game.Players.LocalPlayer:WaitForChild("PlayerGui"):WaitForChild("UI"):WaitForChild("TRASH")
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87.  
  88.  
  89. -- quick type vars
  90. local cframe = CFrame.new
  91. local angles = CFrame.fromEulerAnglesXYZ
  92. local clamp = math.clamp
  93.  
  94. local function renderGrid()
  95. if plot:FindFirstChildOfClass("Texture") then
  96. plot:FindFirstChildOfClass("Texture"):Destroy()
  97. end
  98. local texture = Instance.new("Texture")
  99. texture.StudsPerTileU = GRID_SIZE
  100. texture.StudsPerTileV = GRID_SIZE
  101. texture.Texture = gridTexture
  102. texture.Face = Enum.NormalId.Top
  103. texture.Parent = plot
  104. end
  105.  
  106. local function changeHitboxColor()
  107. if primary then
  108. if collided then
  109. selectionbox.Adornee = primary
  110. selectionbox.Color3 = Color3.new(1,0,0)
  111. else
  112. selectionbox.Adornee = primary
  113. selectionbox.Color3 = Color3.new(0,1,0)
  114. end
  115. end
  116. end
  117. local function handleCollisions()
  118. if object then
  119. collided = false
  120. local collisionPoint = primary.Touched:Connect(function() end)
  121. local collisionPoints = primary:GetTouchingParts()
  122.  
  123. for i = 1, #collisionPoints, 1 do
  124. if not collisionPoints[i]:IsDescendantOf(object) and not collisionPoints[i]:IsDescendantOf(character) then
  125. collided = true
  126.  
  127. break
  128. end
  129. end
  130. collisionPoint:Disconnect()
  131.  
  132. return
  133. end
  134. end
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145. local function bounds(cf, offsetX, offsetZ)
  146. local LOWER_X_BOUND
  147. local LOWER_Z_BOUND
  148. local UPPER_X_BOUND
  149. local UPPER_Z_BOUND
  150.  
  151. LOWER_X_BOUND = plot.Position.X - (plot.Size.X*0.5) + offsetX
  152. UPPER_X_BOUND = plot.Position.X + (plot.Size.X*0.5) - offsetX
  153.  
  154. LOWER_Z_BOUND = plot.Position.Z - (plot.Size.Z*0.5) + offsetZ
  155. UPPER_Z_BOUND = plot.Position.Z + (plot.Size.Z*0.5) - offsetZ
  156.  
  157. local newX = clamp(cf.X, LOWER_X_BOUND, UPPER_X_BOUND)
  158. local newZ = clamp(cf.Z, LOWER_Z_BOUND, UPPER_Z_BOUND)
  159.  
  160. return cframe(newX,posY,newZ)
  161. end
  162. -- calculates the initial y position above an object
  163. local function calculateYPosition(toP,toS,oS)
  164. return (toP + toS*0.5) + oS*0.5
  165. end
  166.  
  167.  
  168. local function rotate(actionName, inputState, inputObj)
  169. if inputState == Enum.UserInputState.Begin then
  170. rotation += rotationStep
  171. rotationVal = not rotationVal
  172. end
  173. end
  174.  
  175. local function cancel(actionName, inputState, inputObj)
  176. if inputState == Enum.UserInputState.Begin then
  177. object:Destroy()
  178. selectionbox:Destroy()
  179. --plot:FindFirstChild("Texture"):Destroy()
  180. mouse.TargetFilter = nil
  181. object = nil
  182. end
  183. end
  184.  
  185. TerminateButton.MouseButton1Click:Connect(function()
  186. if object and selectionbox then
  187. cancel("TerminateButtonClick", Enum.UserInputState.End, nil)
  188.  
  189. end
  190.  
  191. end)
  192.  
  193.  
  194.  
  195. local function snap(c)
  196. local newX = math.round(c.X/GRID_SIZE)*GRID_SIZE
  197. local newZ = math.round(c.Z/GRID_SIZE)*GRID_SIZE
  198. return cframe(newX, 0 , newZ)
  199. end
  200.  
  201. -- sets models position based on pivot
  202. local function calculateItemPosition()
  203. local finalCFrame = cframe(0,0,0)
  204. local x, z
  205. local offsetX,offsetZ
  206.  
  207. if rotationVal then
  208. offsetX, offsetZ = primary.Size.X*0.2, primary.Size.Z*0.5
  209. x, z = mouse.Hit.X - offsetX, mouse.Hit.Z - offsetZ
  210. else
  211. offsetX, offsetZ = primary.Size.Z*0.2, primary.Size.X*0.5
  212. x, z = mouse.Hit.X - offsetX, mouse.Hit.Z - offsetZ
  213.  
  214. end
  215.  
  216. if stackable and mouse.Target and mouse.Target:IsDescendantOf(plot) then
  217. posY = calculateYPosition(mouse.Target.Position.Y, mouse.Target.Size.Y,primary.Size.Y)
  218. else
  219. posY = calculateYPosition(plot.Position.Y,plot.Size.Y,primary.Size.Y)
  220. end
  221.  
  222.  
  223. if moveByGrid then
  224. local pltCFrame = cframe(plot.CFrame.X,plot.CFrame.Y,plot.CFrame.Z)
  225. local pos = cframe(x,0,z)
  226. pos = snap(pos* pltCFrame:Inverse())
  227. finalCFrame = pos*pltCFrame*cframe(offsetX, 0 , offsetZ)
  228. else
  229. finalCFrame = cframe(mouse.Hit.X, posY, mouse.Hit.Z)
  230.  
  231. end
  232. finalCFrame = bounds(cframe(finalCFrame.X, posY, finalCFrame.Z), offsetX,offsetZ)
  233.  
  234.  
  235. return finalCFrame*angles(0,math.rad(rotation), 0)
  236. end
  237.  
  238. local function unbindInputs()
  239. contextActionService:UnbindAction("Rotate")
  240. contextActionService:UnbindAction("Cancel")
  241. end
  242.  
  243. local function bindInputs()
  244. contextActionService:BindAction("Rotate", rotate, false, ROTATE_KEY)
  245. contextActionService:BindAction("Cancel", cancel, false, TERMINATE_KEY)
  246. end
  247.  
  248.  
  249. local function translateObj()
  250. if placedObjects and object and object.Parent == placedObjects then
  251. handleCollisions()
  252. changeHitboxColor()
  253. object:PivotTo(object.PrimaryPart.CFrame:Lerp(calculateItemPosition(), speed))
  254. end
  255. end
  256. -- returns the instant/non interpolated position of the object at any given amount
  257. local function getInstantCFrame()
  258. return calculateItemPosition()
  259. end
  260.  
  261. function placement:place(remote)
  262. if not collided and object then
  263. local cf = getInstantCFrame()
  264. remote:InvokeServer(object.Name, placedObjects, cf, plot)
  265. end
  266. end
  267. -- check of the model will snap evenly on the plot
  268. local function verifyPlane()
  269. return plot.Size.X%GRID_SIZE == 0 and plot.Size.Z%GRID_SIZE == 0
  270. end
  271. -- confirm that the settings are valid for placement
  272. local function approvedPlacement()
  273. if not verifyPlane() then
  274. warn("the model cannot snap on the plot. please change the plot size to fix this.")
  275.  
  276. return false
  277. end
  278. if GRID_SIZE >= math.min(plot.Size.X,plot.Size.Z) then
  279. error("Grid Size is too close to the size of the plot on at least one azis.")
  280. end
  281.  
  282. return true
  283. end
  284. -- Constructor Function
  285. function placement.new(g, objs, r, t)
  286. local data = {}
  287. local metaData = setmetatable(data, placement)
  288.  
  289. GRID_SIZE = g
  290. ITEM_LOCATION = objs
  291. ROTATE_KEY = r
  292. TERMINATE_KEY = t
  293.  
  294. data.grid = GRID_SIZE
  295. data.itemlocation = ITEM_LOCATION
  296. data.rotatekey = ROTATE_KEY or Enum.KeyCode.R
  297. data.terminatekey = TERMINATE_KEY or Enum.KeyCode.X
  298. return data
  299. end
  300.  
  301.  
  302. -- acitvates placement (id = name, pobjs = placedobjects,plt = plot.stk = stackable)
  303. function placement:activate(id, pobjs, plt, stk)
  304. if object then
  305. object:Destroy()
  306. object = nil -- Ensure object reference is cleared
  307. end
  308.  
  309. object = ITEM_LOCATION:FindFirstChild(id):Clone()
  310. selectionbox = Instance.new("SelectionBox")
  311. selectionbox.LineThickness = 0.05
  312. selectionbox.Parent = workspace
  313. primary = object.PrimaryPart
  314. placedObjects = pobjs
  315. plot = plt
  316. stackable = stk
  317. rotation = 0
  318. rotationVal = true
  319.  
  320. -- sets can collide to false so that collisions are ignored
  321. for i, v in pairs(object:GetDescendants()) do
  322. if v:IsA("BasePart") then
  323. v.CanCollide = false
  324. v.Transparency = 0.5
  325. end
  326. end
  327.  
  328. -- Check if placement can activate properly
  329. if not approvedPlacement() then
  330. return "Placement could not activate"
  331. end
  332.  
  333. if not stackable then
  334. mouse.TargetFilter = placedObjects
  335. else
  336. mouse.TargetFilter = object
  337. end
  338.  
  339. -- Speed setup
  340. local tempspeed = 1
  341. if interpolation then
  342. tempspeed = math.clamp(math.abs(tonumber(1 - lerpLevel)), 0, 10)
  343. speed = 1
  344. end
  345.  
  346. renderGrid()
  347. object.Parent = placedObjects
  348. task.wait()
  349. bindInputs()
  350. speed = tempspeed
  351. end
  352.  
  353. runservice:BindToRenderStep("Input", Enum.RenderPriority.Input.Value,translateObj)
  354. return placement
  355.  
Advertisement
Add Comment
Please, Sign In to add comment