NextBot Coding and Discussion Thread

This thread will be for anything related to the new NextBot system, I’ll keep the OP updated with useful information to help anyone who has questions or needs help.

Update 160 added bindings to the nextbot system, which is what CSS, TF2 and L4D bots use.
This allows us to do all kinds of stuff that we couldn’t do before with the old system. Including using coroutines thanks to garry.

[h2]Examples[/h2]
The code for the NextBot is here: link
And here is Garry’s test NPC:
[lua]AddCSLuaFile()

ENT.Base = “base_nextbot”
ENT.Spawnable = true

function ENT:Initialize()
–self:SetModel( “models/props_halloween/ghost_no_hat.mdl” );
–self:SetModel( “models/props_wasteland/controlroom_filecabinet002a.mdl” );
self:SetModel( “models/mossman.mdl” );
end

function ENT:BehaveAct()
end

function ENT:RunBehaviour()
while ( true ) do
– walk somewhere random
self:StartActivity( ACT_WALK ) – walk anims
self.loco:SetDesiredSpeed( 100 ) – walk speeds
self:MoveToPos( self:GetPos() + Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 ) * 200 ) – walk to a random place within about 200 units (yielding)

    self:StartActivity( ACT_IDLE )        -- revert to idle activity


    self:PlaySequenceAndWait( "idle_to_sit_ground" )                            -- Sit on the floor
    self:SetSequence( "sit_ground" )                                            -- Stay sitting
    coroutine.wait( self:PlayScene( "scenes/eli_lab/mo_gowithalyx01.vcd" ) )    -- play a scene and wait for it to finish before progressing
    self:PlaySequenceAndWait( "sit_ground_to_idle" )                            -- Get up


    -- find the furthest away hiding spot
    local pos = self:FindSpot( "random", { type = 'hiding', radius = 5000 } )


    -- if the position is valid
    if ( pos ) then
        self:StartActivity( ACT_RUN )                                            -- run anim
        self.loco:SetDesiredSpeed( 200 )                                        -- run speed
        self:PlayScene( "scenes/npc/female01/watchout.vcd" )                    -- shout something while we run just for a laugh
        self:MoveToPos( pos )                                                    -- move to position (yielding)
        self:PlaySequenceAndWait( "fear_reaction" )                                -- play a fear animation
        self:StartActivity( ACT_IDLE )                                            -- when we finished, go into the idle anim
    else
        -- some activity to signify that we didn't find shit
    end
    coroutine.yield()
end

end

– List the NPC as spawnable
list.Set( “NPC”, “npc_tf2_ghost”, { Name = “TF2 Ghost”,
Class = “npc_tf2_ghost”,
Category = “TF2”
})[/lua]

Here is a NPC that I made, it runs at the player and when its close enough it will jump at them and explode

[lua]AddCSLuaFile()

ENT.Base = “base_nextbot”
ENT.Spawnable = true

function ENT:Initialize()

self:SetModel( "models/weapons/ut2k4_parasite_mine.mdl" );
self:SetSkin(math.random(0,1))
self:SetHealth(50)

self.loco:SetDeathDropHeight(500)	//default 200
self.loco:SetAcceleration(900)		//default 400
self.loco:SetDeceleration(900)		//default 400
self.loco:SetStepHeight(18)			//default 18
self.loco:SetJumpHeight(50)		//default 58

self.Isjumping = false

end

function ENT:Splode()
local Boom = ents.Create(“env_explosion”)
Boom:SetPos(self:GetPos())
Boom:SetKeyValue( “iMagnitude”, “90” )
// Boom:SetOwner(self.Entity:GetOwner())
Boom:SetOwner(self)
Boom:Spawn()
Boom:Fire(“Explode”,0,0)
Boom:Fire(“Kill”,0,0)

self:Remove()

end


– Name: NEXTBOT:BehaveUpdate
– Desc: Called to update the bot’s behaviour
– Arg1: number|interval|How long since the last update
– Ret1:

function ENT:BehaveUpdate( fInterval )

if ( !self.BehaveThread ) then return end

-- If you are not jumping yet and a player is close jump at them
if (!self.Isjumping) then
	local ent = ents.FindInSphere( self:GetPos(), 120 )
	for k,v in pairs( ent ) do
		if v:IsPlayer() then
			self.loco:FaceTowards( v:GetPos() )
			self.loco:Jump( )
			self.Isjumping = true
		end
	end	
else	-- If you are in the air and a player is really close explode
	local ent = ents.FindInSphere( self:GetPos(), 50 )
	for k,v in pairs( ent ) do
		if v:IsPlayer() then
			self:Splode()
		end
	end	
end
	
local ok, message = coroutine.resume( self.BehaveThread )
if ( ok == false ) then


	self.BehaveThread = nil
	Msg( self, "error: ", message, "

" );

end

end

function ENT:RunBehaviour()

while ( true ) do


	-- Find the player
	pos = Entity(1):GetPos()
	-- if the position is valid
	if ( pos ) then
		self:StartActivity( ACT_RUN )				-- run anim
		self.loco:SetDesiredSpeed( 360 )			-- run speed	
		local opts = {	lookahead = 300,
						tolerance = 20,
						draw = true,
						maxage = 1,
						repath = 0.1	}
		
		self:MoveToPos( pos, opts )													-- move to position (yielding)


	else


		-- some activity to signify that we didn't find shit
		self:StartActivity( ACT_RUN )							-- walk anims
		self.loco:SetDesiredSpeed( 360 )						-- walk speeds
		self:MoveToPos( self:GetPos() + Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 ) * 200 ) -- walk to a random place within about 200 units (yielding)
	end


	coroutine.yield()


end

end

function ENT:OnLandOnGround()

self.Isjumping = false
self:StartActivity( ACT_RUN )

end

function ENT:OnKilled( damageinfo )

-- If its killed by something other then it exploding then explode
if ( damageinfo:GetAttacker() != self ) then
	self:Splode()
end
self:BecomeRagdoll( damageinfo )

end


– List the NPC as spawnable

list.Set( “NPC”, “UT2K4_SpiderMine”, { Name = “UT2K4 Spider Mine”,
Class = “UT2K4_SpiderMine”,
Category = “UT2K4”
})[/lua]
Here is it in action:

http://puu.sh/2x9m0

[h2]Useful links[/h2]
Gmod wiki
BotPath
Locomotion
NavArea
NextBot
NextBot Hooks
navmesh library
Valve wiki
Navigation Meshes
[h2]Useful information[/h2]

  • CSS maps have navmeshes but you have to copy them from the gcf to be able to use them in GMod
  • Locomotion is accessible through a NextBot entity’s ‘loco’ property/key.
  • NextBot cvars begin with the nb_ prefix
    [h2]NextBot Console Commands[/h2]

nb_allow_avoiding                        : 1        : , "sv", "cheat"  : 
nb_allow_climbing                        : 1        : , "sv", "cheat"  : 
nb_allow_gap_jumping                     : 1        : , "sv", "cheat"  : 
nb_blind                                 : 0        : , "sv", "cheat"  : Disable vision
nb_command                               : cmd      :                  : Sends a command string to all bots
nb_debug                                 : cmd      :                  : Debug NextBots.  Categories are: BEHAVIOR, LOOK_AT, PATH, ANIMATION, LOCOMOTION, VISION, HEARING, EVENTS, ERRORS.
nb_debug_climbing                        : 0        : , "sv", "cheat"  : 
nb_debug_filter                          : cmd      :                  : Add items to the NextBot debug filter. Items can be entindexes or part of the indentifier of one or more bots.
nb_debug_history                         : 1        : , "sv", "cheat"  : If true, each bot keeps a history of debug output in memory
nb_debug_known_entities                  : 0        : , "sv", "cheat"  : Show the 'known entities' for the bot that is the current spectator target
nb_delete_all                            : cmd      :                  : Delete all non-player NextBot entities.
nb_force_look_at                         : cmd      :                  : Force selected bot to look at the local player's position
nb_goal_look_ahead_range                 : 50       : , "sv", "cheat"  : 
nb_head_aim_resettle_angle               : 100      : , "sv", "cheat"  : After rotating through this angle, the bot pauses to 'recenter' its virtual mouse on its virtual mousepad
nb_head_aim_resettle_time                : 0        : , "sv", "cheat"  : How long the bot pauses to 'recenter' its virtual mouse on its virtual mousepad
nb_head_aim_settle_duration              : 0        : , "sv", "cheat"  : 
nb_head_aim_steady_max_rate              : 100      : , "sv", "cheat"  : 
nb_ladder_align_range                    : 50       : , "sv", "cheat"  : 
nb_last_area_update_tolerance            : 4        : , "sv", "cheat"  : Distance a character needs to travel in order to invalidate cached area
nb_move_to_cursor                        : cmd      :                  : Tell all NextBots to move to the cursor position
nb_path_draw_inc                         : 100      : , "sv", "cheat"  : 
nb_path_draw_segment_count               : 100      : , "sv", "cheat"  : 
nb_path_segment_influence_radius         : 100      : , "sv", "cheat"  : 
nb_player_crouch                         : 0        : , "sv", "cheat"  : Force bots to crouch
nb_player_move                           : 1        : , "sv", "cheat"  : Prevents bots from moving
nb_player_move_direct                    : 0        : , "sv"           : 
nb_player_stop                           : 0        : , "sv", "cheat"  : Stop all NextBotPlayers from updating
nb_player_walk                           : 0        : , "sv", "cheat"  : Force bots to walk
nb_saccade_speed                         : 1000     : , "sv", "cheat"  : 
nb_saccade_time                          : 0        : , "sv", "cheat"  : 
nb_select                                : cmd      :                  : Select the bot you are aiming at for further debug operations.
nb_shadow_dist                           : 400      : , "cl"           : 
nb_speed_look_ahead_range                : 150      : , "sv", "cheat"  : 
nb_stop                                  : 0        : , "sv", "cheat", "rep" : Stop all NextBots
nb_update_debug                          : 0        : , "sv", "cheat"  : 
nb_update_framelimit                     : 15       : , "sv", "cheat"  : 
nb_update_frequency                      : 0        : , "sv", "cheat"  : 
nb_update_maxslide                       : 2        : , "sv", "cheat"  : 
nb_warp_selected_here                    : cmd      :                  : Teleport the selected bot to your cursor position

I’ll make a better OP tonight when I have more time.

Useful article on navigation: https://developer.valvesoftware.com/wiki/Navmesh

[lua]
gamemodes/base/entities/entities/base_nextbot/sv_nextbot.lua:255: bad key to string index (numberNextBot [97][bt_test]error: gamemodes/base/entities/entities/base_nextbot/sv_nextbot.lua:255: bad key to string index (numberOnInjured
O
[/lua]

Hmm… I get those errors and NPCs are not moving.
What I suppose to do?

-snip-

Info was added to the OP.

Here’s a very useful navmesh module. It generates air nodes as well, so it can find almost any path
http://forum.facepunch.com/showthread.php?t=953805

That’s actually for a node graph. They are similar, but different.

Fair enough, but this is a much more complete solution for path-finding. You can adjust the spacing of the nodes as well as the amount.

Thanks, I added everything to the OP

Its not related to Nextbots though, Nextbots use Navmeshes to navigate, not node graphs.

Except nextbot doesn’t use AI nodes?

Well is it possible to implement? I was just throwing this module out there; I haven’t experimented with nextbot yet.

You just need to run “nav_generate” and wait

Are animations automatic or you have to manually control the bots anims?

They work the same as player animations really. So you just have a function where its like if player is jumping, use jump anim. If under water… play swim anim etc.

I added a helper function to do the feet walk speed move_x/move_y stuff for you.

You have to specify the animation using StartActivity, the animation speed should automatically adjust to the speed of the bot.

[lua]self:StartActivity( ACT_RUN )
self.loco:SetDesiredSpeed( 360 )
self:MoveToPos(Vector)[/lua]

-snip- found it on the wiki

Holy shit, thanks for this Garry! Creating NPC’s is going to be a lot easier to do. Can’t wait to start messing with this!

Hey garry, you said if we wanted anything else hooked into that we should find the engine function for you to use. Where can we look them up? I can think of a lot of things I would like exposed but I don’t know where to look.

[editline]10th April 2013[/editline]

Post your code and I’ll see if I can help

A “Use” function would be nice :slight_smile:

Couldn’t the engine’s functions be found on the Valve Development wiki?

I haven’t found anything on there yet