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
parent
0b5a470a38
commit
79ac2a781a
@ -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"
|
@ -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
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue