Add infrastructure necessary to use the generated headers.

As a usage example, allow toggling water level display and idlers,
and implement a ui tweak for easily copying stockpiles.

Also disable df2mc by default - default options shouldn't
require anything not in the base package.
develop
Alexander Gavrilov 2011-12-24 14:51:58 +04:00
parent 0b5a470a38
commit 79ac2a781a
12 changed files with 482 additions and 2 deletions

1
.gitignore vendored

@ -29,6 +29,7 @@ build/CMakeCache.txt
build/cmake_install.cmake build/cmake_install.cmake
build/CMakeFiles build/CMakeFiles
build/doc build/doc
build/lua
build/bin build/bin
build/library build/library
build/tools build/tools

@ -1078,6 +1078,13 @@
<Group name="Notes" description="In-game notes"> <Group name="Notes" description="In-game notes">
<Address name="vector"/> <Address name="vector"/>
</Group> </Group>
<Group name='global'>
<Address name='world'/>
<Address name='ui'/>
<Address name='gview'/>
<Address name='init'/>
<Address name='d_init'/>
</Group>
</Offsets> </Offsets>
</Base> </Base>
@ -2309,6 +2316,13 @@
<Group name="World"> <Group name="World">
<Address name="save_folder" value="0x1847A40" /> <Address name="save_folder" value="0x1847A40" />
</Group> </Group>
<Group name='global'>
<Address name='world' value='0x16b0a58'/>
<Address name='ui' value='0x14ee7e0'/>
<Address name='gview' value='0x14f6070'/>
<Address name='init' value='0x184ae58'/>
<Address name='d_init' value='0x1848350'/>
</Group>
</Offsets> </Offsets>
cmake cmake
item vector: item vector:
@ -3174,6 +3188,13 @@
<Group name="Notes"> <Group name="Notes">
<Address name="vector" value="0x93f635c"/> <Address name="vector" value="0x93f635c"/>
</Group> </Group>
<Group name='global'>
<Address name='world' value='0x93f77a0'/>
<Address name='ui' value='0x93f0780'/>
<Address name='gview' value='0x8c3e900'/>
<Address name='init' value='0x959c2a0'/>
<Address name='d_init' value='0x959d340'/>
</Group>
</Offsets> </Offsets>
</Version> </Version>
</DFHack> </DFHack>

@ -29,6 +29,7 @@ SET(PROJECT_HDRS
include/DFHack.h include/DFHack.h
include/dfhack/Console.h include/dfhack/Console.h
include/dfhack/Core.h include/dfhack/Core.h
include/dfhack/DataDefs.h
include/dfhack/Error.h include/dfhack/Error.h
include/dfhack/Export.h include/dfhack/Export.h
include/dfhack/FakeSDL.h include/dfhack/FakeSDL.h
@ -64,6 +65,8 @@ include/dfhack/modules/Graphic.h
SET(PROJECT_SRCS SET(PROJECT_SRCS
Core.cpp Core.cpp
DataDefs.cpp
DataStatics.cpp
PluginManager.cpp PluginManager.cpp
TileTypes.cpp TileTypes.cpp
VersionInfo.cpp VersionInfo.cpp

@ -37,6 +37,7 @@ using namespace std;
#include "dfhack/Error.h" #include "dfhack/Error.h"
#include "dfhack/Process.h" #include "dfhack/Process.h"
#include "dfhack/Core.h" #include "dfhack/Core.h"
#include "dfhack/DataDefs.h"
#include "dfhack/Console.h" #include "dfhack/Console.h"
#include "dfhack/Module.h" #include "dfhack/Module.h"
#include "dfhack/VersionInfoFactory.h" #include "dfhack/VersionInfoFactory.h"
@ -495,6 +496,10 @@ bool Core::Init()
dump.close(); dump.close();
} }
// initialize data defs
virtual_identity::Init();
InitDataDefGlobals(this);
// create mutex for syncing with interactive tasks // create mutex for syncing with interactive tasks
StackMutex = new mutex(); StackMutex = new mutex();
AccessMutex = new mutex(); AccessMutex = new mutex();

@ -0,0 +1,136 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "Internal.h"
#include <string>
#include <vector>
#include <map>
#include "dfhack/Process.h"
#include "dfhack/Core.h"
#include "dfhack/DataDefs.h"
#include "dfhack/VersionInfo.h"
#include "tinythread.h"
using namespace DFHack;
/* The order of global object constructor calls is
* undefined between compilation units. Therefore,
* this list has to be plain data, so that it gets
* initialized by the loader in the initial mmap.
*/
virtual_identity *virtual_identity::list = NULL;
virtual_identity::virtual_identity(const char *dfhack_name, const char *original_name, virtual_identity *parent)
: dfhack_name(dfhack_name), original_name(original_name), parent(parent),
prev(NULL), vtable_ptr(NULL), has_children(true)
{
// Link into the static list. Nothing else can be safely done at this point.
next = list; list = this;
}
/* Vtable to identity lookup. */
static tthread::mutex *known_mutex = NULL;
std::map<void*, virtual_identity*> virtual_identity::known;
virtual_identity *virtual_identity::get(virtual_class *instance_ptr)
{
if (!instance_ptr) return NULL;
// Actually, a reader/writer lock would be sufficient,
// since the table is only written once per class.
tthread::lock_guard<tthread::mutex> lock(*known_mutex);
void *vtable = get_vtable(instance_ptr);
std::map<void*, virtual_identity*>::iterator it = known.find(vtable);
if (it != known.end())
return it->second;
// If using a reader/writer lock, re-grab as write here, and recheck
Core &core = Core::getInstance();
std::string name = core.p->doReadClassName(vtable);
virtual_identity *actual = NULL;
for (virtual_identity *p = list; p; p = p->next) {
if (strcmp(name.c_str(), p->getOriginalName()) != 0) continue;
known[vtable] = p;
p->vtable_ptr = vtable;
return p;
}
known[vtable] = NULL;
return NULL;
}
bool virtual_identity::check_instance(virtual_class *instance_ptr, bool allow_subclasses)
{
virtual_identity *actual = get(instance_ptr);
if (actual == this) return true;
if (!allow_subclasses || !actual) return false;
do {
actual = actual->parent;
if (actual == this) return true;
} while (actual);
return false;
}
void virtual_identity::Init()
{
if (!known_mutex)
known_mutex = new tthread::mutex();
// This cannot be done in the constructors, because
// they are called in an undefined order.
for (virtual_identity *p = list; p; p = p->next) {
p->has_children = false;
p->children.clear();
}
for (virtual_identity *p = list; p; p = p->next) {
if (p->parent) {
p->parent->children.push_back(p);
p->parent->has_children = true;
}
}
}
#define GLOBAL(name,tname) \
df::tname *df::global::name = NULL;
DF_KNOWN_GLOBALS
#undef GLOBAL
void DFHack::InitDataDefGlobals(Core *core) {
OffsetGroup *global_table = core->vinfo->getGroup("global");
uint32_t tmp;
#define GLOBAL(name,tname) \
if (global_table->getSafeAddress(#name,tmp)) df::global::name = (df::tname*)tmp;
DF_KNOWN_GLOBALS
#undef GLOBAL
}

@ -0,0 +1,5 @@
#include "Internal.h"
#include "dfhack/DataDefs.h"
// Instantiate all the static objects
#include "dfhack/df/static.inc"

@ -190,4 +190,11 @@ namespace DFHack
tthread::mutex * misc_data_mutex; tthread::mutex * misc_data_mutex;
std::map<std::string,void*> misc_data_map; std::map<std::string,void*> misc_data_map;
}; };
class CoreSuspender {
Core *core;
public:
CoreSuspender(Core *core) : core(core) { core->Suspend(); }
~CoreSuspender() { core->Resume(); }
};
} }

@ -0,0 +1,151 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#pragma once
#include <string>
#include <vector>
#include <map>
#include "dfhack/Core.h"
#include "dfhack/BitArray.h"
namespace DFHack
{
class virtual_class {};
class DFHACK_EXPORT virtual_identity {
static virtual_identity *list;
static std::map<void*, virtual_identity*> known;
virtual_identity *prev, *next;
const char *dfhack_name;
const char *original_name;
virtual_identity *parent;
std::vector<virtual_identity*> children;
void *vtable_ptr;
bool has_children;
protected:
virtual_identity(const char *dfhack_name, const char *original_name, virtual_identity *parent);
bool check_instance(virtual_class *instance_ptr, bool allow_subclasses);
static void *get_vtable(virtual_class *instance_ptr) { return *(void**)instance_ptr; }
public:
const char *getName() { return dfhack_name; }
const char *getOriginalName() { return original_name ? original_name : dfhack_name; }
virtual_identity *getParent() { return parent; }
const std::vector<virtual_identity*> &getChildren() { return children; }
static virtual_identity *get(virtual_class *instance_ptr);
bool is_instance(virtual_class *instance_ptr) {
if (!instance_ptr) return false;
if (vtable_ptr) {
void *vtable = get_vtable(instance_ptr);
if (vtable == vtable_ptr) return true;
if (!has_children) return false;
}
return check_instance(instance_ptr, true);
}
bool is_direct_instance(virtual_class *instance_ptr) {
if (!instance_ptr) return false;
return vtable_ptr ? (vtable_ptr == get_vtable(instance_ptr))
: check_instance(instance_ptr, false);
}
static void Init();
};
template<class T>
inline T *virtual_cast(virtual_class *ptr) {
return T::_identity.is_instance(ptr) ? static_cast<T*>(ptr) : NULL;
}
template<class T>
inline T *strict_virtual_cast(virtual_class *ptr) {
return T::_identity.is_direct_instance(ptr) ? static_cast<T*>(ptr) : NULL;
}
void InitDataDefGlobals(Core *core);
template<class T>
T *ifnull(T *a, T *b) { return a ? a : b; }
}
namespace df
{
using DFHack::virtual_class;
using DFHack::BitArray;
template<class T>
class class_virtual_identity : public DFHack::virtual_identity {
public:
class_virtual_identity(const char *dfhack_name, const char *original_name, virtual_identity *parent)
: virtual_identity(dfhack_name, original_name, parent) {};
};
template<class EnumType, class IntType = int32_t>
struct enum_field {
IntType value;
enum_field() {}
enum_field(EnumType ev) : value(IntType(ev)) {}
template<class T>
enum_field(enum_field<EnumType,T> ev) : value(IntType(ev.value)) {}
operator EnumType () { return EnumType(value); }
enum_field<EnumType,IntType> &operator=(EnumType ev) {
value = IntType(ev); return *this;
}
};
namespace enums {}
}
#define ENUM_ATTR(enum,attr,val) (df::enums::enum::get_##attr(val))
#define ENUM_ATTR_STR(enum,attr,val) DFHack::ifnull(ENUM_ATTR(enum,attr,val),"?")
#define ENUM_KEY_STR(enum,val) ENUM_ATTR_STR(enum,key,val)
#define ENUM_FIRST_ITEM(enum) (df::enums::enum::_first_item_of_##enum)
#define ENUM_LAST_ITEM(enum) (df::enums::enum::_last_item_of_##enum)
namespace df {
#define DF_KNOWN_GLOBALS \
GLOBAL(world,world) \
GLOBAL(ui,ui) \
GLOBAL(gview,interface) \
GLOBAL(init,init) \
GLOBAL(d_init,d_init)
#define GLOBAL(name,tname) \
struct tname; \
namespace global { extern DFHACK_EXPORT tname *name; }
DF_KNOWN_GLOBALS
#undef GLOBAL
}

@ -0,0 +1,2 @@
*.h
*.inc

@ -30,7 +30,7 @@ if(BUILD_SERVER)
add_subdirectory (server) add_subdirectory (server)
endif() endif()
OPTION(BUILD_DF2MC "Build DF2MC (needs a checkout first)." ON) OPTION(BUILD_DF2MC "Build DF2MC (needs a checkout first)." OFF)
if(BUILD_DF2MC) if(BUILD_DF2MC)
add_subdirectory (df2mc) add_subdirectory (df2mc)
endif() endif()
@ -57,7 +57,9 @@ DFHACK_PLUGIN(deramp deramp.cpp)
DFHACK_PLUGIN(flows flows.cpp) DFHACK_PLUGIN(flows flows.cpp)
DFHACK_PLUGIN(filltraffic filltraffic.cpp) DFHACK_PLUGIN(filltraffic filltraffic.cpp)
DFHACK_PLUGIN(seedwatch seedwatch.cpp) DFHACK_PLUGIN(seedwatch seedwatch.cpp)
DFHACK_PLUGIN(versionosd versionosd.cpp) DFHACK_PLUGIN(initflags initflags.cpp)
DFHACK_PLUGIN(stockpiles stockpiles.cpp)
#DFHACK_PLUGIN(versionosd versionosd.cpp)
# this is the skeleton plugin. If you want to make your own, make a copy and then change it # this is the skeleton plugin. If you want to make your own, make a copy and then change it
OPTION(BUILD_SKELETON "Build the skeleton plugin." OFF) OPTION(BUILD_SKELETON "Build the skeleton plugin." OFF)

@ -0,0 +1,60 @@
#include <dfhack/Core.h>
#include <dfhack/Console.h>
#include <dfhack/Export.h>
#include <dfhack/PluginManager.h>
#include <dfhack/DataDefs.h>
#include <dfhack/df/d_init.h>
using std::vector;
using std::string;
using std::endl;
using namespace DFHack;
using namespace df::enums;
using df::global::d_init;
DFhackCExport command_result twaterlvl(Core * c, vector <string> & parameters);
DFhackCExport command_result tidlers(Core * c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void )
{
return "initflags";
}
DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &commands)
{
commands.clear();
if (d_init) {
commands.push_back(PluginCommand("twaterlvl", "Toggle display of water/magma depth.", twaterlvl));
commands.push_back(PluginCommand("tidlers", "Toggle display of idlers.", tidlers));
}
std::cerr << "d_init: " << sizeof(df::d_init) << endl;
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}
DFhackCExport command_result twaterlvl(Core * c, vector <string> & parameters)
{
c->Suspend();
df::global::d_init->flags1.toggle(d_init_flags1::SHOW_FLOW_AMOUNTS);
c->con << "Toggled the display of water/magma depth." << endl;
c->Resume();
return CR_OK;
}
DFhackCExport command_result tidlers(Core * c, vector <string> & parameters)
{
c->Suspend();
df::d_init_idlers iv = df::d_init_idlers(int(d_init->idlers) + 1);
if (!d_init_idlers::is_valid(iv))
iv = ENUM_FIRST_ITEM(d_init_idlers);
d_init->idlers = iv;
c->con << "Toggled the display of idlers to " << ENUM_KEY_STR(d_init_idlers, iv) << endl;
c->Resume();
return CR_OK;
}

@ -0,0 +1,87 @@
#include <dfhack/Core.h>
#include <dfhack/Console.h>
#include <dfhack/Export.h>
#include <dfhack/PluginManager.h>
#include <dfhack/DataDefs.h>
#include <dfhack/df/world.h>
#include <dfhack/df/ui.h>
#include <dfhack/df/building_stockpilest.h>
using std::vector;
using std::string;
using std::endl;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::ui;
using df::building_stockpilest;
DFhackCExport command_result copystock(Core * c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void )
{
return "stockpiles";
}
DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &commands)
{
commands.clear();
if (world && ui) {
commands.push_back(PluginCommand("copystock", "Copy stockpile under cursor.", copystock));
}
std::cerr << "world: " << sizeof(df::world) << " ui: " << sizeof(df::ui)
<< " b_stock: " << sizeof(building_stockpilest) << endl;
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}
bool inSelectMode() {
using namespace ui_sidebar_mode;
switch (ui->main.mode) {
case BuildingItems:
case QueryBuilding:
return true;
default:
return false;
}
}
DFhackCExport command_result copystock(Core * c, vector <string> & parameters)
{
CoreSuspender suspend(c);
// For convenience: when used in the stockpiles mode, switch to 'q'
if (ui->main.mode == ui_sidebar_mode::Stockpiles) {
world->selected_building = NULL; // just in case it contains some kind of garbage
ui->main.mode = ui_sidebar_mode::QueryBuilding;
c->con << "Switched back to query building." << endl;
return CR_OK;
}
if (!inSelectMode()) {
c->con << "Cannot copy stockpile in mode " << ENUM_KEY_STR(ui_sidebar_mode, ui->main.mode) << endl;
return CR_OK;
}
building_stockpilest *sp = virtual_cast<building_stockpilest>(world->selected_building);
if (!sp) {
c->con << "Selected building isn't a stockpile." << endl;
return CR_OK;
}
ui->stockpile.custom_settings = sp->settings;
ui->main.mode = ui_sidebar_mode::Stockpiles;
world->selected_stockpile_type = stockpile_category::Custom;
c->con << "Stockpile options copied." << endl;
return CR_OK;
}