In this function below, if the VertexID is invalid then :RemoveVertex()
does an error, but an error still happens despite it being in a pcall.
Check if the pcall is wrapping the intended code properly to catch errors.
What do you see in the output window when this code errors, can you show a screenshot of that?
Is this plugin code, and if so, are you sure youâre looking at the source for the code thatâs actually running? That error looks like itâs coming from a call with no pcall wrapping it. I canât repro this, pcall seems to catch that error just fine for me. If you click the error, does it bring you to outdated code, like a copy in PluginDebugService or something? Any Actor instances involved in this code?
current.mesh is an EditableMesh
no
My suspicion then is that some other EditableMesh code is calling RemoveVertex directly from C++, and that your pcall is not wrapping whatever Lua function call (assuming there is one) is at the top of that call stack. I think this because the error output you show has " - Studio" after it, which is a C++ calling context. If it were your code, youâd see " - Client - YourScriptName:218" after the error.
Try pcalling your entire mouseclick handler, see where the error throws. Maybe RemoveTriangle is what leads to this?
RemoveTriangle is what is meant to fix this issue, as it removes all triangles (faces) that the vertex could possibly be part of, allowing for the vertex to be deleted.
In your code, yes, but what Iâm saying is that there is possibly a bug in Robloxâs C++ code where one of the Lua calls (e.g. RemoveTriangle) results in a call to RemoveVertex (from C++, not from your code) which then throws the error. So pcall will only catch it if the pcall wraps the Lua call thatâs triggering it. i.e. your Lua call to RemoveVertex may not be the RemoveVertex call that is actually erroring.
The line of the error matches up to 218, the same line where current.mesh:RemoveVertex()
is called
A repro file is probably the only thing that can resolve this. I donât know how you know the line number, the error output (below) you posted was from a C++ internal call with no Lua script line number or stack trace . Either way, I think weâre missing critical context required to reproduce your results. I canât get a pcallâd call to RemoveVertex to throw an uncaught error in any context (Client, Server, Edit or Plugin). You must be hitting some special edge case in Robloxâs code.
If neccesary, below is the entire source code for that localscript:
Source
local lplr = game.Players.LocalPlayer
local mouse = lplr:GetMouse()
local keyboard = game.UserInputService
local camera = workspace.CurrentCamera
local keysOn : {[Enum.KeyCode]: boolean} = {}
local mainBase = script.Parent
local nameBox = mainBase.provinceName
local modeB = mainBase.modeB
local areaTXT = mainBase.areaTXT
local undoB = mainBase.undoV
local delB = mainBase.delB
local freeCam = require(game.ReplicatedStorage.freeCam)
local polyTrig = require(game.ReplicatedStorage.polyTrig)
local scale = require(game.ReplicatedStorage.scales)
local provinceYPadding = Vector3.yAxis * 0.1
for _, key: Enum.KeyCode in Enum.KeyCode:GetEnumItems() do
keysOn[key] = false
end
keyboard.InputBegan:Connect(function(i, r) if i.KeyCode and not r then keysOn[i.KeyCode] = true end end)
keyboard.InputEnded:Connect(function(i, r) if i.KeyCode and not r then keysOn[i.KeyCode] = false end end)
type tile =
{
v: {[number]: Vector3},
t: {number},
p: MeshPart,
mesh: EditableMesh,
area: number
}
local tileSet : {[string]: tile} = {}
local function FindClosestVertex(from:Vector3)
local minDis = math.huge
local closest = Vector3.zero
local real = false
for _, data in tileSet do
for _, V in data.v do
real = true
local dis = (V-from).Magnitude
if dis < minDis then
minDis = dis
closest = V
end
end
end
return minDis, closest, real
end
local MCparams = RaycastParams.new()
MCparams.FilterType = Enum.RaycastFilterType.Include
MCparams.FilterDescendantsInstances = {workspace.Baseplate}
local lastVertex
local function EnterCameraMode()
freeCam.begin(nil, freeCam.presets.default)
end
local currentProvince = ''
local function NewProvince(core): tile
lastVertex = nil
local newMesh = game.ReplicatedStorage.MeshPart:Clone()
local eMesh = Instance.new('EditableMesh')
eMesh.Parent = newMesh
newMesh.Parent = workspace.Editor
local index = 'a'..math.random(1, 9999999)
local tileData : tile =
{
mesh = eMesh,
p = newMesh,
t = {},
v = {},
area = 0
}
currentProvince = index
tileSet[index] = tileData
return tileData
end
local function Rename(old, new)
if tileSet[old] then
tileSet[new] = tileSet[old]
tileSet[old] = nil
tileSet[new].p.Name = new
if currentProvince == old then currentProvince = new end
end
end
local tempPart = Instance.new('Part')
tempPart.CanCollide = false
tempPart.CanTouch = false
tempPart.CanQuery = false
tempPart.Size = Vector3.new(.1,.1,.1)
tempPart.Anchored = true
tempPart.Transparency = 0.7
tempPart.Color = Color3.fromRGB(200,50,50)
tempPart.Parent = workspace
local currentTarget = Vector3.zero
local xzRound = function(v:Vector3)
local f = 0.1
return Vector3.new(math.round(v.X/f)*f, v.Y, math.round(v.Z/f)*f)
end
mouse.Move:Connect(function()
local mouseRay = workspace:Raycast(mouse.Origin.Position, mouse.Origin.LookVector * 190, MCparams)
if mouseRay then
local closestDis, tDis, real = FindClosestVertex(mouseRay.Position)
local realPos = xzRound(mouseRay.Position)
if real then
if closestDis < 0.25 then
realPos = xzRound(tDis)
tempPart.Size = Vector3.new(.1, .3, .1)
else
tempPart.Size = Vector3.new(.1,.1,.1)
end
else
tempPart.Size = Vector3.new(.1, .1, .1)
end
currentTarget = realPos
tempPart.Position = realPos
end
end)
local function RenderCurrent()
local current = tileSet[currentProvince]
if current then
local outline= {}
for ID, pos in current.v do
table.insert(outline, {id = ID, pos = pos })
end
local triangles, area, timelen = polyTrig(outline)
print('Took '..((timelen or 0) * 1000)..'ms')
current.area = area
areaTXT.Text = math.floor(area * scale.studKM / 1000) ..' km'
for i, ID in ipairs(current.t) do
current.mesh:RemoveTriangle(ID)
table.remove(current.t, i)
end
for _, verti in triangles do
local newTrig = current.mesh:AddTriangle(verti[1], verti[2], verti[3])
table.insert(current.t, newTrig)
end
print(#current.t..' triangles')
end
end
local function EnterEditMode()
mouse.Button1Down:Connect(function()
if currentProvince ~= '' then
local current = tileSet[currentProvince]
local newVertex = current.mesh:AddVertex(currentTarget + provinceYPadding)
current.v[newVertex] = currentTarget + provinceYPadding
RenderCurrent()
end
end)
end
nameBox:GetPropertyChangedSignal('Text'):Connect(function()
if currentProvince ~= '' then
Rename(currentProvince, nameBox.Text)
end
end)
local modeBS = false
local MBCNCT : RBXScriptConnection
modeB.MouseButton1Click:Connect(function()
if not modeBS then
MBCNCT = mouse.Button1Down:Once(function()
NewProvince(currentTarget + provinceYPadding)
print('Created a new province!')
end)
modeB.Text = 'Editing province'
modeB.BackgroundColor3 = Color3.fromRGB(255, 14, 14)
modeBS = true
undoB.Visible = true
delB.Visible = true
else
if MBCNCT then MBCNCT:Disconnect(); MBCNCT = nil end
currentProvince = ''
modeBS = false
modeB.BackgroundColor3 = Color3.fromRGB(30, 176, 255)
modeB.Text = 'New Province'
undoB.Visible = false
delB.Visible = false
end
end)
undoB.MouseButton1Click:Connect(function()
local current = tileSet[currentProvince]
if current then
local latest = -1
for i, v in pairs(current.v) do
latest = i
end
for i, tid in ipairs(current.t) do
local v0, v1, v2 = current.mesh:GetTriangleVertices(tid)
if v0 == latest or v1 == latest or v2 == latest then
table.remove(current.t, i)
current.mesh:RemoveTriangle(tid)
end
end
if latest == -1 then return end
local suc, err = pcall(function()
current.mesh:RemoveVertex(latest)
end)
if not suc then
print('Cannot undo')
else
current.v[latest] = nil
print('Undone vertex placement')
RenderCurrent()
end
end
end)
delB.MouseButton1Click:Connect(function()
if tileSet[currentProvince] then
tileSet[currentProvince].p:Destroy()
tileSet[currentProvince] = nil
print('Deleted province: '..currentProvince..'!')
currentProvince = ''
end
end)
EnterEditMode()
EnterCameraMode()
When an error happens, the game pauses and the problematic script is viewed something like this:
Also it cannot be predicted when RemoveVertex()
would error, sometimes the undo proccess is successful, other times it would work as fine.
When "Undone vertex placement"
is printed, it shows that there was no error and that the vertex removal was succesful.
Ohhhhh, you have âOn All Exceptionsâ checked in the debugger options, donât you
When that is selected, youâll break at all the errors, even pcallâd ones, because the debuggerâs catch is higher priority than pcall, and that also explains why you saw the error output with " - Studio" after it⌠the debugger is echoing the error it caught.
If you change this to âOn Unhandled Exceptionsâ (or âNeverâ) your pcall should catch the error like you expect.
I actually didnât realize that the debugger didnât propagate the error after catching it, I never use that middle option, my bad.
Hmm yeah this seems like the issue, how do I turn it off?
You just go to the SCRIPT tab (must have a script source open to see it) and choose one of the other 2 options. âNeverâ will never automatically break, it will only break at your manually-set breakpoints. âOn Unhandled Exceptionsâ will only break on errors that your pcalls donât handle; it moves the debugger catch hook to be lower priority than pcall. That is probably what you want. The âOn All Exceptionsâ will break at any error before any pcall can catch it, so you canât test any of your pcalls with that option enabled.
Oh by the way, I donât think that the Vertex function sometimes errors because of that, but the failure seems random:
Right, so the C++ thing was a red herring. The error is only printing from C++ code because the debugger catches the error and then echos it to the output. Your error is not random though, there is a problem in your code in line 212 of your screenshot. Youâre removing elements from your âcurrent.tâ table while iterating through it, which is a no-no because it invalidates the index (variable âiâ). Your loop is supposed to remove all of the triangles that reference the "latestâ vertex, but because of the table.remove, itâs possible to skip over triangles that use that vertex (because table.remove compacts the array). Any time there are two triangles in the list that share the âlatestâ vertex, and they are consecutive in the current.t array, only the first will be removed. So your code can then try to remove the vertex, without having removed all of the triangles that use it.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.