summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov2011-12-24 14:51:58 +0400
committerAlexander Gavrilov2011-12-24 14:51:58 +0400
commit79ac2a781a3bfd3395a5785098a16403c1a9d3ce (patch)
tree91b5942ba1a17f81554f6ae89d95b81d2aeb2ee5
parent0b5a470a3894b1cbaaf3970e4416bd35371493d0 (diff)
downloaddfhack-79ac2a781a3bfd3395a5785098a16403c1a9d3ce.tar.gz
dfhack-79ac2a781a3bfd3395a5785098a16403c1a9d3ce.tar.bz2
dfhack-79ac2a781a3bfd3395a5785098a16403c1a9d3ce.tar.xz
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.
-rw-r--r--.gitignore1
-rw-r--r--Memory.xml21
-rw-r--r--library/CMakeLists.txt3
-rw-r--r--library/Core.cpp5
-rw-r--r--library/DataDefs.cpp136
-rw-r--r--library/DataStatics.cpp5
-rw-r--r--library/include/dfhack/Core.h7
-rw-r--r--library/include/dfhack/DataDefs.h151
-rw-r--r--library/include/dfhack/df/.gitignore2
-rw-r--r--plugins/CMakeLists.txt6
-rw-r--r--plugins/initflags.cpp60
-rw-r--r--plugins/stockpiles.cpp87
12 files changed, 482 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 702a6490..a19302fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,7 @@ build/CMakeCache.txt
build/cmake_install.cmake
build/CMakeFiles
build/doc
+build/lua
build/bin
build/library
build/tools
diff --git a/Memory.xml b/Memory.xml
index 366dc48b..b4f7ce1f 100644
--- a/Memory.xml
+++ b/Memory.xml
@@ -1078,6 +1078,13 @@
<Group name="Notes" description="In-game notes">
<Address name="vector"/>
</Group>
+ <Group name='global'>
+ <Address name='world'/>
+ <Address name='ui'/>
+ <Address name='gview'/>
+ <Address name='init'/>
+ <Address name='d_init'/>
+ </Group>
</Offsets>
</Base>
@@ -2309,6 +2316,13 @@
<Group name="World">
<Address name="save_folder" value="0x1847A40" />
</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>
cmake
item vector:
@@ -3174,6 +3188,13 @@
<Group name="Notes">
<Address name="vector" value="0x93f635c"/>
</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>
</Version>
</DFHack>
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 7e24f365..9a87db9a 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -29,6 +29,7 @@ SET(PROJECT_HDRS
include/DFHack.h
include/dfhack/Console.h
include/dfhack/Core.h
+include/dfhack/DataDefs.h
include/dfhack/Error.h
include/dfhack/Export.h
include/dfhack/FakeSDL.h
@@ -64,6 +65,8 @@ include/dfhack/modules/Graphic.h
SET(PROJECT_SRCS
Core.cpp
+DataDefs.cpp
+DataStatics.cpp
PluginManager.cpp
TileTypes.cpp
VersionInfo.cpp
diff --git a/library/Core.cpp b/library/Core.cpp
index f218f275..5296a057 100644
--- a/library/Core.cpp
+++ b/library/Core.cpp
@@ -37,6 +37,7 @@ using namespace std;
#include "dfhack/Error.h"
#include "dfhack/Process.h"
#include "dfhack/Core.h"
+#include "dfhack/DataDefs.h"
#include "dfhack/Console.h"
#include "dfhack/Module.h"
#include "dfhack/VersionInfoFactory.h"
@@ -494,6 +495,10 @@ bool Core::Init()
dump << vinfo->PrintOffsets();
dump.close();
}
+
+ // initialize data defs
+ virtual_identity::Init();
+ InitDataDefGlobals(this);
// create mutex for syncing with interactive tasks
StackMutex = new mutex();
diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp
new file mode 100644
index 00000000..2de8c156
--- /dev/null
+++ b/library/DataDefs.cpp
@@ -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
+}
diff --git a/library/DataStatics.cpp b/library/DataStatics.cpp
new file mode 100644
index 00000000..57aeb779
--- /dev/null
+++ b/library/DataStatics.cpp
@@ -0,0 +1,5 @@
+#include "Internal.h"
+#include "dfhack/DataDefs.h"
+
+// Instantiate all the static objects
+#include "dfhack/df/static.inc"
diff --git a/library/include/dfhack/Core.h b/library/include/dfhack/Core.h
index 2d7941af..64eae5d3 100644
--- a/library/include/dfhack/Core.h
+++ b/library/include/dfhack/Core.h
@@ -190,4 +190,11 @@ namespace DFHack
tthread::mutex * misc_data_mutex;
std::map<std::string,void*> misc_data_map;
};
+
+ class CoreSuspender {
+ Core *core;
+ public:
+ CoreSuspender(Core *core) : core(core) { core->Suspend(); }
+ ~CoreSuspender() { core->Resume(); }
+ };
}
diff --git a/library/include/dfhack/DataDefs.h b/library/include/dfhack/DataDefs.h
new file mode 100644
index 00000000..aa325958
--- /dev/null
+++ b/library/include/dfhack/DataDefs.h
@@ -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
+}
diff --git a/library/include/dfhack/df/.gitignore b/library/include/dfhack/df/.gitignore
new file mode 100644
index 00000000..11c5ffbb
--- /dev/null
+++ b/library/include/dfhack/df/.gitignore
@@ -0,0 +1,2 @@
+*.h
+*.inc
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index c08bcd9e..ab7e039a 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -30,7 +30,7 @@ if(BUILD_SERVER)
add_subdirectory (server)
endif()
-OPTION(BUILD_DF2MC "Build DF2MC (needs a checkout first)." ON)
+OPTION(BUILD_DF2MC "Build DF2MC (needs a checkout first)." OFF)
if(BUILD_DF2MC)
add_subdirectory (df2mc)
endif()
@@ -57,7 +57,9 @@ DFHACK_PLUGIN(deramp deramp.cpp)
DFHACK_PLUGIN(flows flows.cpp)
DFHACK_PLUGIN(filltraffic filltraffic.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
OPTION(BUILD_SKELETON "Build the skeleton plugin." OFF)
diff --git a/plugins/initflags.cpp b/plugins/initflags.cpp
new file mode 100644
index 00000000..f27a318a
--- /dev/null
+++ b/plugins/initflags.cpp
@@ -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;
+}
diff --git a/plugins/stockpiles.cpp b/plugins/stockpiles.cpp
new file mode 100644
index 00000000..5cd15333
--- /dev/null
+++ b/plugins/stockpiles.cpp
@@ -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;
+}