Files
aya/client/studio/resources/BuiltInPlugins/terrain/08 - roads.lua
2025-12-17 16:47:48 +00:00

292 lines
7.7 KiB
Lua

while game == nil do
wait(1/30)
end
---------------
--PLUGIN SETUP-
---------------
local loaded = false
local on = false
self = PluginManager():CreatePlugin()
mouse = self:GetMouse()
mouse.Button1Down:connect(function() onClicked(mouse) end)
toolbar = self:CreateToolbar("Terrain")
toolbarbutton = toolbar:CreateButton("Roads", "Roads", "roads.png")
toolbarbutton.Click:connect(function()
if on then
Off()
elseif loaded then
On()
end
end)
game:WaitForChild("Workspace")
game.Workspace:WaitForChild("Terrain")
-- Local function definitions
local c = game.Workspace.Terrain
local SetCell = c.SetCell
local GetCell = c.GetCell
local WorldToCellPreferSolid = c.WorldToCellPreferSolid
local WorldToCellPreferEmpty = c.WorldToCellPreferEmpty
local SetCells = c.SetCells
-----------------
--DEFAULT VALUES-
-----------------
local x1 = 200
local y1 = 200
local x2 = 300
local y2 = 300
local h = 20
local mode = 0
local DefaultTerrainMaterial = 1
local roadDragBar, roadFrame,roadFrame, roadCloseEvent = nil
-----------------------
--FUNCTION DEFINITIONS-
-----------------------
--makes a column of blocks from 0 up to height at location (x,z) in cluster c
function coordHeight(x, z, height)
SetCells(c, Region3int16.new(Vector3int16.new(x, 1, z), Vector3int16.new(x, height, z)), DefaultTerrainMaterial, 0, 0)
end
function coordCheck(x, z, height)
for h = height, 0, -1 do
material, wedge, rotation = GetCell(c, x, h, z)
if material.Value > 0 then
return true
elseif height == 0 then
return false
end
end
end
function dist(x1, y1, x2, y2)
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
end
function dist3d(x1, y1, z1, x2, y2, z2)
return math.sqrt(math.pow(dist(x1, y1, x2, y2), 2) + math.pow(z2-z1, 2))
end
--create a path between coordinates (x1,z1) and (x2,z2) at height h in cluster c
--a path is a road with height of 3 instead of 1, and it builds a bridge if there is no existing land under it
--if you want path to come from x direction, make it start at the place
--if you want it to come from z direction, make it end at the place
--if p is true, turns on pillars, otherwise pillars are off
function makePath(x1, z1, x2, z2, h, p)
if x2 < x1 then
incx = -1
n = 1
else
incx = 1
n = -1
end
for x = x1, x2+n, incx do
SetCells(c, Region3int16.new(Vector3int16.new(x, h+1, z1-1), Vector3int16.new(x, h+3, z1+1)), 0, 0, 0)
SetCells(c, Region3int16.new(Vector3int16.new(x, h, z1-1), Vector3int16.new(x, h, z1+1)), DefaultTerrainMaterial, 0, 0)
end
if p then
for x = x1, x2+n, 16*incx do
if coordCheck(x, z1, h-1) then
coordHeight(x, z1, h-1)
end
if coordCheck(x, z1-1, h-1) then
coordHeight(x, z1-1, h-1)
end
if coordCheck(x, z1+1, h-1) then
coordHeight(x, z1+1, h-1)
end
end
end
if z2 < z1 then
incz = -1
m = 1
n = 2
else
incz = 1
m = -1
n = -2
end
for z = z1+m, z2+n, incz do
SetCells(c, Region3int16.new(Vector3int16.new(x2-1, h+1, z), Vector3int16.new(x2+1, h+3, z)), 0, 0, 0)
SetCells(c, Region3int16.new(Vector3int16.new(x2-1, h, z), Vector3int16.new(x2+1, h, z)), DefaultTerrainMaterial, 0, 0)
end
if p then
for z = z1+m, z2+n, 16*incz do
if coordCheck(x2, z, h-1) then
coordHeight(x2, z, h-1)
end
if coordCheck(x2-1, z, h-1) then
coordHeight(x2-1, z, h-1)
end
if coordCheck(x2+1, z, h-1) then
coordHeight(x2+1, z, h-1)
end
end
end
game:GetService("ChangeHistoryService"): SetWaypoint("Roads")
end
-- Do a line/plane intersection. The line starts at the camera. The plane is at y == 0, normal(0, 1, 0)
--
-- vectorPos - End point of the line.
--
-- Return:
-- success - Value is true if there was a plane intersection, false if not.
-- cellPos - Value is the terrain cell intersection point if there is one, vectorPos if there isn't.
function PlaneIntersection(vectorPos)
local currCamera = game.Workspace.CurrentCamera
local startPos = Vector3.new(currCamera.CoordinateFrame.p.X, currCamera.CoordinateFrame.p.Y, currCamera.CoordinateFrame.p.Z)
local endPos = Vector3.new(vectorPos.X, vectorPos.Y, vectorPos.Z)
local normal = Vector3.new(0, 1, 0)
local p3 = Vector3.new(0, 0, 0)
local startEndDot = normal:Dot(endPos - startPos)
local cellPos = vectorPos
local success = false
if startEndDot ~= 0 then
local t = normal:Dot(p3 - startPos) / startEndDot
if(t >=0 and t <=1) then
local intersection = ((endPos - startPos) * t) + startPos
cellPos = c:WorldToCell(intersection)
success = true
end
end
return success, cellPos
end
function onClicked (mouse)
if on then
local cellPos = WorldToCellPreferEmpty(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
local solidCell = WorldToCellPreferSolid(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
local success = false
-- If nothing was hit, do the plane intersection.
if 0 == GetCell(c, solidCell.X, solidCell.Y, solidCell.Z).Value then
--print('Plane Intersection happens')
success, cellPos = PlaneIntersection(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
if not success then
cellPos = solidCell
end
end
local x = cellPos.x
local y = cellPos.y
local z = cellPos.z
if mode == 0 then
x1 = x
y1 = z
h = y
mode = 1
-- first click determines default material
local celMat = GetCell(c, x, y, z)
if celMat.Value > 0 then
DefaultTerrainMaterial = celMat.Value
else
if 0 == DefaultTerrainMaterial then
DefaultTerrainMaterial = 1
end
end
elseif mode == 1 then
x2 = x
y2 = z
makePath(x1, y1, x2, y2, h, true, c)
mode = 0
else
end
end
end
function On()
if not c then
return
end
if self then
self:Activate(true)
end
if toolbarbutton then
toolbarbutton:SetActive(true)
end
if roadDragBar then
roadDragBar.Visible = true
end
mode = 0
on = true
end
function Off()
if toolbarbutton then
toolbarbutton:SetActive(false)
end
if roadDragBar then
roadDragBar.Visible = false
end
on = false
end
------
--GUI-
------
local RbxGui = LoadLibrary("RbxGui")
--screengui
local g = Instance.new("ScreenGui", game:GetService("CoreGui"))
g.Name = "RoadGui"
roadDragBar, roadFrame, roadHelpFrame, roadCloseEvent = RbxGui.CreatePluginFrame("Roads",UDim2.new(0,141,0,80),UDim2.new(0,0,0,0),false,g)
roadDragBar.Visible = false
roadCloseEvent.Event:connect(function ( )
Off()
end)
local roadTextHelper = Instance.new("TextLabel",roadFrame)
roadTextHelper.Text = "Click once to set the starting point and again to set the endpoint of the road."
roadTextHelper.Font = Enum.Font.ArialBold
roadTextHelper.FontSize = Enum.FontSize.Size14
roadTextHelper.TextColor3 = Color3.new(1,1,1)
roadTextHelper.BackgroundTransparency = 1
roadTextHelper.Size = UDim2.new(1,-8,1,-8)
roadTextHelper.Position = UDim2.new(0,4,0,4)
roadTextHelper.TextXAlignment = Enum.TextXAlignment.Left
roadTextHelper.TextYAlignment = Enum.TextYAlignment.Top
roadTextHelper.TextWrap = true
roadHelpFrame.Size = UDim2.new(0,200,0,150)
local helpText = Instance.new("TextLabel",roadHelpFrame)
helpText.Font = Enum.Font.ArialBold
helpText.FontSize = Enum.FontSize.Size12
helpText.TextColor3 = Color3.new(1,1,1)
helpText.BackgroundTransparency = 1
helpText.TextWrap = true
helpText.Size = UDim2.new(1,-10,1,-10)
helpText.Position = UDim2.new(0,5,0,5)
helpText.TextXAlignment = Enum.TextXAlignment.Left
helpText.Text =
[[Creates roads in existing terrain. Roads are created by setting a beginning point (first click on terrain) and an ending point (second click on terrain). The material of terrain is determined by the first click point. After the second click the tool resets and will create a new segment of road, not neccessarily connected to the first road segment created.]]
self.Deactivation:connect(function()
Off()
end)
--------------------------
--SUCCESSFUL LOAD MESSAGE-
--------------------------
loaded = true