222 lines
5.9 KiB
Lua
222 lines
5.9 KiB
Lua
local PlacementManager = {}
|
|
|
|
local ChunkManager = require("./ChunkManager")
|
|
local Util = require("./Util")
|
|
|
|
PlacementManager.ChunkFolder = ChunkManager.ChunkFolder
|
|
|
|
local raycastParams = RaycastParams.new()
|
|
raycastParams.FilterDescendantsInstances = {PlacementManager.ChunkFolder}
|
|
raycastParams.FilterType = Enum.RaycastFilterType.Include
|
|
raycastParams.IgnoreWater = true
|
|
|
|
if _G.SB then return nil end
|
|
_G.SB = true
|
|
|
|
PlacementManager.SelectionBox = script.SelectionBox:Clone()
|
|
PlacementManager.SelectionBox.Name = "$SelectionBox"..(game:GetService("RunService"):IsServer() and "_SERVER" or "")
|
|
PlacementManager.SelectionBox.Parent = game:GetService("Workspace"):FindFirstChildOfClass("Terrain")
|
|
|
|
-- Trash method TODO: Fix this
|
|
local function findParent(i: Instance): Instance
|
|
local f = i:FindFirstAncestorOfClass("Folder")
|
|
local d = i
|
|
repeat
|
|
d = d.Parent
|
|
until d.Parent == f
|
|
return d
|
|
end
|
|
|
|
local Mouse: Mouse = nil
|
|
local lastNormalId: Enum.NormalId? = nil
|
|
|
|
local function normalIdToOffset(normal: Enum.NormalId): Vector3
|
|
if normal == Enum.NormalId.Top then
|
|
return Vector3.new(0, 1, 0)
|
|
elseif normal == Enum.NormalId.Bottom then
|
|
return Vector3.new(0, -1, 0)
|
|
elseif normal == Enum.NormalId.Left then
|
|
return Vector3.new(-1, 0, 0)
|
|
elseif normal == Enum.NormalId.Right then
|
|
return Vector3.new(1, 0, 0)
|
|
elseif normal == Enum.NormalId.Back then
|
|
return Vector3.new(0, 0, 1)
|
|
elseif normal == Enum.NormalId.Front then
|
|
return Vector3.new(0, 0, -1)
|
|
end
|
|
return Vector3.new(0, 0, 0)
|
|
end
|
|
|
|
local function offsetChunkBlock(chunk: Vector3, block: Vector3, offset: Vector3)
|
|
local cx, cy, cz = chunk.X, chunk.Y, chunk.Z
|
|
local bx, by, bz = block.X + offset.X, block.Y + offset.Y, block.Z + offset.Z
|
|
|
|
if bx < 1 then
|
|
bx = 8
|
|
cx -= 1
|
|
elseif bx > 8 then
|
|
bx = 1
|
|
cx += 1
|
|
end
|
|
|
|
if by < 1 then
|
|
by = 8
|
|
cy -= 1
|
|
elseif by > 8 then
|
|
by = 1
|
|
cy += 1
|
|
end
|
|
|
|
if bz < 1 then
|
|
bz = 8
|
|
cz -= 1
|
|
elseif bz > 8 then
|
|
bz = 1
|
|
cz += 1
|
|
end
|
|
|
|
return Vector3.new(cx, cy, cz), Vector3.new(bx, by, bz)
|
|
end
|
|
|
|
-- Gets the block and normalid of the block (and surface) the player is looking at
|
|
function PlacementManager:Raycast()
|
|
if not Mouse then
|
|
Mouse = game:GetService("Players").LocalPlayer:GetMouse()
|
|
end
|
|
task.synchronize()
|
|
local objLookingAt = Mouse.Target
|
|
local dir = Mouse.TargetSurface
|
|
if not objLookingAt then
|
|
PlacementManager.SelectionBox.Adornee = nil
|
|
script.RaycastResult.Value = nil
|
|
lastNormalId = nil
|
|
return
|
|
end
|
|
|
|
--if not objLookingAt:IsDescendantOf(ChunkManager.ChunkFolder) then return end
|
|
local parent = findParent(objLookingAt)
|
|
if parent:GetAttribute("ns") == true then
|
|
PlacementManager.SelectionBox.Adornee = nil
|
|
script.RaycastResult.Value = nil
|
|
lastNormalId = nil
|
|
return
|
|
end
|
|
PlacementManager.SelectionBox.Adornee = parent
|
|
script.RaycastResult.Value = parent
|
|
lastNormalId = dir
|
|
return parent, dir
|
|
end
|
|
|
|
function PlacementManager:RaycastGetResult()
|
|
return script.RaycastResult.Value
|
|
end
|
|
|
|
local remotes = game:GetService("ReplicatedStorage"):WaitForChild("Remotes")
|
|
local placeRemote = remotes:WaitForChild("PlaceBlock")
|
|
local breakRemote = remotes:WaitForChild("BreakBlock")
|
|
local tickRemote = game:GetService("ReplicatedStorage").Tick
|
|
|
|
-- FIRES REMOTE
|
|
function PlacementManager:PlaceBlock(cx, cy, cz, x, y, z, blockId: string)
|
|
--print("placeblock")
|
|
--local chunk = ChunkManager:GetChunk(cx, cy, cz)
|
|
--chunk:CreateBlock(x, y, z, blockData)
|
|
placeRemote:FireServer(cx, cy, cz, x, y, z, blockId)
|
|
end
|
|
|
|
-- FIRES REMOTE
|
|
function PlacementManager:BreakBlock(cx, cy, cz, x, y, z)
|
|
--print("breakblock")
|
|
--local chunk = ChunkManager:GetChunk(cx, cy, cz)
|
|
--chunk:RemoveBlock(x, y, z)
|
|
breakRemote:FireServer(cx, cy, cz, x, y, z)
|
|
end
|
|
|
|
-- CLIENTSIDED
|
|
function PlacementManager:PlaceBlockLocal(cx, cy, cz, x, y, z, blockData)
|
|
local chunk = ChunkManager:GetChunk(cx, cy, cz)
|
|
chunk:CreateBlock(x, y, z, blockData)
|
|
end
|
|
|
|
-- CLIENTSIDED
|
|
function PlacementManager:BreakBlockLocal(cx, cy, cz, x, y, z)
|
|
local chunk = ChunkManager:GetChunk(cx, cy, cz)
|
|
chunk:RemoveBlock(x, y, z)
|
|
end
|
|
|
|
function PlacementManager:GetBlockAtMouse(): nil | {chunk:Vector3, block: Vector3}
|
|
local selectedPart = PlacementManager:RaycastGetResult()
|
|
--print(selectedPart and selectedPart:GetFullName() or nil)
|
|
if selectedPart == nil then
|
|
PlacementManager.SelectionBox.Adornee = nil
|
|
script.RaycastResult.Value = nil
|
|
lastNormalId = nil
|
|
return nil
|
|
end
|
|
if not selectedPart.Parent then
|
|
PlacementManager.SelectionBox.Adornee = nil
|
|
script.RaycastResult.Value = nil
|
|
lastNormalId = nil
|
|
return nil
|
|
end
|
|
local chunkCoords = Util.BlockPosStringToCoords(selectedPart.Parent.Name)
|
|
local blockCoords = Util.BlockPosStringToCoords(selectedPart.Name)
|
|
|
|
return {
|
|
chunk = chunkCoords,
|
|
block = blockCoords
|
|
}
|
|
|
|
end
|
|
|
|
function PlacementManager:GetTargetAtMouse(): nil | {chunk:Vector3, block: Vector3, normal: Enum.NormalId}
|
|
local hit = PlacementManager:GetBlockAtMouse()
|
|
if not hit or not lastNormalId then
|
|
return nil
|
|
end
|
|
|
|
return {
|
|
chunk = hit.chunk,
|
|
block = hit.block,
|
|
normal = lastNormalId
|
|
}
|
|
end
|
|
|
|
function PlacementManager:GetPlacementAtMouse(): nil | {chunk:Vector3, block: Vector3}
|
|
local hit = PlacementManager:GetTargetAtMouse()
|
|
if not hit then
|
|
return nil
|
|
end
|
|
local offset = normalIdToOffset(hit.normal)
|
|
local placeChunk, placeBlock = offsetChunkBlock(hit.chunk, hit.block, offset)
|
|
return {
|
|
chunk = placeChunk,
|
|
block = placeBlock
|
|
}
|
|
end
|
|
|
|
function PlacementManager:Init()
|
|
game:GetService("RunService").Heartbeat:Connect(function()
|
|
local a,b = pcall(function()
|
|
PlacementManager:Raycast()
|
|
end)
|
|
if not a then
|
|
task.synchronize()
|
|
PlacementManager.SelectionBox.Adornee = nil
|
|
script.RaycastResult.Value = nil
|
|
task.desynchronize()
|
|
end
|
|
end)
|
|
tickRemote.OnClientEvent:Connect(function(m, cx, cy, cz, x, y, z, d)
|
|
--warn("PROPOGATED TICK", m, cx, cy, cz, x, y, z, d)
|
|
if m == "B_C" then
|
|
PlacementManager:PlaceBlockLocal(cx, cy, cz, x, y ,z, d)
|
|
end
|
|
if m == "B_D" then
|
|
PlacementManager:BreakBlockLocal(cx, cy, cz, x, y ,z)
|
|
end
|
|
end)
|
|
end
|
|
|
|
return PlacementManager
|