I’m trying to make a placement system however when trying to place the item it’s pulsing towards the camera. here are my two scripts involved.
guiplacement
-- Client-Side Script: PlacementGuiScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local user = Players.LocalPlayer
local placementEvent = ReplicatedStorage:WaitForChild("PlacementEvent")
local getPlotFunction = ReplicatedStorage:WaitForChild("GetPlotFunction") -- Add this line
local leaderstats = user:WaitForChild("leaderstats") -- Wait for leaderstats to be available
local moneyValue = leaderstats:WaitForChild("Money") -- Wait for Money to be available
local getSetMoney = ReplicatedStorage:WaitForChild("GetSetMoney")
-- Function to handle leaderboard setup
local function handleLeaderboardSetup()
end
local leaderboardSetupEvent = ReplicatedStorage:WaitForChild("LeaderboardSetupEvent", 5)
if leaderboardSetupEvent then
leaderboardSetupEvent.OnClientEvent:Connect(handleLeaderboardSetup)
else
end
local buildConfigs = script.Parent
local blocksShowcase = buildConfigs:WaitForChild("BlocksShowcase")
local scrollFrame = blocksShowcase:WaitForChild("ScrollFrame")
local openGuiButton = buildConfigs:WaitForChild("OpenGui")
local closeButton = blocksShowcase:FindFirstChild("Close")
local placementEvent = ReplicatedStorage:WaitForChild("PlacementEvent")
local selectedBlock = nil
local previewBlock = nil
local isPreviewing = false
local function startPreview(selectedBlockModel)
if not selectedBlockModel then
warn("No block selected for preview")
return
end
if previewBlock then
previewBlock:Destroy() -- Remove any existing preview block
end
previewBlock = selectedBlockModel:Clone()
previewBlock.Parent = workspace -- Place it in the workspace
for _, part in pairs(previewBlock:GetDescendants()) do
if part:IsA("BasePart") then
part.Transparency = 0.5 -- Making the block semi-transparent
part.CanCollide = false -- Ensure it doesn't collide with other objects
end
end
isPreviewing = true -- Set the previewing flag
end
local function updatePreview()
if isPreviewing and previewBlock then
local mousePosition = UserInputService:GetMouseLocation()
local ray = workspace.CurrentCamera:ScreenPointToRay(mousePosition.X, mousePosition.Y)
local raycastResult = workspace:Raycast(ray.Origin, ray.Direction * 1000)
if raycastResult then
local hitPosition = raycastResult.Position
previewBlock:SetPrimaryPartCFrame(CFrame.new(hitPosition) * CFrame.new(0, previewBlock.PrimaryPart.Size.Y / 2, 0))
end
end
end
game:GetService("RunService").Heartbeat:Connect(updatePreview)
local placeItemButton = buildConfigs:WaitForChild("PlaceItemButton") -- Adjust according to its actual location
local function handlePlaceItemButtonClick()
if selectedBlock then
local plotName = getPlotFunction:InvokeServer()
if plotName then
placementEvent:FireServer("place", selectedBlock.Name, plotName)
selectedBlock = nil -- Reset selected block after placing
placeItemButton.Visible = false -- Hide the "Place Item" button
else
warn("No plot found for the player")
end
else
warn("No block selected for placement")
end
end
if placeItemButton then
placeItemButton.MouseButton1Click:Connect(handlePlaceItemButtonClick)
end
local function placeBlock()
if isPreviewing and previewBlock and selectedBlock then
local position = previewBlock.PrimaryPart.Position
local rotation = previewBlock.PrimaryPart.Orientation -- Assuming the block has a PrimaryPart
-- Send the placement command with position and rotation
placementEvent:FireServer("place", selectedBlock.Name, position, rotation)
-- Cleanup
previewBlock:Destroy()
previewBlock = nil
isPreviewing = false
selectedBlock = nil
placeItemButton.Visible = false
cancelButton.Visible = false
end
end
-- Connect this function to wherever you want to listen for the mouse movements or touch
updatePreview()
UserInputService.InputBegan:Connect(function(input, isProcessed)
if isProcessed then return end -- Ignore processed inputs
if input.KeyCode == Enum.KeyCode.E then -- Replace with your desired key
placeBlock()
end
end)
-- Function to place a block on a plot
local function placeBlock()
local currentMoney = getSetMoney:InvokeServer("get")
local plotName = getPlotFunction:InvokeServer()
if selectedBlock and currentMoney and plotName then
local cost = selectedBlock:FindFirstChild("Cost")
if cost and currentMoney >= cost.Value then
placementEvent:FireServer("preview", selectedBlock.Name, plotName)
-- Wait for user confirmation here. This is a placeholder; replace it with your confirmation logic.
local userConfirmed = true
if userConfirmed then
getSetMoney:InvokeServer("set", currentMoney - cost.Value)
placementEvent:FireServer("place", selectedBlock.Name, plotName)
else
end
else
end
else
end
end
-- Function to toggle BlocksShowcase GUI visibility
local function toggleGui()
blocksShowcase.Visible = not blocksShowcase.Visible
end
-- Function to close BlocksShowcase GUI
local function closeGui()
blocksShowcase.Visible = false
end
-- Create and configure UIGridLayout
local gridLayout = Instance.new("UIGridLayout")
gridLayout.CellPadding = UDim2.new(0, 10, 0, 10)
gridLayout.CellSize = UDim2.new(0, 128, 0, 128)
gridLayout.FillDirection = Enum.FillDirection.Horizontal
gridLayout.SortOrder = Enum.SortOrder.LayoutOrder
gridLayout.Parent = scrollFrame
-- Populating blocks
for _, category in pairs({"Builds", "Decoration", "Interior"}) do
local categoryFolder = ReplicatedStorage:FindFirstChild("Builder"):FindFirstChild(category)
if categoryFolder then
for _, block in pairs(categoryFolder:GetChildren()) do
if block:IsA("Model") then
local cost = block:FindFirstChild("Cost")
if cost then
local blockButton = Instance.new("TextButton")
blockButton.Size = UDim2.new(0, 128, 0, 128)
blockButton.BackgroundColor3 = Color3.fromRGB(236,236,236) -- Background color of the button
blockButton.Text = ""
blockButton.TextColor3 = Color3.fromRGB(0, 0, 0) -- Text color of the button (not applicable here since Text is empty)
blockButton.Parent = scrollFrame
local viewport = Instance.new("ViewportFrame")
viewport.Size = UDim2.new(1, 0, 1, 0) -- Fill the entire TextButton
viewport.Parent = blockButton
viewport.BackgroundColor3 = Color3.fromRGB(236,236,236)
local camera = Instance.new("Camera")
camera.Parent = viewport
viewport.CurrentCamera = camera
camera.CameraType = Enum.CameraType.Scriptable
if block.PrimaryPart then
camera.CFrame = CFrame.new(block.PrimaryPart.Position + Vector3.new(5, 5, 5), block.PrimaryPart.Position)
end
local rotationCFrame = CFrame.Angles(0, math.rad(10), 0) -- Rotating 10 degrees around Y-axis
if block.PrimaryPart then
local targetPosition = block.PrimaryPart.Position
local originalPosition = targetPosition + Vector3.new(5, 5, 5)
local originalCFrame = CFrame.new(originalPosition, targetPosition)
-- Apply rotation to the original CFrame and re-adjust the position
local rotatedCFrame = originalCFrame * rotationCFrame
local newPosition = rotatedCFrame.Position
camera.CFrame = CFrame.new(newPosition, targetPosition)
end
local costLabel = Instance.new("TextLabel")
costLabel.Size = UDim2.new(1, 0, 0, 20)
costLabel.Position = UDim2.new(0, 0, 1, -20)
costLabel.Text = " " .. block.Name .. " | " .. cost.Value
costLabel.TextColor3 = Color3.fromRGB(255, 255, 255) -- Text color of the label
costLabel.BackgroundColor3 = Color3.fromRGB(85, 85, 0) -- Background color of the label
costLabel.Parent = blockButton
local displayBlock = block:Clone()
displayBlock.Parent = viewport
-- Add rotation here
local rotationCFrame = CFrame.Angles(0, math.rad(210), 0) -- Rotating 10 degrees around Y-axis
displayBlock:SetPrimaryPartCFrame(displayBlock.PrimaryPart.CFrame * rotationCFrame)
local currentlySelectedButton = nil
blockButton.MouseButton1Click:Connect(function()
selectedBlock = block
startPreview(selectedBlock) -- Start the preview (ensure this function is defined correctly)
placeItemButton.Visible = true -- Show the "Place Item" button
blocksShowcase.Visible = false -- Close the blocksShowcase GUI
if currentlySelectedButton then
-- Reset the appearance of the previously selected button
currentlySelectedButton.BackgroundColor3 = Color3.fromRGB(236, 236, 236)
end
-- Change the appearance of the current button to indicate selection
blockButton.BackgroundColor3 = Color3.fromRGB(210, 210, 210)
currentlySelectedButton = blockButton
end)
else
end
else
end
end
else
end
end
local cancelButton = buildConfigs:WaitForChild("CancelButton") -- Assuming you have a CancelButton in your UI
local function handleCancelButtonClick()
if isPreviewing and previewBlock then
previewBlock:Destroy()
previewBlock = nil
isPreviewing = false
selectedBlock = nil
placeItemButton.Visible = false
cancelButton.Visible = false
end
end
if cancelButton then
cancelButton.MouseButton1Click:Connect(handleCancelButtonClick)
end
UserInputService.InputBegan:Connect(function(input, isProcessed)
if isProcessed then return end
if input.KeyCode == Enum.KeyCode.Q then
handleCancelButtonClick()
end
end)
-- Connect the OpenGui button to toggle GUI
if openGuiButton then
openGuiButton.MouseButton1Click:Connect(toggleGui)
end
-- Connect the Close button to close GUI
if closeButton then
closeButton.MouseButton1Click:Connect(closeGui)
end
-- Optionally, you can use UserInputService for touch support
if UserInputService then
UserInputService.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.Touch and input.UserInputState == Enum.UserInputState.Begin then
local touchPos = input.Position
local guiPos = openGuiButton.AbsolutePosition
local guiSize = openGuiButton.AbsoluteSize
if touchPos.x >= guiPos.x and touchPos.x <= guiPos.x + guiSize.x and touchPos.y >= guiPos.y and touchPos.y <= guiPos.y + guiSize.y then
toggleGui()
end
end
end)
else
end
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local restoreEvent = ReplicatedStorage:WaitForChild("restoreEvent")
local restoreButton = script.Parent:FindFirstChild("RestoreButton") -- Replace with the actual path to your Restore button
if restoreButton then
restoreButton.MouseButton1Click:Connect(function()
restoreEvent:FireServer()
end)
end
The placement system script
-- Server-Side Script: PlacementSystem
local HttpService = game:GetService("HttpService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("PlayerBlocksDataStore")
local restoreEvent = Instance.new("RemoteEvent")
restoreEvent.Name = "restoreEvent"
restoreEvent.Parent = ReplicatedStorage
local placementEvent = Instance.new("RemoteEvent")
placementEvent.Name = "PlacementEvent"
placementEvent.Parent = ReplicatedStorage
-- Table to store placed blocks for each player
local playerBlocks = {}
local playerPlots = {}
local function clearPlayerPlot(userId)
local oldPlotIdentifier = playerPlots[userId]
if oldPlotIdentifier then
local oldPlot = game.Workspace.Plots:FindFirstChild(oldPlotIdentifier)
if oldPlot then
for _, child in pairs(oldPlot:GetChildren()) do
child:Destroy()
end
end
playerPlots[userId] = nil -- Remove the plot from the playerPlots table
end
end
-- Helper function to find a block in groups
local function findBlockInGroups(group, blockName)
for _, child in pairs(group:GetChildren()) do
if child.Name == blockName then
return child
elseif child:IsA("Folder") or child:IsA("Model") then
local foundBlock = findBlockInGroups(child, blockName)
if foundBlock then return foundBlock end
end
end
return nil
end
local function onBlockPlaced(player, action, blockName, plotIdentifier, position, rotation)
print("Received on server - Position:", position, "Rotation:", rotation)
-- Ensure position and rotation are valid before proceeding
if not position or not rotation then
warn("Position or rotation is nil for onBlockPlaced.")
return
end
-- Clear the old plot before setting a new one
clearPlayerPlot(player.UserId)
-- Now set the new plot
playerPlots[player.UserId] = plotIdentifier
local builder = ReplicatedStorage:FindFirstChild("Builder")
local blockFound = findBlockInGroups(builder, blockName)
if action == "preview" then
-- Handle preview action
elseif action == "place" then
if blockFound then
local blockToPlace = blockFound:Clone()
local plotsFolder = game.Workspace:FindFirstChild("Plots")
local plot = plotsFolder and plotsFolder:FindFirstChild(plotIdentifier) or nil
if plot then
-- Use the position and rotation provided by the player
local targetPosition = plot.Position + Vector3.new(position.X, position.Y, position.Z)
local targetRotation = CFrame.Angles(math.rad(rotation.X), math.rad(rotation.Y), math.rad(rotation.Z))
local newCFrame = CFrame.new(targetPosition) * targetRotation
blockToPlace:SetPrimaryPartCFrame(newCFrame)
blockToPlace.Parent = plot
-- If the block to place is a Model, anchor all its parts
if blockToPlace:IsA("Model") then
for _, part in pairs(blockToPlace:GetDescendants()) do
if part:IsA("Part") then
part.Anchored = true
end
end
elseif blockToPlace:IsA("Part") then
blockToPlace.Anchored = true
end
if not playerBlocks[player.UserId] then
playerBlocks[player.UserId] = {}
end
table.insert(playerBlocks[player.UserId], blockToPlace)
end
end
end
end
-- Function to save player blocks
local function savePlayerBlocks(player)
if not player then
return
end
local userId = player.UserId
if not userId then
return
end
local blocks = playerBlocks[userId]
local plotIdentifier = playerPlots[userId]
if not blocks and not plotIdentifier then
-- You can use print instead of warn if you prefer.
return
elseif not blocks then
return
elseif not plotIdentifier then
return
end
local plot = game.Workspace.Plots:FindFirstChild(plotIdentifier)
if not plot then
return
end
if blocks and plot then
local plotPosition = plot.Position
local blockData = {}
for _, block in pairs(blocks) do
local position
if block:IsA("Part") then
position = block.Position - plotPosition
elseif block:IsA("Model") and block.PrimaryPart then
position = block.PrimaryPart.Position - plotPosition
else
position = Vector3.new(0, 0, 0)
end
table.insert(blockData, {Name = block.Name, Position = {position.X, position.Y, position.Z}})
end
local jsonBlockData = HttpService:JSONEncode(blockData)
local success, errorMessage = pcall(function()
myDataStore:SetAsync(userId, jsonBlockData)
end)
if not success then
else
end
end
end
--restore blocks using json
local function findBlockInGroups(group, blockName)
for _, child in pairs(group:GetChildren()) do
if child.Name == blockName then
return child
elseif child:IsA("Folder") or child:IsA("Model") then
local foundBlock = findBlockInGroups(child, blockName)
if foundBlock then return foundBlock end
end
end
return nil
end
-- Restore blocks using json
local function restoreBlocks(player, plotName)
if not player then
return
end
local userId = player.UserId
clearPlayerPlot(userId)
local plotIdentifier = plotName or playerPlots[userId]
playerPlots[userId] = plotIdentifier
local plot = game.Workspace.Plots:FindFirstChild(plotIdentifier)
if plot then
local plotPosition = plot.Position
local success, jsonBlockData = pcall(function()
return myDataStore:GetAsync(userId)
end)
if success and jsonBlockData then
local blockData
local decodeSuccess, errorMessage = pcall(function()
blockData = HttpService:JSONDecode(jsonBlockData)
end)
if not decodeSuccess then
return
end
for _, data in pairs(blockData) do
local blockToPlace = findBlockInGroups(ReplicatedStorage.Builder, data.Name)
if not blockToPlace then
return
end
blockToPlace = blockToPlace:Clone()
local relativePosition = Vector3.new(unpack(data.Position))
if blockToPlace then
if blockToPlace:IsA("Model") and blockToPlace.PrimaryPart then
blockToPlace:SetPrimaryPartCFrame(CFrame.new(plotPosition + relativePosition))
elseif blockToPlace:IsA("Part") then
blockToPlace.Position = plotPosition + relativePosition
end
blockToPlace.Parent = plot
-- Handle anchoring correctly for both Model and Part
if blockToPlace:IsA("Model") then
for _, part in pairs(blockToPlace:GetDescendants()) do
if part:IsA("Part") then
part.Anchored = true
end
end
elseif blockToPlace:IsA("Part") then
blockToPlace.Anchored = true
else
end
else
end
end
else
end
else
end
end
-- Connect the function to handle the event
placementEvent.OnServerEvent:Connect(onBlockPlaced)
-- Listen for the restore event
restoreEvent.OnServerEvent:Connect(restoreBlocks)
-- Listen for when a player leaves to save their blocks
Players.PlayerRemoving:Connect(savePlayerBlocks)
Here is a gif of the issue i’m facing.
If anyone can assist in fixing that would be amazing.