Nextbot Pathfinding for Players

Hello there! After a while of perseverance and function requests on Github, I’ve finally completed my goal: Nextbot pathfinding for players, that can be used in StartCommand! If anyone here has wanted deathmatch bots/AI that has great pathfinding, then this is most certainly for you. The code is only in two files, here’s the first:


 -- Put this in autorun/server/playerbots.lua

function CreatePlayerBot( nick )
	if game.MaxPlayers() > 1 then
		local bot = player.CreateNextBot( nick )
		bot.FollowerEnt = ents.Create( "sent_anti_dummynb" )
		bot.FollowerEnt:Spawn()
		bot.LastPath = nil
		bot.CurSegment = 2
		bot.IsNBBot = true
	end
end

function table.EqualValues(t1,t2,ignore_mt)
	ignore_mt = ignore_mt or true
	local ty1 = type(t1)
	local ty2 = type(t2)
	if ty1 ~= ty2 then return false end
	-- non-table types can be directly compared
	if ty1 ~= 'table' and ty2 ~= 'table' then return t1 == t2 end
	-- as well as tables which have the metamethod __eq
	local mt = getmetatable(t1)
	if not ignore_mt and mt and mt.__eq then return t1 == t2 end
	for k1,v1 in pairs(t1) do
		local v2 = t2[k1]
		if v2 == nil or not table.EqualValues(v1,v2) then return false end
	end
	for k2,v2 in pairs(t2) do
		local v1 = t1[k2]
		if v1 == nil or not table.EqualValues(v1,v2) then return false end
	end
	return true
end

debug.getregistry().Player.LookatPosXY = function( self, cmd, pos )
	local our_position = self:GetPos()
	local distance = our_position:Distance( pos )
	
	local pitch = math.atan2( -(pos.z - our_position.z), distance )
	local yaw = math.deg(math.atan2(pos.y - our_position.y, pos.x - our_position.x))
	
	self:SetEyeAngles( Angle( pitch, yaw, 0 ) )
	cmd:SetViewAngles( Angle( pitch, yaw, 0 ) )
end

hook.Add( "StartCommand", "Control_Bots", function( bot, cmd )
	if bot.IsNBBot then -- check if it's a specific NB bot, since ordinary bots obviously
		-- don't spawn with the same vars we've set
		
		cmd:ClearMovement()
		cmd:ClearButtons()
		
		if bot.FollowerEnt:GetPos() ~= bot:GetPos() then
			bot.FollowerEnt:SetPos( bot:GetPos() )
		end
		
		 bot.FollowerEnt.PosGen = Entity( 1 ):GetPos()
			
		if bot.FollowerEnt.P then
			bot.LastPath = bot.FollowerEnt.P:GetAllSegments()
		end
		if bot.CurSegment ~= 2 and !table.EqualValues( bot.LastPath, bot.FollowerEnt.P:GetAllSegments() ) then
			bot.CurSegment = 2
		end
		
		if !bot.LastPath then return end
		local curgoal = bot.LastPath[bot.CurSegment]
		if !curgoal then return end
		bot:LookatPosXY( cmd, curgoal.pos )
		cmd:SetForwardMove( 200 )
		
		if bot:GetPos():Distance( curgoal.pos ) <= 20 then
			bot.CurSegment = bot.CurSegment + 1
		end
		print(bot.CurSegment)
	end
end )

And then, the second file, which should be in lua/entities/sent_anti_dummynb.lua:


if SERVER then AddCSLuaFile() end

ENT.Base = "base_nextbot"
ENT.Type = "nextbot"

function ENT:Initialize()
	self:SetModel( "models/humans/group01/male_03.mdl" )
        -- remove the line below if you want it to be invisible, it's only visible for debug purposes right now
	--self:SetNoDraw( true )
	self:SetSolid( SOLID_NONE )
	self.PosGen = nil
end

function ENT:ChasePos( options )
	self.P = Path( "Follow" )
	self.P:SetMinLookAheadDistance( options.lookahead or 300 )
	self.P:SetGoalTolerance( options.goaltolerance or 20 )
	self.P:Compute( self, self.PosGen )
	
	if !self.P:IsValid() then return end
	while self.P:IsValid() do
		if self.P:GetAge() > 0.1 then
			self.P:Compute( self, self.PosGen )
		end
		self.P:Draw()
		
		if self.loco:IsStuck() then
			self:HandleStuck()
			return
		end
		
		coroutine.yield()
	end
end

function ENT:RunBehaviour()
	while ( true ) do
		if self.PosGen then
			self:ChasePos( {} )
		end
		
		coroutine.yield()
	end
end

I need to fix the jittery movement when a bot gets to the end of a segment, but for now it’s perfect.
Feel free to use this as a base for any AI player base, maybe even one for TTT.

What the hell is up with the camera in your example video? It’s absolutely nauseating. Cool addon though.

Just YouTube “fixing” the video and the GMod demo system.

So can this be used on players themselves? Having the classic MMORPG /follow command would be cool.

Yep. You’d just need to edit the code a bit, but it would work.