File size: 5,270 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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
-- src/StarterPlayer/StarterCharacterScripts/DragController.client.lua
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local CollectionService = game:GetService("CollectionService")

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

local DraggingConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("DraggingConfig"))
local DragEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("DragEvent")
local DropEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("DropEvent")

local isDragging = false
local draggedPart = nil
local targetAttachment = nil
local currentHoldDistance = DraggingConfig.HoldDistance
local highlightedPart = nil
local highlight = nil

local renderConnection = nil
local hoverConnection = nil

-- Create highlight effect
local function createHighlight(part)
	removeHighlight()
	if not part then return end

	highlight = Instance.new("SelectionBox")
	highlight.Adornee = part
	highlight.Color3 = Color3.fromRGB(100, 200, 255)
	highlight.LineThickness = 0.03
	highlight.SurfaceTransparency = 0.8
	highlight.SurfaceColor3 = Color3.fromRGB(100, 200, 255)
	highlight.Parent = part

	highlightedPart = part
end

function removeHighlight()
	if highlight then
		highlight:Destroy()
		highlight = nil
	end
	highlightedPart = nil
end

-- Hover detection for draggable parts
local function updateHover()
	if isDragging then return end

	local target = mouse.Target
	if target and (CollectionService:HasTag(target, "Draggable") or CollectionService:HasTag(target, "TreeSegment")) then
		if target ~= highlightedPart then
			createHighlight(target)
		end
	else
		removeHighlight()
	end
end

local function updateDraggingPosition()
	if not isDragging or not draggedPart or not targetAttachment then return end

	local char = player.Character
	if not char then return end

	local head = char:FindFirstChild("Head")
	if not head then return end

	local rayOrigin = head.Position
	local rayDirection = camera.CFrame.LookVector * currentHoldDistance

	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {char, draggedPart}
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude

	local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)

	local targetPos = rayOrigin + rayDirection
	if raycastResult then
		targetPos = raycastResult.Position
	end

	targetAttachment.WorldCFrame = CFrame.new(targetPos) * CFrame.Angles(0, camera.CFrame.Rotation.Y, 0)
end

local function stopDragging()
	if not isDragging then return end
	isDragging = false
	draggedPart = nil
	targetAttachment = nil
	currentHoldDistance = DraggingConfig.HoldDistance

	if renderConnection then
		renderConnection:Disconnect()
		renderConnection = nil
	end

	DropEvent:FireServer()
end

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

	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		if isDragging then return end

		local targetPart = mouse.Target
		if not targetPart then return end

		if not CollectionService:HasTag(targetPart, "Draggable") and not CollectionService:HasTag(targetPart, "TreeSegment") then return end

		local char = player.Character
		if not char or not char:FindFirstChild("HumanoidRootPart") then return end

		local distance = (char.HumanoidRootPart.Position - targetPart.Position).Magnitude
		if distance > DraggingConfig.MaxGrabDistance then return end

		removeHighlight()

		DragEvent:FireServer(targetPart, mouse.Hit.Position)

		local attachmentName = "TargetAttachment_Player" .. player.UserId

		local t = 0
		while not workspace.Terrain:FindFirstChild(attachmentName) and t < 1 do
			t = t + task.wait()
		end

		targetAttachment = workspace.Terrain:FindFirstChild(attachmentName)

		if targetAttachment then
			isDragging = true
			draggedPart = targetPart
			currentHoldDistance = DraggingConfig.HoldDistance

			renderConnection = RunService.RenderStepped:Connect(updateDraggingPosition)
		end
	end
end

local function onInputEnded(input, gameProcessed)
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		stopDragging()
	end
end

-- Scroll wheel for hold distance adjustment
local function onInputChanged(input)
	if not isDragging then return end

	if input.UserInputType == Enum.UserInputType.MouseWheel then
		currentHoldDistance = math.clamp(
			currentHoldDistance + input.Position.Z * 2,
			3,
			DraggingConfig.MaxGrabDistance
		)
	end
end

-- Respawn handling
player.CharacterAdded:Connect(function(char)
	character = char
	camera = workspace.CurrentCamera
	stopDragging()
end)

-- Hover detection loop
hoverConnection = RunService.RenderStepped:Connect(updateHover)

UserInputService.InputBegan:Connect(onInputBegan)
UserInputService.InputEnded:Connect(onInputEnded)
UserInputService.InputChanged:Connect(onInputChanged)