From 4110e7f2a46ee75a33231e50a8eb3e01a29a7f4d Mon Sep 17 00:00:00 2001 From: AstalNeker Date: Sun, 15 Mar 2026 18:33:41 +0100 Subject: [PATCH 1/7] small fixes --- lua/entities/starfall_cnextbot.lua | 18 ++++++++++++++--- lua/starfall/libs_sv/nextbot.lua | 32 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/lua/entities/starfall_cnextbot.lua b/lua/entities/starfall_cnextbot.lua index 59271f908..dac4e4ee1 100644 --- a/lua/entities/starfall_cnextbot.lua +++ b/lua/entities/starfall_cnextbot.lua @@ -26,7 +26,7 @@ function ENT:Initialize() ent_tbl.RUNACT = ACT_RUN ent_tbl.IDLEACT = ACT_IDLE ent_tbl.MoveSpeed = 200 - + ent_tbl.DeathCallbacks = SF.HookTable() ent_tbl.InjuredCallbacks = SF.HookTable() ent_tbl.LandCallbacks = SF.HookTable() @@ -35,6 +35,9 @@ function ENT:Initialize() ent_tbl.NavChangeCallbacks = SF.HookTable() ent_tbl.ContactCallbacks = SF.HookTable() ent_tbl.ReachCallbacks = SF.HookTable() + ent_tbl.RagCreationCallbacks = SF.HookTable() + + ent_tbl.InstanceRagdollCreationCallback = function() end end local function addPerf(instance, startPerfTime) @@ -136,7 +139,16 @@ function ENT:OnKilled(dmginfo) inst.Types.Vector.Wrap(dmginfo:GetDamageForce()), dmginfo:GetDamageType()) end - if ent_tbl.RagdollOnDeath then self:BecomeRagdoll(dmginfo) end + if ent_tbl.RagdollOnDeath then + local CreatedRagdoll = self:BecomeRagdoll(dmginfo) + ent_tbl.InstanceRagdollCreationCallback(CreatedRagdoll) -- this is used for ragdoll cleanup. check nextbot.lua at line 128 + + if not ent_tbl.RagCreationCallbacks:isEmpty() then + local inst = ent_tbl.instance + ent_tbl.RagCreationCallbacks:run(inst, + inst.WrapObject(CreatedRagdoll)) + end + end end function ENT:OnLandOnGround(groundent) @@ -173,4 +185,4 @@ function ENT:OnContact(colent) if ent_tbl.ContactCallbacks:isEmpty() then return end local inst = ent_tbl.instance ent_tbl.ContactCallbacks:run(inst, inst.WrapObject(colent)) -end +end \ No newline at end of file diff --git a/lua/starfall/libs_sv/nextbot.lua b/lua/starfall/libs_sv/nextbot.lua index 43efb5cb7..55ea0502c 100644 --- a/lua/starfall/libs_sv/nextbot.lua +++ b/lua/starfall/libs_sv/nextbot.lua @@ -35,6 +35,8 @@ registerprivilege("nextbot.addReachCallback", "Add nextbot approach callback", " registerprivilege("nextbot.removeReachCallback", "Remove nextbot approach callback", "Allows the user to remove an approach callback function from the nextbot.", {entities = {}}) registerprivilege("nextbot.addDeathCallback", "Add nextbot death callback", "Allows the user to add a callback function to run when the nextbot dies.", {entities = {}}) registerprivilege("nextbot.removeDeathCallback", "Remove nextbot death callback", "Allows the user to remove a death callback function from the nextbot.", {entities = {}}) +registerprivilege("nextbot.addRagdollCreationCallback", "Add nextbot ragdoll creation callback", "Allows the user to add a callback function to run when the nextbot create a ragdoll.", {entities = {}}) +registerprivilege("nextbot.removeRagdollCreationCallback", "Remove nextbot ragdoll creation callback", "Allows the user to remove a ragdoll creation function from the nextbot.", {entities = {}}) registerprivilege("nextbot.addInjuredCallback", "Add nextbot injured callback", "Allows the user to add a callback function to run when the nextbot is injured.", {entities = {}}) registerprivilege("nextbot.removeInjuredCallback", "Remove nextbot injured callback", "Allows the user to remove an on injured callback function from the nextbot.", {entities = {}}) registerprivilege("nextbot.addLandCallback", "Add nextbot land callback", "Allows the user to add a callback function to run when the nextbot lands on the ground.", {entities = {}}) @@ -62,6 +64,8 @@ registerprivilege("nextbot.setAvoidAllowed", "Nextbot allow avoid", "Allows the registerprivilege("nextbot.setJumpGapsAllowed", "Nextbot allow jump gaps", "Allows the user to set whether the nextbot can jump gaps.", {entities = {}}) local entList = SF.EntManager("nextbots", "nextbots", 30, "The number of props allowed to spawn via Starfall") +local ragdollsList = SF.EntManager("nextbots_ragdolls", "nextbots_ragdolls", -1, "Auto cleanup ragdoll on deinitialize") + return function(instance) local checkpermission = instance.player ~= SF.Superuser and SF.Permissions.check or function() end @@ -81,6 +85,7 @@ end) instance:AddHook("deinitialize", function() entList:deinitialize(instance, true) + ragdollsList:deinitialize(instance, true) end) --- Creates a customizable NextBot @@ -115,7 +120,12 @@ function nextbot_library.create(pos, mdl) if Ent_IsValid(nb) then nb:Remove() end SF.Throw("Failed to create entity (" .. tostring(err) .. ")", 2) end + entList:register(instance, nb) + + -- sorry i can't find a better way :) + local ent_tbl = Ent_GetTable(nb) + ent_tbl.InstanceRagdollCreationCallback = function(ragdoll) ragdollsList:register(instance, ragdoll) end instance:checkCpu() return nbwrap(nb) @@ -468,6 +478,28 @@ function nb_methods:removeContactCallback(id) nb.ContactCallbacks:remove(id) end +--- Adds a callback function that will be run when the nextbot create a ragdoll. Note: this will be called only if nb:ragdollOnDeath() is set to True +-- @server +-- @param string callbackid The unique ID this callback will use. +-- @param function callback The function to run when the NB create a ragdoll. The arguments are: (The ragdoll entity the NB created.) +function nb_methods:addRagdollCreationCallback(id, func) + checkluatype(id, TYPE_STRING) + checkluatype(func, TYPE_FUNCTION) + local nb = nbunwrap(self) + checkpermission(instance, nb, "nextbot.addRagdollCreationCallback") + nb.RagCreationCallbacks:add(id, func) +end + +--- Removes the ragdoll creation callback function from the NextBot if present. +-- @server +-- @param string callbackid The unique ID of the callback to remove. +function nb_methods:removeRagdollCreationCallback(id) + checkluatype(id, TYPE_STRING) + local nb = nbunwrap(self) + checkpermission(instance, nb, "nextbot.removeRagdollCreationCallback") + nb.RagCreationCallbacks:remove(id) +end + --- Enable or disable ragdolling on death for the NextBot. -- @server -- @param boolean ragdollondeath Whether the nextbot should ragdoll on death. From cd704fd4a0aeb3b91877c9969b8f45110a86627a Mon Sep 17 00:00:00 2001 From: AstalNeker <85320199+AstalNeker@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:43:52 +0100 Subject: [PATCH 2/7] fix starfall_cnextbot.lua --- lua/entities/starfall_cnextbot.lua | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lua/entities/starfall_cnextbot.lua b/lua/entities/starfall_cnextbot.lua index dac4e4ee1..7f5fdac90 100644 --- a/lua/entities/starfall_cnextbot.lua +++ b/lua/entities/starfall_cnextbot.lua @@ -19,6 +19,8 @@ end if CLIENT then return end +SF.NextBotRagdolls = SF.EntManager("nextbots_ragdolls", "nextbots_ragdolls", 30, "How many ragdoll can be spawned") + function ENT:Initialize() local ent_tbl = Ent_GetTable(self) ent_tbl.RagdollOnDeath = true @@ -35,9 +37,7 @@ function ENT:Initialize() ent_tbl.NavChangeCallbacks = SF.HookTable() ent_tbl.ContactCallbacks = SF.HookTable() ent_tbl.ReachCallbacks = SF.HookTable() - ent_tbl.RagCreationCallbacks = SF.HookTable() - - ent_tbl.InstanceRagdollCreationCallback = function() end + ent_tbl.RagdollCreationCallbacks = SF.HookTable() end local function addPerf(instance, startPerfTime) @@ -129,8 +129,9 @@ end function ENT:OnKilled(dmginfo) local ent_tbl = Ent_GetTable(self) + local inst = ent_tbl.instance + if not ent_tbl.DeathCallbacks:isEmpty() then - local inst = ent_tbl.instance ent_tbl.DeathCallbacks:run(inst, dmginfo:GetDamage(), inst.WrapObject(dmginfo:GetAttacker()), @@ -139,13 +140,18 @@ function ENT:OnKilled(dmginfo) inst.Types.Vector.Wrap(dmginfo:GetDamageForce()), dmginfo:GetDamageType()) end + if ent_tbl.RagdollOnDeath then + if SF.NextBotRagdolls:check(inst.player) == 0 then + self:Remove() -- so the nextbots dont stay forever until cleanup + return + end + local CreatedRagdoll = self:BecomeRagdoll(dmginfo) - ent_tbl.InstanceRagdollCreationCallback(CreatedRagdoll) -- this is used for ragdoll cleanup. check nextbot.lua at line 128 + SF.NextBotRagdolls:register(inst, CreatedRagdoll) - if not ent_tbl.RagCreationCallbacks:isEmpty() then - local inst = ent_tbl.instance - ent_tbl.RagCreationCallbacks:run(inst, + if not ent_tbl.RagdollCreationCallbacks:isEmpty() then + ent_tbl.RagdollCreationCallbacks:run(inst, inst.WrapObject(CreatedRagdoll)) end end @@ -185,4 +191,4 @@ function ENT:OnContact(colent) if ent_tbl.ContactCallbacks:isEmpty() then return end local inst = ent_tbl.instance ent_tbl.ContactCallbacks:run(inst, inst.WrapObject(colent)) -end \ No newline at end of file +end From 2351d702fef879bab65434809956fec0fe41c3b4 Mon Sep 17 00:00:00 2001 From: AstalNeker <85320199+AstalNeker@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:44:23 +0100 Subject: [PATCH 3/7] fix nextbot.lua + 3 new function --- lua/starfall/libs_sv/nextbot.lua | 37 +++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/lua/starfall/libs_sv/nextbot.lua b/lua/starfall/libs_sv/nextbot.lua index 55ea0502c..a1f5b6db9 100644 --- a/lua/starfall/libs_sv/nextbot.lua +++ b/lua/starfall/libs_sv/nextbot.lua @@ -2,7 +2,6 @@ local registerprivilege = SF.Permissions.registerPrivilege local checkluatype = SF.CheckLuaType local ENT_META = FindMetaTable("Entity") - --- NextBot type -- @name NextBot -- @class type @@ -64,8 +63,6 @@ registerprivilege("nextbot.setAvoidAllowed", "Nextbot allow avoid", "Allows the registerprivilege("nextbot.setJumpGapsAllowed", "Nextbot allow jump gaps", "Allows the user to set whether the nextbot can jump gaps.", {entities = {}}) local entList = SF.EntManager("nextbots", "nextbots", 30, "The number of props allowed to spawn via Starfall") -local ragdollsList = SF.EntManager("nextbots_ragdolls", "nextbots_ragdolls", -1, "Auto cleanup ragdoll on deinitialize") - return function(instance) local checkpermission = instance.player ~= SF.Superuser and SF.Permissions.check or function() end @@ -85,7 +82,7 @@ end) instance:AddHook("deinitialize", function() entList:deinitialize(instance, true) - ragdollsList:deinitialize(instance, true) + SF.NextBotRagdolls:deinitialize(instance, true) end) --- Creates a customizable NextBot @@ -122,10 +119,6 @@ function nextbot_library.create(pos, mdl) end entList:register(instance, nb) - - -- sorry i can't find a better way :) - local ent_tbl = Ent_GetTable(nb) - ent_tbl.InstanceRagdollCreationCallback = function(ragdoll) ragdollsList:register(instance, ragdoll) end instance:checkCpu() return nbwrap(nb) @@ -146,6 +139,30 @@ function nextbot_library.canSpawn() return entList:check(instance.player) > 0 end +--- Checks how many nextbots can be spawned +-- @server +-- @return number Number of nextbots able to be spawned +function nextbot_library.nextbotsLeft() + if not SF.Permissions.hasAccess(instance, nil, "nextbot.create") then return 0 end + return entList:check(instance.player) +end + +--- Checks if a user can spawn anymore nextbots ragdolls. +-- @server +-- @return boolean True if user can spawn nextbots ragdolls, False if not. +function nextbot_library.canSpawnRagdoll() + -- if not SF.Permissions.hasAccess(instance, nil, "nextbot.ragdollOnDeath") then return false end + return SF.NextBotRagdolls:check(instance.player) > 0 +end + +--- Checks how many ragdolls the nextbots can spawn. +-- @server +-- @return number Number how many ragdoll can be spawned. +function nextbot_library.ragdollsLeft() + -- if not SF.Permissions.hasAccess(instance, nil, "nextbot.ragdollOnDeath") then return 0 end + return SF.NextBotRagdolls:check(instance.player) +end + --- Makes the nextbot try to go to a specified position without using navmesh pathfinding (in a straight line). --- setGotoPos takes priority. -- @server @@ -487,7 +504,7 @@ function nb_methods:addRagdollCreationCallback(id, func) checkluatype(func, TYPE_FUNCTION) local nb = nbunwrap(self) checkpermission(instance, nb, "nextbot.addRagdollCreationCallback") - nb.RagCreationCallbacks:add(id, func) + nb.RagdollCreationCallbacks:add(id, func) end --- Removes the ragdoll creation callback function from the NextBot if present. @@ -497,7 +514,7 @@ function nb_methods:removeRagdollCreationCallback(id) checkluatype(id, TYPE_STRING) local nb = nbunwrap(self) checkpermission(instance, nb, "nextbot.removeRagdollCreationCallback") - nb.RagCreationCallbacks:remove(id) + nb.RagdollCreationCallbacks:remove(id) end --- Enable or disable ragdolling on death for the NextBot. From f5f6b981d144f34292e2208dd7adb6a9c469511b Mon Sep 17 00:00:00 2001 From: AstalNeker <85320199+AstalNeker@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:48:03 +0100 Subject: [PATCH 4/7] Uncomment permission checks for nextbot ragdolls a mistake :/ --- lua/starfall/libs_sv/nextbot.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/starfall/libs_sv/nextbot.lua b/lua/starfall/libs_sv/nextbot.lua index a1f5b6db9..1075effed 100644 --- a/lua/starfall/libs_sv/nextbot.lua +++ b/lua/starfall/libs_sv/nextbot.lua @@ -151,7 +151,7 @@ end -- @server -- @return boolean True if user can spawn nextbots ragdolls, False if not. function nextbot_library.canSpawnRagdoll() - -- if not SF.Permissions.hasAccess(instance, nil, "nextbot.ragdollOnDeath") then return false end + if not SF.Permissions.hasAccess(instance, nil, "nextbot.ragdollOnDeath") then return false end return SF.NextBotRagdolls:check(instance.player) > 0 end @@ -159,7 +159,7 @@ end -- @server -- @return number Number how many ragdoll can be spawned. function nextbot_library.ragdollsLeft() - -- if not SF.Permissions.hasAccess(instance, nil, "nextbot.ragdollOnDeath") then return 0 end + if not SF.Permissions.hasAccess(instance, nil, "nextbot.ragdollOnDeath") then return 0 end return SF.NextBotRagdolls:check(instance.player) end From 6657f58fcda1f945e3fd39c7ffd53b1943b0f5db Mon Sep 17 00:00:00 2001 From: thegrb93 Date: Mon, 16 Mar 2026 18:47:13 -0400 Subject: [PATCH 5/7] Replace early return --- lua/entities/starfall_cnextbot.lua | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lua/entities/starfall_cnextbot.lua b/lua/entities/starfall_cnextbot.lua index 7f5fdac90..a3886cd72 100644 --- a/lua/entities/starfall_cnextbot.lua +++ b/lua/entities/starfall_cnextbot.lua @@ -142,17 +142,15 @@ function ENT:OnKilled(dmginfo) end if ent_tbl.RagdollOnDeath then - if SF.NextBotRagdolls:check(inst.player) == 0 then - self:Remove() -- so the nextbots dont stay forever until cleanup - return - end - - local CreatedRagdoll = self:BecomeRagdoll(dmginfo) - SF.NextBotRagdolls:register(inst, CreatedRagdoll) + if SF.NextBotRagdolls:check(inst.player) > 0 then + local CreatedRagdoll = self:BecomeRagdoll(dmginfo) + SF.NextBotRagdolls:register(inst, CreatedRagdoll) - if not ent_tbl.RagdollCreationCallbacks:isEmpty() then - ent_tbl.RagdollCreationCallbacks:run(inst, - inst.WrapObject(CreatedRagdoll)) + if not ent_tbl.RagdollCreationCallbacks:isEmpty() then + ent_tbl.RagdollCreationCallbacks:run(inst, inst.WrapObject(CreatedRagdoll)) + end + else + self:Remove() -- Remove instead of becoming a ragdoll end end end From ec12bfb4f9548979642231a0c113d9a6cf133c7e Mon Sep 17 00:00:00 2001 From: thegrb93 Date: Tue, 17 Mar 2026 15:53:57 -0400 Subject: [PATCH 6/7] Fix not removing when killed --- lua/entities/starfall_cnextbot.lua | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lua/entities/starfall_cnextbot.lua b/lua/entities/starfall_cnextbot.lua index a3886cd72..dd1f3537a 100644 --- a/lua/entities/starfall_cnextbot.lua +++ b/lua/entities/starfall_cnextbot.lua @@ -141,17 +141,15 @@ function ENT:OnKilled(dmginfo) dmginfo:GetDamageType()) end - if ent_tbl.RagdollOnDeath then - if SF.NextBotRagdolls:check(inst.player) > 0 then - local CreatedRagdoll = self:BecomeRagdoll(dmginfo) - SF.NextBotRagdolls:register(inst, CreatedRagdoll) + if ent_tbl.RagdollOnDeath and SF.NextBotRagdolls:check(inst.player) > 0 then + local CreatedRagdoll = self:BecomeRagdoll(dmginfo) + SF.NextBotRagdolls:register(inst, CreatedRagdoll) - if not ent_tbl.RagdollCreationCallbacks:isEmpty() then - ent_tbl.RagdollCreationCallbacks:run(inst, inst.WrapObject(CreatedRagdoll)) - end - else - self:Remove() -- Remove instead of becoming a ragdoll + if not ent_tbl.RagdollCreationCallbacks:isEmpty() then + ent_tbl.RagdollCreationCallbacks:run(inst, inst.WrapObject(CreatedRagdoll)) end + else + self:Remove() -- Remove instead of becoming a ragdoll end end From e787dc0a3f9e348ddefd5c442eee28b29072d3da Mon Sep 17 00:00:00 2001 From: thegrb93 Date: Wed, 18 Mar 2026 01:29:52 -0400 Subject: [PATCH 7/7] Add isValid check --- lua/entities/starfall_cnextbot.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lua/entities/starfall_cnextbot.lua b/lua/entities/starfall_cnextbot.lua index dd1f3537a..65cacd6d0 100644 --- a/lua/entities/starfall_cnextbot.lua +++ b/lua/entities/starfall_cnextbot.lua @@ -142,14 +142,16 @@ function ENT:OnKilled(dmginfo) end if ent_tbl.RagdollOnDeath and SF.NextBotRagdolls:check(inst.player) > 0 then - local CreatedRagdoll = self:BecomeRagdoll(dmginfo) - SF.NextBotRagdolls:register(inst, CreatedRagdoll) + local ragdoll = self:BecomeRagdoll(dmginfo) + if ragdoll:IsValid() then + SF.NextBotRagdolls:register(inst, ragdoll) + end if not ent_tbl.RagdollCreationCallbacks:isEmpty() then - ent_tbl.RagdollCreationCallbacks:run(inst, inst.WrapObject(CreatedRagdoll)) + ent_tbl.RagdollCreationCallbacks:run(inst, inst.WrapObject(ragdoll)) end else - self:Remove() -- Remove instead of becoming a ragdoll + self:Remove() end end