Skip to content

Commit

Permalink
[MIRROR] ai controllers use cell trackers to know when to idle (#2034) (
Browse files Browse the repository at this point in the history
#2938)

* ai controllers use cell trackers to know when to idle (#82691)

## About The Pull Request
this makes ai controllers use cell trackers and signals to determine
when to idle

## Why It's Good For The Game
might be better than looping over all clients for every controller

## Changelog
:cl:
code: The way mobs idle has been refactored, please report any issues
with non-reactive mobs
/:cl:

* ai controllers use cell trackers to know when to idle

---------

Co-authored-by: NovaBot <[email protected]>
Co-authored-by: Ben10Omintrix <[email protected]>
  • Loading branch information
3 people authored Apr 18, 2024
1 parent 4167c40 commit fe59d3f
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 14 deletions.
2 changes: 1 addition & 1 deletion code/__DEFINES/ai/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#define AI_BOT_PATH_LENGTH 150

// How far should we, by default, be looking for interesting things to de-idle?
#define AI_DEFAULT_INTERESTING_DIST 14
#define AI_DEFAULT_INTERESTING_DIST 10

///Cooldown on planning if planning failed last time

Expand Down
14 changes: 1 addition & 13 deletions code/controllers/subsystem/ai_controllers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ SUBSYSTEM_DEF(ai_controllers)

/datum/controller/subsystem/ai_controllers/fire(resumed)
var/timer = TICK_USAGE_REAL
for(var/datum/ai_controller/ai_controller as anything in ai_controllers_by_status[AI_STATUS_IDLE])
for(var/client/client_found in GLOB.clients)
if(get_dist(get_turf(client_found.mob), get_turf(ai_controller.pawn)) <= ai_controller.interesting_dist)
ai_controller.set_ai_status(AI_STATUS_ON)
break
cost_idle = MC_AVERAGE(cost_idle, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))

timer = TICK_USAGE_REAL
Expand All @@ -53,14 +48,7 @@ SUBSYSTEM_DEF(ai_controllers)
ai_controller.SelectBehaviors(wait * 0.1)
if(!LAZYLEN(ai_controller.current_behaviors)) //Still no plan
COOLDOWN_START(ai_controller, failed_planning_cooldown, AI_FAILED_PLANNING_COOLDOWN)
if(ai_controller.can_idle)
var/found_interesting = FALSE
for(var/client/client_found in GLOB.clients)
if(get_dist(get_turf(client_found.mob), get_turf(ai_controller.pawn)) <= ai_controller.interesting_dist)
found_interesting = TRUE
break
if(!found_interesting)
ai_controller.set_ai_status(AI_STATUS_IDLE)

cost_on = MC_AVERAGE(cost_on, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))

///Creates all instances of ai_subtrees and assigns them to the ai_subtrees list.
Expand Down
59 changes: 59 additions & 0 deletions code/datums/ai/_ai_controller.dm
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ multiple modular subtrees with behaviors

///The idle behavior this AI performs when it has no actions.
var/datum/idle_behavior/idle_behavior = null
///our current cell grid
var/datum/cell_tracker/our_cells

// Movement related things here
///Reference to the movement datum we use. Is a type on initialize but becomes a ref afterwards.
Expand Down Expand Up @@ -73,6 +75,7 @@ multiple modular subtrees with behaviors

/datum/ai_controller/Destroy(force)
UnpossessPawn(FALSE)
our_cells = null
set_movement_target(type, null)
if(ai_movement.moving_controllers[src])
ai_movement.stop_moving_towards(src)
Expand Down Expand Up @@ -131,6 +134,59 @@ multiple modular subtrees with behaviors
RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained))
RegisterSignal(pawn, COMSIG_QDELETING, PROC_REF(on_pawn_qdeleted))

our_cells = new(interesting_dist, interesting_dist, 1)
set_new_cells()

RegisterSignal(pawn, COMSIG_MOVABLE_MOVED, PROC_REF(update_grid))

/datum/ai_controller/proc/update_grid(datum/source, datum/spatial_grid_cell/new_cell)
SIGNAL_HANDLER

set_new_cells()

/datum/ai_controller/proc/set_new_cells()

var/turf/our_turf = get_turf(pawn)

if(isnull(our_turf))
return

var/list/cell_collections = our_cells.recalculate_cells(our_turf)

for(var/datum/old_grid as anything in cell_collections[2])
UnregisterSignal(old_grid, list(SPATIAL_GRID_CELL_ENTERED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS), SPATIAL_GRID_CELL_EXITED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS)))

for(var/datum/spatial_grid_cell/new_grid as anything in cell_collections[1])
RegisterSignal(new_grid, SPATIAL_GRID_CELL_ENTERED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS), PROC_REF(on_client_enter))
RegisterSignal(new_grid, SPATIAL_GRID_CELL_EXITED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS), PROC_REF(on_client_exit))

recalculate_idle()

/datum/ai_controller/proc/should_idle()
if(!can_idle)
return FALSE
for(var/datum/spatial_grid_cell/grid as anything in our_cells.member_cells)
if(length(grid.client_contents))
return FALSE
return TRUE

/datum/ai_controller/proc/recalculate_idle()
if(ai_status == AI_STATUS_OFF)
return
if(should_idle())
set_ai_status(AI_STATUS_IDLE)

/datum/ai_controller/proc/on_client_enter(datum/source, atom/target)
SIGNAL_HANDLER

if(ai_status == AI_STATUS_IDLE)
set_ai_status(AI_STATUS_ON)

/datum/ai_controller/proc/on_client_exit(datum/source, datum/exited)
SIGNAL_HANDLER

recalculate_idle()

/// Sets the AI on or off based on current conditions, call to reset after you've manually disabled it somewhere
/datum/ai_controller/proc/reset_ai_status()
set_ai_status(get_expected_ai_status())
Expand All @@ -141,6 +197,7 @@ multiple modular subtrees with behaviors
* Returns AI_STATUS_ON otherwise.
*/
/datum/ai_controller/proc/get_expected_ai_status()

if (!ismob(pawn))
return AI_STATUS_ON

Expand All @@ -160,6 +217,8 @@ multiple modular subtrees with behaviors
#endif
if(!length(SSmobs.clients_by_zlevel[pawn_turf.z]))
return AI_STATUS_OFF
if(should_idle())
return AI_STATUS_IDLE
return AI_STATUS_ON

/datum/ai_controller/proc/get_current_turf()
Expand Down

0 comments on commit fe59d3f

Please sign in to comment.