Code works perfectly (imo) just wondering if theres any parts i can optimize / make better
modules decently long, probably better to look through the roblox place
TestPlace.rbxl (52.0 KB)
local GenerationValues = require(script.GenValues)
local FloorInfo= require(script.FloorInfo)
local Useful = require(script.Useful)
local Randomizer = Random.new()
local _FloorsFolder = workspace.Floors
local FloorAssets = game:GetService("ServerStorage").FloorAssets
local RunService = game:GetService('RunService')
local FloorGenTime = .01
-- Math
local random = math.random
local rad = math.rad
local randomNew = Random.new
local Floors = {}
local function RNGd(PathValues, CurrentWeight : number, RngTable)
local CanRoll = {}
local Rng = Random.new()
local Counter = 0
for Path, PathInfo in pairs(PathValues) do
if PathInfo.Weight <= CurrentWeight then
local ChanceMult = {}
local Chance = PathInfo.Chance
local SpareWeight = CurrentWeight - PathInfo.Weight
local Rolls = RngTable.RollsSinceLastRolled[Path]
local MultipleRolls = RngTable.MultipleRolls[Path]
local BaseMullipier = 1
if SpareWeight > 0 then table.insert(ChanceMult, math.clamp(SpareWeight/55,0,2)) end
if Rolls > PathInfo.Pity then table.insert(ChanceMult, Rolls/5) end
if MultipleRolls > 3 then table.insert(ChanceMult, -(MultipleRolls/5)) end
for i, v in ipairs(ChanceMult) do BaseMullipier += v end
BaseMullipier = math.clamp(BaseMullipier, .1, 4)
local ModifiedChance = math.clamp(Chance * BaseMullipier, 0, 100)
CanRoll[Path] = ModifiedChance
end
end
for _, Chance in pairs(CanRoll) do
Counter += Chance
end
local Chosen = Rng:NextNumber(0, Counter)
for Path, Chance in pairs(CanRoll) do
Counter -= Chance
if Chosen > Counter then
return Path
end
end
end
local function PathPlacementCheck(AttachTo : Attachment, AttachFrom : Attachment, AttachmentModel : Model, BoundingBoxPart : Part, Olp : OverlapParams)
for i = 1, 5 do
local BaseOlp = OverlapParams.new()
BaseOlp.FilterType = Enum.RaycastFilterType.Include
BaseOlp.FilterDescendantsInstances = {workspace.Floors}
local PlacementCFrame = AttachTo.WorldCFrame * CFrame.fromOrientation(0, math.rad(90 * (i-1)), 0)
AttachmentModel:PivotTo(PlacementCFrame)
local Check1 = (AttachTo.WorldPosition - AttachFrom.WorldPosition).Magnitude < .01
local OverlappingParts = workspace:GetPartsInPart(BoundingBoxPart, if not Olp then BaseOlp else Olp)
local Check2 = #OverlappingParts == 0
if Check1 and Check2 then
return true
end
end
return false
end
local function WallPlacementCheck(WallAttachment : Attachment, AttachFrom : Attachment, ChosenWall : string, WallPathValues)
if ChosenWall == "openwall" then
WallAttachment.Parent.Parent = nil
return true
elseif WallPathValues[ChosenWall].Instance then
local Wall = WallPathValues[ChosenWall].Instance:Clone()
Wall:PivotTo(WallAttachment.Parent.CFrame)
Wall.Parent = WallAttachment.Parent.Parent
WallAttachment.Parent.Parent = nil
return true
end
end
local function CheckForPathToPathConnection(Floor, TempAttachmentList, AllAttachments) -- Checks If any attachment on the path connections with another paths attachment that is unattached
for Attachment2, _ in pairs(Floor.ConnectableAttachments) do
for _, TempAttachment2 in ipairs(TempAttachmentList) do
if (Attachment2.WorldPosition - TempAttachment2.WorldPosition).Magnitude < .01 then
Floor.ConnectableAttachments[Attachment2] = nil
table.remove(TempAttachmentList, table.find(TempAttachmentList, TempAttachment2))
AllAttachments[Attachment2] = nil
end
end
end
end
local function CheckForPathToWallConnection(Floor, TempAttachmentList, FloorWeight, WallPathValues) -- Checks If any attachment on the path connects to a wall, will roll rng to try and change the wall
local WallConnectionRngTable = Floor.RollTables.WallConnectionRolls
for _, TempAttachment2 in ipairs(TempAttachmentList) do
for _, WallAttachment in ipairs(Floor.ConnectableWallAttachments) do
if (WallAttachment.WorldPosition - TempAttachment2.WorldPosition).Magnitude < 0.01 then
table.remove(TempAttachmentList, table.find(TempAttachmentList, TempAttachment2))
table.remove(Floor.ConnectableWallAttachments, table.find(Floor.ConnectableWallAttachments, WallAttachment))
local ChosenWall = RNGd(WallPathValues, FloorWeight, WallConnectionRngTable)
local Result2 = WallPlacementCheck(WallAttachment, TempAttachment2, ChosenWall, WallPathValues)
if Result2 then
FloorWeight -= WallPathValues[ChosenWall].Cost
for Wall, Num in pairs(WallConnectionRngTable.RollsSinceLastRolled) do
if ChosenWall ~= Wall then
WallConnectionRngTable.RollsSinceLastRolled[Wall] += 1
WallConnectionRngTable.MultipleRolls[Wall] = 0
else
WallConnectionRngTable.RollsSinceLastRolled[Wall] = 0
WallConnectionRngTable.MultipleRolls[Wall] += 1
end
end
end
end
end
end
end
local function CheckForWallToPathConnection(Floor, TempWallAttachmentList, AllAttachments, FloorWeight, WallPathValues)
local WallConnectionRngTable = Floor.RollTables.WallConnectionRolls-- Checks if any wall attachment connects to a path, will roll wall (happens pretty rarely)
for _, TempWallAttachment in ipairs(TempWallAttachmentList) do
for Attachment2, _ in pairs(AllAttachments) do
if (TempWallAttachment.WorldPosition - Attachment2.WorldPosition).Magnitude < 0.01 then
table.remove(TempWallAttachmentList, table.find(TempWallAttachmentList, TempWallAttachment))
AllAttachments[Attachment2] = nil
local ChosenWall = RNGd(WallPathValues, FloorWeight, WallConnectionRngTable)
local Result2 = WallPlacementCheck(TempWallAttachment, Attachment2, ChosenWall, WallPathValues)
if Result2 then
FloorWeight -= WallPathValues[ChosenWall].Cost
for Wall, Num in pairs(WallConnectionRngTable.RollsSinceLastRolled) do
if ChosenWall ~= Wall then
WallConnectionRngTable.RollsSinceLastRolled[Wall] += 1
WallConnectionRngTable.MultipleRolls[Wall] = 0
else
WallConnectionRngTable.RollsSinceLastRolled[Wall] = 0
WallConnectionRngTable.MultipleRolls[Wall] += 1
end
end
end
end
end
end
end
local GenerationModule = {}
GenerationModule.StartGeneration = function()
local NonSpecialFloorNums = 0
for Floor, Info in pairs(FloorInfo) do
local CombinedTable = Useful.CombineTables(Info, {
["GenerationStatus"] = "NotGenerated",
["GenerationPercentage"] = 0,
["CurrentPaths"] = 0,
["ConnectableAttachments"] = {},
["ConnectableWallAttachments"] = {},
})
if not CombinedTable.SpecialFloor then
NonSpecialFloorNums += 1
local FloorFolder = Instance.new("Folder")
FloorFolder.Name = Floor
FloorFolder.Parent = _FloorsFolder
end
Floors[Floor] = CombinedTable
end
for FloorNum = 1, NonSpecialFloorNums do
local FloorNameString = "floor" .. FloorNum
local Floor = Floors[FloorNameString]
if Floor.GenerationStatus == "NotGenerated" then
Floor.GenerationStatus = "Generating"
local PathInfo = GenerationValues[FloorNameString].Paths
local WallConnectionInfo = GenerationValues[FloorNameString].WallConnections
local PathOverlapParams = OverlapParams.new()
PathOverlapParams.FilterType = Enum.RaycastFilterType.Include
PathOverlapParams.FilterDescendantsInstances = {_FloorsFolder}
local TotalPaths = random(Floor.miniumRooms, Floor.maxiumRooms)
local FirstWeightRoll = Floor.FirstWeightRoll
local MinWeightRoll = Floor.MinWeightRoll
local MaxWeightRoll = Floor.MaxWeightRoll
local CurrentRooms = Floor.CurrentRooms
local MaxDistance = Floor.MaxDistance
local FloorFolder = _FloorsFolder:FindFirstChild(FloorNameString)
local FloorWeight = 0
local RollTables = {
["RoomRolls"] = {
["RollsSinceLastRolled"] = {},
["MultipleRolls"] = {}
},
["WallConnectionRolls"] ={
["RollsSinceLastRolled"] = {},
["MultipleRolls"] = {}
},
["WallRolls"] = {
}
}
Floor.RollTables = RollTables
local AllAttachments = {}
local ConnectableAttachments = Floor.ConnectableAttachments
local ConnectableWallAttachments = Floor.ConnectableWallAttachments
local StartTime = os.clock()
local RoomRolls = RollTables.RoomRolls
local WallConnectionRolls = RollTables.WallConnectionRolls
local WallRolls = RollTables.WallRolls
for Path, _ in pairs(PathInfo) do
RoomRolls.RollsSinceLastRolled[Path] = 0
RoomRolls.MultipleRolls[Path] = 0
end
for ConnectionWall, _ in pairs(WallConnectionInfo) do
WallConnectionRolls.RollsSinceLastRolled[ConnectionWall] = 0
WallConnectionRolls.MultipleRolls[ConnectionWall] = 0
end
local StartingPath = PathInfo[RNGd(PathInfo, FirstWeightRoll, RoomRolls)].Instance:Clone()
StartingPath.Parent = FloorFolder
Floor.CurrentPaths += 1
StartingPath:PivotTo(CFrame.new(0,100 * (FloorNum-1), 0))
for Num, Attachment in ipairs(StartingPath:GetDescendants()) do
if Attachment:IsA("Attachment") and Attachment.Name:lower() == "connector" then
ConnectableAttachments[Attachment] = {["FailedAttaches"] = 0}
elseif Attachment:IsA("Attachment") and Attachment.Name:lower() == "wallconnector" then
table.insert(ConnectableWallAttachments, Attachment)
end
end
while task.wait() do
local function Pathical(UseWall : boolean)
local TempAttachmentList = {}
local TempWallAttachmentList = {}
local ChosenPath = RNGd(PathInfo, FloorWeight, RoomRolls)
local PathModel = PathInfo[ChosenPath].Instance:Clone()
for Num, Attachment in ipairs(PathModel:GetDescendants()) do
if Attachment:IsA("Attachment") and Attachment.Name:lower() == "connector" then
table.insert(TempAttachmentList, Attachment)
elseif Attachment:IsA("Attachment") and Attachment.Name:lower() == "wallconnector" then
table.insert(TempWallAttachmentList, Attachment)
end
end
local Cf, Size = PathModel:GetBoundingBox()
local BoundingBox = Useful.BoundBox(Cf, Size, PathModel)
local function PathAttach(Attachment, AttachmentInfo)
for TempAttachmentNum, TempAttachment in ipairs(TempAttachmentList) do
PathModel.PrimaryPart.CFrame = TempAttachment.WorldCFrame
local Result = PathPlacementCheck(Attachment, TempAttachment, PathModel, BoundingBox, PathOverlapParams)
if Result then
ConnectableAttachments[Attachment] = nil
AllAttachments[Attachment] = nil
table.remove(TempAttachmentList, table.find(TempAttachmentList, TempAttachment))
CheckForPathToPathConnection(Floor, TempAttachmentList, AllAttachments)
CheckForPathToWallConnection(Floor, TempAttachmentList, FloorWeight, WallConnectionInfo)
CheckForWallToPathConnection(Floor, TempWallAttachmentList, AllAttachments, FloorWeight, WallConnectionInfo)
for i, v in ipairs(TempAttachmentList) do
if (StartingPath.PrimaryPart.Position - v.WorldPosition).Magnitude < MaxDistance then
ConnectableAttachments[v] = {["FailedAttaches"] = 0}
end
AllAttachments[v] = false
end
for i, v in ipairs(TempWallAttachmentList) do
if (v.WorldPosition - StartingPath.PrimaryPart.Position).Magnitude < MaxDistance then
table.insert(ConnectableWallAttachments, v)
end
end
for Path, Num in pairs(RoomRolls.RollsSinceLastRolled) do
if ChosenPath ~= Path then
RoomRolls.RollsSinceLastRolled[Path] += 1
RoomRolls.MultipleRolls[Path] = 0
else
RoomRolls.RollsSinceLastRolled[Path] = 0
RoomRolls.MultipleRolls[Path] += 1
end
end
return Result, ChosenPath, PathModel
elseif not Result then
AttachmentInfo.FailedAttaches += 1
end
end
return false, ChosenPath, PathModel
end
local function WallAttach(WallAttachment)
for TempAttachmentNum, TempAttachment in ipairs(TempAttachmentList) do
PathModel.PrimaryPart.CFrame = TempAttachment.WorldCFrame
local Result = PathPlacementCheck(WallAttachment, TempAttachment, PathModel, BoundingBox, PathOverlapParams)
if Result then
table.remove(ConnectableWallAttachments, table.find(ConnectableWallAttachments, WallAttachment))
table.remove(TempAttachmentList, table.find(TempAttachmentList, TempAttachment))
CheckForPathToPathConnection(Floor, TempAttachmentList, AllAttachments)
CheckForPathToWallConnection(Floor, TempAttachmentList, FloorWeight, WallConnectionInfo)
CheckForWallToPathConnection(Floor, TempWallAttachmentList, AllAttachments, FloorWeight, WallConnectionInfo)
for i, v in ipairs(TempAttachmentList) do
if (StartingPath.PrimaryPart.Position - v.WorldPosition).Magnitude < MaxDistance then
ConnectableAttachments[v] = {["FailedAttaches"] = 0}
end
AllAttachments[v] = false
end
for i, v in ipairs(TempWallAttachmentList) do
if (v.WorldPosition - StartingPath.PrimaryPart.Position).Magnitude < MaxDistance then
table.insert(ConnectableWallAttachments, v)
end
end
for Path, Num in pairs(RoomRolls.RollsSinceLastRolled) do
if ChosenPath ~= Path then
RoomRolls.RollsSinceLastRolled[Path] += 1
RoomRolls.MultipleRolls[Path] = 0
else
RoomRolls.RollsSinceLastRolled[Path] = 0
RoomRolls.MultipleRolls[Path] += 1
end
end
return Result, ChosenPath, PathModel, WallAttachment
end
end
return false, ChosenPath, PathModel, WallAttachment
end
if UseWall then
local WallAttachment = nil
for _, wAttachment in ipairs(ConnectableWallAttachments) do
task.wait()
local Result, ChosenPath, PathModel, Attachment = WallAttach(wAttachment)
WallAttachment = Attachment
if Result then
return Result, ChosenPath, PathModel, WallAttachment
end
end
return false, ChosenPath, PathModel, WallAttachment
elseif UseWall == nil or not UseWall then
for Attachment, AttachmentInfo in pairs(ConnectableAttachments) do
local Result, ChosenPath, PathModel = PathAttach(Attachment, AttachmentInfo)
if Result then
return Result, ChosenPath, PathModel
end
end
return false, ChosenPath, PathModel
end
end
local function RolledRoom(Result, ChosenPath, PathModel, WallAttachment)
if Result then
Floor.CurrentPaths += 1
PathModel.Parent = FloorFolder
FloorWeight -= PathInfo[ChosenPath].Cost
if WallAttachment then
table.remove(ConnectableWallAttachments, table.find(ConnectableWallAttachments, WallAttachment))
WallAttachment.Parent:Destroy()
end
elseif not Result and Result ~= nil then
PathModel:Destroy()
end
end
RolledRoom(Pathical(false))
local RemainingAttachments = 0
FloorWeight += Randomizer:NextNumber(MinWeightRoll,MaxWeightRoll)
for Attachment, AttachmentInfo in pairs(Floor.ConnectableAttachments) do
RemainingAttachments += 1
if AttachmentInfo.FailedAttaches >= 5 then
Floor.ConnectableAttachments[Attachment] = nil
end
end
print(math.clamp((Floor.CurrentPaths/TotalPaths)*100, 0, 100) .. "% Complete, Current Floor Weight: " .. FloorWeight)
if RemainingAttachments == 0 then
warn("No Remaining attachble attachments, attempting to use wall attachments.")
local Result, ChosenPath, PathModel, WallAttachment = Pathical(true)
RolledRoom(Result, ChosenPath, PathModel, WallAttachment)
if not Result and Result ~= nil then
warn("Unable to attach to any walls, stopping operation.")
break
end
elseif Floor.CurrentPaths >= TotalPaths then
print("Generation Complete, Generated: " .. Floor.CurrentPaths .. "/" .. TotalPaths .. " Rooms | Took " .. os.clock() - StartTime .. " Seconds")
break
end
end
for i, v in pairs(AllAttachments) do
i.Parent.Transparency = 0
end
end
end
end
GenerationModule.__index = GenerationModule
return GenerationModule