File size: 4,614 Bytes
0712d5f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
-- src/StarterPlayer/StarterCharacterScripts/BuildController.client.lua

local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

local BuildingConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("BuildingConfig"))
local PlaceBlueprintEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("PlaceBlueprintEvent")

local player = Players.LocalPlayer
local mouse = player:GetMouse()
local character = player.Character or player.CharacterAdded:Wait()

local buildModeActive = false
local currentStructureIndex = 1
local currentStructure = BuildingConfig.StructureOrder[1]
local currentRotation = 0
local previewModel = nil

local function snapToGrid(position, gridSize)
	return Vector3.new(
		math.floor((position.X + gridSize/2) / gridSize) * gridSize,
		position.Y,
		math.floor((position.Z + gridSize/2) / gridSize) * gridSize
	)
end

local function getStructureSize()
	local config = BuildingConfig.Structures[currentStructure]
	if config and config.Size then
		return config.Size
	end
	return Vector3.new(10, 10, 1)
end

local function cleanupPreview()
	if previewModel then
		previewModel:Destroy()
		previewModel = nil
	end
end

local function createPreview()
	cleanupPreview()
	local size = getStructureSize()

	previewModel = Instance.new("Part")
	previewModel.Size = size
	previewModel.Transparency = 0.5
	previewModel.BrickColor = BrickColor.new("Neon blue")
	previewModel.CanCollide = false
	previewModel.Anchored = true
	previewModel.Material = Enum.Material.ForceField
	previewModel.Parent = workspace.Terrain

	-- Add label
	local billboard = Instance.new("BillboardGui")
	billboard.Size = UDim2.new(0, 200, 0, 50)
	billboard.StudsOffset = Vector3.new(0, size.Y/2 + 2, 0)
	billboard.AlwaysOnTop = true
	billboard.Parent = previewModel

	local label = Instance.new("TextLabel")
	label.Name = "StructureLabel"
	label.Size = UDim2.new(1, 0, 1, 0)
	label.BackgroundTransparency = 0.3
	label.BackgroundColor3 = Color3.new(0, 0, 0)
	label.TextColor3 = Color3.new(1, 1, 1)
	label.TextScaled = true
	label.Font = Enum.Font.GothamBold

	local config = BuildingConfig.Structures[currentStructure]
	label.Text = (config and config.Name or currentStructure) .. " [Q] Cycle [R] Rotate"
	label.Parent = billboard
end

local function toggleBuildMode()
	buildModeActive = not buildModeActive
	if not buildModeActive then
		cleanupPreview()
	else
		createPreview()
	end
end

local function cycleStructure()
	currentStructureIndex = currentStructureIndex + 1
	if currentStructureIndex > #BuildingConfig.StructureOrder then
		currentStructureIndex = 1
	end
	currentStructure = BuildingConfig.StructureOrder[currentStructureIndex]
	if buildModeActive then
		createPreview()
	end
end

local function updatePreview()
	if not buildModeActive or not previewModel then return end

	local char = player.Character
	if char and char:FindFirstChild("HumanoidRootPart") then
		local distance = (char.HumanoidRootPart.Position - mouse.Hit.Position).Magnitude
		if distance <= BuildingConfig.MaxPlacementDistance then
			local snappedPos = snapToGrid(mouse.Hit.Position, BuildingConfig.GridSnap)
			snappedPos = Vector3.new(snappedPos.X, mouse.Hit.Position.Y + (previewModel.Size.Y / 2), snappedPos.Z)

			previewModel.CFrame = CFrame.new(snappedPos) * CFrame.Angles(0, math.rad(currentRotation), 0)
			previewModel.BrickColor = BrickColor.new("Neon blue")
		else
			previewModel.Position = mouse.Hit.Position
			previewModel.BrickColor = BrickColor.new("Really red")
		end
	end
end

local function onInputBegan(input, gameProcessed)
	if gameProcessed then return end

	if input.KeyCode == Enum.KeyCode.B then
		toggleBuildMode()
	end

	if input.KeyCode == Enum.KeyCode.Q and buildModeActive then
		cycleStructure()
	end

	if input.KeyCode == Enum.KeyCode.R and buildModeActive then
		currentRotation = (currentRotation + 90) % 360
	end

	if input.UserInputType == Enum.UserInputType.MouseButton1 and buildModeActive then
		if previewModel and previewModel.BrickColor.Name == "Neon blue" then
			PlaceBlueprintEvent:FireServer(currentStructure, previewModel.CFrame)
		end
	end
end

player.CharacterAdded:Connect(function(char)
	character = char
end)

UserInputService.InputBegan:Connect(onInputBegan)

RunService.RenderStepped:Connect(function()
	if buildModeActive then
		updatePreview()
	end
end)