Initial commit

This commit is contained in:
2025-12-17 16:47:48 +00:00
commit 13813f3363
4964 changed files with 1079753 additions and 0 deletions

View File

@@ -0,0 +1,225 @@
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
add_executable(Studio
src/main.cpp
resources/qt.qrc
src/AddEmulationDeviceDialog.cpp
src/AddEmulationDeviceDialog.hpp
src/AuthenticationHelper.cpp
src/AuthenticationHelper.hpp
src/AuthoringSettings.cpp
src/AuthoringSettings.hpp
src/AutoSaveDialog.cpp
src/AutoSaveDialog.hpp
src/CommonInsertWidget.cpp
src/CommonInsertWidget.hpp
src/CSGOperations.cpp
src/CSGOperations.hpp
src/DebuggerClient.cpp
src/DebuggerClient.hpp
src/DebuggerWidgets.cpp
src/DebuggerWidgets.hpp
src/DocDockManager.cpp
src/DocDockManager.hpp
src/DocDockWidget.cpp
src/DocDockWidget.hpp
src/DocTabManager.cpp
src/DocTabManager.hpp
src/ExternalHandlers.cpp
src/ExternalHandlers.hpp
src/FindDialog.cpp
src/FindDialog.hpp
src/FunctionMarshaller.cpp
src/FunctionMarshaller.hpp
src/GalleryItemColor.cpp
src/GalleryItemColor.hpp
src/IExternalHandler.hpp
src/InsertObjectListWidget.cpp
src/InsertObjectListWidget.hpp
src/InsertObjectListWidgetItem.cpp
src/InsertObjectListWidgetItem.hpp
src/InsertServiceDialog.cpp
src/InsertServiceDialog.hpp
src/IRobloxDoc.hpp
src/KeepSavedChangesDialog.cpp
src/KeepSavedChangesDialog.hpp
src/LogProvider.cpp
src/LogProvider.hpp
src/LuaSourceBuffer.cpp
src/LuaSourceBuffer.hpp
src/ManageEmulationDeviceDialog.cpp
src/ManageEmulationDeviceDialog.hpp
src/NameValueStoreManager.cpp
src/NameValueStoreManager.hpp
src/ogrewidget.cpp
src/ogrewidget.hpp
src/PluginAction.hpp
src/PropertyItems.cpp
src/PropertyItems.hpp
src/QDirBoundProp.hpp
src/QFontBoundProp.hpp
src/QtUtilities.cpp
src/QtUtilities.hpp
src/RbxContent.cpp
src/RbxContent.hpp
src/RbxWorkspace.cpp
src/RbxWorkspace.hpp
src/RenderStatsItem.cpp
src/RenderStatsItem.hpp
src/Roblox.cpp
src/Roblox.hpp
src/RobloxApplicationManager.cpp
src/RobloxApplicationManager.hpp
src/RobloxBasicDoc.cpp
src/RobloxBasicDoc.hpp
src/RobloxBrowser.cpp
src/RobloxBrowser.hpp
src/RobloxCookieJar.cpp
src/RobloxCookieJar.hpp
src/RobloxCustomWidgets.cpp
src/RobloxCustomWidgets.hpp
src/RobloxDiagnosticsView.cpp
src/RobloxDiagnosticsView.hpp
src/RobloxDocManager.cpp
src/RobloxDocManager.hpp
src/RobloxFindWidget.cpp
src/RobloxFindWidget.hpp
src/RobloxGameExplorer.cpp
src/RobloxGameExplorer.hpp
src/RobloxIDEDoc.cpp
src/RobloxIDEDoc.hpp
src/RobloxInputConfigDialog.cpp
src/RobloxInputConfigDialog.hpp
src/RobloxKeyboardConfig.cpp
src/RobloxKeyboardConfig.hpp
src/RobloxMainWindow.cpp
src/RobloxMainWindow.hpp
src/RobloxMouseConfig.cpp
src/RobloxMouseConfig.hpp
src/RobloxNetworkAccessManager.cpp
src/RobloxNetworkAccessManager.hpp
src/RobloxNetworkReply.cpp
src/RobloxNetworkReply.hpp
src/RobloxObjectBrowserDoc.cpp
src/RobloxObjectBrowserDoc.hpp
src/RobloxPluginHost.cpp
src/RobloxPluginHost.hpp
src/RobloxPropertyWidget.cpp
src/RobloxPropertyWidget.hpp
src/RobloxQuickAccessConfig.cpp
src/RobloxQuickAccessConfig.hpp
src/RobloxReportView.cpp
src/RobloxReportView.hpp
src/RobloxRibbonMainWindow.cpp
src/RobloxRibbonMainWindow.hpp
src/RobloxSavingStateDialog.cpp
src/RobloxSavingStateDialog.hpp
src/RobloxScriptDoc.cpp
src/RobloxScriptDoc.hpp
src/RobloxScriptReview.cpp
src/RobloxScriptReview.hpp
src/RobloxSettings.cpp
src/RobloxSettings.hpp
src/RobloxSettingsDialog.cpp
src/RobloxSettingsDialog.hpp
src/RobloxStudioVerbs.cpp
src/RobloxStudioVerbs.hpp
src/RobloxStudioVersion.hpp
src/RobloxTabWidget.hpp
src/RobloxTaskScheduler.cpp
src/RobloxTaskScheduler.hpp
src/RobloxTextOutputWidget.cpp
src/RobloxTextOutputWidget.hpp
src/RobloxToolBox.cpp
src/RobloxToolBox.hpp
src/RobloxTreeWidget.cpp
src/RobloxTreeWidget.hpp
src/RobloxUser.cpp
src/RobloxUser.hpp
src/RobloxView.cpp
src/RobloxView.hpp
src/RobloxWebDoc.cpp
src/RobloxWebDoc.hpp
src/RobloxWebPage.cpp
src/RobloxWebPage.hpp
src/ScopedDebugTimer.hpp
src/ScriptAnalysisWidget.cpp
src/ScriptAnalysisWidget.hpp
src/ScriptComboBox.cpp
src/ScriptComboBox.hpp
src/ScriptPickerDialog.cpp
src/ScriptPickerDialog.hpp
src/ScriptSideWidget.cpp
src/ScriptSideWidget.hpp
src/ScriptSyntaxHighlighter.cpp
src/ScriptSyntaxHighlighter.hpp
src/ScriptTextEditor.cpp
src/ScriptTextEditor.hpp
src/SelectionHighlightAdornable.cpp
src/SelectionHighlightAdornable.hpp
src/ShortcutHelpDialog.cpp
src/ShortcutHelpDialog.hpp
src/SplineEditor.cpp
src/SplineEditor.hpp
src/stdafx.cpp
src/stdafx.hpp
src/StudioDeviceEmulator.cpp
src/StudioDeviceEmulator.hpp
src/StudioIntellesense.cpp
src/StudioIntellesense.hpp
src/StudioMacUtilities.hpp
src/StudioSerializerHelper.cpp
src/StudioSerializerHelper.hpp
src/StudioUtilities.cpp
src/StudioUtilities.hpp
src/UpdateUIManager.cpp
src/UpdateUIManager.hpp
src/UserInput.cpp
src/UserInput.hpp
src/UserInputUtil.cpp
src/UserInputUtil.hpp
src/WebDialog.cpp
src/WebDialog.hpp
${CLIENT_DIR}/common/AppSettings.cpp
${CLIENT_DIR}/common/AppSettings.hpp
${CLIENT_DIR}/common/GrayChatBar.hpp
${CLIENT_DIR}/common/GrayChatBar.cpp
${CLIENT_DIR}/common/SDLGameController.cpp
${CLIENT_DIR}/common/SDLGameController.hpp
)
target_link_libraries(Studio
3D
AppStudio
Core
RakNet
BulletPhysics
NetworkStudio
Graphics
QtitanRibbon
)
if(AYA_OS_WINDOWS)
target_sources(Studio PRIVATE
resources/winrc.h
resources/script.rc
)
set_target_properties(Studio PROPERTIES WIN32_EXECUTABLE TRUE)
windeployqt(Studio)
endif()
target_compile_definitions(Studio PRIVATE QT_NO_KEYWORDS)
target_include_directories(Studio PRIVATE src resources)
set_target_properties(Studio PROPERTIES OUTPUT_NAME "Aya.Studio")
add_custom_command(TARGET Studio POST_BUILD
COMMENT "Copying runtime files to build directory"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${RUNTIME_FILES}"
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
)

View File

@@ -0,0 +1,852 @@
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="4">
<External>null</External>
<External>nil</External>
<Item class="Model" referent="RBX3F9EDB07622E42D797B3F001F3E09746">
<Properties>
<CoordinateFrame name="ModelInPrimary">
<X>0</X>
<Y>0</Y>
<Z>0</Z>
<R00>1</R00>
<R01>0</R01>
<R02>0</R02>
<R10>0</R10>
<R11>1</R11>
<R12>0</R12>
<R20>0</R20>
<R21>0</R21>
<R22>1</R22>
</CoordinateFrame>
<string name="Name">PhysicsAnalyzerPlugin</string>
<Ref name="PrimaryPart">null</Ref>
</Properties>
<Item class="Script" referent="RBXB4C77FAE3AAF45D291F682F80C833828">
<Properties>
<bool name="Disabled">false</bool>
<Content name="LinkedSource">
<null></null>
</Content>
<string name="Name">PhysicsAnalyzerScript</string>
<ProtectedString name="Source"><![CDATA[-- Detector will send a signal with an int parameter, this is the number of problems detected
-- This script can query for a list of parts for each problem
-- The plugin is responsible for:
-- 1) Pausing the game
-- 2) Highlighting the parts
-- 3) Selecting the parts in the Explorer
-- 4) Focus on the parts in a group
-- 5) Providing an interface for skipping to next issue
-----------
--MODULES--
-----------
local Extent = require(script.Parent.Extent)
local Camera = require(script.Parent.Camera)
-------
--GUI--
-------
local PhysicsAnalyzerGui = script.Parent.PhysicsAnalyzerGui
local MainFrame = PhysicsAnalyzerGui.MainFrame
local NumberFound = MainFrame.NumberFound
local CurrentStatus = MainFrame.CurrentStatus
local RunButton = MainFrame.RunButton
local ScrollingFrame = MainFrame.ScrollingFrame
local Canvas = ScrollingFrame.Canvas
local ItemTemplate = MainFrame.ItemTemplate
local HelpButton = MainFrame.HelpButton
------------
--SERVICES--
------------
local SelectionService = game:GetService("Selection")
local RunService = game:GetService("RunService")
PhysicsAnalyzerGui.Parent = game:GetService("CoreGui")
-----------
--SIGNALS--
-----------
local PhysicsAnalyzerIssuesSignal = nil
local RunServiceSteppedSignal = nil
local RunButtonInputSignal = nil
local HelpButtonSignal = nil
-------------
--VARIABLES--
-------------
local previousIssueCount = 0;
local issues = {}
-------------
--FUNCTIONS--
-------------
local function clearAllIssues()
for i = 1, #issues do
issues[i][3]:disconnect()
issues[i][2]:Destroy()
end
issues = {}
NumberFound.Text = ""
end
local function addIssue(issue)
-- local label = "Issue " .. #issues .. (issue[1] and (": " .. issue[1].Name ..
-- (issue[2] and " / " .. issue[2].Name or "")) or (""))
local label = "Issue " .. #issues .. ": "
for j=1, #issue do
if( j > 1 ) then
label = label .. " / "
end
label = label .. issue[j].Name
end
local item = ItemTemplate:Clone()
item.Parent = Canvas
item.Position = UDim2.new(0, 0, 0, 21 * #issues)
item.Text = label
local itemConnection = item.InputBegan:connect(function(evt)
if evt.UserInputType == Enum.UserInputType.MouseButton1 then
moveAndSelectParts(issue)
end
end)
item.Visible = true
issues[#issues + 1] = {issue, item, itemConnection}
ScrollingFrame.CanvasSize = UDim2.new(0, 0, 0, #issues * 21)
if (ScrollingFrame.CanvasSize.Y.Offset > ScrollingFrame.AbsoluteSize.Y) then
Canvas.Size = UDim2.new(1, -16, 1, 0)
else
Canvas.Size = UDim2.new(1, 0, 1, 0)
end
previousIssueCount = #issues;
end
function moveAndSelectParts(parts)
game.Selection:Set(parts)
local extents = Extent.getExtents(parts)
Camera.zoomToExtents(extents)
end
local function gotIssues(count)
MainFrame.Size = UDim2.new(0, 200, 0, 200)
ScrollingFrame.Visible = true
if (count == previousIssueCount) then
return
end
clearAllIssues()
RunService:Pause()
game.Workspace:SetPhysicsAnalyzerBreakOnIssue(true)
--Updating GUI
NumberFound.Text = count .. " overconstraints detected"
RunButton.Visible = true
CurrentStatus.Text = "Paused"
for i = 0, count - 1 do
local issue = game.Workspace:GetPhysicsAnalyzerIssue(i)
addIssue(issue)
end
game.Workspace:SetPhysicsAnalyzerBreakOnIssue(false)
end
local function connectEvents()
RunServiceSteppedSignal = RunService.Stepped:connect(function()
clearAllIssues()
CurrentStatus.Text = "Running"
end)
RunButtonInputSignal = RunButton.InputBegan:connect(function(evt)
if (evt.UserInputType == Enum.UserInputType.MouseButton1) then
RunService:Run()
RunButton.Visible = false
end
end)
HelpButtonSignal = HelpButton.InputBegan:connect(function(evt)
if (evt.UserInputType == Enum.UserInputType.MouseButton1) then
plugin:OpenWikiPage("Physics_Analyzer")
end
end)
PhysicsAnalyzerIssuesSignal = game.Workspace.PhysicsAnalyzerIssuesFound:connect(gotIssues)
end
local function disconnectEvents()
if PhysicsAnalyzerIssuesSignal then
PhysicsAnalyzerIssuesSignal:disconnect()
end
if RunServiceSteppedSignal then
RunServiceSteppedSignal:disconnect()
end
if RunButtonInputSignal then
RunButtonInputSignal:disconnect()
end
if HelpButtonSignal then
HelpButtonSignal:disconnect()
end
end
local function physicsAnalyzerEnabled(enabled)
MainFrame.Visible = enabled
if enabled then
connectEvents()
else
disconnectEvents()
end
end
----------
--EVENTS--
----------
settings().Physics.Changed:connect(function(itemChanged)
if itemChanged == "PhysicsAnalyzerEnabled" then
physicsAnalyzerEnabled(settings().Physics.PhysicsAnalyzerEnabled)
end
end)
physicsAnalyzerEnabled(settings().Physics.PhysicsAnalyzerEnabled)
]]> </ProtectedString>
</Properties>
</Item>
<Item class="ModuleScript" referent="RBXDB111B99CBE14ED8A5E9B4B20FA6CCA3">
<Properties>
<Content name="LinkedSource">
<null></null>
</Content>
<string name="Name">Extent</string>
<ProtectedString name="Source"><![CDATA[------------------
--MODULE EXTENTS--
------------------
--[[
This modulescript is used for calculating the extents of a group of parts
--]]
-------------
--FUNCTIONS--
-------------
local function createExtents()
local extents = {}
extents.mt = {}
setmetatable(extents, extents.mt)
extents.min = Vector3.new(1,1,1) * math.huge
extents.max = Vector3.new(1,1,1) * -math.huge
extents.mt.__index = function (t, k)
if k == "center" then
return (extents.min + extents.max) * 0.5
end
if k == "addPoint" then
return function (point)
if point.x < extents.min.x then extents.min = Vector3.new(point.x, extents.min.y, extents.min.z) end
if point.y < extents.min.y then extents.min = Vector3.new(extents.min.x, point.y, extents.min.z) end
if point.z < extents.min.z then extents.min = Vector3.new(extents.min.x, extents.min.y, point.z) end
if point.x > extents.max.x then extents.max = Vector3.new(point.x, extents.max.y, extents.max.z) end
if point.y > extents.max.y then extents.max = Vector3.new(extents.max.x, point.y, extents.max.z) end
if point.z > extents.max.z then extents.max = Vector3.new(extents.max.x, extents.max.y, point.z) end
end
end
end
return extents
end
local function addToExtents(extents, part)
for i = 0, 7 do
local corner = (Vector3.new(math.floor(i / 4), math.floor(i / 2) % 2, i % 2) * 2) - Vector3.new(1, 1, 1)
local worldPosition = part.CFrame:pointToWorldSpace(corner * part.Size)
extents.addPoint(worldPosition)
end
return extents
end
local function getExtents(parts)
local extents = createExtents()
for i = 1, #parts do
if parts[i]:IsA("BasePart") then
extents = addToExtents(extents, parts[i])
end
end
return extents
end
-----------------
--ENCAPSULATION--
-----------------
local module = {}
module.getExtents = getExtents
return module
]]> </ProtectedString>
</Properties>
</Item>
<Item class="ModuleScript" referent="RBXF7D9C89485434B36B2422E149374F5DF">
<Properties>
<Content name="LinkedSource">
<null></null>
</Content>
<string name="Name">Camera</string>
<ProtectedString name="Source"><![CDATA[-----------------
--MODULE CAMERA--
-----------------
--[[
This modulescript is used for zooming the camera to given extents
--]]
-------------
--FUNCTIONS--
-------------
local distanceFromRadius = 3
local function zoomToExtents(extents)
local camera = game.Workspace.CurrentCamera
local center = extents.center
local radius = (extents.min - center).magnitude
camera.CameraType = Enum.CameraType.Fixed
local rotation = camera.CoordinateFrame - camera.CoordinateFrame.p
local position = center - (rotation.lookVector * (radius + distanceFromRadius))
camera.CoordinateFrame = rotation + position
camera.Focus = CFrame.new(center)
end
-----------------
--ENCAPSULATION--
-----------------
local module = {}
module.zoomToExtents = zoomToExtents
return module
]]> </ProtectedString>
</Properties>
</Item>
<Item class="ScreenGui" referent="RBXC61727E732814E20A690ED394899F571">
<Properties>
<string name="Name">PhysicsAnalyzerGui</string>
</Properties>
<Item class="Frame" referent="RBX9C1A115B17C64C2DA4C550472FC4C2FC">
<Properties>
<bool name="Active">true</bool>
<Color3 name="BackgroundColor3">4294967295</Color3>
<float name="BackgroundTransparency">0</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">1</int>
<bool name="ClipsDescendants">false</bool>
<bool name="Draggable">false</bool>
<string name="Name">MainFrame</string>
<Ref name="NextSelectionDown">null</Ref>
<Ref name="NextSelectionLeft">null</Ref>
<Ref name="NextSelectionRight">null</Ref>
<Ref name="NextSelectionUp">null</Ref>
<UDim2 name="Position">
<XS>0</XS>
<XO>0</XO>
<YS>0</YS>
<YO>0</YO>
</UDim2>
<float name="Rotation">0</float>
<bool name="Selectable">false</bool>
<Ref name="SelectionImageObject">null</Ref>
<UDim2 name="Size">
<XS>0</XS>
<XO>200</XO>
<YS>0</YS>
<YO>70</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<token name="Style">6</token>
<bool name="Visible">true</bool>
<int name="ZIndex">1</int>
</Properties>
<Item class="TextLabel" referent="RBX21D1D53505FA4E5EA81BC1E4FEE93833">
<Properties>
<bool name="Active">false</bool>
<Color3 name="BackgroundColor3">4294967295</Color3>
<float name="BackgroundTransparency">0.75</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">0</int>
<bool name="ClipsDescendants">false</bool>
<bool name="Draggable">false</bool>
<token name="Font">4</token>
<token name="FontSize">6</token>
<string name="Name">TitleLabel</string>
<Ref name="NextSelectionDown">null</Ref>
<Ref name="NextSelectionLeft">null</Ref>
<Ref name="NextSelectionRight">null</Ref>
<Ref name="NextSelectionUp">null</Ref>
<UDim2 name="Position">
<XS>0</XS>
<XO>0</XO>
<YS>0</YS>
<YO>0</YO>
</UDim2>
<float name="Rotation">0</float>
<bool name="Selectable">false</bool>
<Ref name="SelectionImageObject">null</Ref>
<UDim2 name="Size">
<XS>1</XS>
<XO>0</XO>
<YS>0</YS>
<YO>25</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<string name="Text">Physics Analyzer</string>
<Color3 name="TextColor3">4294967295</Color3>
<bool name="TextScaled">false</bool>
<Color3 name="TextStrokeColor3">4278190080</Color3>
<float name="TextStrokeTransparency">1</float>
<float name="TextTransparency">0</float>
<bool name="TextWrapped">false</bool>
<token name="TextXAlignment">2</token>
<token name="TextYAlignment">1</token>
<bool name="Visible">true</bool>
<int name="ZIndex">1</int>
</Properties>
</Item>
<Item class="ScrollingFrame" referent="RBX903E924BF45441B8948310D28BDE9938">
<Properties>
<bool name="Active">false</bool>
<Color3 name="BackgroundColor3">4294967295</Color3>
<float name="BackgroundTransparency">1</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">0</int>
<Content name="BottomImage">
<url>ayaasset://textures/ui/studs.png</url>
</Content>
<Vector2 name="CanvasPosition">
<X>0</X>
<Y>0</Y>
</Vector2>
<UDim2 name="CanvasSize">
<XS>0</XS>
<XO>0</XO>
<YS>0</YS>
<YO>100</YO>
</UDim2>
<bool name="ClipsDescendants">true</bool>
<bool name="Draggable">false</bool>
<Content name="MidImage">
<url>ayaasset://textures/ui/smooth.png</url>
</Content>
<string name="Name">ScrollingFrame</string>
<Ref name="NextSelectionDown">null</Ref>
<Ref name="NextSelectionLeft">null</Ref>
<Ref name="NextSelectionRight">null</Ref>
<Ref name="NextSelectionUp">null</Ref>
<UDim2 name="Position">
<XS>0</XS>
<XO>0</XO>
<YS>0</YS>
<YO>75</YO>
</UDim2>
<float name="Rotation">0</float>
<int name="ScrollBarThickness">12</int>
<bool name="ScrollingEnabled">true</bool>
<bool name="Selectable">true</bool>
<Ref name="SelectionImageObject">null</Ref>
<UDim2 name="Size">
<XS>1</XS>
<XO>0</XO>
<YS>1</YS>
<YO>-75</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<Content name="TopImage">
<url>ayaasset://textures/ui/studs.png</url>
</Content>
<bool name="Visible">false</bool>
<int name="ZIndex">1</int>
</Properties>
<Item class="Frame" referent="RBX0748620B01764D05897BE23D03333C45">
<Properties>
<bool name="Active">false</bool>
<Color3 name="BackgroundColor3">4294967295</Color3>
<float name="BackgroundTransparency">1</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">0</int>
<bool name="ClipsDescendants">true</bool>
<bool name="Draggable">false</bool>
<string name="Name">Canvas</string>
<Ref name="NextSelectionDown">null</Ref>
<Ref name="NextSelectionLeft">null</Ref>
<Ref name="NextSelectionRight">null</Ref>
<Ref name="NextSelectionUp">null</Ref>
<UDim2 name="Position">
<XS>0</XS>
<XO>0</XO>
<YS>0</YS>
<YO>0</YO>
</UDim2>
<float name="Rotation">0</float>
<bool name="Selectable">false</bool>
<Ref name="SelectionImageObject">null</Ref>
<UDim2 name="Size">
<XS>1</XS>
<XO>-16</XO>
<YS>1</YS>
<YO>0</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<token name="Style">0</token>
<bool name="Visible">true</bool>
<int name="ZIndex">1</int>
</Properties>
</Item>
</Item>
<Item class="TextButton" referent="RBX5909EC7335A24E6E8BD4123F5940CB4A">
<Properties>
<bool name="Active">true</bool>
<bool name="AutoButtonColor">true</bool>
<Color3 name="BackgroundColor3">4294967295</Color3>
<float name="BackgroundTransparency">0.899999976</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">0</int>
<bool name="ClipsDescendants">false</bool>
<bool name="Draggable">false</bool>
<token name="Font">3</token>
<token name="FontSize">5</token>
<bool name="Modal">false</bool>
<string name="Name">ItemTemplate</string>
<Ref name="NextSelectionDown">null</Ref>
<Ref name="NextSelectionLeft">null</Ref>
<Ref name="NextSelectionRight">null</Ref>
<Ref name="NextSelectionUp">null</Ref>
<UDim2 name="Position">
<XS>0</XS>
<XO>0</XO>
<YS>0</YS>
<YO>0</YO>
</UDim2>
<float name="Rotation">0</float>
<bool name="Selectable">true</bool>
<bool name="Selected">false</bool>
<Ref name="SelectionImageObject">null</Ref>
<UDim2 name="Size">
<XS>1</XS>
<XO>0</XO>
<YS>0</YS>
<YO>20</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<token name="Style">0</token>
<string name="Text">Problem 0</string>
<Color3 name="TextColor3">4294967295</Color3>
<bool name="TextScaled">false</bool>
<Color3 name="TextStrokeColor3">4278190080</Color3>
<float name="TextStrokeTransparency">1</float>
<float name="TextTransparency">0</float>
<bool name="TextWrapped">false</bool>
<token name="TextXAlignment">2</token>
<token name="TextYAlignment">1</token>
<bool name="Visible">false</bool>
<int name="ZIndex">1</int>
</Properties>
</Item>
<Item class="TextLabel" referent="RBXCDD1A7B9C4994E1B9948AF615DD254A1">
<Properties>
<bool name="Active">false</bool>
<Color3 name="BackgroundColor3">4294967295</Color3>
<float name="BackgroundTransparency">1</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">0</int>
<bool name="ClipsDescendants">false</bool>
<bool name="Draggable">false</bool>
<token name="Font">4</token>
<token name="FontSize">5</token>
<string name="Name">Status</string>
<Ref name="NextSelectionDown">null</Ref>
<Ref name="NextSelectionLeft">null</Ref>
<Ref name="NextSelectionRight">null</Ref>
<Ref name="NextSelectionUp">null</Ref>
<UDim2 name="Position">
<XS>0</XS>
<XO>0</XO>
<YS>0</YS>
<YO>30</YO>
</UDim2>
<float name="Rotation">0</float>
<bool name="Selectable">false</bool>
<Ref name="SelectionImageObject">null</Ref>
<UDim2 name="Size">
<XS>0</XS>
<XO>50</XO>
<YS>0</YS>
<YO>20</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<string name="Text">Status:</string>
<Color3 name="TextColor3">4294967295</Color3>
<bool name="TextScaled">false</bool>
<Color3 name="TextStrokeColor3">4278190080</Color3>
<float name="TextStrokeTransparency">1</float>
<float name="TextTransparency">0</float>
<bool name="TextWrapped">false</bool>
<token name="TextXAlignment">2</token>
<token name="TextYAlignment">1</token>
<bool name="Visible">true</bool>
<int name="ZIndex">1</int>
</Properties>
</Item>
<Item class="TextLabel" referent="RBX9B7E5EB7F2C64FF4AEE9FD0D4EFACF49">
<Properties>
<bool name="Active">false</bool>
<Color3 name="BackgroundColor3">4294967295</Color3>
<float name="BackgroundTransparency">1</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">0</int>
<bool name="ClipsDescendants">false</bool>
<bool name="Draggable">false</bool>
<token name="Font">3</token>
<token name="FontSize">5</token>
<string name="Name">CurrentStatus</string>
<Ref name="NextSelectionDown">null</Ref>
<Ref name="NextSelectionLeft">null</Ref>
<Ref name="NextSelectionRight">null</Ref>
<Ref name="NextSelectionUp">null</Ref>
<UDim2 name="Position">
<XS>0</XS>
<XO>47</XO>
<YS>0</YS>
<YO>31</YO>
</UDim2>
<float name="Rotation">0</float>
<bool name="Selectable">false</bool>
<Ref name="SelectionImageObject">null</Ref>
<UDim2 name="Size">
<XS>0</XS>
<XO>50</XO>
<YS>0</YS>
<YO>20</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<string name="Text">Ready</string>
<Color3 name="TextColor3">4294967295</Color3>
<bool name="TextScaled">false</bool>
<Color3 name="TextStrokeColor3">4278190080</Color3>
<float name="TextStrokeTransparency">1</float>
<float name="TextTransparency">0</float>
<bool name="TextWrapped">false</bool>
<token name="TextXAlignment">0</token>
<token name="TextYAlignment">1</token>
<bool name="Visible">true</bool>
<int name="ZIndex">1</int>
</Properties>
</Item>
<Item class="TextLabel" referent="RBXB4BD17ABC60E45D2A4F98110C999CEA9">
<Properties>
<bool name="Active">false</bool>
<Color3 name="BackgroundColor3">4294967295</Color3>
<float name="BackgroundTransparency">1</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">0</int>
<bool name="ClipsDescendants">false</bool>
<bool name="Draggable">false</bool>
<token name="Font">4</token>
<token name="FontSize">5</token>
<string name="Name">NumberFound</string>
<Ref name="NextSelectionDown">null</Ref>
<Ref name="NextSelectionLeft">null</Ref>
<Ref name="NextSelectionRight">null</Ref>
<Ref name="NextSelectionUp">null</Ref>
<UDim2 name="Position">
<XS>0</XS>
<XO>5</XO>
<YS>0</YS>
<YO>55</YO>
</UDim2>
<float name="Rotation">0</float>
<bool name="Selectable">false</bool>
<Ref name="SelectionImageObject">null</Ref>
<UDim2 name="Size">
<XS>1</XS>
<XO>-5</XO>
<YS>0</YS>
<YO>20</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<string name="Text"></string>
<Color3 name="TextColor3">4294924122</Color3>
<bool name="TextScaled">false</bool>
<Color3 name="TextStrokeColor3">4278190080</Color3>
<float name="TextStrokeTransparency">1</float>
<float name="TextTransparency">0</float>
<bool name="TextWrapped">false</bool>
<token name="TextXAlignment">0</token>
<token name="TextYAlignment">1</token>
<bool name="Visible">true</bool>
<int name="ZIndex">1</int>
</Properties>
</Item>
<Item class="ImageButton" referent="RBXB619D19972004CB3992613F98E612BD0">
<Properties>
<bool name="Active">true</bool>
<bool name="AutoButtonColor">true</bool>
<Color3 name="BackgroundColor3">4294967295</Color3>
<float name="BackgroundTransparency">1</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">0</int>
<bool name="ClipsDescendants">false</bool>
<bool name="Draggable">false</bool>
<Content name="Image">
<url>roblox.com/asset?id=358274726</url>
</Content>
<Color3 name="ImageColor3">4294967295</Color3>
<Vector2 name="ImageRectOffset">
<X>0</X>
<Y>0</Y>
</Vector2>
<Vector2 name="ImageRectSize">
<X>0</X>
<Y>0</Y>
</Vector2>
<float name="ImageTransparency">0</float>
<bool name="Modal">false</bool>
<string name="Name">RunButton</string>
<Ref name="NextSelectionDown">null</Ref>
<Ref name="NextSelectionLeft">null</Ref>
<Ref name="NextSelectionRight">null</Ref>
<Ref name="NextSelectionUp">null</Ref>
<UDim2 name="Position">
<XS>1</XS>
<XO>-25</XO>
<YS>0</YS>
<YO>30</YO>
</UDim2>
<float name="Rotation">0</float>
<token name="ScaleType">0</token>
<bool name="Selectable">true</bool>
<bool name="Selected">false</bool>
<Ref name="SelectionImageObject">null</Ref>
<UDim2 name="Size">
<XS>0</XS>
<XO>20</XO>
<YS>0</YS>
<YO>20</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<Rect2D name="SliceCenter">
<min>
<X>0</X>
<Y>0</Y>
</min>
<max>
<X>0</X>
<Y>0</Y>
</max>
</Rect2D>
<token name="Style">0</token>
<bool name="Visible">false</bool>
<int name="ZIndex">1</int>
</Properties>
</Item>
<Item class="ImageButton" referent="RBX18E6EA46987C449D9CA4697F8E7FC57B">
<Properties>
<bool name="Active">true</bool>
<bool name="AutoButtonColor">true</bool>
<Color3 name="BackgroundColor3">4294967295</Color3>
<float name="BackgroundTransparency">1</float>
<Color3 name="BorderColor3">4279970357</Color3>
<int name="BorderSizePixel">0</int>
<bool name="ClipsDescendants">false</bool>
<bool name="Draggable">false</bool>
<Content name="Image">
<url>roblox.com/asset?id=320903644</url>
</Content>
<Color3 name="ImageColor3">4294967295</Color3>
<Vector2 name="ImageRectOffset">
<X>0</X>
<Y>0</Y>
</Vector2>
<Vector2 name="ImageRectSize">
<X>0</X>
<Y>0</Y>
</Vector2>
<float name="ImageTransparency">0</float>
<bool name="Modal">false</bool>
<string name="Name">HelpButton</string>
<Ref name="NextSelectionDown">null</Ref>
<Ref name="NextSelectionLeft">null</Ref>
<Ref name="NextSelectionRight">null</Ref>
<Ref name="NextSelectionUp">null</Ref>
<UDim2 name="Position">
<XS>1</XS>
<XO>-19</XO>
<YS>0</YS>
<YO>4</YO>
</UDim2>
<float name="Rotation">0</float>
<token name="ScaleType">0</token>
<bool name="Selectable">true</bool>
<bool name="Selected">false</bool>
<Ref name="SelectionImageObject">null</Ref>
<UDim2 name="Size">
<XS>0</XS>
<XO>16</XO>
<YS>0</YS>
<YO>16</YO>
</UDim2>
<token name="SizeConstraint">0</token>
<Rect2D name="SliceCenter">
<min>
<X>0</X>
<Y>0</Y>
</min>
<max>
<X>0</X>
<Y>0</Y>
</max>
</Rect2D>
<token name="Style">0</token>
<bool name="Visible">true</bool>
<int name="ZIndex">1</int>
</Properties>
</Item>
</Item>
</Item>
</Item>
</roblox>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,996 @@
-- Local function definitions
while game == nil do
wait(1/30)
end
---------------
--PLUGIN SETUP-
---------------
local loaded = false
local on = false
local plugin = PluginManager():CreatePlugin()
local toolbar = plugin:CreateToolbar("Terrain")
local toolbarbutton = toolbar:CreateButton("Generator", "Terrain Generator", "terrain.png")
toolbarbutton.Click:connect(function()
if on then
Off()
elseif loaded then
On()
end
end)
game:WaitForChild("Workspace")
game.Workspace:WaitForChild("Terrain")
local c = game.Workspace.Terrain
local SetCell = c.SetCell
local GetCell = c.GetCell
local SetCells = c.SetCells
local AutoWedge = c.AutowedgeCells
local CellCenterToWorld = c.CellCenterToWorld
-- Create a set of terrain options. Contains everything needed to now how to generate terrain.
local TerrainOptions = {}
TerrainOptions.__index = TerrainOptions
-- This will create with default options.
function TerrainOptions.Create()
local options = {}
setmetatable(options, TerrainOptions)
-- Offset to create terrain at.
options.xpos = 0
options.zpos = 0
-- X width
options.width = 512
-- Z length
options.length = 512
-- Amplitude, how high hills can be. The higher the number the higher a hill can be.
options.a = 30
-- Frequency, how often hills occur. The higher the number the more hills.
options.f = 8
-- How deep water should be. 0 means no water.
options.waterHeight = 0
-- How how the base of the world should be. 0 means no base.
options.baseHeight = 1
-- What material type terrain will be.
options.terrainMaterial = 1
-- Display the location.
return options
end
-- Stores the current terrain options to set/display.
local terrainOptions = TerrainOptions.Create()
-- This will store a copy of terrainOptions when the generate button is pressed.
-- This will then be used for the generation instead of terrainOptions. This way terrainOptions can be changed while generating without messing up what is being generated.
local generateOptions = nil
-- Create a deep copy of a table.
-- Copies the elements.
function CopyTable(object)
local holdTable = {}
local function Copy(object)
if type(object) ~= "table" then
return object
elseif holdTable[object] then
return holdTable[object]
end
local clone = {}
holdTable[object] = clone
for index, value in pairs(object) do
clone[Copy(index)] = Copy(value)
end
return setmetatable(clone, getmetatable(object))
end
return Copy(object)
end
-- Creates a copy of terrain options data.
--
-- Return:
-- Value is a new terrain options set with the old terrain options data.
function TerrainOptions:Clone(ID)
return CopyTable(self)
end
-----------------
--DEFAULT VALUES-
-----------------
-- Stores the conformation popup when confirming a choice. If not nil then some actions should be blocked.
local ConfirmationPopupObject = nil
-- If true, the clear terrain conformation won't be shown.
local hideClearConformation = false
-- If true, the genearte terrain conformation won't be shown.
local hideGenerateConformation = false
------
--GUI-
------
--screengui
local g = Instance.new("ScreenGui", game:GetService("CoreGui"))
g.Name = 'TerrainCreatorGui'
-- UI gui load. Required for sliders.
local RbxGui = LoadLibrary("RbxGui")
-- Gui frame for the plugin.
local terrainPropertiesDragBar, terrainFrame, terrainHelpFrame, terrainCloseEvent = RbxGui.CreatePluginFrame("Terrain Generator",UDim2.new(0,186,0,428),UDim2.new(0,0,0,0),false,g)
terrainPropertiesDragBar.Visible = false
terrainCloseEvent.Event:connect(function ( )
Off()
end)
terrainHelpFrame.Size = UDim2.new(0,300,0,350)
local terrainHelpText = Instance.new("TextLabel",terrainHelpFrame)
terrainHelpText.Name = "HelpText"
terrainHelpText.Font = Enum.Font.ArialBold
terrainHelpText.FontSize = Enum.FontSize.Size12
terrainHelpText.TextColor3 = Color3.new(227/255,227/255,227/255)
terrainHelpText.TextXAlignment = Enum.TextXAlignment.Left
terrainHelpText.TextYAlignment = Enum.TextYAlignment.Top
terrainHelpText.Position = UDim2.new(0,4,0,4)
terrainHelpText.Size = UDim2.new(1,-8,0,157)
terrainHelpText.BackgroundTransparency = 1
terrainHelpText.TextWrap = true
terrainHelpText.Text = [[Create terrain with hills, water.
X-Offset and Z-Offset:
Center point of terrain that will be created.
Terrain must be in a specific region. If part of the terrain is outside that region, it won't be created.
Width: Terrain size in the X direction
Length: Terrain size in the Z direction
Amplitude:
Maximum height of hills.
]]
local helpSecondText = terrainHelpText:clone()
helpSecondText.Name = "HelpSecondText"
helpSecondText.Position = UDim2.new(0,0,1,0)
helpSecondText.Size = UDim2.new(1,0,0,180)
helpSecondText.Text = [[Frequency:
How often hills are made.
Base Height:
How high the base of terrain should be.
Water Height:
How high water should be. Terrain will overwrite water.
]]
helpSecondText.Parent = terrainHelpText
local helpThirdText = helpSecondText:clone()
helpThirdText.Name = "HelpThirdText"
helpThirdText.Position = UDim2.new(0,0,.6,0)
helpThirdText.Size = UDim2.new(1,0,0,180)
helpThirdText.Text = [[
Generate Button:
Create the terrain.
Clear Button:
Remove all terrain.
]]
helpThirdText.Parent = helpSecondText
-- Used to create a highlighter.
-- A highlighter is a open, rectuangular area displayed in 3D.
local Highlighter = {}
Highlighter.__index = Highlighter
-- Create a highlighter object.
--
-- position - Where the highlighter should be displayed. If nil, the highlighter will not be shown immediatly.
-- ID - Number ID to use for the box.
-- color -- Color to use for the highlighter. Something like BrickColor.new("Really red")
function Highlighter.Create(position,
ID,
color)
-- This will be the created highlighter.
local highlighter = {}
-- How high to show the highlighter.
highlighter.height = 0
highlighter.width = 0
highlighter.length = 0
highlighter.x = 0
highlighter.y = 0
highlighter.z = 0
-- Create the part that the highlighter will be attached to.
highlighter.selectionPart = Instance.new("Part")
highlighter.selectionPart.Name = "SelectionPart"
highlighter.selectionPart.Archivable = false
highlighter.selectionPart.Transparency = 1
highlighter.selectionPart.Anchored = true
highlighter.selectionPart.Locked = true
highlighter.selectionPart.CanCollide = false
highlighter.selectionPart.FormFactor = Enum.FormFactor.Custom
highlighter.selectionBox = Instance.new("SelectionBox")
highlighter.selectionBox.Name = 'box' .. ID
highlighter.selectionBox.Archivable = false
highlighter.selectionBox.Color = color
highlighter.selectionBox.Adornee = highlighter.selectionPart
setmetatable(highlighter, Highlighter)
return highlighter
end
-- Hide the highlighter.
function Highlighter:DisablePreview()
self.selectionBox.Parent = nil
end
-- Show the highlighter.
function Highlighter:EnablePreview()
self.selectionBox.Parent = game:GetService("CoreGui") -- This will make it not show up in workspace.
end
-- Update where the highlighter is displayed.
-- cellPos - Where to display the highlighter, in cells.
function Highlighter:UpdatePosition(cellPos)
if not cellPos then
self:DisablePreview()
return
end
local regionToSelect = nil
self.x = cellPos.x
self.y = cellPos.y
self.z = cellPos.z
local lowVec = CellCenterToWorld(c, cellPos.x - self.width/2 , cellPos.y - 1, cellPos.z - self.length/2)
local highVec = CellCenterToWorld(c, cellPos.x + self.width/2, cellPos.y + self.height, cellPos.z + self.length/2)
regionToSelect = Region3.new(lowVec, highVec)
self.selectionPart.Size = regionToSelect.Size - Vector3.new(-4,4,-4)
self.selectionPart.CFrame = regionToSelect.CFrame
end
-- Set the dimensions of the highlighter.
-- Updates the display size.
-- length - Length of the area (z direction)
-- width - Width of the area (x direction)
-- height - Height of the area (y direction)
function Highlighter:UpdateDimensions(length, width, height)
self.length = length
self.width = width
self.height = height
self:UpdatePosition(Vector3.new(self.x, self.y, self.z))
end
-- Create a standard text label. Use this for all lables in the popup so it is easy to standardize.
-- labelName - What to set the text label name as.
-- pos - Where to position the label. Should be of type UDim2.
-- size - How large to make the label. Should be of type UDim2.
-- text - Text to display.
-- parent - What to set the text parent as.
-- Return:
-- Value is the created label.
function CreateStandardLabel(labelName,
pos,
size,
text,
parent)
local label = Instance.new("TextLabel", parent)
label.Name = labelName
label.Position = pos
label.Size = size
label.Text = text
label.TextColor3 = Color3.new(0.95, 0.95, 0.95)
label.Font = Enum.Font.ArialBold
label.FontSize = Enum.FontSize.Size14
label.TextXAlignment = Enum.TextXAlignment.Left
label.BackgroundTransparency = 1
label.Parent = parent
return label
end
-- Create a standardized slider.
-- name - Name to use for the slider.
-- pos - Position to display the slider at.
-- steps - How many steps there are in the slider.
-- funcOnChange - Function to call when the slider changes.
-- initValue - Initial value to set the slider to. If nil the slider stays at the default.
-- parent - What to set as the parent.
-- Return:
-- sliderGui - Slider gui object.
-- sliderPosition - Object that can set the slider value.
function CreateStandardSlider(name,
pos,
lengthBarPos,
steps,
funcOnChange,
initValue,
parent)
local sliderGui, sliderPosition = RbxGui.CreateSlider(steps, 0, UDim2.new(0,0,0,0))
sliderGui.Name = name
sliderGui.Parent = parent
sliderGui.Position = pos
sliderGui.Size = UDim2.new(1,0,0,20)
local lengthBar = sliderGui:FindFirstChild("Bar")
lengthBar.Size = UDim2.new(1, -21, 0, 5)
lengthBar.Position = lengthBarPos
if nil ~= funcOnChange then
sliderPosition.Changed:connect(function() funcOnChange(sliderPosition) end)
end
if nil ~= initValue then
sliderPosition.Value = initValue
end
return sliderGui, sliderPosition
end
-- Create a standard dropdown. Use this for all dropdowns in the popup so it is easy to standardize.
-- name - What to set the text label name as.
-- pos - Where to position the label. Should be of type UDim2.
-- values - A table of the values that will be in the dropbox, in the order they are to be shown.
-- initValue - Initial value the dropdown should be set to.
-- funcOnChange - Function to run when a dropdown selection is made.
-- parent - What to set the parent as.
-- Return:
-- dropdown - The dropdown gui.
-- updateSelection - Object to use to change the current dropdown.
function CreateStandardDropdown(name,
pos,
values,
initValue,
funcOnChange,
parent)
-- Create a dropdown selection for the modes to fill in a river
local dropdown, updateSelection=RbxGui.CreateDropDownMenu(values, funcOnChange);
dropdown.Name = name
dropdown.Position = pos
dropdown.Active = true
dropdown.Size = UDim2.new(0,150,0,32)
dropdown.Parent = parent
updateSelection(initValue)
return dropdown, updateSelection
end
-- Keep common button properties here to make it easer to change them all at once.
-- These are the default properties to use for a button.
buttonTextColor = Color3.new(1, 1, 1);
buttonFont = Enum.Font.ArialBold;
buttonFontSize = Enum.FontSize.Size18;
-- Create a standard dropdown. Use this for all dropdowns in the popup so it is easy to standardize.
-- name - What to use.
-- pos - Where to position the button. Should be of type UDim2.
-- text - Text to show in the button.
-- funcOnPress - Function to run when the button is pressed.
-- parent - What to set the parent as.
-- Return:
-- button - The button gui.
function CreateStandardButton(name,
pos,
text,
funcOnPress,
parent,
size)
button = Instance.new("TextButton", parent)
button.Name = name
button.Position = pos
button.Size = UDim2.new(0,120,0,40)
button.Text = text
if size then
button.Size = size
end
button.Style = Enum.ButtonStyle.RobloxButton
button.TextColor3 = buttonTextColor
button.Font = buttonFont
button.FontSize = buttonFontSize
button.MouseButton1Click:connect(funcOnPress)
return button
end
cancelValues = {cancelAction = false, -- Used to cancel currently occuring actions. If set to true then terrain generation will stop.
progressBar = nil, -- Will store the progress bar when needed.
setAmountFunc = nil, -- Stores a function tied to the progres bar that sets the progress bar precentage done.
bindForCancel = nil} -- Stores a function bind that will be set with the function to run when the cancel button is pressed in the progress bar.
-- Load the progress bar to display when drawing a river.
-- text - Text to display.
function LoadProgressBar(text)
if cancelValues.progressBar == nil then
cancelValues.isDrawing = true
-- Start the progress bar.
cancelValues.progressBar, cancelValues.setAmountFunc, cancelValues.bindForCancel = RbxGui.CreateLoadingFrame(text)
cancelValues.progressBar.Position = UDim2.new(.5, -cancelValues.progressBar.Size.X.Offset/2, 0, 15)
cancelValues.progressBar.Parent = g
cancelValues.bindForCancel.Event:connect(function(arguments)
cancelValues.cancelActions = true -- Set the flag that everything should stop.
coroutine.yield()
end)
else
print('Tried to start the progress bar when it was already running.')
end
end
-- Unload the progress bar.
function UnloadProgressBar()
cancelValues.isDrawing = false
cancelValues.cancelActions = false
if nil ~= cancelValues.progressBar then
cancelValues.progressBar.Parent = nil
cancelValues.progressBar = nil
cancelValues.setAmountFunc = nil
cancelValues.bindForCancel = nil
end
end
-- Slider for controlling the x offset to generate terrain at.
offsetXLabel = CreateStandardLabel("offsetXLabel", UDim2.new(0, 8, 0, 10), UDim2.new(0, 67, 0, 14), "", terrainFrame)
offsetXSliderGui, offsetXSliderPosition = CreateStandardSlider('offsetXSliderGui', UDim2.new(0,1,0,26), UDim2.new(0,10,0.5,-2), 128,
function(offsetXSliderPosition)
terrainOptions.xpos = (offsetXSliderPosition.Value - 1) * 4 - 252
offsetXLabel.Text = "X-Offset: "..terrainOptions.xpos
end, nil, terrainFrame)
offsetXSliderPosition.Value = (terrainOptions.xpos+252)/4 + 1
-- Slider for controlling the z offset to generate terrain at.
offsetZLabel = CreateStandardLabel("OffsetZLabel", UDim2.new(0, 8, 0, 51), UDim2.new(0, 67, 0, 14), "", terrainFrame)
offsetZSliderGui, offsetZSliderPosition = CreateStandardSlider('OffsetZSliderGui', UDim2.new(0,1,0,67), UDim2.new(0,10,0.5,-2), 128,
function(offsetZSliderPosition)
terrainOptions.zpos = (offsetZSliderPosition.Value - 1) * 4 - 252
offsetZLabel.Text = "Z-Offset: "..terrainOptions.zpos
end, nil, terrainFrame)
offsetZSliderPosition.Value = (terrainOptions.zpos+252)/4 + 1
-----------------------
--FUNCTION DEFINITIONS-
-----------------------
--makes a column of blocks from 1 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)), terrainOptions.terrainMaterial, 0, 0)
end
--makes a heightmap for a layer of mountains (width x depth)
--with a width frequency wf and depthfrequency df (width should be divisible by wf, depth should be divisible by df) (for unsquished results, width/wf = depth/df)
--with a range of amplitudes between 0 and a
function mountLayer(width, depth, wf, df, a)
local heightmap = {}
for i = 0, width-1 do
heightmap[i] = {}
for k = 0, depth-1 do
heightmap[i][k] = 0
end
end
math.randomseed(tick())
local corners = {}
for i = 0,wf do
corners[i] = {}
for k = 0, df do
corners[i][k] = a*math.random()
end
end
for i = 0, wf do
corners[i][0] = 0
corners[i][math.floor(df)] = 0
end
for k = 0, df do
corners[0][k]=0
corners[math.floor(wf)][k]=0
end
for i = 0, width-(width/wf), width/wf do
for k = 0, depth-(depth/df), depth/df do
local c1 = corners[i/(width/wf)][k/(depth/df)]
local c2 = corners[i/(width/wf)][(k+depth/df)/(depth/df)]
local c3 = corners[(i+width/wf)/(width/wf)][k/(depth/df)]
local c4 = corners[(i+width/wf)/(width/wf)][(k+depth/df)/(depth/df)]
for x = i, i+(width/wf)-1 do
for z = k, k+(depth/df)-1 do
local avgc1c3 = (math.abs(x-i)*c3 + math.abs(x-(i+width/wf))*c1)/(width/wf)
local avgc2c4 = (math.abs(x-i)*c4 + math.abs(x-(i+width/wf))*c2)/(width/wf)
local avg = math.floor((math.abs(z-k)*avgc2c4 + math.abs(z-(k+depth/df))*avgc1c3)/(depth/df))
if (avg > 100) then
print(avg)
avg = 1
end
heightmap[x][z]= avg
end
end
end
end
return heightmap
end
--makes a shell around block at coordinate x, z using heightmap
function makeShell(x, z, heightmap, shellheightmap)
local originalheight = heightmap[x][z]
for i = x - 1, x + 1 do
for k = z - 1, z + 1 do
if shellheightmap[i][k] < originalheight then
for h = originalheight, shellheightmap[i][k] - 2, -1 do
if h > 0 then
SetCell(c, i, h, k, terrainOptions.terrainMaterial, 0, 0)
end
end
shellheightmap[i][k] = originalheight
end
end
end
return shellheightmap
end
-- Set the camera to look at the terrain from a distance so that all terrain will be in view.
-- centerX, centerZ - Center coordinate of land. This doesn't take into account clipping.
-- length, width - Land dimensions.
function SetCamera(centerX, centerZ,
length, width, height)
local currCamera = game.Workspace.CurrentCamera
local cameraPos = Vector3.new(0, 400, 1600)
local cameraFocus = Vector3.new(0, height * 4, 0)
-- Nothing set so use the default.
if nil ~= centerX then
local scale = 0
local lengthScale = 0
local widthScale = 0
if length <= 64 then
lengthScale = .35
elseif length <= 128 then
lengthScale = .5
elseif length <= 256 then
lengthScale = .7
else
lengthScale = 1.3
end
if width <= 64 then
widthScale = .35
elseif width <= 128 then
widthScale = .4
elseif width <= 256 then
widthScale = .4
else
widthScale = .7
end
if widthScale > lengthScale then
scale = widthScale
else
scale = lengthScale
end
local distance = Vector3.new(0, (200*scale) + 200, (1100*scale))
cameraPos = Vector3.new(centerX + distance.X, distance.Y, centerZ + distance.Z)
cameraFocus = Vector3.new(centerX, height * 4, centerZ)
end
currCamera.CoordinateFrame = CFrame.new(cameraPos.X, cameraPos.Y, cameraPos.Z)
currCamera.Focus = CFrame.new(cameraFocus.X, cameraFocus.Y, cameraFocus.Z)
end
-- Function used by the clear button. Prompts the user first.
-- Will not show if disabled or terrain is being processed.
function ConfirmClearTerrain()
-- Only do if something isn't already being processed.
if nil == cancelValues.progressBar then
if nil == ConfirmationPopupObject then
if not hideClearConformation then
ConfirmationPopupObject = ConfirmationPopup.Create("Clear Terrain?",
"Clear",
"Cancel",
function()
ClearConformation()
ClearTerrain()
end,
ClearConformation,
function()
hideClearConformation = not hideClearConformation
return not hideClearConformation
end)
else
ClearTerrain()
end
end
end
end
-- Function used by the generate button. Prompts the user first.
-- Will not show if disabled or terrain is being processed.
function ConfirmGenerateTerrain()
-- Only do if something isn't already being processed.
if nil == cancelValues.progressBar then
if nil == ConfirmationPopupObject then
if not hideGenerateConformation then
ConfirmationPopupObject = ConfirmationPopup.Create("Generate Terrain?",
"Generate",
"Cancel",
function()
ClearConformation()
GenerateTerrain()
end,
ClearConformation,
function()
hideGenerateConformation = not hideGenerateConformation
return not hideGenerateConformation
end)
else
GenerateTerrain()
end
end
end
end
-- Create terrain based on the current properties.
function GenerateTerrain()
toolbarbutton:SetActive(false)
generateOptions = terrainOptions:Clone()
-- Turn off the plugin
Off()
-- Create the progress bar that will track terrain creation completion.
LoadProgressBar("Generating Terrain")
--Generate Terrain
-- offset terrain additionally by whatever the smallest cell is
--xpos2 = generateOptions.xpos + game.Workspace.Terrain.MaxExtents.Min.X
--zpos2 = generateOptions.zpos + game.Workspace.Terrain.MaxExtents.Min.Z
xpos2 = generateOptions.xpos - generateOptions.width/2
zpos2 = generateOptions.zpos - generateOptions.length/2
-- Reposition to get a good view.
SetCamera(generateOptions.xpos, generateOptions.zpos, generateOptions.length, generateOptions.width, math.max(generateOptions.baseHeight, generateOptions.a / 2))
--make 3 layers of mountains (you can change the frequency and amplitude of each layer and add or remove layers as you see fit (but don't forget to add the new layers to the loop below)
a1 = mountLayer(generateOptions.width, generateOptions.length, generateOptions.f * generateOptions.width/512, generateOptions.f * generateOptions.length/512, 3/5*generateOptions.a)
a2 = mountLayer(generateOptions.width, generateOptions.length, 2 * generateOptions.f *generateOptions.width/512, 2 * generateOptions.f * generateOptions.length/512, 2/5*generateOptions.a)
heightmap = {}
for x = 0, generateOptions.width - 1 do
heightmap[x + xpos2] = {}
for z = 0, generateOptions.length - 1 do
heightmap[x + xpos2][z + zpos2] = a1[x][z] + a2[x][z]
end
end
shellheightmap = {}
for x = 0, generateOptions.width - 1 do
shellheightmap[x + xpos2] = {}
for z = 0, generateOptions.length - 1 do
shellheightmap[x + xpos2][z + zpos2] = heightmap[x + xpos2][z + zpos2]
end
end
gprogress = 0
k = 1 + zpos2
local waitCount = 0
-- Fill in the edges that don't get done in the terrain calculations.
if 0 ~= generateOptions.waterHeight then
SetCells(c, Region3int16.new(Vector3int16.new(xpos2, 1, zpos2), Vector3int16.new(xpos2, generateOptions.waterHeight, zpos2 + generateOptions.length-1)), Enum.CellMaterial.Water, 0, 0)
SetCells(c, Region3int16.new(Vector3int16.new(xpos2 + generateOptions.width-1, 1, zpos2), Vector3int16.new(xpos2 + generateOptions.width-1, generateOptions.waterHeight, zpos2 + generateOptions.length-1)), Enum.CellMaterial.Water, 0, 0)
SetCells(c, Region3int16.new(Vector3int16.new(xpos2, 1, zpos2), Vector3int16.new(xpos2 + generateOptions.width-1, generateOptions.waterHeight, zpos2)), Enum.CellMaterial.Water, 0, 0)
SetCells(c, Region3int16.new(Vector3int16.new(xpos2, 1, zpos2 + generateOptions.length-1), Vector3int16.new(xpos2 + generateOptions.width-1, generateOptions.waterHeight, zpos2 + generateOptions.length-1)), Enum.CellMaterial.Water, 0, 0)
end
if 0 ~= generateOptions.baseHeight then
SetCells(c, Region3int16.new(Vector3int16.new(xpos2, 0, zpos2), Vector3int16.new(xpos2, generateOptions.baseHeight, zpos2 + generateOptions.length-1)), terrainOptions.terrainMaterial, 0, 0)
SetCells(c, Region3int16.new(Vector3int16.new(xpos2 + generateOptions.width-1, 0, zpos2), Vector3int16.new(xpos2 + generateOptions.width-1, generateOptions.baseHeight, zpos2 + generateOptions.length-1)), terrainOptions.terrainMaterial, 0, 0)
SetCells(c, Region3int16.new(Vector3int16.new(xpos2, 0, zpos2), Vector3int16.new(xpos2 + generateOptions.width-1, generateOptions.baseHeight, zpos2)), terrainOptions.terrainMaterial, 0, 0)
SetCells(c, Region3int16.new(Vector3int16.new(xpos2, 0, zpos2 + generateOptions.length-1), Vector3int16.new(xpos2 + generateOptions.width-1, generateOptions.baseHeight, zpos2 + generateOptions.length-1)), terrainOptions.terrainMaterial, 0, 0)
end
while k < generateOptions.length - 1 + zpos2 do
for x = 1 + xpos2, generateOptions.width - 2 + xpos2 do
-- End on cancel.
if cancelValues.cancelActions then
game:GetService("ChangeHistoryService"): SetWaypoint("CancelGenerate")
UnloadProgressBar()
return
end
-- Create water.
if 0 ~= generateOptions.waterHeight then
SetCells(c, Region3int16.new(Vector3int16.new(x, 1, k), Vector3int16.new(x, generateOptions.waterHeight, k)), Enum.CellMaterial.Water, 0, 0)
end
-- Create the base for terrain.
if 0 ~= generateOptions.baseHeight then
SetCells(c, Region3int16.new(Vector3int16.new(x, 0, k), Vector3int16.new(x, generateOptions.baseHeight, k)), terrainOptions.terrainMaterial, 0, 0)
end
coordHeight(x, k, heightmap[x][k])
shellheightmap = makeShell(x, k, heightmap, shellheightmap)
end
k = k + 1
gprogress = gprogress + 2/(generateOptions.length * 3)
-- Update the amount completed.
cancelValues.setAmountFunc(gprogress)
if waitCount > 5 then waitCount = 0 wait(0.01) else waitCount = waitCount + 1 end
end
k = 1 + zpos2
waitCount = 0
local maxHeight = -1
local oldK = k
while k < generateOptions.length - 1 + zpos2 do
for x = 1 + xpos2, generateOptions.width - 2 + xpos2 do
-- End on cancel.
if cancelValues.cancelActions then
game:GetService("ChangeHistoryService"): SetWaypoint("GenerateGenerate")
UnloadProgressBar()
return
end
height = shellheightmap[x][k]
if height == nil then
height = -1
end
if height > maxHeight then
maxHeight = height
end
end
k = k + 1
gprogress = gprogress + 1/(generateOptions.length * 3)
-- Update the amount completed.
cancelValues.setAmountFunc(gprogress)
if waitCount > 10 then
waitCount = 0
AutoWedge(c, Region3int16.new(Vector3int16.new(1 + xpos2, 0, oldK), Vector3int16.new(generateOptions.width - 2 + xpos2, maxHeight, k)))
oldK = k+1
maxHeight = -1
wait()
else waitCount = waitCount + 1 end
if k == generateOptions.length - 2 + zpos2 then
AutoWedge(c, Region3int16.new(Vector3int16.new(1 + xpos2, 0, oldK), Vector3int16.new(generateOptions.width - 2 + xpos2, maxHeight, k)))
end
end
-- Clean up the progress bar.
UnloadProgressBar()
--Generate Terrain End
game:GetService("ChangeHistoryService"): SetWaypoint("Generate")
end
-- Clears all terrain.
-- Clearing is immediate.
function ClearTerrain()
toolbarbutton:SetActive(false)
Off()
--Erase Terrain
LoadProgressBar('Clearing Terrain')
wait()
c:Clear()
--Erase Terrain End
UnloadProgressBar()
game:GetService("ChangeHistoryService"): SetWaypoint("Reset")
end
-- Used to create a highlighter.
-- A highlighter is a open, rectuangular area displayed in 3D.
ConfirmationPopup = {}
ConfirmationPopup.__index = ConfirmationPopup
-- Create a confirmation popup.
--
-- confirmText - What to display in the popup.
-- confirmButtonText - What to display in the popup.
-- declineButtonText - What to display in the popup.
-- confirmFunction - Function to run on confirmation.
-- declineFunction - Function to run when declining.
--
-- Return:
-- Value a table with confirmation gui and options.
function ConfirmationPopup.Create(confirmText,
confirmButtonText,
declineButtonText,
confirmFunction,
declineFunction)
local popup = {}
popup.confirmButton = nil -- Hold the button to confirm a choice.
popup.declineButton = nil -- Hold the button to decline a choice.
popup.confirmationFrame = nil -- Hold the conformation frame.
popup.confirmationText = nil -- Hold the text label to display the conformation message.
popup.confirmationHelpText = nil -- Hold the text label to display the conformation message help.
popup.confirmationFrame = Instance.new("Frame", g)
popup.confirmationFrame.Name = "ConfirmationFrame"
popup.confirmationFrame.Size = UDim2.new(0, 280, 0, 140)
popup.confirmationFrame.Position = UDim2.new(.5, -popup.confirmationFrame.Size.X.Offset/2, 0.5, -popup.confirmationFrame.Size.Y.Offset/2)
popup.confirmationFrame.Style = Enum.FrameStyle.RobloxRound
popup.confirmLabel = CreateStandardLabel("ConfirmLabel", UDim2.new(0,0,0,15), UDim2.new(1, 0, 0, 24), confirmText, popup.confirmationFrame)
popup.confirmLabel.FontSize = Enum.FontSize.Size18
popup.confirmLabel.TextXAlignment = Enum.TextXAlignment.Center
-- Confirm
popup.confirmButton = CreateStandardButton("ConfirmButton",
UDim2.new(0.5, -120, 1, -50),
confirmButtonText,
confirmFunction,
popup.confirmationFrame)
-- Decline
popup.declineButton = CreateStandardButton("DeclineButton",
UDim2.new(0.5, 0, 1, -50),
declineButtonText,
declineFunction,
popup.confirmationFrame)
setmetatable(popup, ConfirmationPopup)
return popup
end
-- Clear the popup, free up assets.
function ConfirmationPopup:Clear()
if nil ~= self.confirmButton then
self.confirmButton.Parent = nil
end
if nil ~= self.declineButton then
self.declineButton.Parent = nil
end
if nil ~= self.confirmationFrame then
self.confirmationFrame.Parent = nil
end
if nil ~= self.confirmLabel then
self.confirmLabel.Parent = nil
end
self.confirmButton = nil
self.declineButton = nil
self.conformationFrame = nil
self.conformText = nil
end
--------------------------------------------------------------------------------------------
-- Create Gui Interfaces
--------------------------------------------------------------------------------------------
local maxXZExtentsLog = c.MaxExtents.Max.X > 512 and 6 or 4
local maxYExtents = math.min(c.MaxExtents.Max.Y, 256)
-- Slider for controlling the width of the terran area. Terran is created in a region this wide.
widthLabel = CreateStandardLabel("WidthLabel", UDim2.new(0, 8, 0, 92), UDim2.new(0, 67, 0, 14), "", terrainFrame)
widthSliderGui, widthSliderPosition = CreateStandardSlider('WidthSliderGui', UDim2.new(0,1,0,108), UDim2.new(0,10,0.5,-2), maxXZExtentsLog,
function(widthSliderPosition)
terrainOptions.width = math.pow(2, widthSliderPosition.Value + 5)
widthLabel.Text = "Width: "..terrainOptions.width
end, 4, terrainFrame)
-- Slider for controlling the length of the terran area. Terran is created in a region this long.
lengthLabel = CreateStandardLabel("LengthLabel", UDim2.new(0, 8, 0, 133), UDim2.new(0, 67, 0, 14), "", terrainFrame)
lengthSliderGui, lengthSliderPosition = CreateStandardSlider('LengthSliderGui', UDim2.new(0,1,0,149), UDim2.new(0,10,0.5,-2), maxXZExtentsLog,
function(lengthSliderPosition)
terrainOptions.length = math.pow(2, lengthSliderPosition.Value + 5)
lengthLabel.Text = "Length: "..terrainOptions.length
end, 4, terrainFrame)
-- Slider for controlling the amplitude of hills.
amplitudeLabel = CreateStandardLabel("AmplitudeLabel", UDim2.new(0, 8, 0, 174), UDim2.new(0, 67, 0, 14), "", terrainFrame)
amplitudeSliderGui, amplitudeSliderPosition = CreateStandardSlider('AmplitudeSliderGui', UDim2.new(0,1,0,190), UDim2.new(0,10,0.5,-2), 62,
function(amplitudeSliderPosition)
terrainOptions.a = amplitudeSliderPosition.Value + 1
amplitudeLabel.Text = "Amplitude: ".. terrainOptions.a
end, nil, terrainFrame)
amplitudeSliderPosition.Value = terrainOptions.a-1
-- Slider for controlling the frequency of hills.
frequencyLabel = CreateStandardLabel("FrequencyLabel", UDim2.new(0, 8, 0, 215), UDim2.new(0, 67, 0, 14), "", terrainFrame)
frequencySliderGui, frequencySliderPosition = CreateStandardSlider('FrequencySliderGui', UDim2.new(0,1,0,231), UDim2.new(0,10,0.5,-2), 8,
function(frequencySliderPosition)
terrainOptions.f = math.pow(2, frequencySliderPosition.Value - 1)
frequencyLabel.Text = "Frequency: ".. terrainOptions.f
end, nil, terrainFrame)
frequencySliderPosition.Value = 4
-- Slider for controlling the baseHeight, how deep the base terrain should be.
baseHeightLabel = CreateStandardLabel("BaseHeightLabel", UDim2.new(0, 8, 0, 256), UDim2.new(0, 67, 0, 14), "", terrainFrame)
baseHeightSliderGui, baseHeightSliderPosition = CreateStandardSlider('BaseHeightSliderGui', UDim2.new(0,1,0,272), UDim2.new(0,10,0.5,-2), maxYExtents,
function(baseHeightSliderPosition)
terrainOptions.baseHeight = baseHeightSliderPosition.Value - 1
baseHeightLabel.Text = "Base Height: ".. (terrainOptions.baseHeight)
end, nil, terrainFrame)
baseHeightSliderPosition.Value = terrainOptions.baseHeight + 1
-- Slider for controlling the waterHeight, how much water to fill.
waterHeightLabel = CreateStandardLabel("WaterHeightLabel", UDim2.new(0, 8, 0, 297), UDim2.new(0, 67, 0, 14), "", terrainFrame)
waterHeightSliderGui, waterHeightSliderPosition = CreateStandardSlider('WaterHeightSliderGui', UDim2.new(0,1,0,313), UDim2.new(0,10,0.5,-2), maxYExtents,
function(waterHeightSliderPosition)
terrainOptions.waterHeight = waterHeightSliderPosition.Value - 1
waterHeightLabel.Text = "Water Height: ".. (terrainOptions.waterHeight)
end, nil, terrainFrame)
waterHeightSliderPosition.Value = terrainOptions.waterHeight + 1
-- Button to generate terrain using the current settings.
generateButton = CreateStandardButton("GenerateButton",
UDim2.new(0.5, -75, 0, 343),
'Generate',
ConfirmGenerateTerrain,
terrainFrame,
UDim2.new(0,150,0,40))
-- Button to clear terrain using. All terrain will be removed.
clearButton = CreateStandardButton("ClearButton",
UDim2.new(0.5, -75, 0, 385),
'Clear',
ConfirmClearTerrain,
terrainFrame,
UDim2.new(0,150,0,40))
-- Unload the conformation popup if it exists.
-- Does nothing if the popup isn't set.
function ClearConformation()
if nil ~= ConfirmationPopupObject then
ConfirmationPopupObject:Clear()
ConfirmationPopupObject = nil
end
end
-- Run when the popup is activated.
function On()
if not c then
return
end
plugin:Activate(true)
toolbarbutton:SetActive(true)
terrainPropertiesDragBar.Visible = true
on = true
end
-- Run when the popup is deactivated.
function Off()
toolbarbutton:SetActive(false)
ClearConformation()
on = false
-- Hide the popup gui.
terrainPropertiesDragBar.Visible = false
end
plugin.Deactivation:connect(function()
Off()
end)
loaded = true

View File

@@ -0,0 +1,340 @@
while game == nil do
wait(1/30)
end
---------------
--PLUGIN SETUP-
---------------
loaded = false
-- True if the plugin is on, false if not.
on = false
plugin = PluginManager():CreatePlugin()
mouse = plugin:GetMouse()
mouse.Button1Down:connect(function() onClicked(mouse) end)
toolbar = plugin:CreateToolbar("Terrain")
toolbarbutton = toolbar:CreateButton("Builder", "Builder", "builder.png")
toolbarbutton.Click:connect(function()
if on then
Off()
elseif loaded then
On()
end
end)
game:WaitForChild("Workspace")
game.Workspace:WaitForChild("Terrain")
local c = game.Workspace.Terrain
local SetCell = c.SetCell
local GetCell = c.GetCell
local WorldToCellPreferSolid = c.WorldToCellPreferSolid
local CellCenterToWorld = c.CellCenterToWorld
local AutoWedge = c.AutowedgeCells
local WorldToCellPreferEmpty = c.WorldToCellPreferEmpty
local GetWaterCell = c.GetWaterCell
local SetWaterCell = c.SetWaterCell
-----------------
--DEFAULT VALUES-
-----------------
-- Stores selection properties.
selectionProps = {}
selectionProps.isWater = nil -- True if what will be built is water.
selectionProps.waterForce = nil -- Water force.
selectionProps.waterDirection = nil -- Water direction.
selectionProps.terrainMaterial = 0 -- Terrain material to use
-- What color to use for the mouse highlighter.
mouseHighlightColor = BrickColor.new("Lime green")
-- Used to create a highlighter that follows the mouse.
-- It is a class mouse highlighter. To use, call MouseHighlighter.Create(mouse) where mouse is the mouse to track.
MouseHighlighter = {}
MouseHighlighter.__index = MouseHighlighter
-- Create a mouse movement highlighter.
-- plugin - Plugin to get the mouse from.
function MouseHighlighter.Create(mouseUse)
local highlighter = {}
local mouse = mouseUse
highlighter.OnClicked = nil
highlighter.mouseDown = false
-- Store the last point used to draw.
highlighter.lastUsedPoint = nil
-- Will hold a part the highlighter will be attached to. This will be moved where the mouse is.
highlighter.selectionPart = nil
-- Hook the mouse up to check for movement.
mouse.Move:connect(function() MouseMoved() end)
mouse.Button1Down:connect(function() highlighter.mouseDown = true end)
mouse.Button1Up:connect(function() highlighter.mouseDown = false
end)
-- Create the part that the highlighter will be attached to.
highlighter.selectionPart = Instance.new("Part")
highlighter.selectionPart.Name = "SelectionPart"
highlighter.selectionPart.Archivable = false
highlighter.selectionPart.Transparency = 1
highlighter.selectionPart.Anchored = true
highlighter.selectionPart.Locked = true
highlighter.selectionPart.CanCollide = false
highlighter.selectionPart.FormFactor = Enum.FormFactor.Custom
highlighter.selectionBox = Instance.new("SelectionBox")
highlighter.selectionBox.Archivable = false
highlighter.selectionBox.Color = mouseHighlightColor
highlighter.selectionBox.Adornee = highlighter.selectionPart
mouse.TargetFilter = highlighter.selectionPart
setmetatable(highlighter, MouseHighlighter)
-- Function to call when the mouse has moved. Updates where to display the highlighter.
function MouseMoved()
if on then
UpdatePosition(mouse.Hit)
end
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
-- Update where the highlighter is displayed.
-- position - Where to display the highlighter, in world space.
function UpdatePosition(position)
if not position then
return
end
-- NOTE:
-- Change this gui to be the one you want to use.
highlighter.selectionBox.Parent = game:GetService("CoreGui")
local vectorPos = Vector3.new(position.x,position.y,position.z)
local cellPos = WorldToCellPreferEmpty(c, vectorPos)
local solidCell = WorldToCellPreferSolid(c, vectorPos)
local success = false
-- If nothing was hit, do the plane intersection.
if 0 == GetCell(c, solidCell.X, solidCell.Y, solidCell.Z).Value then
success, cellPos = PlaneIntersection(vectorPos)
if not success then
cellPos = solidCell
end
else
highlighter.lastUsedPoint = cellPos
end
local regionToSelect = nil
local lowVec = CellCenterToWorld(c, cellPos.x , cellPos.y - 1, cellPos.z)
local highVec = CellCenterToWorld(c, cellPos.x, cellPos.y + 1, cellPos.z)
regionToSelect = Region3.new(lowVec, highVec)
highlighter.selectionPart.Size = regionToSelect.Size - Vector3.new(-4, 4, -4)
highlighter.selectionPart.CFrame = regionToSelect.CFrame
if nil ~= highlighter.OnClicked and highlighter.mouseDown then
if nil == highlighter.lastUsedPoint then
highlighter.lastUsedPoint = WorldToCellPreferEmpty(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
else
cellPos = WorldToCellPreferEmpty(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
end
end
end
return highlighter
end
-- Hide the highlighter.
function MouseHighlighter:DisablePreview()
self.selectionBox.Parent = nil
end
-- Show the highlighter.
function MouseHighlighter:EnablePreview()
self.selectionBox.Parent = game:GetService("CoreGui") -- This will make it not show up in workspace.
end
-- Create the mouse movement highlighter.
mouseHighlighter = MouseHighlighter.Create(mouse)
mouseHighlighter:DisablePreview()
-- Create a standard text label. Use this for all lables in the popup so it is easy to standardize.
-- labelName - What to set the text label name as.
-- pos - Where to position the label. Should be of type UDim2.
-- size - How large to make the label. Should be of type UDim2.
-- text - Text to display.
-- parent - What to set the text parent as.
-- Return:
-- Value is the created label.
function CreateStandardLabel(labelName,
pos,
size,
text,
parent)
local label = Instance.new("TextLabel", parent)
label.Name = labelName
label.Position = pos
label.Size = size
label.Text = text
label.TextColor3 = Color3.new(0.95, 0.95, 0.95)
label.Font = Enum.Font.ArialBold
label.FontSize = Enum.FontSize.Size14
label.TextXAlignment = Enum.TextXAlignment.Left
label.BackgroundTransparency = 1
label.Parent = parent
return label
end
------
--GUI-
------
--screengui
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
g.Name = 'BuilderGui'
-- UI gui load. Required for sliders.
local RbxGui = LoadLibrary("RbxGui")
-- Store properties here.
local properties = {autoWedgeEnabled = false}
-- Gui frame for the plugin.
builderPropertiesDragBar, builderFrame, builderHelpFrame, builderCloseEvent = RbxGui.CreatePluginFrame("Builder",UDim2.new(0,123,0,40),UDim2.new(0,0,0,0),false,g)
builderPropertiesDragBar.Visible = false
builderCloseEvent.Event:connect(function ( )
Off()
end)
builderHelpFrame.Size = UDim2.new(0,160,0,85)
local builderHelpText = Instance.new("TextLabel",builderHelpFrame)
builderHelpText.Name = "HelpText"
builderHelpText.Font = Enum.Font.ArialBold
builderHelpText.FontSize = Enum.FontSize.Size12
builderHelpText.TextColor3 = Color3.new(227/255,227/255,227/255)
builderHelpText.TextXAlignment = Enum.TextXAlignment.Left
builderHelpText.TextYAlignment = Enum.TextYAlignment.Top
builderHelpText.Position = UDim2.new(0,4,0,4)
builderHelpText.Size = UDim2.new(1,-8,0,177)
builderHelpText.BackgroundTransparency = 1
builderHelpText.TextWrap = true
builderHelpText.Text = [[
Clicking terrain adds a single block into the selection box shown. The terrain material and type will be the same as the cell that was clicked on.]]
addText = CreateStandardLabel("AddText", UDim2.new(0, 8, 0, 10), UDim2.new(0, 67, 0, 14), "Click to add terrain.", builderFrame)
-- Function to connect to the mouse button 1 down event. This is what will run when the user clicks.
-- Adding and autowedging done here.
-- mouse - Mouse data.
function onClicked(mouse)
if on then
local cellPos = WorldToCellPreferEmpty(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
local x = cellPos.x
local y = cellPos.y
local z = cellPos.z
local solidCellPos = WorldToCellPreferSolid(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
local celMat = GetCell(c, solidCellPos.x, solidCellPos.y, solidCellPos.z)
local success = false
if celMat.Value > 0 then
selectionProps.terrainMaterial = celMat.Value
selectionProps.isWater, selectionProps.waterForce, selectionProps.waterDirection = GetWaterCell(c, solidCellPos.X, solidCellPos.Y, solidCellPos.Z)
else
if 0 == selectionProps.terrainMaterial then
-- It was nothing, give it a default type and the plane intersection.
selectionProps.isWater = false
selectionProps.terrainMaterial = 1
end
success, cellPos = PlaneIntersection(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
if not success then
cellPos = solidCellPos
end
x = cellPos.x
y = cellPos.y
z = cellPos.z
end
if selectionProps.isWater and 17 == selectionProps.terrainMaterial then
SetWaterCell(c, x, y, z, selectionProps.waterForce, selectionProps.waterDirection)
else
SetCell(c, x, y, z, selectionProps.terrainMaterial, 0, 0)
end
if properties.autoWedgeEnabled then
AutoWedge(c, Region3int16.new(Vector3int16.new(x - 1, y - 1, z - 1), Vector3int16.new(x + 1, y + 1, z + 1)))
end
-- Mark undo point.
game:GetService("ChangeHistoryService"):SetWaypoint("Builder")
UpdatePosition(mouse.Hit)
end
end
mouseHighlighter.OnClicked = onClicked
-- Run when the popup is activated.
function On()
if not c then
return
end
plugin:Activate(true)
toolbarbutton:SetActive(true)
builderPropertiesDragBar.Visible = true
on = true
end
-- Run when the popup is deactivated.
function Off()
toolbarbutton:SetActive(false)
on = false
-- Hide the popup gui.
builderPropertiesDragBar.Visible = false
mouseHighlighter:DisablePreview()
end
plugin.Deactivation:connect(function()
Off()
end)
loaded = true

View File

@@ -0,0 +1,285 @@
while game == nil do
wait(1/30)
end
-----------------
--DEFAULT VALUES-
-----------------
loaded = false
-- True if the plugin is on, false if not.
on = false
---------------
--PLUGIN SETUP-
---------------
plugin = PluginManager():CreatePlugin()
mouse = plugin:GetMouse()
mouse.Button1Down:connect(function() onClicked(mouse) end)
toolbar = plugin:CreateToolbar("Terrain")
toolbarbutton = toolbar:CreateButton("Remover", "Remover", "destroyer.png")
toolbarbutton.Click:connect(function()
if on then
Off()
elseif loaded then
On()
end
end)
game:WaitForChild("Workspace")
game.Workspace:WaitForChild("Terrain")
local c = game.Workspace.Terrain
local SetCell = c.SetCell
local GetCell = c.GetCell
local WorldToCellPreferSolid = c.WorldToCellPreferSolid
local CellCenterToWorld = c.CellCenterToWorld
local AutoWedge = c.AutowedgeCells
-- What color to use for the mouse highlighter.
mouseHighlightColor = BrickColor.new("Really red")
-- Used to create a highlighter that follows the mouse.
-- It is a class mouse highlighter. To use, call MouseHighlighter.Create(mouse) where mouse is the mouse to track.
MouseHighlighter = {}
MouseHighlighter.__index = MouseHighlighter
-- Create a mouse movement highlighter.
-- plugin - Plugin to get the mouse from.
function MouseHighlighter.Create(mouseUse)
local highlighter = {}
local mouse = mouseUse
highlighter.OnClicked = nil
highlighter.mouseDown = false
-- Store the last point used to draw.
highlighter.lastUsedPoint = nil
-- Will hold a part the highlighter will be attached to. This will be moved where the mouse is.
highlighter.selectionPart = nil
-- Hook the mouse up to check for movement.
mouse.Move:connect(function() MouseMoved() end)
mouse.Button1Down:connect(function() highlighter.mouseDown = true end)
mouse.Button1Up:connect(function() highlighter.mouseDown = false
end)
-- Create the part that the highlighter will be attached to.
highlighter.selectionPart = Instance.new("Part")
highlighter.selectionPart.Name = "SelectionPart"
highlighter.selectionPart.Archivable = false
highlighter.selectionPart.Transparency = 1
highlighter.selectionPart.Anchored = true
highlighter.selectionPart.Locked = true
highlighter.selectionPart.CanCollide = false
highlighter.selectionPart.FormFactor = Enum.FormFactor.Custom
highlighter.selectionBox = Instance.new("SelectionBox")
highlighter.selectionBox.Archivable = false
highlighter.selectionBox.Color = mouseHighlightColor
highlighter.selectionBox.Adornee = highlighter.selectionPart
mouse.TargetFilter = highlighter.selectionPart
setmetatable(highlighter, MouseHighlighter)
-- Function to call when the mouse has moved. Updates where to display the highlighter.
function MouseMoved()
if on then
UpdatePosition(mouse.Hit)
end
end
-- Update where the highlighter is displayed.
-- position - Where to display the highlighter, in world space.
function UpdatePosition(position)
if not position then
return
end
if not mouse.Target then
highlighter.selectionBox.Parent = nil
return
end
-- NOTE:
-- Change this gui to be the one you want to use.
highlighter.selectionBox.Parent = game:GetService("CoreGui")
local vectorPos = Vector3.new(position.x,position.y,position.z)
local cellPos = WorldToCellPreferSolid(c, vectorPos)
local regionToSelect = nil
local lowVec = CellCenterToWorld(c, cellPos.x , cellPos.y - 1, cellPos.z)
local highVec = CellCenterToWorld(c, cellPos.x, cellPos.y + 1, cellPos.z)
regionToSelect = Region3.new(lowVec, highVec)
highlighter.selectionPart.Size = regionToSelect.Size - Vector3.new(-4, 4, -4)
highlighter.selectionPart.CFrame = regionToSelect.CFrame
if nil ~= highlighter.OnClicked and highlighter.mouseDown then
if nil == highlighter.lastUsedPoint then
highlighter.lastUsedPoint = WorldToCellPreferSolid(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
else
cellPos = WorldToCellPreferSolid(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
holdChange = cellPos - highlighter.lastUsedPoint
-- Require terrain.
if 0 == GetCell(c, cellPos.X, cellPos.Y, cellPos.Z).Value then
return
else
highlighter.lastUsedPoint = cellPos
end
end
end
end
return highlighter
end
-- Hide the highlighter.
function MouseHighlighter:DisablePreview()
self.selectionBox.Parent = nil
end
-- Show the highlighter.
function MouseHighlighter:EnablePreview()
self.selectionBox.Parent = game:GetService("CoreGui") -- This will make it not show up in workspace.
end
-- Create the mouse movement highlighter.
mouseHighlighter = MouseHighlighter.Create(mouse)
-- Create a standard text label. Use this for all lables in the popup so it is easy to standardize.
-- labelName - What to set the text label name as.
-- pos - Where to position the label. Should be of type UDim2.
-- size - How large to make the label. Should be of type UDim2.
-- text - Text to display.
-- parent - What to set the text parent as.
-- Return:
-- Value is the created label.
function CreateStandardLabel(labelName,
pos,
size,
text,
parent)
local label = Instance.new("TextLabel", parent)
label.Name = labelName
label.Position = pos
label.Size = size
label.Text = text
label.TextColor3 = Color3.new(0.95, 0.95, 0.95)
label.Font = Enum.Font.ArialBold
label.FontSize = Enum.FontSize.Size14
label.TextXAlignment = Enum.TextXAlignment.Left
label.BackgroundTransparency = 1
label.Parent = parent
return label
end
------
--GUI-
------
--screengui
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
g.Name = 'RemoverGui'
-- UI gui load. Required for sliders.
local RbxGui = LoadLibrary("RbxGui")
-- Store properties here.
local properties = {autoWedgeEnabled = false}
-- Gui frame for the plugin.
removerPropertiesDragBar, removerFrame, removerHelpFrame, removerCloseEvent = RbxGui.CreatePluginFrame("Remover",UDim2.new(0,143,0,40),UDim2.new(0,0,0,0),false,g)
removerPropertiesDragBar.Visible = false
removerCloseEvent.Event:connect(function ( )
Off()
end)
removerHelpFrame.Size = UDim2.new(0,160,0,60)
local removerHelpText = Instance.new("TextLabel",removerHelpFrame)
removerHelpText.Name = "HelpText"
removerHelpText.Font = Enum.Font.ArialBold
removerHelpText.FontSize = Enum.FontSize.Size12
removerHelpText.TextColor3 = Color3.new(227/255,227/255,227/255)
removerHelpText.TextXAlignment = Enum.TextXAlignment.Left
removerHelpText.TextYAlignment = Enum.TextYAlignment.Top
removerHelpText.Position = UDim2.new(0,4,0,4)
removerHelpText.Size = UDim2.new(1,-8,0,177)
removerHelpText.BackgroundTransparency = 1
removerHelpText.TextWrap = true
removerHelpText.Text = [[
Clicking terrain removes a single block at the location clicked (shown with red highlight).]]
removeText = CreateStandardLabel("removeText", UDim2.new(0, 8, 0, 10), UDim2.new(0, 67, 0, 14), "Click to remove terrain", removerFrame)
-- Function to connect to the mouse button 1 down event. This is what will run when the user clicks.
-- mouse - Mouse data.
function onClicked(mouse)
if on then
local cellPos = WorldToCellPreferSolid(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
local x = cellPos.x
local y = cellPos.y
local z = cellPos.z
SetCell(c, x, y, z, 0, 0, 0)
-- Mark undo point.
game:GetService("ChangeHistoryService"):SetWaypoint("Remover")
UpdatePosition(mouse.Hit)
if properties.autoWedgeEnabled then
AutoWedge(c, Region3int16.new(Vector3int16.new(x - 1, y - 1, z - 1), Vector3int16.new(x + 1, y + 1, z + 1)))
end
end
end
mouseHighlighter.OnClicked = onClicked
-- Run when the popup is activated.
function On()
if not c then
return
end
if plugin then
plugin:Activate(true)
end
if toolbarbutton then
toolbarbutton:SetActive(true)
end
if removerPropertiesDragBar then
removerPropertiesDragBar.Visible = true
end
on = true
end
-- Run when the popup is deactivated.
function Off()
on = false
if toolbarbutton then
toolbarbutton:SetActive(false)
end
-- Hide the popup gui.
if removerPropertiesDragBar then
removerPropertiesDragBar.Visible = false
end
if mouseHighlighter then
mouseHighlighter:DisablePreview()
end
end
plugin.Deactivation:connect(function()
Off()
end)
loaded = true

View File

@@ -0,0 +1,556 @@
while game == nil do
wait(1/30)
end
---------------
--PLUGIN SETUP-
---------------
loaded = false
-- True if the plugin is on, false if not.
on = false
plugin = PluginManager():CreatePlugin()
mouse = plugin:GetMouse()
mouse.Button1Down:connect(function() onClicked(mouse) end)
toolbar = plugin:CreateToolbar("Terrain")
toolbarbutton = toolbar:CreateButton("Elevation Adjuster", "Elevation Adjuster", "elevation.png")
toolbarbutton.Click:connect(function()
if on then
Off()
elseif loaded then
On()
end
end)
game:WaitForChild("Workspace")
game.Workspace:WaitForChild("Terrain")
local c = game.Workspace.Terrain
local SetCell = c.SetCell
local SetWaterCell = c.SetWaterCell
local GetCell = c.GetCell
local GetWaterCell = c.GetWaterCell
local WorldToCellPreferSolid = c.WorldToCellPreferSolid
local WorldToCellPreferEmpty = c.WorldToCellPreferEmpty
local CellCenterToWorld = c.CellCenterToWorld
local AutoWedge = c.AutowedgeCell
-----------------
--DEFAULT VALUES-
-----------------
-- The ID number that represents water.
waterMaterialID = 17
-- Elevation related options. Contains everything needed for making the elevation.
elevationOptions = {
r = 0, -- Radius of the elevation area. The larger it is, the wider the top of the elevation will be.
s = 1, -- Slope of the elevation area. The larger it is, the steeper the slope.
defaultTerrainMaterial = 1, -- The material that the elevation should be made of.
waterForce = nil, -- What force the material has if it is water.
waterDirection = nil, -- What direction the material has if it is water.
autowedge = true -- Whether smoothing should be applied. True if it should, false if not.
}
-- What color to use for the mouse highlighter.
mouseHighlightColor = BrickColor.new("Lime green")
-- Used to create a highlighter that follows the mouse.
-- It is a class mouse highlighter. To use, call MouseHighlighter.Create(mouse) where mouse is the mouse to track.
MouseHighlighter = {}
MouseHighlighter.__index = MouseHighlighter
-- Create a mouse movement highlighter.
-- plugin - Plugin to get the mouse from.
function MouseHighlighter.Create(mouseUse)
local highlighter = {}
local mouse = mouseUse
highlighter.OnClicked = nil
highlighter.mouseDown = false
-- Store the last point used to draw.
highlighter.lastUsedPoint = nil
-- Will hold a part the highlighter will be attached to. This will be moved where the mouse is.
highlighter.selectionPart = nil
-- Hook the mouse up to check for movement.
mouse.Move:connect(function() MouseMoved() end)
mouse.Button1Down:connect(function() highlighter.mouseDown = true end)
mouse.Button1Up:connect(function() highlighter.mouseDown = false
end)
-- Create the part that the highlighter will be attached to.
highlighter.selectionPart = Instance.new("Part")
highlighter.selectionPart.Name = "SelectionPart"
highlighter.selectionPart.Archivable = false
highlighter.selectionPart.Transparency = 1
highlighter.selectionPart.Anchored = true
highlighter.selectionPart.Locked = true
highlighter.selectionPart.CanCollide = false
highlighter.selectionPart.FormFactor = Enum.FormFactor.Custom
highlighter.selectionBox = Instance.new("SelectionBox")
highlighter.selectionBox.Archivable = false
highlighter.selectionBox.Color = mouseHighlightColor
highlighter.selectionBox.Adornee = highlighter.selectionPart
mouse.TargetFilter = highlighter.selectionPart
setmetatable(highlighter, MouseHighlighter)
-- Function to call when the mouse has moved. Updates where to display the highlighter.
function MouseMoved()
if on then
UpdatePosition(mouse.Hit)
end
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
-- Update where the highlighter is displayed.
-- position - Where to display the highlighter, in world space.
function UpdatePosition(position)
if not position then
return
end
-- NOTE:
-- Change this gui to be the one you want to use.
highlighter.selectionBox.Parent = game:GetService("CoreGui")
local vectorPos = Vector3.new(position.x,position.y,position.z)
local cellPos = WorldToCellPreferEmpty(c, vectorPos)
local solidCell = WorldToCellPreferSolid(c, vectorPos)
local success = false
-- If nothing was hit, do the plane intersection.
if 0 == GetCell(c, solidCell.X, solidCell.Y, solidCell.Z).Value then
success, cellPos = PlaneIntersection(vectorPos)
if not success then
cellPos = solidCell
end
else
highlighter.lastUsedPoint = cellPos
end
local regionToSelect = nil
local lowVec = CellCenterToWorld(c, cellPos.x , cellPos.y - 1, cellPos.z)
local highVec = CellCenterToWorld(c, cellPos.x, cellPos.y + 1, cellPos.z)
regionToSelect = Region3.new(lowVec, highVec)
highlighter.selectionPart.Size = regionToSelect.Size - Vector3.new(-4, 4, -4)
highlighter.selectionPart.CFrame = regionToSelect.CFrame
if nil ~= highlighter.OnClicked and highlighter.mouseDown then
if nil == highlighter.lastUsedPoint then
highlighter.lastUsedPoint = WorldToCellPreferEmpty(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
else
cellPos = WorldToCellPreferEmpty(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
end
end
end
return highlighter
end
-- Hide the highlighter.
function MouseHighlighter:DisablePreview()
self.selectionBox.Parent = nil
end
-- Show the highlighter.
function MouseHighlighter:EnablePreview()
self.selectionBox.Parent = game:GetService("CoreGui") -- This will make it not show up in workspace.
end
-- Create the mouse movement highlighter.
mouseHighlighter = MouseHighlighter.Create(mouse)
------
--GUI-
------
--screengui
local g = Instance.new("ScreenGui", game:GetService("CoreGui"))
g.Name = 'ElevationGui'
-- UI gui load. Required for sliders.
local RbxGui = LoadLibrary("RbxGui")
-- Create a standard text label. Use this for all lables in the popup so it is easy to standardize.
-- labelName - What to set the text label name as.
-- pos - Where to position the label. Should be of type UDim2.
-- size - How large to make the label. Should be of type UDim2.
-- text - Text to display.
-- parent - What to set the text parent as.
-- Return:
-- Value is the created label.
function CreateStandardLabel(labelName,
pos,
size,
text,
parent)
local label = Instance.new("TextLabel", parent)
label.Name = labelName
label.Position = pos
label.Size = size
label.Text = text
label.TextColor3 = Color3.new(0.95, 0.95, 0.95)
label.Font = Enum.Font.ArialBold
label.FontSize = Enum.FontSize.Size14
label.TextXAlignment = Enum.TextXAlignment.Left
label.BackgroundTransparency = 1
label.Parent = parent
return label
end
-- Create a standardized slider.
-- name - Name to use for the slider.
-- pos - Position to display the slider at.
-- steps - How many steps there are in the slider.
-- funcOnChange - Function to call when the slider changes.
-- initValue - Initial value to set the slider to. If nil the slider stays at the default.
-- parent - What to set as the parent.
-- Return:
-- sliderGui - Slider gui object.
-- sliderPosition - Object that can set the slider value.
function CreateStandardSlider(name,
pos,
lengthBarPos,
steps,
funcOnChange,
initValue,
parent)
local sliderGui, sliderPosition = RbxGui.CreateSlider(steps, 0, UDim2.new(0,0,0,0))
sliderGui.Name = name
sliderGui.Parent = parent
sliderGui.Position = pos
sliderGui.Size = UDim2.new(1,0,0,20)
local lengthBar = sliderGui:FindFirstChild("Bar")
lengthBar.Size = UDim2.new(1, -20, 0, 5)
lengthBar.Position = lengthBarPos
if nil ~= funcOnChange then
sliderPosition.Changed:connect(function() funcOnChange(sliderPosition) end)
end
if nil ~= initValue then
sliderPosition.Value = initValue
end
return sliderGui, sliderPosition
end
-- Gui frame for the plugin.
elevationPropertiesDragBar, elevationFrame, elevationHelpFrame, elevationCloseEvent = RbxGui.CreatePluginFrame("Elevation Adjuster",UDim2.new(0,185,0,100),UDim2.new(0,0,0,0),false,g)
elevationPropertiesDragBar.Visible = false
elevationCloseEvent.Event:connect(function ( )
Off()
end)
elevationHelpFrame.Size = UDim2.new(0,300,0,130)
local elevationHelpText = Instance.new("TextLabel",elevationHelpFrame)
elevationHelpText.Name = "HelpText"
elevationHelpText.Font = Enum.Font.ArialBold
elevationHelpText.FontSize = Enum.FontSize.Size12
elevationHelpText.TextColor3 = Color3.new(227/255,227/255,227/255)
elevationHelpText.TextXAlignment = Enum.TextXAlignment.Left
elevationHelpText.TextYAlignment = Enum.TextYAlignment.Top
elevationHelpText.Position = UDim2.new(0,4,0,4)
elevationHelpText.Size = UDim2.new(1,-8,0,177)
elevationHelpText.BackgroundTransparency = 1
elevationHelpText.TextWrap = true
elevationHelpText.Text = [[
Use to drag terrain up or down. Hold the left mouse button down and drag the mouse up or down to create a mountain or valley.
Radius:
The larger it is, the wider the top of the elevation will be.
Slope:
The larger it is, the steeper the slope.]]
-- Slider for controlling radius.
radiusLabel = CreateStandardLabel("RadiusLabel", UDim2.new(0, 8, 0, 10), UDim2.new(0, 67, 0, 14), "", elevationFrame)
radiusSliderGui, radiusSliderPosition = CreateStandardSlider('radiusSliderGui', UDim2.new(0,1,0,26), UDim2.new(0,10,0.5,-2), 11,
function(radiusSliderPosition)
elevationOptions.r = radiusSliderPosition.Value -- 1
radiusLabel.Text = "Radius: "..elevationOptions.r
end, nil, elevationFrame)
radiusSliderPosition.Value = 1
-- Slider for controlling the z offset to generate terrain at.
slopeLabel = CreateStandardLabel("SlopeLabel", UDim2.new(0, 8, 0, 51), UDim2.new(0, 67, 0, 14), "", elevationFrame)
slopeSliderGui, slopeSliderPosition = CreateStandardSlider('slopeSliderGui', UDim2.new(0,1,0,67), UDim2.new(0,10,0.5,-2), 16,
function()
elevationOptions.s = slopeSliderPosition.Value / 10 + 0.4
slopeLabel.Text = "Slope: ".. elevationOptions.s
end, nil, elevationFrame)
slopeSliderPosition.Value = 1
-----------------------
--FUNCTION DEFINITIONS-
-----------------------
--find height at coordinate x, z
function findHeight(x, z)
h = 0
material, wedge, rotation = GetCell(c, x, h + 1, z)
while material.Value > 0 do
h = h + 1
material, wedge, rotation = GetCell(c, x, h + 1, z)
end
return h
end
--makes a shell around block at coordinate x, z using heightmap
function makeShell(x, z, heightmap, shellheightmap)
local originalheight = heightmap[x][z]
for i = x - 1, x + 1 do
for k = z - 1, z + 1 do
if shellheightmap[i][k] < originalheight then
for h = originalheight, shellheightmap[i][k] - 2, -1 do
if h > 0 then
if waterMaterialID == elevationOptions.defaultTerrainMaterial then
SetWaterCell(c, i, h, k, elevationOptions.waterForce, elevationOptions.waterDirection)
else
SetCell(c, i, h, k, elevationOptions.defaultTerrainMaterial, 0, 0)
end
end
end
shellheightmap[i][k] = originalheight
end
end
end
return shellheightmap
end
--elevates terrain at point (x, y, z) in cluster c
--within radius r1 from x, z the elevation should become y + d
--from radius r1 to r2 the elevation should be a gradient
function elevate(x, y, z, r1, r2, d, range)
for i = x - (range + 2), x + (range + 2) do
if oldheightmap[i] == nil then
oldheightmap[i] = {}
end
for k = z - (range + 2), z + (range + 2) do
if oldheightmap[i][k] == nil then
oldheightmap[i][k] = findHeight(i, k)
end
--figure out the height to make coordinate (i, k)
local distance = dist(i, k, x, z)
if distance < r1 then
height = y + d
elseif distance < r2 then
height = math.floor((y + d) * (1 - (distance - r1)/(r2 - r1)) + oldheightmap[i][k] * (distance - r1)/(r2 - r1))
else
height = oldheightmap[i][k]
end
if height == 0 then
height = -1
end
--heightmap[i][k] should be the current height of coordinate (i, k)
if heightmap[i] == nil then
heightmap[i] = {}
end
if heightmap[i][k] == nil then
heightmap[i][k] = oldheightmap[i][k]
end
--the height is either greater than or less than the current height
if height > heightmap[i][k] then
for h = heightmap[i][k] - 2, height do
SetCell(c, i, h, k, elevationOptions.defaultTerrainMaterial, 0, 0)
end
heightmap[i][k] = height
elseif height < heightmap[i][k] then
for h = heightmap[i][k], height + 1, -1 do
SetCell(c, i, h, k, 0, 0, 0)
end
heightmap[i][k] = height
end
end
end
--copy heightmap into shellheightmap
shellheightmap = {}
for i = x - (range + 2), x + (range + 2) do
if shellheightmap[i] == nil then
shellheightmap[i] = {}
end
for k = z - (range + 2), z + (range + 2) do
shellheightmap[i][k] = heightmap[i][k]
end
end
--shell everything
for i = x - range , x + range do
for k = z - range, z + range do
if shellheightmap[i][k] ~= oldheightmap[i][k] then
shellheightmap = makeShell(i, k, heightmap, shellheightmap)
end
end
end
for i = x - (range + 2), x + (range + 2) do
for k = z - (range + 2), z + (range + 2) do
heightmap[i][k] = shellheightmap[i][k]
end
end
for k = z - (range + 1), z + (range + 1) do
for i = x - (range + 1), x + (range + 1) do
local height = heightmap[i][k]
if height == nil then
height = -1
end
-- Autowedge if enabled.
if elevationOptions.autowedge then
for h = height, 1, -1 do
if not AutoWedge(c, i, h, k) then
break
end
end
end
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, z1, x2, z2), 2) + math.pow(math.abs(y2-y1)*100/d, 2))
end
-- Run when the mouse gets clicked. If the click is on terrain, then it will be used as the starting point of the elevation area.
function onClicked(mouse)
if on then
oldheightmap = {}
heightmap = {}
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
local celMat = GetCell(c, x, y, z)
if celMat.Value > 0 then
elevationOptions.defaultTerrainMaterial = celMat.Value
local isWater
isWater, elevationOptions.waterForce, elevationOptions.waterDirection = GetWaterCell(c, cellPos.X, cellPos.Y, cellPos.Z)
else
if 0 == elevationOptions.defaultTerrainMaterial then
-- It was nothing, give it a default type and the plane intersection.
elevationOptions.isWater = false
elevationOptions.defaultTerrainMaterial = 1
end
end
-- Hide the selection area while dragging.
mouseHighlighter:DisablePreview()
mousedown = true
local originalY = mouse.Y
local prevY = originalY
local d = 0
local range = 0
while mousedown == true do
if math.abs(mouse.Y - prevY) >= 5 then
prevY = mouse.Y
r2 = elevationOptions.r + math.floor(50 * 1/elevationOptions.s * math.abs(originalY - prevY)/mouse.ViewSizeY)
if r2 > range then
range = r2
end
d = math.floor(50 * (originalY - prevY)/mouse.ViewSizeY)
elevate(x, y, z, elevationOptions.r, r2, d, range)
end
wait(0)
end
game:GetService("ChangeHistoryService"): SetWaypoint("Elevation")
end
end
mouseHighlighter.OnClicked = onClicked
mouse = plugin:GetMouse()
mouse.Button1Up:connect(function()
mousedown = false
mouseHighlighter:EnablePreview()
end)
-- Run when the popup is activated.
function On()
if not c then
return
end
plugin:Activate(true)
toolbarbutton:SetActive(true)
elevationPropertiesDragBar.Visible = true
on = true
end
-- Run when the popup is deactivated.
function Off()
toolbarbutton:SetActive(false)
on = false
-- Hide the popup gui.
elevationPropertiesDragBar.Visible = false
mouseHighlighter:DisablePreview()
end
plugin.Deactivation:connect(function()
Off()
end)
loaded = true

View File

@@ -0,0 +1,639 @@
while game == nil do
wait(1/30)
end
---------------
--PLUGIN SETUP-
---------------
local loaded = false
local on = false
self = PluginManager():CreatePlugin()
toolbar = self:CreateToolbar("Terrain")
toolbarbutton = toolbar:CreateButton("Brush", "Brush", "brush.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 GetCell = c.GetCell
local SetCell = c.SetCell
local SetCells = c.SetCells
local AutowedgeCells = c.AutowedgeCells
local AutowedgeCell = c.AutowedgeCell
local WorldToCellPreferSolid = c.WorldToCellPreferSolid
local CellCenterToWorld = c.CellCenterToWorld
local AutoWedge = c.AutowedgeCell
local buildTerrainMode = 'Add'
local removeTerrainMode = 'Remove'
-----------------
--DEFAULT VALUES-
-----------------
local radius = 5
local depth = 0
local mousedown = false
local mousemoving = false
local brushheight = nil
local material = 1
local lastMousePos = Vector2.new(-1,-1)
local lastCellFillTime = 0
local maxYExtents = math.min(c.MaxExtents.Max.Y, 512)
-- Which mode (build/remove) it is.
local mode = buildTerrainMode
-- Height and depth to use for the different modes.
local buildTerrainHeight = 5
local removeTerrainDepth = -5
local mouse = self:GetMouse()
mouse.Button1Down:connect(function() buttonDown() end)
mouse.Button1Up:connect(function()
mousedown = false
brushheight = nil
enablePreview()
updatePreviewSelection(mouse.Hit)
game:GetService("ChangeHistoryService"):SetWaypoint("Brush")
end)
mouse.Move:connect(function() mouseMoved() end)
local selectionPart = Instance.new("Part")
selectionPart.Name = "SelectionPart"
selectionPart.Archivable = false
selectionPart.Transparency = 1
selectionPart.Anchored = true
selectionPart.Locked = true
selectionPart.CanCollide = false
selectionPart.FormFactor = Enum.FormFactor.Custom
local selectionBox = Instance.new("SelectionBox")
selectionBox.Archivable = false
selectionBox.Color = BrickColor.new("Lime green")
selectionBox.Adornee = selectionPart
mouse.TargetFilter = selectionPart
-----------------------
--FUNCTION DEFINITIONS-
-----------------------
-- searches the y depth of a particular cell position to find the lowest y that is empty
function findLowestEmptyCell(x,y,z)
local cellMat = GetCell(c, x,y,z)
local lowestY = y
while cellMat == Enum.CellMaterial.Empty do
lowestY = y
if y > 0 then
y = y - 1
cellMat = GetCell(c, x,y,z)
else
lowestY = 0
cellMat = nil
end
end
return lowestY
end
-- finds the lowest cell that is not filled in the radius that is currently specified
function findLowPoint(x,y,z)
local lowestPoint = maxYExtents + 1
for i = -radius, radius do
local zPos = z + i
for j = -radius, radius do
local xPos = x + i
local cellMat = GetCell(c, xPos, y, zPos)
if cellMat == Enum.CellMaterial.Empty then
local emptyDepth = findLowestEmptyCell(xPos, y, zPos)
if emptyDepth < lowestPoint then
lowestPoint = emptyDepth
end
end
end
end
return lowestPoint
end
--brushes terrain at point (x, y, z) in cluster c
function brush(x, y, z)
if depth == 0 then return end
if depth > 0 then
local findY = findLowPoint(x,y + depth,z)
local yWithDepth = y + depth
local lowY = nil
if findY < yWithDepth then
lowY = findY
else
lowY = yWithDepth
end
local lowVec = Vector3int16.new(x - radius, lowY, z - radius)
local highVec = Vector3int16.new(x + radius, yWithDepth, z + radius)
local regionToFill = Region3int16.new(lowVec,highVec)
SetCells(c, regionToFill, material, 0, 0)
AutowedgeCells(c, regionToFill)
else
local lowVec = Vector3int16.new(x - radius, y + depth + 1, z - radius)
local highVec = Vector3int16.new(x + radius, maxYExtents, z + radius)
local regionToEmpty = Region3int16.new(lowVec,highVec)
SetCells(c,regionToEmpty,Enum.CellMaterial.Empty,0,0)
end
end
function disablePreview()
selectionBox.Parent = nil
end
function enablePreview()
selectionBox.Parent = game.Workspace
end
function updatePreviewSelection(position)
if not position then return end
--if not mouse.Target then disablePreview() return end
if depth == 0 then disablePreview() return end
local vectorPos = Vector3.new(position.x,position.y,position.z)
local cellPos = WorldToCellPreferSolid(c, vectorPos)
local solidCell = WorldToCellPreferSolid(c, vectorPos)
-- If nothing was hit, do the plane intersection.
if 0 == GetCell(c, solidCell.X, solidCell.Y, solidCell.Z).Value then
local success = false
success, cellPos = PlaneIntersection(vectorPos)
if not success then
if mouse.Target then
cellPos = solidCell
else
return
end
end
end
local regionToSelect = nil
if depth > 0 then
local yWithDepth = nil
if brushheight then
yWithDepth = brushheight + depth
else
yWithDepth = cellPos.y + depth
end
local lowY = nil
if brushheight then
lowY = brushheight + 1
else
local findY = findLowPoint(cellPos.x,yWithDepth,cellPos.z)
if findY < yWithDepth then
lowY = findY
else
lowY = yWithDepth
end
end
local lowVec = CellCenterToWorld(c, cellPos.x - radius, lowY - 1, cellPos.z - radius)
local highVec = CellCenterToWorld(c, cellPos.x + radius, yWithDepth + 1, cellPos.z + radius)
selectionBox.Color = BrickColor.new("Lime green")
regionToSelect = Region3.new(lowVec,highVec)
else
local yPos = cellPos.y + depth
if brushheight then
yPos = brushheight + depth
end
local lowVec = CellCenterToWorld(c, cellPos.x - radius, yPos, cellPos.z - radius)
local highVec = CellCenterToWorld(c, cellPos.x + radius, maxYExtents, cellPos.z + radius)
selectionBox.Color = BrickColor.new("Really red")
regionToSelect = Region3.new(lowVec,highVec)
end
selectionPart.Size = regionToSelect.Size - Vector3.new(-4,4,-4)
selectionPart.CFrame = regionToSelect.CFrame
enablePreview()
end
function doFillCells(position, mouseDrag, needsCellPos)
if mouseDrag then
local timeBetweenFills = tick() - lastCellFillTime
local totalDragPixels = math.abs(mouseDrag.x) + math.abs(mouseDrag.y)
local editDistance = (game.Workspace.CurrentCamera.CoordinateFrame.p -
Vector3.new(position.x,position.y,position.z)).magnitude
if (timeBetweenFills <= 0.05) then
if editDistance * totalDragPixels < 450 then
lastCellFillTime = tick()
return
end
end
end
local x = position.x
local y = position.y
local z = position.z
if needsCellPos then
local cellPos = WorldToCellPreferSolid(c, Vector3.new(x,y,z))
local solidCell = WorldToCellPreferSolid(c, Vector3.new(x,y,z))
-- If nothing was hit, do the plane intersection.
if 0 == GetCell(c, solidCell.X, solidCell.Y, solidCell.Z).Value then
local success = false
success, cellPos = PlaneIntersection(Vector3.new(x,y,z))
if not success then
if mouse.Target then
cellPos = solidCell
else
return
end
end
end
x = cellPos.x
y = cellPos.y
z = cellPos.z
end
if brushheight == nil then
brushheight = y
end
brush(x, brushheight, z)
lastCellFillTime = tick()
end
function mouseMoved()
if on then
if mousedown == true then
if mousemoving then return end
mousemoving = true
local currMousePos = Vector2.new(mouse.X,mouse.Y)
local mouseDrag = currMousePos - lastMousePos
doFillCells(mouse.Hit, mouseDrag, true)
lastMousePos = currMousePos
mousemoving = false
end
updatePreviewSelection(mouse.Hit)
end
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.
-- intersection - 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 buttonDown()
if on then
local firstCellPos = WorldToCellPreferSolid(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))
-- If nothing was hit, do the plane intersection.
if 0 == GetCell(c, solidCell.X, solidCell.Y, solidCell.Z).Value then
local success = false
success, firstCellPos = PlaneIntersection(Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
if not success then
if mouse.Target then
firstCellPos = solidCell
else
return
end
end
end
local celMat = GetCell(c, firstCellPos.x, firstCellPos.y, firstCellPos.z)
if celMat.Value > 0 then
material = celMat.Value
else
if 0 == material then
-- It was nothing, give it a default type and the plane intersection.
material = 1
end
end
brushheight = firstCellPos.y
lastMousePos = Vector2.new(mouse.X,mouse.Y)
doFillCells(firstCellPos)
mousedown = true
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 enablePreview then
enablePreview()
end
if brushDragBar then
brushDragBar.Visible = true
end
on = true
end
function Off()
if toolbarbutton then
toolbarbutton:SetActive(false)
end
if disablePreview then
disablePreview()
end
if brushDragBar then
brushDragBar.Visible = false
end
on = false
end
------
--GUI-
------
--load library for with sliders
local RbxGui = LoadLibrary("RbxGui")
-- Create a standard dropdown. Use this for all dropdowns in the popup so it is easy to standardize.
-- name - What to set the text label name as.
-- pos - Where to position the label. Should be of type UDim2.
-- values - A table of the values that will be in the dropbox, in the order they are to be shown.
-- initValue - Initial value the dropdown should be set to.
-- funcOnChange - Function to run when a dropdown selection is made.
-- parent - What to set the parent as.
-- Return:
-- dropdown - The dropdown gui.
-- updateSelection - Object to use to change the current dropdown.
function CreateStandardDropdown(name,
pos,
values,
initValue,
funcOnChange,
parent)
-- Create a dropdown selection for the modes to fill in a river
local dropdown, updateSelection=RbxGui.CreateDropDownMenu(values, funcOnChange);
dropdown.Name = name
dropdown.Position = pos
dropdown.Active = true
dropdown.Size = UDim2.new(0,150,0,32)
dropdown.Parent = parent
updateSelection(initValue)
return dropdown, updateSelection
end
-- Create a standard text label. Use this for all lables in the popup so it is easy to standardize.
-- labelName - What to set the text label name as.
-- pos - Where to position the label. Should be of type UDim2.
-- size - How large to make the label. Should be of type UDim2.
-- text - Text to display.
-- parent - What to set the text parent as.
-- Return:
-- Value is the created label.
function CreateStandardLabel(labelName,
pos,
size,
text,
parent)
local label = Instance.new("TextLabel", parent)
label.Name = labelName
label.Position = pos
label.Size = size
label.Text = text
label.TextColor3 = Color3.new(0.95, 0.95, 0.95)
label.Font = Enum.Font.ArialBold
label.FontSize = Enum.FontSize.Size14
label.TextXAlignment = Enum.TextXAlignment.Left
label.BackgroundTransparency = 1
label.Parent = parent
return label
end
-- Create a standardized slider.
-- name - Name to use for the slider.
-- pos - Position to display the slider at.
-- steps - How many steps there are in the slider.
-- funcOnChange - Function to call when the slider changes.
-- initValue - Initial value to set the slider to. If nil the slider stays at the default.
-- parent - What to set as the parent.
-- Return:
-- sliderGui - Slider gui object.
-- sliderPosition - Object that can set the slider value.
function CreateStandardSlider(name,
pos,
lengthBarPos,
steps,
funcOnChange,
initValue,
parent)
local sliderGui, sliderPosition = RbxGui.CreateSlider(steps, 0, UDim2.new(0,0,0,0))
sliderGui.Name = name
sliderGui.Parent = parent
sliderGui.Position = pos
sliderGui.Size = UDim2.new(0,160,0,20)
local lengthBar = sliderGui:FindFirstChild("Bar")
lengthBar.Size = UDim2.new(1, -20, 0, 5)
lengthBar.Position = lengthBarPos
if nil ~= funcOnChange then
sliderPosition.Changed:connect(function() funcOnChange(sliderPosition) end)
end
if nil ~= initValue then
sliderPosition.Value = initValue
end
return sliderGui, sliderPosition
end
--screengui
local g = Instance.new("ScreenGui", game:GetService("CoreGui"))
g.Name = "TerrainBrushGui"
brushDragBar, elevationFrame, elevationHelpFrame, elevationCloseEvent = RbxGui.CreatePluginFrame("Terrain Brush",UDim2.new(0,151,0,160),UDim2.new(0,0,0,0),false,g)
brushDragBar.Visible = false
elevationCloseEvent.Event:connect(function ( )
Off()
end)
elevationHelpFrame.Size = UDim2.new(0,200,0,210)
local helpText = Instance.new("TextLabel",elevationHelpFrame)
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 =
[[Drag the mouse by holding the left mouse button to either create or destroy terrain defined by the selection box.
Radius:
Half of the width of the selection box to be used.
Height:
How tall to make terrain from the mouse location. If this value is negative, the brush will remove terrain instead of creating terrain (indicated by the red selection box).
]]
--current radius display label
radl = Instance.new("TextLabel", elevationFrame)
radl.Position = UDim2.new(0,0,0,70)
radl.Size = UDim2.new(1, 0, 0, 14)
radl.Text = ""
radl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
radl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
radl.Font = Enum.Font.ArialBold
radl.FontSize = Enum.FontSize.Size14
radl.TextXAlignment = Enum.TextXAlignment.Left
radl.BorderColor3 = Color3.new(0, 0, 0)
radl.BackgroundTransparency = 1
--radius slider
radSliderGui, radSliderPosition = RbxGui.CreateSlider(5, 0, UDim2.new(0, 10, 0, 92))
radSliderGui.Parent = elevationFrame
radBar = radSliderGui:FindFirstChild("Bar")
radBar.Size = UDim2.new(1,-20,0,5)
radSliderPosition.Changed:connect(function()
radius = radSliderPosition.Value + 1
radl.Text = " Radius: ".. radius
end)
radSliderPosition.Value = radius - 1
--current depth factor display label
dfl = Instance.new("TextLabel", elevationFrame)
dfl.Position = UDim2.new(0, 0, 0, 110)
dfl.Size = UDim2.new(1, 0, 0, 14)
dfl.Text = ""
dfl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
dfl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
dfl.Font = Enum.Font.ArialBold
dfl.FontSize = Enum.FontSize.Size14
dfl.BorderColor3 = Color3.new(0, 0, 0)
dfl.TextXAlignment = Enum.TextXAlignment.Left
dfl.BackgroundTransparency = 1
--depth factor slider
addSliderGui, addSliderPosition = RbxGui.CreateSlider(31, 0, UDim2.new(0, 10, 0,132))
addSliderGui.Parent = elevationFrame
dfBar = addSliderGui:FindFirstChild("Bar")
dfBar.Size = UDim2.new(1,-20,0,5)
addSliderPosition.Changed:connect(function()
depth = addSliderPosition.Value
dfl.Text = " Height: ".. depth
end)
addSliderPosition.Value = buildTerrainHeight
--depth factor slider
removeSliderGui, removeSliderPosition = RbxGui.CreateSlider(31, 0, UDim2.new(0, 10, 0,132))
removeSliderGui.Parent = elevationFrame
dfBar = removeSliderGui:FindFirstChild("Bar")
dfBar.Size = UDim2.new(1,-20,0,5)
removeSliderPosition.Changed:connect(function()
depth = -(removeSliderPosition.Value)
dfl.Text = " Height: ".. depth
end)
removeSliderPosition.Value = removeTerrainDepth
-- Set which mode is to be used. Show/hide as needed.
--
-- mode - Which build mode to run.
function SetMode(mode)
if mode == buildTerrainMode then
addSliderGui.Visible = true
local hold = addSliderPosition.Value
addSliderPosition.Value = 0
addSliderPosition.Value = hold
removeSliderGui.Visible = false
elseif mode == removeTerrainMode then
addSliderGui.Visible = false
removeSliderGui.Visible = true
local hold = removeSliderPosition.Value
removeSliderPosition.Value = 0
removeSliderPosition.Value = hold
end
end
-- Create/Remove mode
-- Create the build mode gui.
buildModeLabel = CreateStandardLabel("BuildModeLabel", UDim2.new(0, 8, 0, 10), UDim2.new(0, 67, 0, 14), "Build Mode:", elevationFrame)
buildModeDropdown, buildModeSet = CreateStandardDropdown("BuildModeDropdown",
UDim2.new(0,1,0,26),
{buildTerrainMode, removeTerrainMode},
buildMode,
function(value)
if 'Add' == value then
SetMode(buildTerrainMode)
elseif 'Remove' == value then
SetMode(removeTerrainMode)
end
end,
elevationFrame)
--[[
buildModeSet(buildTerrainMode)
buildModeSet(removeTerrainMode)
--]]
buildModeSet(mode)
SetMode(mode)
self.Deactivation:connect(function()
Off()
end)
--------------------------
--SUCCESSFUL LOAD MESSAGE-
--------------------------
loaded = true

View File

@@ -0,0 +1,253 @@
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("Crater", "Crater", "craters.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 AutoWedge = c.AutowedgeCell
-----------------
--DEFAULT VALUES-
-----------------
local r = 20
local d = 20
local craterDragBar, craterFrame, craterHelpFrame, craterCloseEvent = nil
-----------------------
--FUNCTION DEFINITIONS-
-----------------------
--makes a crater at point (x, y, z) in cluster c
--d is the depth factor, a percent of the depth of a perfect sphere
function makeCrater(x, y, z, r, d)
local heightmap = {}
for i = x - (r + 1), x + (r + 1) do
heightmap[i] = {}
end
for j = 0, r + 1 do
local cellschanged = false
for i = x - (r + 1), x + (r + 1) do
for k = z - (r + 1), z + (r + 1) do
distance = math.sqrt(math.pow(dist(x, z, i, k), 2) + math.pow(y - (y - j*(100/d)), 2))
if distance < r then
SetCell(c, i, y + j, k, 0, 0, 0)
SetCell(c, i, y - j, k, 0, 0, 0)
cellschanged = true
elseif heightmap[i] and heightmap[i][k] == nil then
material, wedge, rotation = GetCell(c, i, y - j, k)
if material.Value > 0 then
heightmap[i][k] = y - j
end
end
end
end
if cellschanged == false then
break
end
wait(0)
end
for ri = 0, r do
wait(0)
i = x - ri
for k = z - r, z + r do
height = heightmap[i][k]
if height == nil then
height = -1
end
for h = height, 0, -1 do
if not AutoWedge(c, i, h, k) then
break
end
end
end
i = x + ri
for k = z - r, z + r do
height = heightmap[i][k]
if height == nil then
height = -1
end
for h = height, 0, -1 do
if not AutoWedge(c, i, h, k) then
break
end
end
end
end
end
function dist(x1, y1, x2, y2)
return math.sqrt(math.pow(x2-x1, 2) + math.pow(y2-y1, 2))
end
local debounce = false
function onClicked(mouse)
if on and not debounce then
debounce = true
local cellPos = WorldToCellPreferSolid(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
local x = cellPos.x
local y = cellPos.y
local z = cellPos.z
makeCrater(x, y, z, r, d)
debounce = false
game:GetService("ChangeHistoryService"):SetWaypoint("Crater")
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 craterDragBar then
craterDragBar.Visible = true
end
on = true
end
function Off()
if toolbarbutton then
toolbarbutton:SetActive(false)
end
if craterDragBar then
craterDragBar.Visible = false
end
on = false
end
------
--GUI-
------
--load library for with sliders
local RbxGui = LoadLibrary("RbxGui")
--screengui
g = Instance.new("ScreenGui", game:GetService("CoreGui"))
g.Name = "CraterGui"
craterDragBar, craterFrame, craterHelpFrame, craterCloseEvent = RbxGui.CreatePluginFrame("Crater",UDim2.new(0,141,0,100),UDim2.new(0,0,0,0),false,g)
craterDragBar.Visible = false
craterCloseEvent.Event:connect(function ( )
Off()
end)
craterHelpFrame.Size = UDim2.new(0,200,0,170)
local helpText = Instance.new("TextLabel",craterHelpFrame)
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 craters in existing terrain. Click on a point in terrain to make a crater.
Radius:
Half of the width of the crater to be created.
Depth:
A percentage value, representing a perfect spherical crater. 0% is no crater, 100% will make a crater the same depth as the radius.
]]
--current radius display label
radl = Instance.new("TextLabel", craterFrame)
radl.Position = UDim2.new(0,0,0,10)
radl.Size = UDim2.new(1, 0, 0, 14)
radl.Text = ""
radl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
radl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
radl.Font = Enum.Font.ArialBold
radl.FontSize = Enum.FontSize.Size14
radl.BorderColor3 = Color3.new(0, 0, 0)
radl.TextXAlignment = Enum.TextXAlignment.Left
radl.BackgroundTransparency = 1
--radius slider
radSliderGui, radSliderPosition = RbxGui.CreateSlider(128, 0, UDim2.new(0, 10, 0, 32))
radSliderGui.Parent = craterFrame
radBar = radSliderGui:FindFirstChild("Bar")
radBar.Size = UDim2.new(1,-20,0,5)
radSliderPosition.Changed:connect(function()
r = radSliderPosition.Value
radl.Text = " Radius: "..r
end)
radSliderPosition.Value = r
--current depth factor display label
dfl = Instance.new("TextLabel", craterFrame)
dfl.Position = UDim2.new(0, 0, 0, 50)
dfl.Size = UDim2.new(1, 0, 0, 14)
dfl.Text = ""
dfl.BackgroundColor3 = Color3.new(0.4, 0.4, 0.4)
dfl.TextColor3 = Color3.new(0.95, 0.95, 0.95)
dfl.Font = Enum.Font.ArialBold
dfl.FontSize = Enum.FontSize.Size14
dfl.BorderColor3 = Color3.new(0, 0, 0)
dfl.TextXAlignment = Enum.TextXAlignment.Left
dfl.BackgroundTransparency = 1
--depth factor slider
dfSliderGui, dfSliderPosition = RbxGui.CreateSlider(100, 0, UDim2.new(0, 10, 0, 72))
dfSliderGui.Parent = craterFrame
dfBar = dfSliderGui:FindFirstChild("Bar")
dfBar.Size = UDim2.new(1,-20,0,5)
dfSliderPosition.Changed:connect(function()
d = dfSliderPosition.Value
dfl.Text = " Depth: "..d.."%"
end)
dfSliderPosition.Value = d
self.Deactivation:connect(function()
Off()
end)
--------------------------
--SUCCESSFUL LOAD MESSAGE-
--------------------------
loaded = true

View File

@@ -0,0 +1,291 @@
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

View File

@@ -0,0 +1,625 @@
while game == nil do
wait(1/30)
end
---------------
--PLUGIN SETUP-
---------------
loaded = false
on = false
self = PluginManager():CreatePlugin()
mouse = self:GetMouse()
mouse.Button1Down:connect(function() mouseDown(mouse) end)
mouse.Button1Up:connect(function() mouseUp(mouse) end)
mouse.Move:connect(function() mouseMove(mouse) end)
toolbar = self:CreateToolbar("Terrain")
toolbarbutton = toolbar:CreateButton("Material Brush", "Material Brush", "materialBrush.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 SetWaterCell = c.SetWaterCell
local GetWaterCell = c.GetWaterCell
local GetCell = c.GetCell
local WorldToCellPreferSolid = c.WorldToCellPreferSolid
local CellCenterToWorld = c.CellCenterToWorld
local waterMaterial = 17
local brushTypes = {"Circular", "Square"}
local waterForceDirections = {"NegX","X","NegY","Y","NegZ","Z"}
local waterForces = {"None", "Small", "Medium", "Strong", "Max"}
local mediumWaterForce = Enum.WaterForce.Medium
-----------------
--DEFAULT VALUES-
-----------------
local terrainSelectorGui, terrainSelected, radiusLabel, dragBar, closeEvent, helpFrame, currSelectionUpdate, currSelectionDestroy, lastCell, lastLastCell, waterPanel = nil
local dragging = false
local painting = false
--- exposed values to user via gui
local currentMaterial = Enum.CellMaterial.Grass
local radius = 3
local brushType = "Square"
local currWaterForceDirection = "NegX"
local currWaterForce = "None"
-- lua library load
local RbxGui = LoadLibrary("RbxGui")
local RbxUtil = LoadLibrary("RbxUtility")
-----------------------
--FUNCTION DEFINITIONS-
-----------------------
function paintWaterfall(setCells)
if setCells then
for i = 1, #setCells do
SetWaterCell(c, setCells[i].xPos, setCells[i].yPos, setCells[i].zPos, mediumWaterForce, Enum.WaterDirection.NegY)
end
end
end
function setWaterDirection(mouseCellPos, setCells)
if not setCells then return end
if #setCells <= 0 then return end
if directionIsDown(lastCell, mouseCellPos) then
paintWaterfall(setCells)
return
end
local initX = setCells[1].xPos
local initZ = setCells[1].zPos
local endX = setCells[#setCells].xPos
local endZ = setCells[#setCells].zPos
local zWidth = math.abs(endZ - initZ)
local zMiddle = math.ceil(zWidth/2 + initZ)
local xMiddle = math.ceil(zWidth/2 + initX)
local down = endX - initX
local up,left,right = nil
if down < 0 then
down = Enum.WaterDirection.NegX
up = Enum.WaterDirection.X
left = Enum.WaterDirection.Z
right = Enum.WaterDirection.NegZ
else
down = Enum.WaterDirection.X
up = Enum.WaterDirection.NegX
left = Enum.WaterDirection.NegZ
right = Enum.WaterDirection.Z
end
if #setCells == 1 then
if not mouseCellPos or not lastCell then return end
local overallDirection = (mouseCellPos - lastCell).unit
if math.abs(overallDirection.x) > math.abs(overallDirection.y) and math.abs(overallDirection.x) > math.abs(overallDirection.z) then
if overallDirection.x > 0 then
SetWaterCell(c, setCells[1].xPos, setCells[1].yPos, setCells[1].zPos, mediumWaterForce, Enum.WaterDirection.X)
else
SetWaterCell(c, setCells[1].xPos, setCells[1].yPos, setCells[1].zPos, mediumWaterForce, Enum.WaterDirection.NegX)
end
elseif math.abs(overallDirection.z) > math.abs(overallDirection.y) and math.abs(overallDirection.z) > math.abs(overallDirection.x) then
if overallDirection.z > 0 then
SetWaterCell(c, setCells[1].xPos, setCells[1].yPos, setCells[1].zPos, mediumWaterForce, Enum.WaterDirection.Z)
else
SetWaterCell(c, setCells[1].xPos, setCells[1].yPos, setCells[1].zPos, mediumWaterForce, Enum.WaterDirection.NegZ)
end
elseif math.abs(overallDirection.y) > math.abs(overallDirection.z) and math.abs(overallDirection.y) > math.abs(overallDirection.x) then
if overallDirection.y > 0 then
SetWaterCell(c, setCells[1].xPos, setCells[1].yPos, setCells[1].zPos, mediumWaterForce, Enum.WaterDirection.Y)
else
SetWaterCell(c, setCells[1].xPos, setCells[1].yPos, setCells[1].zPos, mediumWaterForce, Enum.WaterDirection.NegY)
end
end
else
for i = 1, #setCells do
if(setCells[i].xPos == initX) then
SetWaterCell(c, setCells[i].xPos, setCells[i].yPos, setCells[i].zPos, mediumWaterForce, down)
elseif(setCells[i].xPos == endX) then
SetWaterCell(c, setCells[i].xPos, setCells[i].yPos, setCells[i].zPos, mediumWaterForce, up)
else
if setCells[i].zPos < zMiddle then
SetWaterCell(c, setCells[i].xPos, setCells[i].yPos, setCells[i].zPos, mediumWaterForce, right)
elseif setCells[i].zPos > zMiddle then
SetWaterCell(c, setCells[i].xPos, setCells[i].yPos, setCells[i].zPos, mediumWaterForce, left)
else
if setCells[i].xPos < xMiddle then
SetWaterCell(c, setCells[i].xPos, setCells[i].yPos, setCells[i].zPos, mediumWaterForce, down)
elseif setCells[i].xPos > xMiddle then
SetWaterCell(c, setCells[i].xPos, setCells[i].yPos, setCells[i].zPos, mediumWaterForce, up)
end
end
end
end
end
end
function getSquare( cellPos, setCells)
local finalX = cellPos.x + radius - 1
local finalZ = cellPos.z + radius - 1
local finalY = cellPos.y + radius - 1
for x = cellPos.x - radius + 1, finalX do
for z = cellPos.z - radius + 1, finalZ do
for y = cellPos.y - radius + 1, finalY do
local tempCellPos = Vector3.new(x, y, z)
local oldMaterial, oldType, oldOrientation = GetCell(c, x, y, z)
if oldMaterial.Value > 0 then
table.insert(setCells,{xPos = x, yPos = y, zPos = z, theType = oldType, orientation = oldOrientation})
end
end
end
end
end
function getCircular( cellPos, setCells)
local radiusSquared = radius * radius
local finalX = cellPos.x + radius
local finalZ = cellPos.z + radius
local finalY = cellPos.y + radius
for x = cellPos.x - radius, finalX do
for z = cellPos.z - radius, finalZ do
for y = cellPos.y - radius, finalY do
local tempCellPos = Vector3.new(x, y, z)
local holdDist = tempCellPos - cellPos
local distSq = (holdDist):Dot(holdDist)
if (distSq < radiusSquared) then
local oldMaterial, oldType, oldOrientation = GetCell(c, x, y, z)
if oldMaterial.Value > 0 then
table.insert(setCells,{xPos = x, yPos = y, zPos = z, theType = oldType, orientation = oldOrientation})
end
end
end
end
end
end
function paintCircular(cellPos, setCells)
getCircular(cellPos, setCells)
if currentMaterial ~= waterMaterial then
for i = 1, #setCells do
SetCell(c, setCells[i].xPos, setCells[i].yPos, setCells[i].zPos, currentMaterial, setCells[i].theType, setCells[i].orientation)
end
end
end
function paintSquare(cellPos, setCells)
getSquare(cellPos, setCells)
if currentMaterial ~= waterMaterial then
for i = 1, #setCells do
SetCell(c, setCells[i].xPos, setCells[i].yPos, setCells[i].zPos, currentMaterial, setCells[i].theType, setCells[i].orientation)
end
end
end
function paint(startPos)
if startPos and c then
local cellPos = startPos
local setCells = {}
if brushType == "Circular" then
paintCircular(cellPos, setCells)
elseif brushType == "Square" then
paintSquare(cellPos, setCells)
end
if (currentMaterial == waterMaterial) then
setWaterDirection(cellPos, setCells)
end
return setCells
end
end
function getAffectedCells(startPos)
local setCells = {}
if startPos and c then
if brushType == "Circular" then
getCircular(startPos, setCells)
elseif brushType == "Square" then
getSquare(startPos, setCells)
end
end
return setCells
end
function calculateRegion( mouse )
local cellPos = WorldToCellPreferSolid(c, mouse.Hit.p)
local lowVec = Vector3.new(cellPos.x - radius,cellPos.y - radius,cellPos.z - radius)
local highVec = Vector3.new(cellPos.x + radius,cellPos.y + radius,cellPos.z + radius)
lowVec = CellCenterToWorld(c,lowVec.x,lowVec.y,lowVec.z)
highVec = CellCenterToWorld(c,highVec.x,highVec.y,highVec.z)
return Region3.new(lowVec + Vector3.new(2,2,2),highVec - Vector3.new(2,2,2))
end
function createSelection(mouse, massSelection)
currSelectionUpdate, currSelectionDestroy = RbxUtil.SelectTerrainRegion(calculateRegion(mouse),BrickColor.new("Lime green"),massSelection,game.CoreGui)
end
function updateSelection(mouse)
if not currSelectionUpdate then
createSelection(mouse, radius > 4)
else
currSelectionUpdate(calculateRegion(mouse),BrickColor.new("Lime green"))
end
end
function setPositionDirectionality()
if nil == lastCell then
return
end
-- no dragging occured, lets set our water to be stagnant or be a waterfall
if lastCell and not lastLastCell then
local cellsToSet = paint(lastCell)
if directionIsDown(nil, lastCell) then
paintWaterfall(cellsToSet)
else
for i = 1, #cellsToSet do
SetWaterCell(c, cellsToSet[i].xPos, cellsToSet[i].yPos, cellsToSet[i].zPos, Enum.WaterForce.None, Enum.WaterDirection.NegX)
end
end
return
end
if directionIsDown(lastLastCell, lastCell) then
local cellsToSet = paint(lastCell)
paintWaterfall(cellsToSet)
return
end
local overallDirection = (lastCell - lastLastCell).unit
local cellsToSet = paint(lastCell)
local absX, absY, absZ = math.abs(overallDirection.X),math.abs(overallDirection.Y),math.abs(overallDirection.Z)
local direction = nil
if absX > absY and absX > absZ then
if overallDirection.X > 0 then
direction = Enum.WaterDirection.X
else
direction = Enum.WaterDirection.NegX
end
elseif absY > absX and absY > absZ then
if overallDirection.Y > 0 then
direction = Enum.WaterDirection.Y
else
direction = Enum.WaterDirection.NegY
end
elseif absZ > absX and absZ > absY then
if overallDirection.Z > 0 then
direction = Enum.WaterDirection.Z
else
direction = Enum.WaterDirection.NegZ
end
end
if not direction then -- this should never be hit, but just in case
direction = Enum.WaterDirection.NegX
end
for i = 1, #cellsToSet do
SetWaterCell(c, cellsToSet[i].xPos, cellsToSet[i].yPos, cellsToSet[i].zPos, mediumWaterForce, direction)
end
end
function mouseDown(mouse)
if on and mouse.Target == game.Workspace.Terrain then
dragging = true
if mouse and mouse.Hit then
if mouse.Target == game.Workspace.Terrain then
local newCell = WorldToCellPreferSolid(c, mouse.Hit.p)
if newCell then
local setCells = paint(newCell)
if currentMaterial == waterMaterial and directionIsDown(lastCell, newCell) then
paintWaterfall(setCells)
end
lastCell = newCell
end
end
end
end
end
function mouseUp(mouse)
dragging = false
-- we need to fix directionality on last cell set (if water)
if currentMaterial == waterMaterial then
setPositionDirectionality()
end
game:GetService("ChangeHistoryService"): SetWaypoint("MaterialPaint")
lastLastCell = nil
lastCell = nil
end
function mouseMove(mouse)
if on then
if mouse.Target == game.Workspace.Terrain then
if lastCell ~= WorldToCellPreferSolid(c, mouse.Hit.p) then
updateSelection(mouse)
local newCell = WorldToCellPreferSolid(c, mouse.Hit.p)
if dragging then
painting = true
paint(newCell)
if lastCell and newCell then
if (lastCell - newCell).magnitude > 1 then
paintBetweenPoints(lastCell,newCell)
end
end
lastLastCell = lastCell
lastCell = newCell
painting = false
end
end
else
destroySelection()
end
end
end
function directionIsDown(fromCell, toCell)
if not toCell then
return false
end
if toCell and fromCell then
local direction = (toCell - fromCell).unit
local absX,absY,absZ = math.abs(direction.X),math.abs(direction.Y),math.abs(direction.Z)
if absY > absX and absY > absZ then
return true
end
end
local viableCells = getAffectedCells(toCell)
if not viableCells then return false end
if #viableCells < 2 then return false end
local lowX, lowY,lowZ = viableCells[1].xPos,viableCells[1].yPos,viableCells[1].zPos
local highX, highY, highZ = lowX, lowY,lowZ
for i = 2, #viableCells do
if viableCells[i].xPos < lowX then lowX = viableCells[i].xPos end
if viableCells[i].xPos > highX then highX = viableCells[i].xPos end
if viableCells[i].yPos < lowY then lowY = viableCells[i].yPos end
if viableCells[i].yPos > highY then highY = viableCells[i].yPos end
if viableCells[i].zPos < lowZ then lowZ = viableCells[i].zPos end
if viableCells[i].zPos > highZ then highZ = viableCells[i].zPos end
end
local xRange, yRange, zRange = math.abs(highX - lowX), math.abs(highY - lowY), math.abs(highZ - lowZ)
local xzPlaneArea = xRange * zRange
local xyPlaneArea = xRange * yRange
local yzPlaneArea = yRange * zRange
if xyPlaneArea > xzPlaneArea then
return true
end
if yzPlaneArea > xzPlaneArea then
return true
end
return false
end
function destroySelection()
if currSelectionUpdate then
currSelectionUpdate = nil
end
if currSelectionDestroy then
currSelectionDestroy()
currSelectionDestroy = nil
end
end
function moveTowardsGoal(direction, currPos, goalPos, currCell)
if currPos ~= goalPos then
if currPos < goalPos then
if direction == "X" then
currCell = Vector3.new(currCell.X + 1, currCell.Y,currCell.Z)
elseif direction == "Y" then
currCell = Vector3.new(currCell.X, currCell.Y + 1,currCell.Z)
elseif direction == "Z" then
currCell = Vector3.new(currCell.X, currCell.Y,currCell.Z + 1)
end
elseif currPos > goalPos then
if direction == "X" then
currCell = Vector3.new(currCell.X - 1, currCell.Y,currCell.Z)
elseif direction == "Y" then
currCell = Vector3.new(currCell.X, currCell.Y - 1,currCell.Z)
elseif direction == "Z" then
currCell = Vector3.new(currCell.X, currCell.Y,currCell.Z - 1)
end
end
end
return currCell
end
function interpolateOneDim(direction, currPos, goalPos, currCell)
if currPos ~= goalPos then
currCell = moveTowardsGoal(direction,currPos,goalPos,currCell)
paint(currCell)
end
return currCell
end
function paintBetweenPoints( lastCell,newCell)
local currCell = lastCell
while currCell.X ~= newCell.X or currCell.Z ~= newCell.Z or currCell.Y ~= newCell.Y do
currCell = interpolateOneDim("X",currCell.X,newCell.X,currCell)
currCell = interpolateOneDim("Z",currCell.Z,newCell.Z,currCell)
currCell = interpolateOneDim("Y",currCell.Y,newCell.Y,currCell)
end
end
function On()
if not c then
return
end
self:Activate(true)
toolbarbutton:SetActive(true)
dragBar.Visible = true
on = true
end
function Off()
toolbarbutton:SetActive(false)
destroySelection()
dragBar.Visible = false
on = false
end
------
--GUI-
------
--screengui
local g = Instance.new("ScreenGui", game:GetService("CoreGui"))
g.Name = "MaterialPainterGui"
dragBar, containerFrame, helpFrame, closeEvent = RbxGui.CreatePluginFrame("Material Brush",UDim2.new(0,163,0,285),UDim2.new(0,0,0,0),false,g)
dragBar.Visible = false
-- End dragging if it goes over the gui frame.
containerFrame.MouseEnter:connect(function() dragging = false end)
dragBar.MouseEnter:connect(function() dragging = false end)
helpFrame.Size = UDim2.new(0,200,0,250)
helpFrame.ZIndex = 3
local textHelp = Instance.new("TextLabel",helpFrame)
textHelp.Name = "TextHelp"
textHelp.Font = Enum.Font.ArialBold
textHelp.FontSize = Enum.FontSize.Size12
textHelp.TextColor3 = Color3.new(1,1,1)
textHelp.Size = UDim2.new(1,-6,1,-6)
textHelp.Position = UDim2.new(0,3,0,3)
textHelp.TextXAlignment = Enum.TextXAlignment.Left
textHelp.TextYAlignment = Enum.TextYAlignment.Top
textHelp.Position = UDim2.new(0,4,0,4)
textHelp.BackgroundTransparency = 1
textHelp.TextWrap = true
textHelp.ZIndex = 4
textHelp.Text = [[Changes existing terrain blocks to the specified material. Simply hold the mouse down and drag to 'paint' the terrain (only cells inside the selection box will be affected).
Size:
The size of the brush we paint terrain with.
Brush Type:
The shape we paint terrain with inside of our selection box.
Material Selection:
The terrain material we will paint.]]
closeEvent.Event:connect(function() Off() end)
terrainSelectorGui, terrainSelected, forceTerrainSelection = RbxGui.CreateTerrainMaterialSelector(UDim2.new(1, -10, 0, 184),UDim2.new(0, 5, 1, -190))
terrainSelectorGui.Parent = containerFrame
terrainSelectorGui.BackgroundTransparency = 1
terrainSelectorGui.BorderSizePixel = 0
terrainSelected.Event:connect(function ( newMaterial )
currentMaterial = newMaterial
end)
-- Purpose:
-- Retrive the size text to display for a given radius, where 1 == 1 block and 2 == 3 blocks, etc.
function SizeText(radius)
return 'Size: ' .. (((radius-1) * 2) + 1)
end
--current radius display label
radiusLabel = Instance.new("TextLabel", containerFrame)
radiusLabel.Name = "RadiusLabel"
radiusLabel.Position = UDim2.new(0, 10, 0, 5)
radiusLabel.Size = UDim2.new(1, -3, 0, 14)
radiusLabel.Text = SizeText(radius)
radiusLabel.TextColor3 = Color3.new(0.95, 0.95, 0.95)
radiusLabel.Font = Enum.Font.ArialBold
radiusLabel.FontSize = Enum.FontSize.Size14
radiusLabel.BorderColor3 = Color3.new(0, 0, 0)
radiusLabel.BackgroundTransparency = 1
radiusLabel.TextXAlignment = Enum.TextXAlignment.Left
--radius slider
radSliderGui, radSliderPosition = RbxGui.CreateSlider(6, 0, UDim2.new(0, 0, 0, 18))
radSliderGui.Size = UDim2.new(1,-2,0,20)
radSliderGui.Position = UDim2.new(0,0,0,24)
radSliderGui.Parent = containerFrame
radBar = radSliderGui:FindFirstChild("Bar")
radBar.Size = UDim2.new(1, -20, 0, 5)
radBar.Position = UDim2.new(0,10,0.5,-3)
radSliderPosition.Value = radius
radSliderPosition.Changed:connect(function()
radius = radSliderPosition.Value
radiusLabel.Text = SizeText(radius)
destroySelection()
end)
local brushTypeChanged = function(newBrush)
brushType = newBrush
end
-- brush type drop-down
local brushDropDown, forceSelection = RbxGui.CreateDropDownMenu(brushTypes, brushTypeChanged)
forceSelection("Square")
brushDropDown.Size = UDim2.new(1,-10,0.01,25)
brushDropDown.Position = UDim2.new(0,5,0,65)
brushDropDown.Parent = containerFrame
local brushLabel = radiusLabel:Clone()
brushLabel.Name = "BrushLabel"
brushLabel.Text = "Brush Type"
brushLabel.Position = UDim2.new(0,10,0,50)
brushLabel.Parent = containerFrame
self.Deactivation:connect(function()
Off()
end)
--------------------------
--SUCCESSFUL LOAD MESSAGE-
--------------------------
loaded = true

View File

@@ -0,0 +1,411 @@
while game == nil do
wait(1/30)
end
---------------
--PLUGIN SETUP-
---------------
local on = false
local loaded = false
self = PluginManager():CreatePlugin()
toolbar = self:CreateToolbar("Terrain")
toolbarbutton = toolbar:CreateButton("Stamper", "Part Stamper - Toggle List (Shift + F)", "stamp.png")
toolbarbutton.Click:connect(function()
if on then
Off()
elseif loaded then
On()
end
end)
game:WaitForChild("Workspace")
game.Workspace:WaitForChild("Terrain")
-----------------
--DEFAULT VALUES-
-----------------
local partButtonOn = true
local currStampGui = nil
local currStampId = nil
local recentsFrame = nil
local waterTypeChangedEvent = nil
local waterForceAndDirection = {"None","NegX"}
local setPanelVisibility = nil
local getPanelVisibility = nil
local stampControl = nil
local lastStampModel = nil
local keyCon = nil
-- ids of users we want to load sets in from
local userSetIds = {11744447,18881789,18881808,18881829,18881853,18881866}
local recentButtonStack = {}
-- mouse management
local mouse = nil
-- Libraries
local RbxStamper = nil
local RbxGui = nil
Spawn(function()
RbxGui = LoadLibrary("RbxGui")
RbxStamper = LoadLibrary("RbxStamper")
end)
local BaseUrl = game:GetService("ContentProvider").BaseUrl:lower()
-----------------------
--FUNCTION DEFINITIONS-
-----------------------
function getRbxGui()
if not RbxGui then
print("teh new rbxgui")
RbxGui = LoadLibrary("RbxGui")
end
return RbxGui
end
function getRbxStamper()
if not RbxStamper then
print("teh new stamper")
RbxStamper = LoadLibrary("RbxStamper")
end
return RbxStamper
end
function showLoadingDialog()
currStampGui.LoadingFrame.LoadingText:TweenPosition(UDim2.new(0,150,0,0), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 2, true)
currStampGui.LoadingFrame.Visible = true
end
function hideLoadingDialog()
currStampGui.LoadingFrame.LoadingText:TweenPosition(UDim2.new(0,0,0,0), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.1, true)
currStampGui.LoadingFrame.Visible = false
end
local partSelected = function(name, id, terrainShape)
if not id then
return
end
if not name then
return
end
currStampId = id
if stampControl then
stampControl.Destroy()
end
if stampCon then
stampCon:disconnect()
stampCon = nil
end
setPanelVisibility(false)
showLoadingDialog()
lastStampModel = getRbxStamper().GetStampModel(id, terrainShape)
updateRecentParts(name, id, terrainShape)
hideLoadingDialog()
if lastStampModel.Name == "MegaClusterCube" then
local clusterTag = lastStampModel:FindFirstChild("ClusterMaterial")
-- we are going to stamp water, send info to stamper about this
if clusterTag and clusterTag:isA("Vector3Value") and clusterTag.Value.X == 17 then
local waterForceTag = Instance.new("StringValue",lastStampModel)
waterForceTag.Name = "WaterForceTag"
waterForceTag.Value = waterForceAndDirection[1]
local waterForceDirectionTag = Instance.new("StringValue",lastStampModel)
waterForceDirectionTag.Name = "WaterForceDirectionTag"
waterForceDirectionTag.Value = waterForceAndDirection[2]
end
end
setupStamper(lastStampModel, mouse)
end
function updateWaterInfo()
if stampControl then
stampControl.Destroy()
end
if stampCon then
stampCon:disconnect()
stampCon = nil
end
showLoadingDialog()
lastStampModel = getRbxStamper().GetStampModel(currStampId)
hideLoadingDialog()
if lastStampModel.Name == "MegaClusterCube" then
local clusterTag = lastStampModel:FindFirstChild("ClusterMaterial")
-- we are going to stamp water, send info to stamper about this
if clusterTag and clusterTag.Value.X == 17 then
local waterForceTag = Instance.new("StringValue",lastStampModel)
waterForceTag.Name = "WaterForceTag"
waterForceTag.Value = waterForceAndDirection[1]
local waterForceDirectionTag = Instance.new("StringValue",lastStampModel)
waterForceDirectionTag.Name = "WaterForceDirectionTag"
waterForceDirectionTag.Value = waterForceAndDirection[2]
end
end
setupStamper(lastStampModel, mouse)
end
local dialogClosed = function()
if lastStampModel then
if stampControl then
stampControl.Destroy()
end
setupStamper(lastStampModel, mouse)
end
end
function pickPart()
if stampControl then
stampControl.Destroy()
end
setPanelVisibility(true)
end
function keyHandler(key)
if key == 'f' then
handlePartShow()
end
end
function partOn()
pickPart()
partButtonOn = true
end
function partOff()
setPanelVisibility(false)
if lastStampModel then
if stampControl then
stampControl.Destroy()
end
setupStamper(lastStampModel, mouse)
end
partButtonOn = false
end
function handlePartShow()
if getPanelVisibility() then
partOff()
else
partOn()
end
end
function On()
if not game.Workspace.Terrain then
return
end
if self then
self:Activate(true)
mouse = self:GetMouse()
end
if toolbarbutton then
toolbarbutton:SetActive(true)
end
if not currStampGui then -- first load, lets make the gui
createGui()
end
if setPanelVisibility then
setPanelVisibility(true)
end
if recentsFrame then
recentsFrame.Visible = true
end
if keyHandler then
keyCon = mouse.KeyDown:connect(keyHandler)
end
on = true
end
function Off()
if toolbarbutton then
toolbarbutton:SetActive(false)
end
if stampControl then
stampControl.Destroy()
end
if keyCon then
keyCon:disconnect()
keyCon = nil
end
if currStampGui and currStampGui:FindFirstChild("WaterFrame") then
currStampGui.WaterFrame.Visible = false
end
if lastStampModel then
lastStampModel:Destroy()
end
if setPanelVisibility then
setPanelVisibility(false)
end
if recentsFrame then
recentsFrame.Visible = false
end
on = false
end
------------------------------------------------------------------------------------------
-- Connect to deactivation event once the handler is defined
------------------------------------------------------------------------------------------
self.Deactivation:connect(function()
Off()
end)
function setupStamper(model, mouse)
if model then
stampControl = getRbxStamper().SetupStamperDragger(model,mouse)
if stampControl then
stampCon = stampControl.Stamped.Changed:connect(function()
if stampControl.Stamped.Value then
stampControl.ReloadModel()
end
end)
end
end
end
function updateRecentParts(newName, newId, newTerrainShape)
if newId then
for i = 1, #recentButtonStack do
if recentButtonStack[i].Id == newId then -- already have item, nothing to do
return
end
end
for i = #recentButtonStack - 1, 1, -1 do
recentButtonStack[i + 1].Id = recentButtonStack[i].Id
recentButtonStack[i + 1].Name = recentButtonStack[i].Name
recentButtonStack[i + 1].TerrainShape = recentButtonStack[i].TerrainShape
recentButtonStack[i + 1].Button.Image = recentButtonStack[i].Button.Image
end
recentButtonStack[1].Id = newId
recentButtonStack[1].Name = newName
recentButtonStack[1].TerrainShape = newTerrainShape
recentButtonStack[1].Button.Image = BaseUrl .. "Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=75&ht=75&aid=" .. tostring(newId)
end
end
------
--GUI-
------
function createGui()
--Insert Panel
currStampGui, setPanelVisibility, getPanelVisibility, waterTypeChangedEvent =
getRbxGui().CreateSetPanel(userSetIds, partSelected, dialogClosed, UDim2.new(0.8, 0, 0.9, 0), UDim2.new(0.1,0,0.05,0), true)
setPanelVisibility(false)
currStampGui.Parent = game:GetService("CoreGui")
waterTypeChangedEvent.Event:connect(function(waterTable)
waterForceAndDirection = waterTable
updateWaterInfo()
end)
-- Loading Gui
local loadingFrame = Instance.new("Frame")
loadingFrame.Name = "LoadingFrame"
loadingFrame.Style = Enum.FrameStyle.RobloxRound
loadingFrame.Size = UDim2.new(0,350,0,60)
loadingFrame.Visible = false
loadingFrame.Position = UDim2.new(0.5,-175,0.5,-30)
local loadingText = Instance.new("TextLabel")
loadingText.Name = "LoadingText"
loadingText.BackgroundTransparency = 1
loadingText.Size = UDim2.new(0,155,1,0)
loadingText.Font = Enum.Font.ArialBold
loadingText.FontSize = Enum.FontSize.Size36
loadingText.Text = "Loading..."
loadingText.TextColor3 = Color3.new(1,1,1)
loadingText.TextStrokeTransparency = 0
loadingText.Parent = loadingFrame
loadingFrame.Parent = currStampGui
-- Recents Stack Gui
recentsFrame = Instance.new("Frame")
recentsFrame.BackgroundTransparency = 0.5
recentsFrame.Name = "RecentsFrame"
recentsFrame.BackgroundColor3 = Color3.new(0,0,0)
recentsFrame.Size = UDim2.new(0,50,0,150)
recentsFrame.Visible = false
recentsFrame.Parent = currStampGui
local recentButtonOne = Instance.new("ImageButton")
recentButtonOne.Style = Enum.ButtonStyle.RobloxButton
recentButtonOne.Name = "RecentButtonOne"
recentButtonOne.Size = UDim2.new(0,50,0,50)
recentButtonOne.Parent = recentsFrame
local recentButtonTwo = recentButtonOne:clone()
recentButtonTwo.Name = "RecentButtonTwo"
recentButtonTwo.Position = UDim2.new(0,0,0,50)
recentButtonTwo.Parent = recentsFrame
local recentButtonThree = recentButtonOne:clone()
recentButtonThree.Name = "RecentButtonThree"
recentButtonThree.Position = UDim2.new(0,0,0,100)
recentButtonThree.Parent = recentsFrame
for i = 1, 3 do
recentButtonStack[i] = {}
recentButtonStack[i].Name = nil
recentButtonStack[i].Id = nil
recentButtonStack[i].TerrainShape = nil
end
recentButtonStack[1].Button = recentButtonOne
recentButtonStack[2].Button = recentButtonTwo
recentButtonStack[3].Button = recentButtonThree
local buttonClicked = false
for i = 1, #recentButtonStack do
recentButtonStack[i].Button.MouseButton1Click:connect(function()
if buttonClicked then return end
buttonClicked = true
partSelected(recentButtonStack[i].Name, recentButtonStack[i].Id, recentButtonStack[i].TerrainShape)
buttonClicked = false
end)
end
end
--------------------------
--SUCCESSFUL LOAD MESSAGE-
--------------------------
loaded = true

View File

@@ -0,0 +1,765 @@
while game == nil do
wait(1/30)
end
---------------
--PLUGIN SETUP-
---------------
local loaded = false
local on = false
self = PluginManager():CreatePlugin()
local mouse = self:GetMouse()
mouse.Button1Down:connect(function() mouseDown(mouse) end)
mouse.Button1Up:connect(function() mouseUp(mouse) end)
toolbar = self:CreateToolbar("Terrain")
toolbarbutton = toolbar:CreateButton("Flood Fill", "Flood Fill", "floodFill.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 WorldToCellPreferSolid = c.WorldToCellPreferSolid
local WorldToCellPreferEmpty = c.WorldToCellPreferEmpty
local CellCenterToWorld = c.CellCenterToWorld
local GetCell = c.GetCell
local SetCell = c.SetCell
local maxYExtents = c.MaxExtents.Max.Y
local emptyMaterial = Enum.CellMaterial.Empty
local waterMaterial = Enum.CellMaterial.Water
local floodFill = nil
-----------------
--DEFAULT VALUES-
-----------------
local startCell = nil
local processing = false
-- gui values
local screenGui = nil
local dragBar, closeEvent, helpFrame, lastCell = nil
local progressBar, setProgressFunc, cancelEvent = nil
local ConfirmationPopupObject = nil
--- exposed values to user via gui
local currentMaterial = 1
-- load our libraries
local RbxGui = LoadLibrary("RbxGui")
local RbxUtil = LoadLibrary("RbxUtility")
game:GetService("ContentProvider"):Preload("http://www.roblox.com/asset/?id=82741829")
------------------------- OBJECT DEFINITIONS ---------------------
-- helper function for objects
function getClosestColorToTerrainMaterial(terrainValue)
if terrainValue == 1 then return BrickColor.new("Bright green")
elseif terrainValue == 2 then return BrickColor.new("Bright yellow")
elseif terrainValue == 3 then return BrickColor.new("Bright red")
elseif terrainValue == 4 then return BrickColor.new("Sand red")
elseif terrainValue == 5 then return BrickColor.new("Black")
elseif terrainValue == 6 then return BrickColor.new("Dark stone grey")
elseif terrainValue == 7 then return BrickColor.new("Sand blue")
elseif terrainValue == 8 then return BrickColor.new("Deep orange")
elseif terrainValue == 9 then return BrickColor.new("Dark orange")
elseif terrainValue == 10 then return BrickColor.new("Reddish brown")
elseif terrainValue == 11 then return BrickColor.new("Light orange")
elseif terrainValue == 12 then return BrickColor.new("Light stone grey")
elseif terrainValue == 13 then return BrickColor.new("Sand green")
elseif terrainValue == 14 then return BrickColor.new("Medium stone grey")
elseif terrainValue == 15 then return BrickColor.new("Really red")
elseif terrainValue == 16 then return BrickColor.new("Really blue")
elseif terrainValue == 17 then return BrickColor.new("Bright blue")
else return BrickColor.new("Bright green")
end
end
-- Used to create a highlighter that follows the mouse.
-- It is a class mouse highlighter. To use, call MouseHighlighter.Create(mouse) where mouse is the mouse to track.
MouseHighlighter = {}
MouseHighlighter.__index = MouseHighlighter
-- Create a mouse movement highlighter.
-- plugin - Plugin to get the mouse from.
function MouseHighlighter.Create(mouseUse)
local highlighter = {}
local mouse = mouseUse
highlighter.OnClicked = nil
highlighter.mouseDown = false
-- Store the last point used to draw.
highlighter.lastUsedPoint = nil
-- Will hold a part the highlighter will be attached to. This will be moved where the mouse is.
highlighter.selectionPart = nil
-- Hook the mouse up to check for movement.
mouse.Move:connect(function() MouseMoved() end)
mouse.Button1Down:connect(function() highlighter.mouseDown = true end)
mouse.Button1Up:connect(function() highlighter.mouseDown = false
end)
-- Create the part that the highlighter will be attached to.
highlighter.selectionPart = Instance.new("Part")
highlighter.selectionPart.Name = "SelectionPart"
highlighter.selectionPart.Archivable = false
highlighter.selectionPart.Transparency = 0.5
highlighter.selectionPart.Anchored = true
highlighter.selectionPart.Locked = true
highlighter.selectionPart.CanCollide = false
highlighter.selectionPart.FormFactor = Enum.FormFactor.Custom
highlighter.selectionPart.Size = Vector3.new(4,4,4)
highlighter.selectionPart.BottomSurface = 0
highlighter.selectionPart.TopSurface = 0
highlighter.selectionPart.BrickColor = getClosestColorToTerrainMaterial(currentMaterial)
highlighter.selectionPart.Parent = game.Workspace
local billboardGui = Instance.new("BillboardGui",highlighter.selectionPart)
billboardGui.Size = UDim2.new(5,0,5,0)
billboardGui.StudsOffset = Vector3.new(0,2.5,0)
local imageLabel = Instance.new("ImageLabel",billboardGui)
imageLabel.BackgroundTransparency = 1
imageLabel.Size = UDim2.new(1,0,1,0)
imageLabel.Position = UDim2.new(-0.35,0,-0.5,0)
imageLabel.Image = "http://www.roblox.com/asset/?id=82741829"
local lastTweenChange = nil
function startTween()
while tweenUp or tweenDown do
wait(0.2)
end
lastTweenChange = tick()
delay(0,function ( )
local thisTweenStamp = lastTweenChange
local tweenDown, tweenUp = nil
tweenDown = function()
if imageLabel and imageLabel:IsDescendantOf(game.Workspace) and thisTweenStamp == lastTweenChange then
imageLabel:TweenPosition(UDim2.new(-0.35,0,-0.5,0), Enum.EasingDirection.In, Enum.EasingStyle.Quad,0.4,true,tweenUp)
end
end
tweenUp = function()
if imageLabel and imageLabel:IsDescendantOf(game.Workspace) and thisTweenStamp == lastTweenChange then
imageLabel:TweenPosition(UDim2.new(-0.35,0,-0.7,0), Enum.EasingDirection.Out, Enum.EasingStyle.Sine,0.4,true,tweenDown)
end
end
tweenUp()
end)
end
function stopTween()
lastTweenChange = tick()
end
mouse.TargetFilter = highlighter.selectionPart
setmetatable(highlighter, MouseHighlighter)
-- Function to call when the mouse has moved. Updates where to display the highlighter.
function MouseMoved()
if on and not processing then
UpdatePosition(mouse.Hit)
end
end
-- Update where the highlighter is displayed.
-- position - Where to display the highlighter, in world space.
function UpdatePosition(position)
if not position then
return
end
if not mouse.Target then
stopTween()
highlighter.selectionPart.Parent = nil
return
end
if highlighter.selectionPart.Parent ~= game.Workspace then
highlighter.selectionPart.Parent = game.Workspace
startTween()
end
local vectorPos = Vector3.new(position.x,position.y,position.z)
local cellPos = WorldToCellPreferEmpty(c, vectorPos)
local regionToSelect = nil
local cellMaterial = GetCell(c, cellPos.x,cellPos.y,cellPos.z)
local y = cellPos.y
-- only select empty cells
while cellMaterial ~= emptyMaterial do
y = y + 1
cellMaterial = GetCell(c, cellPos.x,y,cellPos.z)
end
cellPos = Vector3.new(cellPos.x,y,cellPos.z)
local lowVec = CellCenterToWorld(c, cellPos.x , cellPos.y - 1, cellPos.z)
local highVec = CellCenterToWorld(c, cellPos.x, cellPos.y + 1, cellPos.z)
regionToSelect = Region3.new(lowVec, highVec)
highlighter.selectionPart.CFrame = regionToSelect.CFrame
if nil ~= highlighter.OnClicked and highlighter.mouseDown then
if nil == highlighter.lastUsedPoint then
highlighter.lastUsedPoint = WorldToCellPreferEmpty(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
else
cellPos = WorldToCellPreferEmpty(c, Vector3.new(mouse.Hit.x, mouse.Hit.y, mouse.Hit.z))
holdChange = cellPos - highlighter.lastUsedPoint
-- Require terrain.
if 0 == GetCell(c, cellPos.X, cellPos.Y, cellPos.Z).Value then
return
else
highlighter.lastUsedPoint = cellPos
end
end
end
end
return highlighter
end
function MouseHighlighter:SetMaterial(newMaterial)
self.selectionPart.BrickColor = getClosestColorToTerrainMaterial(newMaterial)
end
function MouseHighlighter:GetPosition()
local position = self.selectionPart.CFrame.p
return WorldToCellPreferEmpty(c,position)
end
-- Hide the highlighter.
function MouseHighlighter:DisablePreview()
stopTween()
self.selectionPart.Parent = nil
end
-- Show the highlighter.
function MouseHighlighter:EnablePreview()
self.selectionPart.Parent = game.Workspace
startTween()
end
-- Create the mouse movement highlighter.
local mouseHighlighter = MouseHighlighter.Create(mouse)
mouseHighlighter:DisablePreview()
-- Used to create a highlighter.
-- A highlighter is a open, rectuangular area displayed in 3D.
ConfirmationPopup = {}
ConfirmationPopup.__index = ConfirmationPopup
-- Create a standard text label. Use this for all lables in the popup so it is easy to standardize.
-- labelName - What to set the text label name as.
-- pos - Where to position the label. Should be of type UDim2.
-- size - How large to make the label. Should be of type UDim2.
-- text - Text to display.
-- parent - What to set the text parent as.
-- Return:
-- Value is the created label.
function CreateStandardLabel(labelName,
pos,
size,
text,
parent)
local label = Instance.new("TextLabel", parent)
label.Name = labelName
label.Position = pos
label.Size = size
label.Text = text
label.TextColor3 = Color3.new(0.95, 0.95, 0.95)
label.Font = Enum.Font.ArialBold
label.FontSize = Enum.FontSize.Size14
label.TextXAlignment = Enum.TextXAlignment.Left
label.BackgroundTransparency = 1
label.Parent = parent
return label
end
-- Keep common button properties here to make it easer to change them all at once.
-- These are the default properties to use for a button.
buttonTextColor = Color3.new(1, 1, 1);
buttonFont = Enum.Font.ArialBold;
buttonFontSize = Enum.FontSize.Size18;
-- Create a standard dropdown. Use this for all dropdowns in the popup so it is easy to standardize.
-- name - What to use.
-- pos - Where to position the button. Should be of type UDim2.
-- text - Text to show in the button.
-- funcOnPress - Function to run when the button is pressed.
-- parent - What to set the parent as.
-- Return:
-- button - The button gui.
function CreateStandardButton(name,
pos,
text,
funcOnPress,
parent,
size)
button = Instance.new("TextButton", parent)
button.Name = name
button.Position = pos
button.Size = UDim2.new(0,120,0,40)
button.Text = text
if size then
button.Size = size
end
button.Style = Enum.ButtonStyle.RobloxButton
button.TextColor3 = buttonTextColor
button.Font = buttonFont
button.FontSize = buttonFontSize
button.MouseButton1Click:connect(funcOnPress)
return button
end
-- Create a confirmation popup.
--
-- confirmText - What to display in the popup.
-- textOffset - Offset to position text at.
-- confirmFunction - Function to run on confirmation.
-- declineFunction - Function to run when declining.
--
-- Return:
-- Value a table with confirmation gui and options.
function ConfirmationPopup.Create(confirmText,
confirmSmallText,
confirmButtonText,
declineButtonText,
confirmFunction,
declineFunction)
local popup = {}
popup.confirmButton = nil -- Hold the button to confirm a choice.
popup.declineButton = nil -- Hold the button to decline a choice.
popup.confirmationFrame = nil -- Hold the conformation frame.
popup.confirmationText = nil -- Hold the text label to display the conformation message.
popup.confirmationHelpText = nil -- Hold the text label to display the conformation message help.
popup.confirmationFrame = Instance.new("Frame",screenGui)
popup.confirmationFrame.Name = "ConfirmationFrame"
popup.confirmationFrame.Size = UDim2.new(0, 280, 0, 160)
popup.confirmationFrame.Position = UDim2.new(.5, -popup.confirmationFrame.Size.X.Offset/2, 0.5, -popup.confirmationFrame.Size.Y.Offset/2)
popup.confirmationFrame.Style = Enum.FrameStyle.RobloxRound
popup.confirmLabel = CreateStandardLabel("ConfirmLabel", UDim2.new(0,0,0,15), UDim2.new(1, 0, 0, 24), confirmText, popup.confirmationFrame)
popup.confirmLabel.FontSize = Enum.FontSize.Size18
popup.confirmLabel.TextXAlignment = Enum.TextXAlignment.Center
popup.confirmationHelpText = CreateStandardLabel("ConfirmSmallLabel", UDim2.new(0,0,0,40), UDim2.new(1, 0, 0, 28), confirmSmallText, popup.confirmationFrame)
popup.confirmationHelpText.FontSize = Enum.FontSize.Size14
popup.confirmationHelpText.TextWrap = true
popup.confirmationHelpText.Font = Enum.Font.Arial
popup.confirmationHelpText.TextXAlignment = Enum.TextXAlignment.Center
-- Confirm
popup.confirmButton = CreateStandardButton("ConfirmButton",
UDim2.new(0.5, -120, 1, -50),
confirmButtonText,
confirmFunction,
popup.confirmationFrame)
-- Decline
popup.declineButton = CreateStandardButton("DeclineButton",
UDim2.new(0.5, 0, 1, -50),
declineButtonText,
declineFunction,
popup.confirmationFrame)
setmetatable(popup, ConfirmationPopup)
return popup
end
-- Clear the popup, free up assets.
function ConfirmationPopup:Clear()
if nil ~= self.confirmButton then
self.confirmButton.Parent = nil
end
if nil ~= self.declineButton then
self.declineButton.Parent = nil
end
if nil ~= self.confirmationFrame then
self.confirmationFrame.Parent = nil
end
if nil ~= self.confirmLabel then
self.confirmLabel.Parent = nil
end
self.confirmButton = nil
self.declineButton = nil
self.conformationFrame = nil
self.conformText = nil
end
-----------------------
--FUNCTION DEFINITIONS-
-----------------------
local floodFill = function ( x,y,z )
LoadProgressBar("Processing")
breadthFill(x,y,z)
UnloadProgressBar()
game:GetService("ChangeHistoryService"): SetWaypoint("FloodFill")
end
-- Function used when we try and flood fill. Prompts the user first.
-- Will not show if disabled or terrain is being processed.
function ConfirmFloodFill(x,y,z)
-- Only do if something isn't already being processed.
if not processing then
processing = true
if nil == ConfirmationPopupObject then
ConfirmationPopupObject = ConfirmationPopup.Create("Flood Fill At Selected Location?",
"This operation may take some time.",
"Fill",
"Cancel",
function()
ConfirmationPopupObject:Clear()
ConfirmationPopupObject = nil
floodFill(x,y,z)
ConfirmationPopupObject = nil
end,
function()
ConfirmationPopupObject:Clear()
ConfirmationPopupObject = nil
processing = false
end)
end
end
end
function mouseDown(mouse)
if on and mouse.Target == game.Workspace.Terrain then
startCell = mouseHighlighter:GetPosition()
end
end
function mouseUp(mouse)
if processing then return end
local upCell = mouseHighlighter:GetPosition()
if startCell == upCell then
ConfirmFloodFill(upCell.x,upCell.y,upCell.z)
end
end
function getMaterial( x,y,z )
local material = GetCell(c,x,y,z)
return material
end
function startLoadingFrame( )
end
-- Load the progress bar to display when drawing a river.
-- text - Text to display.
function LoadProgressBar(text)
processing = true
-- Start the progress bar.
progressBar, setProgressFunc, cancelEvent = RbxGui.CreateLoadingFrame(text)
progressBar.Position = UDim2.new(.5, -progressBar.Size.X.Offset/2, 0, 15)
progressBar.Parent = screenGui
local loadingPercent = progressBar:FindFirstChild("LoadingPercent",true)
if loadingPercent then
loadingPercent.Parent = nil
end
local loadingBar = progressBar:FindFirstChild("LoadingBar",true)
if loadingBar then
loadingBar.Parent = nil
end
local cancelButton = progressBar:FindFirstChild("CancelButton",true)
if cancelButton then
cancelButton.Text = "Stop"
end
cancelEvent.Event:connect(function(arguments)
processing = false
spin = false
end)
local spinnerFrame = Instance.new("Frame",progressBar)
spinnerFrame.Name = "Spinner"
spinnerFrame.Size = UDim2.new(0, 80, 0, 80)
spinnerFrame.Position = UDim2.new(0.5, -40, 0.5, -55)
spinnerFrame.BackgroundTransparency = 1
local spinnerIcons = {}
local spinnerNum = 1
while spinnerNum <= 8 do
local spinnerImage = Instance.new("ImageLabel")
spinnerImage.Name = "Spinner"..spinnerNum
spinnerImage.Size = UDim2.new(0, 16, 0, 16)
spinnerImage.Position = UDim2.new(.5+.3*math.cos(math.rad(45*spinnerNum)), -8, .5+.3*math.sin(math.rad(45*spinnerNum)), -8)
spinnerImage.BackgroundTransparency = 1
spinnerImage.Image = "http://www.roblox.com/Asset/?id=45880710"
spinnerImage.Parent = spinnerFrame
spinnerIcons[spinnerNum] = spinnerImage
spinnerNum = spinnerNum + 1
end
--Make it spin
delay(0, function()
local spinPos = 0
while processing do
local pos = 0
while pos < 8 do
if pos == spinPos or pos == ((spinPos+1)%8) then
spinnerIcons[pos+1].Image = "http://www.roblox.com/Asset/?id=45880668"
else
spinnerIcons[pos+1].Image = "http://www.roblox.com/Asset/?id=45880710"
end
pos = pos + 1
end
spinPos = (spinPos + 1) % 8
wait(0.2)
end
end)
end
-- Unload the progress bar.
function UnloadProgressBar()
processing = false
if progressBar then
progressBar.Parent = nil
progressBar = nil
end
if setProgressFunc then
setProgressFunc = nil
end
if cancelEvent then
cancelEvent = nil
end
end
function breadthFill( x,y,z )
local yDepthChecks = doBreadthFill(x,y,z)
while yDepthChecks and #yDepthChecks > 0 do
local newYChecks = {}
for i = 1, #yDepthChecks do
local currYDepthChecks = doBreadthFill(yDepthChecks[i].xPos,yDepthChecks[i].yPos,yDepthChecks[i].zPos)
if not processing then
return
end
if currYDepthChecks and #currYDepthChecks > 0 then
for i = 1, #currYDepthChecks do
table.insert(newYChecks,{xPos = currYDepthChecks[i].xPos, yPos = currYDepthChecks[i].yPos, zPos = currYDepthChecks[i].zPos})
end
end
end
yDepthChecks = newYChecks
end
end
function doBreadthFill(x,y,z)
if getMaterial(x,y,z) ~= emptyMaterial then
return
end
local yDepthChecks = {}
local cellsToCheck = breadthFillHelper(x,y,z,yDepthChecks)
local count = 0
while cellsToCheck and #cellsToCheck > 0 do
local cellCheckQueue = {}
for i = 1, #cellsToCheck do
if not processing then
return
end
count = count + 1
local newCellsToCheck = breadthFillHelper(cellsToCheck[i].xPos,cellsToCheck[i].yPos,cellsToCheck[i].zPos,yDepthChecks)
if newCellsToCheck and #newCellsToCheck > 0 then
for i = 1, #newCellsToCheck do
table.insert(cellCheckQueue,{xPos = newCellsToCheck[i].xPos, yPos = newCellsToCheck[i].yPos, zPos = newCellsToCheck[i].zPos})
end
end
if count >= 3000 then
wait()
count = 0
end
end
cellsToCheck = cellCheckQueue
end
return yDepthChecks
end
function cellInTerrain( x,y,z )
if x < c.MaxExtents.Min.X or x >= c.MaxExtents.Max.X then
return false
end
if y < c.MaxExtents.Min.Y or y >= c.MaxExtents.Max.Y then
return false
end
if z < c.MaxExtents.Min.Z or z >= c.MaxExtents.Max.Z then
return false
end
return true
end
function breadthFillHelper(x,y,z,yDepthChecks)
-- first, lets try and fill this cell
if cellInTerrain( x,y,z ) and getMaterial( x, y, z) == emptyMaterial then
SetCell(c,x,y,z,currentMaterial,0,0)
end
local cellsToFill = {}
if cellInTerrain( x + 1,y,z ) and getMaterial( x + 1, y, z) == emptyMaterial then
table.insert(cellsToFill,{xPos = x + 1, yPos = y, zPos = z})
end
if cellInTerrain( x - 1,y,z ) and getMaterial( x - 1, y, z) == emptyMaterial then
table.insert(cellsToFill,{xPos = x - 1, yPos = y, zPos = z})
end
if cellInTerrain( x,y,z + 1) and getMaterial( x, y, z + 1) == emptyMaterial then
table.insert(cellsToFill,{xPos = x, yPos = y, zPos = z + 1})
end
if cellInTerrain( x,y,z - 1) and getMaterial( x, y, z - 1) == emptyMaterial then
table.insert(cellsToFill,{xPos = x, yPos = y, zPos = z - 1})
end
if cellInTerrain( x,y-1,z) and getMaterial( x, y-1, z) == emptyMaterial then
table.insert(yDepthChecks,{xPos = x, yPos = y - 1, zPos = z})
end
for i = 1, #cellsToFill do
SetCell(c,cellsToFill[i].xPos,cellsToFill[i].yPos,cellsToFill[i].zPos,currentMaterial,0,0)
end
if #cellsToFill <= 0 then
return nil
end
return cellsToFill
end
function On()
if not c then
return
end
if self then
self:Activate(true)
end
if toolbarbutton then
toolbarbutton:SetActive(true)
end
if dragBar then
dragBar.Visible = true
end
on = true
end
function Off()
if toolbarbutton then
toolbarbutton:SetActive(false)
end
if mouseHighlighter then
mouseHighlighter:DisablePreview()
end
if dragBar then
dragBar.Visible = false
end
on = false
end
mouseHighlighter.OnClicked = mouseUp
------
--GUI-
------
screenGui = Instance.new("ScreenGui", game:GetService("CoreGui"))
screenGui.Name = "FloodFillGui"
dragBar, containerFrame, helpFrame, closeEvent = RbxGui.CreatePluginFrame("Flood Fill",UDim2.new(0,163,0,195),UDim2.new(0,0,0,0),false,screenGui)
dragBar.Visible = false
helpFrame.Size = UDim2.new(0,200,0,190)
local textHelp = Instance.new("TextLabel",helpFrame)
textHelp.Name = "TextHelp"
textHelp.Font = Enum.Font.ArialBold
textHelp.FontSize = Enum.FontSize.Size12
textHelp.TextColor3 = Color3.new(1,1,1)
textHelp.Size = UDim2.new(1,-6,1,-6)
textHelp.Position = UDim2.new(0,3,0,3)
textHelp.TextXAlignment = Enum.TextXAlignment.Left
textHelp.TextYAlignment = Enum.TextYAlignment.Top
textHelp.BackgroundTransparency = 1
textHelp.TextWrap = true
textHelp.Text =
[[
Quickly replace empty terrain cells with a selected material. Clicking the mouse will cause any empty terrain cells around the point clicked to be filled with the current material, and will also spread to surrounding empty cells (including any empty cells below, but not above).
Simply click on a different material to fill with that material. The floating paint bucket and cube indicate where filling will start.
]]
closeEvent.Event:connect(function() Off() end)
local terrainSelectorGui, terrainSelected, forceTerrainMaterialSelection = RbxGui.CreateTerrainMaterialSelector(UDim2.new(1, -10, 0, 184),UDim2.new(0, 5, 0, 5))
terrainSelectorGui.Parent = containerFrame
terrainSelectorGui.BackgroundTransparency = 1
terrainSelectorGui.BorderSizePixel = 0
terrainSelected.Event:connect(function ( newMaterial )
currentMaterial = newMaterial
if mouseHighlighter then
mouseHighlighter:SetMaterial(currentMaterial)
end
end)
forceTerrainMaterialSelection(Enum.CellMaterial.Water)
self.Deactivation:connect(function()
Off()
end)
--------------------------
--SUCCESSFUL LOAD MESSAGE-
--------------------------
loaded = true

View File

@@ -0,0 +1,35 @@
while game == nil do
wait(1/30)
end
self = PluginManager():CreatePlugin()
toolbar = self:CreateToolbar("Terrain")
toolbarbutton = toolbar:CreateButton("Convert To Smooth", "Convert To Smooth", "smooth.png")
toolbarbutton.Click:connect(function()
local RbxGui = LoadLibrary("RbxGui")
local g = Instance.new("ScreenGui", game:GetService("CoreGui"))
if not workspace.Terrain.IsSmooth then
if workspace.Terrain:CountCells() > 0 then
local result = nil
local confirm = RbxGui.CreateMessageDialog("Convert To Smooth?",
"You are converting voxel terrain to smooth voxel terrain. Some materials are not supported any more. This action can not be undone. Proceed?",
{{Text="Convert", Function=function() result = true end}, {Text="Cancel", Function=function() result = false end}})
confirm.Parent = g
while result == nil do
wait(0.1)
end
confirm:Destroy()
if not result then
return
end
end
workspace.Terrain:ConvertToSmooth()
end
end)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,245 @@
<?xml version="1.0" encoding="UTF-8" ?>
<StudioAutocomplete>
<LuaLibrary name="math">
<StaticFunction name ="abs" tooltip="number math.abs(x)%1Returns the absolute value of x." />
<StaticFunction name ="acos" tooltip="number math.acos(x)%1Returns the arc cosine of x (in radians)." />
<StaticFunction name ="asin" tooltip="number math.asin(x)%1Returns the arc sine of x (in radians)." />
<StaticFunction name ="atan" tooltip="number math.atan(x)%1Returns the arc tangent of x (in radians)." />
<StaticFunction name ="atan2" tooltip="number math.atan2(y, x)%1Returns the arc tangent of y/x (in radians), but uses the signs of both parameters to find the quadrant of the result. (It also handles correctly the case of x being zero.)" />
<StaticFunction name ="ceil" tooltip="number math.ceil(x)%1Returns the smallest integer larger than or equal to x." />
<StaticFunction name ="cos" tooltip="number math.cos(x)%1Returns the cosine of x (assumed to be in radians)." />
<StaticFunction name ="cosh" tooltip="number math.cosh(x)%1Returns the hyperbolic cosine of x." />
<StaticFunction name ="deg" tooltip="number math.deg(x)%1Returns the angle x (given in radians) in degrees." />
<StaticFunction name ="exp" tooltip="number math.exp(x)%1Returns the value e^x." />
<StaticFunction name ="floor" tooltip="number math.floor(x)%1Returns the largest integer smaller than or equal to x." />
<StaticFunction name ="fmod" tooltip="number math.fmod(x, y)%1Returns the remainder of the division of x by y that rounds the quotient towards zero." />
<StaticFunction name ="frexp" tooltip="number math.frexp(x)%1Returns m and e such that x = m2^e, e is an integer and the absolute value of m is in the range [0.5, 1) (or zero when x is zero)." />
<StaticFunction name ="ldexp" tooltip="number math.ldexp(x, e)%1Returns m2^e (e should be an integer)." />
<StaticFunction name ="log" tooltip="number math.log(x)%1Returns the natural logarithm of x." />
<StaticFunction name ="log10" tooltip="number math.log10(x)%1Returns the base-10 logarithm of x." />
<StaticFunction name ="max" tooltip="number math.max(x, ...)%1Returns the maximum value among its arguments." />
<StaticFunction name ="min" tooltip="number math.min(x, ...)%1Returns the minimum value among its arguments." />
<StaticFunction name ="modf" tooltip="number math.modf(x)%1Returns two numbers, the integral part of x and the fractional part of x." />
<StaticFunction name ="noise" tooltip="number math.noise(x [, y [, z]])%1Returns a value between -0.5 and 0.5 generated from its arguments" />
<StaticFunction name ="pow" tooltip="number math.pow(x, y)%1Returns x^y. (You can also use the expression x^y to compute this value.)" />
<StaticFunction name ="rad" tooltip="number math.rad(x)%1Returns the angle x (given in degrees) in radians." />
<StaticFunction name ="random" tooltip="number math.random([m [, n]])%1This function is an interface to the simple pseudo-random generator function rand provided by ANSI C. (No guarantees can be given for its statistical properties.)%1%1When called without arguments, returns a uniform pseudo-random real number in the range [0,1). When called with an integer number m, math.random returns a uniform%1pseudo-random integer in the range [1, m]. When called with two integer numbers m and n, math.random returns a uniform pseudo-random integer in the range [m, n]." />
<StaticFunction name ="randomseed" tooltip="number math.randomseed(x)%1Sets x as the seed for the pseudo-random generator: equal seeds produce equal sequences of numbers." />
<StaticFunction name ="sin" tooltip="number math.sin(x)%1Returns the sine of x (assumed to be in radians)." />
<StaticFunction name ="sinh" tooltip="number math.sinh(x)%1Returns the hyperbolic sine of x." />
<StaticFunction name ="sqrt" tooltip="number math.sqrt(x)%1Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)" />
<StaticFunction name ="tan" tooltip="number math.tan(x)%1Returns the tangent of x (assumed to be in radians)." />
<StaticFunction name ="tanh" tooltip="number math.tanh(x)%1Returns the hyperbolic tangent of x." />
<StaticProperty name="huge" tooltip="The value HUGE_VAL, a value larger than or equal to any other numerical value."/>
<StaticProperty name ="pi" tooltip="The value of pi."/>
</LuaLibrary>
<LuaLibrary name="string">
<StaticFunction name="byte" tooltip="string string.byte(s[,i[,j]])%1Returns the internal numerical codes of the characters s[i], s[i+1], ..., s[j]. The default value for i is 1; the default value for j is i. These indices are corrected following the same rules of function string.sub."/>
<StaticFunction name="char" tooltip="string string.char(...)%1Receives zero or more integers. Returns a string with length equal to the number of arguments, in which each character has the internal numerical code equal to its corresponding argument."/>
<StaticFunction name="dump" tooltip="string string.dump(function)%1Returns a string containing a binary representation of the given function, so that a later load on this string returns a copy of the function (but with new upvalues)."/>
<StaticFunction name="find" tooltip="number string.find(s, pattern [, init [, plain]])%1Looks for the first match of pattern in the string s. If it finds a match, then find returns the indices of s where this occurrence starts and ends; otherwise, it returns nil. A third, optional numerical argument init specifies where to start the search; its default value is 1 and can be negative. A value of true as a fourth, optional argument plain turns off the pattern matching facilities, so the function does a plain 'find='' substring=''' operation"/>
<StaticFunction name="format" tooltip="string string.format(formatstring, ...)%1Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string)."/>
<StaticFunction name="gmatch" tooltip="function string.gmatch(s, pattern)%1Returns an iterator function that, each time it is called, returns the next captures from pattern over the string s."/>
<StaticFunction name="gsub" tooltip="string string.gsub(s, pattern, repl [, n])%1Returns a copy of s in which all (or the first n, if given) occurrences of the pattern have been replaced by a replacement string specified by repl, which can be a string, a table, or a function. gsub also returns, as its second value, the total number of matches that occurred."/>
<StaticFunction name="len" tooltip="number string.len(s)%1Receives a string and returns its length."/>
<StaticFunction name="lower" tooltip="string string.lower(s)%1Receives a string and returns a copy of this string with all uppercase letters changed to lowercase."/>
<StaticFunction name="rep" tooltip="string string.rep(s, n [, sep])%1Returns a string that is the concatenation of n copies of the string s separated by the string sep."/>
<StaticFunction name="reverse" tooltip="string string.reverse(s)%1Returns a string that is the string s reversed."/>
<StaticFunction name="sub" tooltip="string string.sub(s, i [, j])%1Returns the substring of s that starts at i and continues until j; i and j can be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). "/>
<StaticFunction name="upper" tooltip="string string.upper(s)%1Receives a string and returns a copy of this string with all lowercase letters changed to uppercase. All other characters are left unchanged."/>
</LuaLibrary>
<LuaLibrary name="table">
<StaticFunction name="concat" tooltip="string table.concat(list [, sep [, i [, j]]])%1Given a list where all elements are strings or numbers, returns the string list[i]..sep..list[i+1] ... sep..list[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is #list. If i is greater than j, returns the empty string."/>
<StaticFunction name="foreach" tooltip="void table.foreach(table, f)%1Apply the function f to the elements of the table passed" />
<StaticFunction name="foreachi" tooltip="void table.foreachi(table, f)%1This is similar to table.foreach() except that index-value pairs are passed, not key-value pairs." />
<StaticFunction name="getn" tooltip="number table.getn(table)%1Returns the number of elements in the table passed" />
<StaticFunction name="insert" tooltip="void table.insert(list, [pos,] value)%1Inserts element value at position pos in list, shifting up the elements list[pos], list[pos+1], ..., list[#list]. The default value for pos is #list+1, so that a call table.insert(t,x) inserts x at the end of list t."/>
<StaticFunction name="remove" tooltip="value table.remove(list [, pos])%1Removes from list the element at position pos, returning the value of the removed element. When pos is an integer between 1 and #list, it shifts down the elements list[pos+1], list[pos+2], ..., list[#list] and erases element list[#list]; The index pos can also be 0 when #list is 0, or #list + 1; in those cases, the function erases the element list[pos]."/>
<StaticFunction name="sort" tooltip="bool table.sort(list [, comp])%1Sorts list elements in a given order, in-place, from list[1] to list[#list]. If comp is given, then it must be a function that receives two list elements and returns true when the first element must come before the second in the final order (so that not comp(list[i+1],list[i]) will be true after the sort). If comp is not given, then the standard Lua operator [less than] is used instead."/>
</LuaLibrary>
<LuaLibrary name="coroutine">
<StaticFunction name="create" tooltip="thread coroutine.create(f)%1Creates a new coroutine, with body f. f must be a Lua function."/>
<StaticFunction name="resume" tooltip="bool coroutine.resume(co [, val1, ...])%1Starts or continues the execution of coroutine co. The first time you resume a coroutine, it starts running its body. The values val1, ... are passed as the arguments to the body function. If the coroutine has yielded, resume restarts it; the values val1, ... are passed as the results from the yield. If the coroutine runs without any errors, resume returns true plus any values passed to yield (if the coroutine yields) or any values returned by the body function (if the coroutine terminates). If there is any error, resume returns false plus the error message."/>
<StaticFunction name="running" tooltip="thread coroutine.running()%1Returns the running coroutine plus a boolean, true when the running coroutine is the main one."/>
<StaticFunction name="status" tooltip="string coroutine.status(co)%1Returns the status of coroutine co, as a string: 'running', if the coroutine is running (that is, it called status); 'suspended', if the coroutine is suspended in a call to yield, or if it has not started running yet; 'normal' if the coroutine is active but not running (that is, it has resumed another coroutine); and 'dead' if the coroutine has finished its body function, or if it has stopped with an error."/>
<StaticFunction name="wrap" tooltip="function coroutine.wrap(f)%1Creates a new coroutine, with body f. f must be a Lua function. Returns a function that resumes the coroutine each time it is called. Any arguments passed to the function behave as the extra arguments to resume. Returns the same values returned by resume, except the first boolean. In case of error, propagates the error."/>
<StaticFunction name="yield" tooltip="void coroutine.yield(...)%1Suspends the execution of the calling coroutine. Any arguments to yield are passed as extra results to resume."/>
</LuaLibrary>
<ItemStruct name="Instance">
<StaticFunction name="new" tooltip="Instance Instance.new(val [, parent])%1Creates an new object of type val. The parent argument is optional; If it is supplied, the object will be parented to that object"/>
</ItemStruct>
<LuaLibrary name="os">
<StaticFunction name="time" tooltip="number os.time()%1Returns the number of seconds since the epoch (1 January 1970, 00:00:00)" />
<StaticFunction name="difftime" tooltip="number os.difftime(number t1, number t2)%1Returns the number of seconds from t1 to t2" />
</LuaLibrary>
<ItemStruct name="Vector2">
<StaticFunction name="new" tooltip="Vector2 Vector2.new(x, y)%1Creates a new Vector2 using ordinates x and y"/>
<Property name="X" tooltip="Number Vector2.X%1The x-coordinate"/>
<Property name="Y" tooltip="Number Vector2.Y%1The y-coordinate"/>
<Property name="unit" tooltip="Vector2 Vector2.unit%1A normalized copy of the vector"/>
<Property name="magnitude" tooltip="Number Vector2.magnitudeThe length of the vector"/>
<Function name="lerp" tooltip="Vector2 Vector2:lerp(Vector2 v, number alpha)%1Returns a Vector2 linearly interpolated between this Vector2 and v by the fraction alpha"/>
</ItemStruct>
<ItemStruct name="Vector2int16">
<StaticFunction name="new" tooltip="Vector2int16 Vector2int16.new(x, y)%1Creates a new Vector2int16 using ordinates x and y. Similar to Vector2, but uses integral coordinates"/>
<Property name="X" tooltip="Number Vector2int16.X%1The x-coordinate"/>
<Property name="Y" tooltip="Number Vector2int16.Y%1The y-coordinate"/>
</ItemStruct>
<ItemStruct name="Vector3">
<StaticFunction name="new" tooltip="Vector3 Vector3.new(x, y, z)%1Constructs a new Vector3 using coordinates x, y, z." />
<StaticFunction name="FromNormalId" tooltip="Vector3 Vector3.FromNormalID(Enum.NormalId normalId)%1Constructs a new Vector3 in a particular direction." />
<StaticFunction name="FromAxis" tooltip="Vector3 Vector3.FromAxis(Enum.Axis axis)%1Constructs a new Vector3 for a particular axis." />
<Property name="X" tooltip="number Vector3.X%1The x-coordinate" />
<Property name="Y" tooltip="number Vector3.Y%1The y-coordinate" />
<Property name="Z" tooltip="number Vector3.Z%1The z-coordinate" />
<Property name="Unit" tooltip="Vector3 Vector3.Unit%1A normalized copy of the vector - one which has the same direction as the original but a magnitude of 1"/>
<Property name="Magnitude" tooltip="Number Vector3.Magnitude%1The length of the vector"/>
<Function name="Lerp" tooltip="Vector3 Vector3:Lerp(Vector3 goal, number alpha)%1Returns a Vector3 linearly interpolated between this Vector3 and the goal by the fraction alpha"/>
<Function name="Dot" tooltip="number Vector3:Dot(Vector3 other)%1Returns a scalar dot product of the two vectors"/>
<Function name="Cross" tooltip="Vector3 Vector3:Cross(Vector3 other)%1Returns the cross product of the two vectors"/>
<Function name="isClose" tooltip="bool Vector3:isClose(Vector3 other [, number epsilon]%1"/>
</ItemStruct>
<ItemStruct name="Vector3int16">
<StaticFunction name="new" tooltip="Vector3int16 Vector3int16.new(x, y, z)%1Creates a new Vector3int16 using coordinate x, y, z."/>
<Property name="X" tooltip="Number Vector3int16.X%1The x-coordinate" />
<Property name="Y" tooltip="Number Vector3int16.Y%1The y-coordinate" />
<Property name="Z" tooltip="Number Vector3int16.Z%1The z-coordinate" />
</ItemStruct>
<ItemStruct name="CFrame">
<StaticFunction name="new" tooltip="CFrame CFrame.new(number x, number y, number z)%1Creates a CFrame from position (x, y, z) &lt;a href=&#34;http://wiki.roblox.com/index.php/CFrame&#34;&gt;More Info&lt;/a&gt;"/>
<StaticFunction name="fromEulerAnglesXYZ" tooltip="CFrame CFrame.fromEulerAnglesXYZ(number rx, number ry, number rz)%1Creates a rotated CFrame using angles (rx, ry, rz) in radians"/>
<StaticFunction name="Angles" tooltip="CFrame CFrame.Angles(number rx, number ry, number rz)%1Equivalent to fromEulerAnglesXYZ"/>
<StaticFunction name="fromAxisAngle" tooltip="CFrame CFrame.fromAxisAngle(Vector3 v, number r)%1Creates a rotated CFrame from a Unit Vector3 and a rotation in radians"/>
<Property name="p" tooltip="Vector3 CFrame.p%1The 3D position of the CFrame"/>
<Property name="X" tooltip="Number CFrame.X%1The x-coordinate of the position" />
<Property name="Y" tooltip="Number CFrame.Y%1The y-coordinate of the position" />
<Property name="Z" tooltip="Number CFrame.Z%1The z-coordinate of the position" />
<Property name="lookVector" tooltip="Vector3 CFrame.lookVector%1Returns the facing direction"/>
<Function name="inverse" tooltip="CFrame CFrame:inverse()%1Returns the inverse of this CFrame"/>
<Function name="lerp" tooltip="CFrame CFrame:lerp(CFrame goal, float alpha)%1Returns a CFrame interpolated between this CFrame and the goal by the fraction alpha"/>
<Function name="toWorldSpace" tooltip="CFrame CFrame:toWorldSpace(CFrame cf)%1Returns a CFrame transformed from Object to World space. Equivalent to [CFrame * cf]"/>
<Function name="toObjectSpace" tooltip="CFrame CFrame:toObjectSpace(CFrame cf)%1Returns a CFrame transformed from World to Object space. Equivalent to [CFrame:inverse() * cf]"/>
<Function name="pointToWorldSpace" tooltip="Vector3 CFrame:pointToWorldSpace(Vector3 v3)%1Returns a Vector3 transformed from Object to World space. Equivalent to [CFrame * v3]"/>
<Function name="pointToObjectSpace" tooltip="Vector3 CFrame:pointtoObjectSpace(Vector3 v3)%1Returns a Vector3 transformed from World to Object space. Equivalent to [CFrame:inverse() * v3]"/>
<Function name="vectorToWorldSpace" tooltip="Vector3 CFrame:vectorToWorldSpace(Vector3 v3)%1Returns a Vector3 rotated from Object to World space. Equivalent to [(CFrame - CFrame.p) *v3]"/>
<Function name="vectorToObjectSpace" tooltip="Vector3 CFrame:vectorToObjectSpace(Vector3 v3)%1Returns a Vector3 rotated from World to Object space.%1Equivalent to [(CFrame:inverse() - CFrame:inverse().p) * v3]"/>
<Function name="components" tooltip="... CFrame:components()%1Returns the values: x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22"/>
<Function name="toEulerAnglesXYZ" tooltip="... CFrame:toEulerAnglesXYZ()%1Returns approximate angles that could be used to generate CFrame"/>
</ItemStruct>
<ItemStruct name="Region3">
<StaticFunction name="new" tooltip="Region3 Region3.new(Vector3, Vector3)%1Creates a new Region3 out of two Vector3 values."/>
<Property name="CFrame" tooltip="CFrame%1The center location and rotation of the Region3"/>
<Property name="Size" tooltip="Vector3%1The 3D size of the Region3"/>
</ItemStruct>
<ItemStruct name="Region3int16">
<StaticFunction name="new" tooltip="Region3int16 Region3int16.new(Vector3int16, Vector3int16)%1Creates a new Region3int16 out of two Vector3int16 structs"/>
</ItemStruct>
<ItemStruct name="BrickColor">
<StaticFunction name="new" tooltip="BrickColor BrickColor.new(r, g, b)%1Returns a BrickColor from the values r, g and b. &lt;a href=&#34;http://wiki.roblox.com/index.php/BrickColor&#34;&gt;More Info&lt;/a&gt;"/>
<StaticFunction name="palette" tooltip="BrickColor BrickColor.palette(val)%1Returns a BrickColor from val"/>
<StaticFunction name="Random" tooltip="BrickColor BrickColor.Random()%1Returns a random BrickColor"/>
<StaticFunction name="White" tooltip="BrickColor BrickColor.White()%1Returns the BrickColor white"/>
<StaticFunction name="Gray" tooltip="BrickColor BrickColor.Gray()%1Returns the BrickColor Medium stone grey"/>
<StaticFunction name="DarkGray" tooltip="BrickColor BrickColor.DarkGray()%1Returns the BrickColor Dark stone grey" />
<StaticFunction name="Black" tooltip="BrickColor BrickColor.Black()%1Returns the BrickColor Black" />
<StaticFunction name="Red" tooltip="BrickColor BrickColor.Red()%1Returns the BrickColor Bright Red" />
<StaticFunction name="Yellow" tooltip="BrickColor BrickColor.Yellow()%1Returns the BrickColor Bright Yellow" />
<StaticFunction name="Green" tooltip="BrickColor BrickColor.Green()%1Returns the BrickColor Dark Green" />
<StaticFunction name="Blue" tooltip="BrickColor BrickColor.Blue()%1Returns the BrickColor Bright Blue" />
<Property name="Number" tooltip="Number BrickColor.Number%1The unique number that identifies the BrickColor"/>
<Property name="Name" tooltip="String BrickColor.Name%1The name associated with the BrickColor"/>
<Property name="Color" tooltip="Color3 BrickColor.Color%1The Color3 associated with the BrickColor"/>
<Property name="r" tooltip="Number BrickColor.R%1The red component (between 0 and 1)"/>
<Property name="g" tooltip="Number BrickColor.G%1The green component (between 0 and 1)"/>
<Property name="b" tooltip="Number BrickColor.B%1The blue component (between 0 and 1)"/>
</ItemStruct>
<ItemStruct name="Ray">
<StaticFunction name="new" tooltip="Ray Ray.new(Vector3 Origin, Vector3 Direction)%1Creates a new Ray with given Origin and Direction"/>
<Property name="Origin" tooltip="Vector3 Ray.Origin%1The position of the origin"/>
<Property name="Direction" tooltip="Vector3 Ray.Direction%1The direction vector of the ray"/>
<Property name="Unit" tooltip="Ray Ray.Unit%1The Ray with a normalized direction"/>
<Function name="ClosestPoint" tooltip="Vector3 Ray:ClosestPoint(Vector3 point)%1Returns the closest point on the Ray to point. Note Rays are unidirectional"/>
<Function name="Distance" tooltip="Number Ray:Distance(Vector3 point)%1 Returns the distance from point to ClosestPoint(point)"/>
</ItemStruct>
<ItemStruct name="UDim">
<StaticFunction name="new" tooltip="UDim UDim.new(number Scale, number Offset)%1Creates a new UDim from components"/>
<Property name="Scale" tooltip="Number UDim.Scale%1The scale value"/>
<Property name="Offset" tooltip="Number UDim.Offset%1The offset value"/>
</ItemStruct>
<ItemStruct name="UDim2">
<StaticFunction name="new" tooltip="UDim2 UDim2.new(Number XScale, Number XOffset, Number YScale, Number YOffset)%1"/>
<Property name="X" tooltip="The x dimension scale and offset" />
<Property name="Y" tooltip="The y dimension scale and offset" />
</ItemStruct>
<ItemStruct name="Color3">
<StaticFunction name="new" tooltip="Color3 Color3.new(r, g, b)%1Returns a Color3 from the values r, g and b. &lt;a href=&#34;http://wiki.roblox.com/index.php/Color3&#34;&gt;More Info&lt;/a&gt;"/>
<Property name="r" tooltip="Number Color3.r%1The red value of the color"/>
<Property name="g" tooltip="Number Color3.g%1The green value of the color"/>
<Property name="b" tooltip="Number Color3.b%1The blue value of the color"/>
</ItemStruct>
<ItemStruct name="ColorSequence">
<StaticFunction name="new" tooltip="ColorSequence ColorSequence.new(Color3 c)%1Creates a sequence of two keypoints with `c` for each value"/>
<StaticFunction name="new" tooltip="ColorSequence ColorSequence.new(Color3 c0, Color3 c1)%1Creates a sequence of two keypoints with `c0` and `c1` as the value"/>
<Property name="Keypoints" tooltip="Array ColorSequence.Keypoints%1An array containing keypoint values for the ColorSequence"/>
</ItemStruct>
<ItemStruct name="NumberSequence">
<StaticFunction name="new" tooltip="NumberSequence NumberSequence.new(float n)%1Creates a sequence of two keypoints with `n` for each value"/>
<StaticFunction name="new" tooltip="NumberSequence NumberSequence.new(float n0, float n1)%1Creates a sequence of two keypoints with `n0` and `n1` as the value"/>
<StaticFunction name="new" tooltip="NumberSequence NumberSequence.new(Array keypoints)%1Creates a sequence from a list of keypoints"/>
<Property name="Keypoints" tooltip="Array NumberSequence.Keypoints%1An array containing keypoint values for the NumberSequence"/>
</ItemStruct>
<ItemStruct name="NumberRange">
<StaticFunction name="new" tooltip="NumberRange NumberRange.new(float value)%1Creates a new NumberRange with the same minimum and maximum"/>
<StaticFunction name="new" tooltip="NumberRange NumberRange.new(float min, float max)%1Creates a new NumberRange with the provided minimum and maximum."/>
<Property name="Min" tooltip="float NumberRange.Min%1Minimum value. Will always be less than or equal to the maximum."/>
<Property name="Max" tooltip="float NumberRange.Max%1Maximum value. Will always be greater than or equal to the minimum."/>
</ItemStruct>
<ItemStruct name="Faces">
<StaticFunction name="new" tooltip="Faces Faces.new(NormalId, NormalId, ...)%1Creates a new Faces using list of faces" />
<Property name="Top" tooltip="bool Faces.Top%1Whether the top face is included" />
<Property name="Bottom" tooltip="bool Faces.Bottom%1Whether the bottom face is included" />
<Property name="Left" tooltip="bool Faces.Left%1Whether the left face is included" />
<Property name="Right" tooltip="bool Faces.Right%1Whether the right face is included" />
<Property name="Back" tooltip="bool Faces.Back%1Whether the back face is included" />
<Property name="Front" tooltip="bool Faces.Front%1Whether the front face is included" />
</ItemStruct>
<ItemStruct name="Axes">
<StaticFunction name="new" tooltip="Axes Axes.new(Axis\NormalId, Axis/NormalId, ...)%1Creates a new Axes using list of axes and/or faces. NormalIds (faces) are converted to the corresponding axes." />
<Property name="X" tooltip="bool Axes.X%1Whether the X axis is enabled" />
<Property name="Y" tooltip="bool Axes.Y%1Whether the Y axis is enabled" />
<Property name="Z" tooltip="bool Axes.Z%1Whether the Z axis is enabled" />
<Property name="Top" tooltip="bool Axes.Top%1Whether the top face is included" />
<Property name="Bottom" tooltip="bool Axes.Bottom%1Whether the bottom face is included" />
<Property name="Left" tooltip="bool Axes.Left%1Whether the left face is included" />
<Property name="Right" tooltip="bool Axes.Right%1Whether the right face is included" />
<Property name="Back" tooltip="bool Axes.Back%1Whether the back face is included" />
<Property name="Front" tooltip="bool Axes.Front%1Whether the front face is included" />
</ItemStruct>
<ItemStruct name="ColorSequenceKeypoint">
<StaticFunction name="new" tooltip="ColorSequenceKeypoint ColorSequenceKeypoint.new(float time, Color3 color)%1Creates a keypoint with a specified time and color." />
<Property name="Time" tooltip="float ColorSequenceKeypoint.Time%1The relative time at which the keypoint is located." />
<Property name="Value" tooltip="Color3 ColorSequenceKeypoint.Value%1The Color3 value at the keypoint." />
</ItemStruct>
<ItemStruct name="NumberSequenceKeypoint">
<StaticFunction name="new" tooltip="NumberSequenceKeypoint NumberSequenceKeypoint.new(float time, float value)%1Creates a keypoint with a specified time and value." />
<StaticFunction name="new" tooltip="NumberSequenceKeypoint NumberSequenceKeypoint.new(float time, float value, float envelop)%1Creates a keypoint with a specified time, value, and envelope." />
<Property name="Envelope" tooltip="float NumberSequenceKeypoint.Envelope%1Indicates the amount of variance allowed from the Value. A computed value." />
<Property name="Time" tooltip="float NumberSequenceKeypoint.Time%1The relative time at which the keypoint is positioned." />
</ItemStruct>
<ItemStruct name="Rect">
<StaticFunction name="new" tooltip="Rect Rect.new(min, max)%1Constructs a new Rect with Vector2 min as top left corner and Vector2 max as bottom right corner." />
<Property name="Min" tooltip="Number Rect.Min%1The top-left corner" />
<Property name="Max" tooltip="Number Rect.Max%1The bottom-right corner" />
<Property name="Width" tooltip="Number Rect.Width%1The x width of rect" />
<Property name="Height" tooltip="Number Rect.Height%1The y height of rect"/>
</ItemStruct>
<ItemStruct name="PhysicalProperties">
<StaticFunction name="new" tooltip="PhysicalProperties PhysicalProperties.new(material)%1 Constructs a new PhysicalProperties container from the Enum.Material object." />
<StaticFunction name="new" tooltip="PhysicalProperties PhysicalProperties.new(density, friction, elasticity, frictionWeight, elasticityWeight)%1Constructs a new PhysicalProperties container." />
<Property name="Density" tooltip="Number PhysicalProperties.Density%1Density" />
<Property name="Friction" tooltip="Number PhysicalProperties.Friction%1Friction" />
<Property name="Elasticity" tooltip="Number PhysicalProperties.Elasticity%1Elasticity" />
<Property name="FrictionWeight" tooltip="Number PhysicalProperties.FrictionWeight%1FrictionWeight determines how dominant the object's friction is when interacting with other objects. Default = 1"/>
<Property name="ElasticityWeight" tooltip="Number PhysicalProperties.ElasticityWeight%1ElasticityWeight determins how dominant the object's elasticity is when interacting with other objects. Default = 1"/>
</ItemStruct>
</StudioAutocomplete>

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1015 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Some files were not shown because too many files have changed in this diff Show More