@ -5,12 +5,15 @@
# include "TileTypes.h"
# include "modules/Burrows.h"
# include "modules/EventManager.h"
# include "modules/Job.h"
# include "modules/Persistence.h"
# include "modules/World.h"
# include "df/block_burrow.h"
# include "df/burrow.h"
# include "df/map_block.h"
# include "df/plotinfost.h"
# include "df/tile_designation.h"
# include "df/unit.h"
# include "df/world.h"
@ -22,6 +25,7 @@ using namespace DFHack;
DFHACK_PLUGIN ( " burrow " ) ;
DFHACK_PLUGIN_IS_ENABLED ( is_enabled ) ;
REQUIRE_GLOBAL ( plotinfo ) ;
REQUIRE_GLOBAL ( window_z ) ;
REQUIRE_GLOBAL ( world ) ;
@ -30,35 +34,15 @@ namespace DFHack {
// for configuration-related logging
DBG_DECLARE ( burrow , status , DebugCategory : : LINFO ) ;
// for logging during the periodic scan
DBG_DECLARE ( burrow , cycle , DebugCategory : : LINFO ) ;
}
static const auto CONFIG_KEY = std : : string ( plugin_name ) + " /config " ;
static PersistentDataItem config ;
enum ConfigValues {
CONFIG_IS_ENABLED = 0 ,
} ;
static int get_config_val ( int index ) {
if ( ! config . isValid ( ) )
return - 1 ;
return config . ival ( index ) ;
}
static bool get_config_bool ( int index ) {
return get_config_val ( index ) = = 1 ;
}
static void set_config_val ( int index , int value ) {
if ( config . isValid ( ) )
config . ival ( index ) = value ;
}
static void set_config_bool ( int index , bool value ) {
set_config_val ( index , value ? 1 : 0 ) ;
DBG_DECLARE ( burrow , event , DebugCategory : : LINFO ) ;
}
static const int32_t CYCLE_TICKS = 100 ;
static int32_t cycle_timestamp = 0 ; // world->frame_counter at last cycle
static std : : unordered_map < df : : coord , df : : tiletype > active_dig_jobs ;
static command_result do_command ( color_ostream & out , vector < string > & parameters ) ;
static void do_cycle ( color_ostream & out ) ;
static void init_diggers ( color_ostream & out ) ;
static void jobStartedHandler ( color_ostream & out , void * ptr ) ;
static void jobCompletedHandler ( color_ostream & out , void * ptr ) ;
DFhackCExport command_result plugin_init ( color_ostream & out , std : : vector < PluginCommand > & commands ) {
DEBUG ( status , out ) . print ( " initializing %s \n " , plugin_name ) ;
@ -69,18 +53,21 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector<PluginC
return CR_OK ;
}
DFhackCExport command_result plugin_enable ( color_ostream & out , bool enable ) {
if ( ! Core : : getInstance ( ) . isWorldLoaded ( ) ) {
out . printerr ( " Cannot enable %s without a loaded world. \n " , plugin_name ) ;
return CR_FAILURE ;
static void reset ( ) {
EventManager : : unregisterAll ( plugin_self ) ;
active_dig_jobs . clear ( ) ;
}
DFhackCExport command_result plugin_enable ( color_ostream & out , bool enable ) {
if ( enable ! = is_enabled ) {
is_enabled = enable ;
DEBUG ( status , out ) . print ( " %s from the API; persisting \n " , is_enabled ? " enabled " : " disabled " ) ;
set_config_bool ( CONFIG_IS_ENABLED , is_enabled ) ;
if ( enable )
do_cycle ( out ) ;
DEBUG ( status , out ) . print ( " %s from the API \n " , is_enabled ? " enabled " : " disabled " ) ;
reset ( ) ;
if ( enable ) {
init_diggers ( out ) ;
EventManager : : registerListener ( EventManager : : EventType : : JOB_STARTED , EventManager : : EventHandler ( jobStartedHandler , 0 ) , plugin_self ) ;
EventManager : : registerListener ( EventManager : : EventType : : JOB_COMPLETED , EventManager : : EventHandler ( jobCompletedHandler , 0 ) , plugin_self ) ;
}
}
else {
DEBUG ( status , out ) . print ( " %s from the API, but already %s; no action \n " , is_enabled ? " enabled " : " disabled " , is_enabled ? " enabled " : " disabled " ) ;
@ -90,41 +77,13 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) {
DFhackCExport command_result plugin_shutdown ( color_ostream & out ) {
DEBUG ( status , out ) . print ( " shutting down %s \n " , plugin_name ) ;
return CR_OK ;
}
DFhackCExport command_result plugin_load_data ( color_ostream & out ) {
cycle_timestamp = 0 ;
config = World : : GetPersistentData ( CONFIG_KEY ) ;
if ( ! config . isValid ( ) ) {
DEBUG ( status , out ) . print ( " no config found in this save; initializing \n " ) ;
config = World : : AddPersistentData ( CONFIG_KEY ) ;
set_config_bool ( CONFIG_IS_ENABLED , is_enabled ) ;
}
// we have to copy our enabled flag into the global plugin variable, but
// all the other state we can directly read/modify from the persistent
// data structure.
is_enabled = get_config_bool ( CONFIG_IS_ENABLED ) ;
DEBUG ( status , out ) . print ( " loading persisted enabled state: %s \n " , is_enabled ? " true " : " false " ) ;
reset ( ) ;
return CR_OK ;
}
DFhackCExport command_result plugin_onstatechange ( color_ostream & out , state_change_event event ) {
if ( event = = DFHack : : SC_WORLD_UNLOADED ) {
if ( is_enabled ) {
DEBUG ( status , out ) . print ( " world unloaded; disabling %s \n " , plugin_name ) ;
is_enabled = false ;
}
}
return CR_OK ;
}
DFhackCExport command_result plugin_onupdate ( color_ostream & out ) {
CoreSuspender suspend ;
if ( is_enabled & & world - > frame_counter - cycle_timestamp > = CYCLE_TICKS )
do_cycle ( out ) ;
if ( event = = DFHack : : SC_WORLD_UNLOADED )
reset ( ) ;
return CR_OK ;
}
@ -172,15 +131,107 @@ static command_result do_command(color_ostream &out, vector<string> ¶meters)
}
/////////////////////////////////////////////////////
// cyc le logic
// list ener logic
//
static void do_cycle ( color_ostream & out )
static void init_diggers ( color_ostream & out ) {
if ( ! Core : : getInstance ( ) . isWorldLoaded ( ) ) {
DEBUG ( status , out ) . print ( " world not yet loaded; not scanning jobs \n " ) ;
return ;
}
std : : vector < df : : job * > pvec ;
int start_id = 0 ;
if ( Job : : listNewlyCreated ( & pvec , & start_id ) ) {
for ( auto job : pvec ) {
if ( Job : : getWorker ( job ) )
jobStartedHandler ( out , job ) ;
}
}
}
static void jobStartedHandler ( color_ostream & out , void * ptr ) {
DEBUG ( event , out ) . print ( " entering jobStartedHandler \n " ) ;
df : : job * job = ( df : : job * ) ptr ;
auto type = ENUM_ATTR ( job_type , type , job - > job_type ) ;
if ( type ! = job_type_class : : Digging )
return ;
const df : : coord & pos = job - > pos ;
DEBUG ( event , out ) . print ( " dig job started: id=%d, pos=(%d,%d,%d), type=%s \n " ,
job - > id , pos . x , pos . y , pos . z , ENUM_KEY_STR ( job_type , job - > job_type ) . c_str ( ) ) ;
df : : tiletype * tt = Maps : : getTileType ( pos ) ;
if ( tt )
active_dig_jobs [ pos ] = * tt ;
}
static void add_walls_to_burrow ( color_ostream & out , df : : burrow * b ,
const df : : coord & pos1 , const df : : coord & pos2 )
{
// mark that we have recently run
cycle_timestamp = world - > frame_counter ;
for ( int z = pos1 . z ; z < = pos2 . z ; z + + ) {
for ( int y = pos1 . y ; y < = pos2 . y ; y + + ) {
for ( int x = pos1 . x ; x < = pos2 . x ; x + + ) {
df : : coord pos ( x , y , z ) ;
df : : tiletype * tt = Maps : : getTileType ( pos ) ;
if ( tt & & isWallTerrain ( * tt ) )
Burrows : : setAssignedTile ( b , pos , true ) ;
}
}
}
}
static void expand_burrows ( color_ostream & out , const df : : coord & pos , df : : tiletype prev_tt , df : : tiletype tt ) {
if ( ! isWalkable ( tt ) )
return ;
bool changed = false ;
for ( auto b : plotinfo - > burrows . list ) {
if ( ! b - > name . ends_with ( ' + ' ) | | ! Burrows : : isAssignedTile ( b , pos ) )
continue ;
// TODO
if ( ! isWalkable ( prev_tt ) ) {
changed = true ;
add_walls_to_burrow ( out , b , pos + df : : coord ( - 1 , - 1 , 0 ) , pos + df : : coord ( 1 , 1 , 0 ) ) ;
if ( isWalkableUp ( tt ) )
Burrows : : setAssignedTile ( b , pos + df : : coord ( 0 , 0 , 1 ) , true ) ;
if ( tileShape ( tt ) = = tiletype_shape : : RAMP )
add_walls_to_burrow ( out , b , pos + df : : coord ( - 1 , - 1 , 1 ) , pos + df : : coord ( 1 , 1 , 1 ) ) ;
}
if ( LowPassable ( tt ) & & ! LowPassable ( prev_tt ) ) {
changed = true ;
Burrows : : setAssignedTile ( b , pos - df : : coord ( 0 , 0 , 1 ) , true ) ;
if ( tileShape ( tt ) = = tiletype_shape : : RAMP_TOP )
add_walls_to_burrow ( out , b , pos + df : : coord ( - 1 , - 1 , - 1 ) , pos + df : : coord ( 1 , 1 , - 1 ) ) ;
}
}
if ( changed )
Job : : checkDesignationsNow ( ) ;
}
static void jobCompletedHandler ( color_ostream & out , void * ptr ) {
DEBUG ( event , out ) . print ( " entering jobCompletedHandler \n " ) ;
df : : job * job = ( df : : job * ) ptr ;
auto type = ENUM_ATTR ( job_type , type , job - > job_type ) ;
if ( type ! = job_type_class : : Digging )
return ;
const df : : coord & pos = job - > pos ;
DEBUG ( event , out ) . print ( " dig job completed: id=%d, pos=(%d,%d,%d), type=%s \n " ,
job - > id , pos . x , pos . y , pos . z , ENUM_KEY_STR ( job_type , job - > job_type ) . c_str ( ) ) ;
df : : tiletype prev_tt = active_dig_jobs [ pos ] ;
df : : tiletype * tt = Maps : : getTileType ( pos ) ;
if ( tt & & * tt & & * tt ! = prev_tt )
expand_burrows ( out , pos , prev_tt , * tt ) ;
active_dig_jobs . erase ( pos ) ;
}
/////////////////////////////////////////////////////
@ -633,423 +684,3 @@ DFHACK_PLUGIN_LUA_COMMANDS {
DFHACK_LUA_COMMAND ( burrow_units_remove ) ,
DFHACK_LUA_END
} ;
/*
# include "Core.h"
# include "Console.h"
# include "Export.h"
# include "PluginManager.h"
# include "Error.h"
# include "DataFuncs.h"
# include "LuaTools.h"
# include "modules/Gui.h"
# include "modules/Job.h"
# include "modules/Maps.h"
# include "modules/MapCache.h"
# include "modules/World.h"
# include "modules/Units.h"
# include "TileTypes.h"
# include "DataDefs.h"
# include "df/plotinfost.h"
# include "df/world.h"
# include "df/unit.h"
# include "df/burrow.h"
# include "df/map_block.h"
# include "df/block_burrow.h"
# include "df/job.h"
# include "df/job_list_link.h"
# include "MiscUtils.h"
# include <stdlib.h>
using std : : vector ;
using std : : string ;
using std : : endl ;
using namespace DFHack ;
using namespace df : : enums ;
using namespace dfproto ;
DFHACK_PLUGIN ( " burrow " ) ;
REQUIRE_GLOBAL ( plotinfo ) ;
REQUIRE_GLOBAL ( world ) ;
REQUIRE_GLOBAL ( gamemode ) ;
static void init_map ( color_ostream & out ) ;
static void deinit_map ( color_ostream & out ) ;
DFhackCExport command_result plugin_init ( color_ostream & out , std : : vector < PluginCommand > & commands )
{
if ( Core : : getInstance ( ) . isMapLoaded ( ) )
init_map ( out ) ;
return CR_OK ;
}
DFhackCExport command_result plugin_shutdown ( color_ostream & out )
{
deinit_map ( out ) ;
return CR_OK ;
}
DFhackCExport command_result plugin_onstatechange ( color_ostream & out , state_change_event event )
{
switch ( event ) {
case SC_MAP_LOADED :
deinit_map ( out ) ;
if ( gamemode & &
* gamemode = = game_mode : : DWARF )
init_map ( out ) ;
break ;
case SC_MAP_UNLOADED :
deinit_map ( out ) ;
break ;
default :
break ;
}
return CR_OK ;
}
static int name_burrow_id = - 1 ;
static void handle_burrow_rename ( color_ostream & out , df : : burrow * burrow ) ;
DEFINE_LUA_EVENT_1 ( onBurrowRename , handle_burrow_rename , df : : burrow * ) ;
static void detect_burrow_renames ( color_ostream & out )
{
if ( plotinfo - > main . mode = = ui_sidebar_mode : : Burrows & &
plotinfo - > burrows . in_edit_name_mode & &
plotinfo - > burrows . sel_id > = 0 )
{
name_burrow_id = plotinfo - > burrows . sel_id ;
}
else if ( name_burrow_id > = 0 )
{
auto burrow = df : : burrow : : find ( name_burrow_id ) ;
name_burrow_id = - 1 ;
if ( burrow )
onBurrowRename ( out , burrow ) ;
}
}
struct DigJob {
int id ;
df : : job_type job ;
df : : coord pos ;
df : : tiletype old_tile ;
} ;
static int next_job_id_save = 0 ;
static std : : map < int , DigJob > diggers ;
static void handle_dig_complete ( color_ostream & out , df : : job_type job , df : : coord pos ,
df : : tiletype old_tile , df : : tiletype new_tile , df : : unit * worker ) ;
DEFINE_LUA_EVENT_5 ( onDigComplete , handle_dig_complete ,
df : : job_type , df : : coord , df : : tiletype , df : : tiletype , df : : unit * ) ;
static void detect_digging ( color_ostream & out )
{
for ( auto it = diggers . begin ( ) ; it ! = diggers . end ( ) ; )
{
auto worker = df : : unit : : find ( it - > first ) ;
if ( ! worker | | ! worker - > job . current_job | |
worker - > job . current_job - > id ! = it - > second . id )
{
//out.print("Dig job %d expired.\n", it->second.id);
df : : coord pos = it - > second . pos ;
if ( auto block = Maps : : getTileBlock ( pos ) )
{
df : : tiletype new_tile = block - > tiletype [ pos . x & 15 ] [ pos . y & 15 ] ;
//out.print("Tile %d -> %d\n", it->second.old_tile, new_tile);
if ( new_tile ! = it - > second . old_tile )
{
onDigComplete ( out , it - > second . job , pos , it - > second . old_tile , new_tile , worker ) ;
}
}
auto cur = it ; + + it ; diggers . erase ( cur ) ;
}
else
+ + it ;
}
std : : vector < df : : job * > jvec ;
if ( Job : : listNewlyCreated ( & jvec , & next_job_id_save ) )
{
for ( size_t i = 0 ; i < jvec . size ( ) ; i + + )
{
auto job = jvec [ i ] ;
auto type = ENUM_ATTR ( job_type , type , job - > job_type ) ;
if ( type ! = job_type_class : : Digging )
continue ;
auto worker = Job : : getWorker ( job ) ;
if ( ! worker )
continue ;
df : : coord pos = job - > pos ;
auto block = Maps : : getTileBlock ( pos ) ;
if ( ! block )
continue ;
auto & info = diggers [ worker - > id ] ;
//out.print("New dig job %d.\n", job->id);
info . id = job - > id ;
info . job = job - > job_type ;
info . pos = pos ;
info . old_tile = block - > tiletype [ pos . x & 15 ] [ pos . y & 15 ] ;
}
}
}
DFHACK_PLUGIN_IS_ENABLED ( active ) ;
static bool auto_grow = false ;
static std : : vector < int > grow_burrows ;
DFhackCExport command_result plugin_onupdate ( color_ostream & out )
{
if ( ! active )
return CR_OK ;
detect_burrow_renames ( out ) ;
if ( auto_grow )
detect_digging ( out ) ;
return CR_OK ;
}
static std : : map < std : : string , int > name_lookup ;
static void parse_names ( )
{
auto & list = plotinfo - > burrows . list ;
grow_burrows . clear ( ) ;
name_lookup . clear ( ) ;
for ( size_t i = 0 ; i < list . size ( ) ; i + + )
{
auto burrow = list [ i ] ;
std : : string name = burrow - > name ;
if ( ! name . empty ( ) )
{
name_lookup [ name ] = burrow - > id ;
if ( name [ name . size ( ) - 1 ] = = ' + ' )
{
grow_burrows . push_back ( burrow - > id ) ;
name . resize ( name . size ( ) - 1 ) ;
}
if ( ! name . empty ( ) )
name_lookup [ name ] = burrow - > id ;
}
}
}
static void reset_tracking ( )
{
diggers . clear ( ) ;
next_job_id_save = 0 ;
}
static void init_map ( color_ostream & out )
{
auto config = World : : GetPersistentData ( " burrows/config " ) ;
if ( config . isValid ( ) )
{
auto_grow = ! ! ( config . ival ( 0 ) & 1 ) ;
}
parse_names ( ) ;
name_burrow_id = - 1 ;
reset_tracking ( ) ;
active = true ;
if ( auto_grow & & ! grow_burrows . empty ( ) )
out . print ( " Auto-growing %zu burrows. \n " , grow_burrows . size ( ) ) ;
}
static void deinit_map ( color_ostream & out )
{
active = false ;
auto_grow = false ;
reset_tracking ( ) ;
}
static PersistentDataItem create_config ( color_ostream & out )
{
bool created ;
auto rv = World : : GetPersistentData ( " burrows/config " , & created ) ;
if ( created & & rv . isValid ( ) )
rv . ival ( 0 ) = 0 ;
if ( ! rv . isValid ( ) )
out . printerr ( " Could not write configuration. " ) ;
return rv ;
}
static void enable_auto_grow ( color_ostream & out , bool enable )
{
if ( enable = = auto_grow )
return ;
auto config = create_config ( out ) ;
if ( ! config . isValid ( ) )
return ;
if ( enable )
config . ival ( 0 ) | = 1 ;
else
config . ival ( 0 ) & = ~ 1 ;
auto_grow = enable ;
if ( enable )
reset_tracking ( ) ;
}
static void handle_burrow_rename ( color_ostream & out , df : : burrow * burrow )
{
parse_names ( ) ;
}
static void add_to_burrows ( std : : vector < df : : burrow * > & burrows , df : : coord pos )
{
for ( size_t i = 0 ; i < burrows . size ( ) ; i + + )
Burrows : : setAssignedTile ( burrows [ i ] , pos , true ) ;
}
static void add_walls_to_burrows ( color_ostream & out , std : : vector < df : : burrow * > & burrows ,
MapExtras : : MapCache & mc , df : : coord pos1 , df : : coord pos2 )
{
for ( int x = pos1 . x ; x < = pos2 . x ; x + + )
{
for ( int y = pos1 . y ; y < = pos2 . y ; y + + )
{
for ( int z = pos1 . z ; z < = pos2 . z ; z + + )
{
df : : coord pos ( x , y , z ) ;
auto tile = mc . tiletypeAt ( pos ) ;
if ( isWallTerrain ( tile ) )
add_to_burrows ( burrows , pos ) ;
}
}
}
}
static void handle_dig_complete ( color_ostream & out , df : : job_type job , df : : coord pos ,
df : : tiletype old_tile , df : : tiletype new_tile , df : : unit * worker )
{
if ( ! isWalkable ( new_tile ) )
return ;
std : : vector < df : : burrow * > to_grow ;
for ( size_t i = 0 ; i < grow_burrows . size ( ) ; i + + )
{
auto b = df : : burrow : : find ( grow_burrows [ i ] ) ;
if ( b & & Burrows : : isAssignedTile ( b , pos ) )
to_grow . push_back ( b ) ;
}
//out.print("%d to grow.\n", to_grow.size());
if ( to_grow . empty ( ) )
return ;
MapExtras : : MapCache mc ;
bool changed = false ;
if ( ! isWalkable ( old_tile ) )
{
changed = true ;
add_walls_to_burrows ( out , to_grow , mc , pos + df : : coord ( - 1 , - 1 , 0 ) , pos + df : : coord ( 1 , 1 , 0 ) ) ;
if ( isWalkableUp ( new_tile ) )
add_to_burrows ( to_grow , pos + df : : coord ( 0 , 0 , 1 ) ) ;
if ( tileShape ( new_tile ) = = tiletype_shape : : RAMP )
{
add_walls_to_burrows ( out , to_grow , mc ,
pos + df : : coord ( - 1 , - 1 , 1 ) , pos + df : : coord ( 1 , 1 , 1 ) ) ;
}
}
if ( LowPassable ( new_tile ) & & ! LowPassable ( old_tile ) )
{
changed = true ;
add_to_burrows ( to_grow , pos - df : : coord ( 0 , 0 , 1 ) ) ;
if ( tileShape ( new_tile ) = = tiletype_shape : : RAMP_TOP )
{
add_walls_to_burrows ( out , to_grow , mc ,
pos + df : : coord ( - 1 , - 1 , - 1 ) , pos + df : : coord ( 1 , 1 , - 1 ) ) ;
}
}
if ( changed & & worker & & ! worker - > job . current_job )
Job : : checkDesignationsNow ( ) ;
}
static void renameBurrow ( color_ostream & out , df : : burrow * burrow , std : : string name )
{
CHECK_NULL_POINTER ( burrow ) ;
// The event makes this absolutely necessary
CoreSuspender suspend ;
burrow - > name = name ;
onBurrowRename ( out , burrow ) ;
}
static df : : burrow * findByName ( color_ostream & out , std : : string name , bool silent = false )
{
int id = - 1 ;
if ( name_lookup . count ( name ) )
id = name_lookup [ name ] ;
auto rv = df : : burrow : : find ( id ) ;
if ( ! rv & & ! silent )
out . printerr ( " Burrow not found: '%s' \n " , name . c_str ( ) ) ;
return rv ;
}
DFHACK_PLUGIN_LUA_FUNCTIONS {
DFHACK_LUA_FUNCTION ( renameBurrow ) ,
DFHACK_LUA_FUNCTION ( findByName ) ,
DFHACK_LUA_FUNCTION ( copyUnits ) ,
DFHACK_LUA_FUNCTION ( copyTiles ) ,
DFHACK_LUA_FUNCTION ( setTilesByKeyword ) ,
DFHACK_LUA_END
} ;
DFHACK_PLUGIN_LUA_EVENTS {
DFHACK_LUA_EVENT ( onBurrowRename ) ,
DFHACK_LUA_EVENT ( onDigComplete ) ,
DFHACK_LUA_END
} ;
*/