@@ -2,11 +2,13 @@ use bevy_math::UVec3;
22use bonsai_bt:: {
33 Action ,
44 Behavior :: { AlwaysSucceed , If , Select , WhenAny } ,
5- Event , Sequence , Status , UpdateArgs , BT , RUNNING ,
5+ Event , Sequence ,
6+ Status :: { self } ,
7+ UpdateArgs , BT , RUNNING ,
68} ;
79use itertools:: Itertools ;
810use oktree:: prelude:: * ;
9- use parking_lot:: RwLock ;
11+ use parking_lot:: { Mutex , RwLock } ;
1012use rrplug:: {
1113 bindings:: class_types:: { cbaseentity:: CBaseEntity , client:: CClient , cplayer:: CPlayer } ,
1214 prelude:: * ,
@@ -17,22 +19,31 @@ use shared::{
1719 utils:: { get_player_index, is_alive, lookup_ent, nudge_type, trace_ray} ,
1820} ;
1921use std:: {
20- collections:: { BTreeMap , BTreeSet , HashMap , VecDeque } ,
22+ collections:: { BTreeSet , HashMap , VecDeque } ,
2123 sync:: { Arc , LazyLock } ,
2224} ;
2325
2426use crate :: {
2527 async_pathfinding:: { GoalFloat , PathReceiver } ,
28+ gamemode_cp:: { run_cp, GamemodeCP , GamemodeCPAction , SharedGamemodeCP } ,
2629 loader:: { Navmesh , NavmeshStatus , Octree32 } ,
2730 movement:: { run_movement, Movement , MovementAction } ,
2831 nav_points:: { tuvec_to_vector3, vector3_to_tuvec, NavPoint } ,
29- pathfinding:: { find_path, AreaCost , Goal } ,
30- targeting:: { run_targeting, Target , Targeting , TargetingAction } ,
32+ pathfinding:: { find_path, Goal } ,
33+ targeting:: { run_targeting, Targeting , TargetingAction } ,
3134} ;
3235
3336static BEHAVIOR : LazyLock < RwLock < HashMap < u16 , BT < BotAction , BotBrain > > > > =
3437 LazyLock :: new ( || RwLock :: new ( HashMap :: new ( ) ) ) ;
38+ static SHARED : LazyLock < Arc < Mutex < SharedBotBrain > > > =
39+ LazyLock :: new ( || Arc :: new ( Mutex :: new ( SharedBotBrain :: default ( ) ) ) ) ;
3540
41+ #[ derive( Debug , Clone , Default ) ]
42+ pub struct SharedBotBrain {
43+ pub cp : SharedGamemodeCP ,
44+ }
45+
46+ #[ derive( Debug , Clone ) ]
3647pub struct BotBrain {
3748 pub navmesh : Arc < RwLock < Navmesh > > ,
3849 pub path_receiver : Option < PathReceiver > ,
@@ -45,10 +56,13 @@ pub struct BotBrain {
4556 pub last_alive_state : bool ,
4657 pub looked_at_death_record : bool ,
4758 pub needs_new_path : bool ,
59+ gamemode : String ,
60+ pub shared : Arc < Mutex < SharedBotBrain > > ,
4861
4962 /// movement
5063 pub m : Movement ,
5164 pub t : Targeting ,
65+ pub cp : GamemodeCP ,
5266}
5367
5468#[ derive( Debug , Clone ) ]
@@ -60,10 +74,13 @@ pub enum BotAction {
6074 DeadState ,
6175 Movement ( MovementAction ) ,
6276 Targeting ( TargetingAction ) ,
77+ GamemodeCP ( GamemodeCPAction ) ,
78+ IsGamemode ( & ' static str ) ,
6379}
6480
6581pub fn drop_behaviors ( ) {
6682 BEHAVIOR . write ( ) . clear ( ) ;
83+ * SHARED . lock ( ) = Default :: default ( ) ;
6784}
6885
6986pub extern "C" fn init_bot ( edict : u16 , client : & CClient ) {
@@ -104,6 +121,15 @@ pub extern "C" fn init_bot(edict: u16, client: &CClient) {
104121 Action ( TargetingAction :: TargetSwitching . into( ) ) ,
105122 ] ) ;
106123
124+ let gamemode_cp = AlwaysSucceed ( Box :: new ( Sequence ( vec ! [
125+ Select ( vec![
126+ Action ( BotAction :: IsGamemode ( "cp" ) ) ,
127+ Action ( BotAction :: IsGamemode ( "mcp" ) ) ,
128+ ] ) ,
129+ Action ( GamemodeCPAction :: UpdateGamemodeState . into( ) ) ,
130+ Action ( GamemodeCPAction :: DetermineTarget . into( ) ) ,
131+ ] ) ) ) ;
132+
107133 let target_tracking = Sequence ( vec ! [
108134 Action ( TargetingAction :: FindTarget . into( ) ) ,
109135 Action ( BotAction :: RenderPath ) ,
@@ -118,8 +144,17 @@ pub extern "C" fn init_bot(edict: u16, client: &CClient) {
118144 Action ( BotAction :: CheckNavmesh ) ,
119145 If (
120146 Box :: new( Action ( BotAction :: IsDead ) ) ,
121- Box :: new( Action ( BotAction :: DeadState ) ) ,
122- Box :: new( target_tracking) ,
147+ Box :: new( Sequence ( vec![
148+ Action ( BotAction :: DeadState ) ,
149+ Select ( vec![ Sequence ( vec![
150+ Select ( vec![
151+ Action ( BotAction :: IsGamemode ( "cp" ) ) ,
152+ Action ( BotAction :: IsGamemode ( "mcp" ) ) ,
153+ ] ) ,
154+ Action ( GamemodeCPAction :: RemoveTarget . into( ) ) ,
155+ ] ) ] ) ,
156+ ] ) ) ,
157+ Box :: new( Sequence ( vec![ gamemode_cp, target_tracking] ) ) ,
123158 ) ,
124159 ] ) ;
125160
@@ -141,29 +176,15 @@ pub extern "C" fn init_bot(edict: u16, client: &CClient) {
141176 angles : Vector3 :: ZERO ,
142177 abs_origin : Vector3 :: ZERO ,
143178 needs_new_path : true ,
179+ gamemode : String :: new ( ) ,
180+
181+ t : Targeting :: default ( ) ,
182+
183+ m : Movement :: default ( ) ,
184+
185+ cp : GamemodeCP :: default ( ) ,
144186
145- t : Targeting {
146- current_target : Target :: None ,
147- last_target : Target :: None ,
148- reacts_at : 0. ,
149- spread : Vec :: new ( ) ,
150- spread_rigth : true ,
151- hates : BTreeMap :: default ( ) ,
152- } ,
153-
154- m : Movement {
155- can_move : true ,
156- next_wall_point : None ,
157- next_point_override : None ,
158- view_lock : false ,
159- clamped_view : Some ( 0. ) ,
160- jump_tick : 0 ,
161- vault_tick : 0 ,
162- down_tick : 0 ,
163- area_cost : AreaCost :: default ( ) ,
164- last_path_points : Vec :: new ( ) ,
165- last_point_reached_delta : 0. ,
166- } ,
187+ shared : Arc :: clone ( & * SHARED ) ,
167188 } ,
168189 ) ) ;
169190}
@@ -193,6 +214,10 @@ pub extern "C" fn wallpathfining_bots(helper: &CUserCmdHelper, bot: &mut CPlayer
193214 bt. blackboard_mut ( ) . origin = unsafe { * bot. get_origin ( & mut v) } ;
194215 bt. blackboard_mut ( ) . angles = unsafe { * bot. eye_angles ( & mut v) } ;
195216 bt. blackboard_mut ( ) . abs_origin = bot. m_vecAbsOrigin ;
217+ bt. blackboard_mut ( ) . gamemode =
218+ ConVarStruct :: find_convar_by_name ( "mp_gamemode" , unsafe { EngineToken :: new_unchecked ( ) } )
219+ . map ( |convar| convar. get_value_string ( ) )
220+ . unwrap_or_default ( ) ;
196221
197222 if is_alive ( bot) != bt. blackboard ( ) . last_alive_state {
198223 bt. reset_bt ( ) ;
@@ -341,11 +366,8 @@ pub extern "C" fn wallpathfining_bots(helper: &CUserCmdHelper, bot: &mut CPlayer
341366
342367 ( Status :: Success , 0. )
343368 }
344-
345369 BotAction :: Movement ( movement) => run_movement ( movement, brain, bot, helper) ,
346-
347370 BotAction :: Targeting ( targeting) => run_targeting ( targeting, brain, bot, helper) ,
348-
349371 BotAction :: IsDead => {
350372 if brain. last_alive_state {
351373 brain. looked_at_death_record = false ;
@@ -354,7 +376,6 @@ pub extern "C" fn wallpathfining_bots(helper: &CUserCmdHelper, bot: &mut CPlayer
354376 ( Status :: Success , 0. )
355377 }
356378 }
357-
358379 BotAction :: DeadState => {
359380 brain. needs_new_path = true ;
360381 // this a bit dangerous since if FindPath is running in parallel it can cause lot's of tasks to get pushed to the worker threads which will overwhelm them
@@ -371,6 +392,14 @@ pub extern "C" fn wallpathfining_bots(helper: &CUserCmdHelper, bot: &mut CPlayer
371392
372393 ( Status :: Success , 0. )
373394 }
395+ BotAction :: IsGamemode ( gamemode) => {
396+ if & brain. gamemode == gamemode {
397+ ( Status :: Success , 0. )
398+ } else {
399+ ( Status :: Failure , 0. )
400+ }
401+ }
402+ BotAction :: GamemodeCP ( gamemode_cp) => run_cp ( gamemode_cp, brain, bot, helper) ,
374403 } ) ;
375404
376405 if bt. is_finished ( ) {
0 commit comments