I was just making a game called "Mayor Sphereoid's Community Place" and I was trying to create build tools. To add some context to why I'm not using the Tool instance, the characters are not humanoids but they are balls with custom controls and a custom camera, meaning that most things compatible with a normal Roblox avatar won't work with my characters.
In my game, there is: A remote function, PartFunction, used to run part functions as a client A remote event, PartMod, used to change values of parts as a client A custom configuration folder put inside a player instance containing the currently held tool
These scripts worked a minute ago and I barely changed anything!
ServerScriptService PartMod (Script)
game.ReplicatedStorage:WaitForChild("PartMod").OnServerEvent:Connect(function(player, part, attr, value, operation) if operation == "add" then part[attr] = part[attr] + value elseif operation == "multiply" then part[attr] = part[attr] * value else part[attr] = value end end) game.ReplicatedStorage:WaitForChild("PartFunction").OnServerInvoke = function(player, part, func, ...) if func == "Clone" then local result = part:Clone() result.Parent = game.ReplicatedStorage.StoredParts result.Name = string.format("%x", math.random(0, 15)) .. "x" .. string.format("%x", player.UserId) return {name=part.Name, key=result.Name} elseif func == "Destroy" then part:Destroy() elseif func == "Resize" then local testPart = part:Clone() testPart:Resize(...) if testPart.Size.X <= 0.05 or testPart.Size.Y <= 0.05 or testPart.Size.Z <= 0.05 then testPart:Destroy() return false end testPart:Destroy() return part:Resize(...) end end
StarterPlayerScripts ToolControl (LocalScript)
local player = game.Players.LocalPlayer local config = player:WaitForChild("Configuration") local mouse = player:GetMouse() local rs = game.ReplicatedStorage local partMod = function(...) rs.PartMod:FireServer(...) end local partFunc = function(...) return rs.PartFunction:InvokeServer(...) end -- partMod(part, attr, val, [operation]) -- partFunc(part, func, ...) local part = nil local handles = Instance.new("Handles", player.PlayerGui) local ogMoveDistance = 0 local ogResizeDistance = 0 local function round(x, y) return math.floor(x / y + 0.5) * y end local function handleHandlerInit() ogMoveDistance = 0 ogResizeDistance = 0 end local function handleHandler(face, distance) local inc = 0.25 if face == Enum.NormalId.Top or face == Enum.NormalId.Bottom then inc = inc * 1.2 end -- Resize if config.Tool.Value == "resize" then distance = distance / 4 local delta = distance - ogResizeDistance if math.abs(delta) >= inc then local sizeDelta = math.floor(delta / inc + 0.5) * inc print(sizeDelta) if partFunc(part, "Resize", face, sizeDelta) then ogResizeDistance = distance end end -- Move elseif config.Tool.Value == "move" then local delta = distance - ogMoveDistance if math.abs(delta) >= inc then local sizeDelta = math.floor(delta / inc + 0.5) * inc partMod(part, "CFrame", CFrame.new(Vector3.FromNormalId(face) * sizeDelta), "multiply") ogMoveDistance = distance end end end handles.Name = "BToolHandles" handles.MouseButton1Down:Connect(handleHandlerInit) handles.MouseDrag:Connect(handleHandler) game:GetService("UserInputService").InputBegan:Connect(function(key) if key.UserInputType == Enum.UserInputType.MouseButton1 and key.UserInputState == Enum.UserInputState.Begin then if mouse.Target and mouse.X < mouse.ViewSizeX - 90 then if mouse.Target.Parent == workspace.BuildingParts then -- Clone tool if config.Tool.Value == "clone" then local info = partFunc(mouse.Target, "Clone") part = rs.StoredParts:FindFirstChild(info.key) partMod(part, "CFrame", CFrame.new(0, part.Size.Y, 0), "multiply") partMod(part, "Name", info.name) if not part:FindFirstChild("Ownership") then local ownership = Instance.new("IntValue", part) ownership.Name = "Ownership" ownership.Value = player.UserId end partMod(part, "Parent", workspace.BuildingParts) end -- Select tool if config.Tool.Value == "select" and not mouse.Target.Locked and part.Ownership then if part.Ownership.Value == player.UserId then handles.Adornee = part end -- Destroy tool if config.Tool.Value == "destroy" and not mouse.Target.Locked and part:FindFirstChild("Ownership") then if part.Ownership.Value == player.UserId then partFunc(mouse.Target, "Destroy") end end end -- Remove unused handles elseif config.Tool.Value == "select" and mouse.X < mouse.ViewSizeX - 90 then handles.Adornee = nil end end end)
This is just so weird! Please help immediately!
NOTES:
I wanted to make it so that parts can't go to 0.05x0.05x0.05 size
I have a control panel on the right which I don't want anyone to click through (hence mouse.X < mouse.ViewSizeX - 90)
There are no errors that appear!
Edit: There is an error that appears, actually. Look at my answer for more info.
Tada! I was dumb! Turns out that hidden among so many useless errors from broken plugins was this thing:
Players.Owengren.PlayerScripts.ToolControl:112: Expected identifier when parsing expression, got ')'
Sorry!