Merge remote-tracking branch 'upstream/master'

develop
Kelly Martin 2012-04-14 20:38:16 -05:00
commit e9542fb239
25 changed files with 437 additions and 71 deletions

@ -14,6 +14,11 @@ endif(CMAKE_CONFIGURATION_TYPES)
cmake_minimum_required(VERSION 2.8 FATAL_ERROR) cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(dfhack) project(dfhack)
if(MSVC)
# disable C4819 code-page warning
add_definitions( "/wd4819" )
endif()
# set up folder structures for IDE solutions # set up folder structures for IDE solutions
# MSVC Express won't load solutions that use this. It also doesn't include MFC supported # MSVC Express won't load solutions that use this. It also doesn't include MFC supported
# Check for MFC! # Check for MFC!
@ -58,9 +63,9 @@ set(DF_VERSION_MINOR "34")
set(DF_VERSION_PATCH "07") set(DF_VERSION_PATCH "07")
set(DF_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}") set(DF_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}")
set(DFHACK_RELEASE "1") SET(DFHACK_RELEASE "r1" CACHE STRING "Current release revision.")
set(DFHACK_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}-r${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION_MAJOR}.${DF_VERSION_MINOR}.${DF_VERSION_PATCH}-${DFHACK_RELEASE}")
add_definitions(-DDFHACK_VERSION="${DFHACK_VERSION}") add_definitions(-DDFHACK_VERSION="${DFHACK_VERSION}")
## where to install things (after the build is done, classic 'make install' or package structure) ## where to install things (after the build is done, classic 'make install' or package structure)

@ -0,0 +1,8 @@
@echo off
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2010
cd VC2010
echo generating a build folder
for /f "delims=" %%a in ('DATE /T') do @set myvar=breakfast-%%a
cmake ..\.. -G"Visual Studio 10" -DDFHACK_RELEASE="%myvar%" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_DF2MC=1 -DBUILD_DFUSION=1 -DBUILD_STONESENSE=1 -DBUILD_SERVER=1

@ -861,13 +861,9 @@ int Core::TileUpdate()
// should always be from simulation thread! // should always be from simulation thread!
int Core::Update() int Core::Update()
{ {
if(!started)
Init();
if(errorstate) if(errorstate)
return -1; return -1;
color_ostream_proxy out(con);
// Pretend this thread has suspended the core in the usual way // Pretend this thread has suspended the core in the usual way
{ {
lock_guard<mutex> lock(d->AccessMutex); lock_guard<mutex> lock(d->AccessMutex);
@ -877,6 +873,22 @@ int Core::Update()
d->df_suspend_depth = 1000; d->df_suspend_depth = 1000;
} }
// Initialize the core
bool first_update = false;
if(!started)
{
first_update = true;
Init();
if(errorstate)
return -1;
}
color_ostream_proxy out(con);
if (first_update)
plug_mgr->OnStateChange(out, SC_CORE_INITIALIZED);
// detect if the game was loaded or unloaded in the meantime // detect if the game was loaded or unloaded in the meantime
void *new_wdata = NULL; void *new_wdata = NULL;
void *new_mapdata = NULL; void *new_mapdata = NULL;

@ -745,6 +745,22 @@ static int lua_dfhack_with_suspend(lua_State *L)
return lua_gettop(L); return lua_gettop(L);
} }
static int dfhack_open_plugin(lua_State *L)
{
luaL_checktype(L, 1, LUA_TTABLE);
luaL_checktype(L, 2, LUA_TSTRING);
const char *name = lua_tostring(L, 2);
PluginManager *pmgr = Core::getInstance().getPluginManager();
Plugin *plugin = pmgr->getPluginByName(name);
if (!plugin)
luaL_error(L, "plugin not found: '%s'", name);
plugin->open_lua(L, 1);
return 0;
}
static const luaL_Reg dfhack_funcs[] = { static const luaL_Reg dfhack_funcs[] = {
{ "print", lua_dfhack_print }, { "print", lua_dfhack_print },
{ "println", lua_dfhack_println }, { "println", lua_dfhack_println },
@ -757,6 +773,7 @@ static const luaL_Reg dfhack_funcs[] = {
{ "onerror", dfhack_onerror }, { "onerror", dfhack_onerror },
{ "call_with_finalizer", dfhack_call_with_finalizer }, { "call_with_finalizer", dfhack_call_with_finalizer },
{ "with_suspend", lua_dfhack_with_suspend }, { "with_suspend", lua_dfhack_with_suspend },
{ "open_plugin", dfhack_open_plugin },
{ NULL, NULL } { NULL, NULL }
}; };

@ -1030,6 +1030,12 @@ static int meta_global_newindex(lua_State *state)
static int meta_call_function(lua_State *state) static int meta_call_function(lua_State *state)
{ {
auto id = (function_identity_base*)lua_touserdata(state, UPVAL_CONTAINER_ID); auto id = (function_identity_base*)lua_touserdata(state, UPVAL_CONTAINER_ID);
return method_wrapper_core(state, id);
}
int LuaWrapper::method_wrapper_core(lua_State *state, function_identity_base *id)
{
if (lua_gettop(state) != id->getNumArgs()) if (lua_gettop(state) != id->getNumArgs())
field_error(state, UPVAL_METHOD_NAME, "invalid argument count", "invoke"); field_error(state, UPVAL_METHOD_NAME, "invalid argument count", "invoke");

@ -14,7 +14,7 @@
#include <map> #include <map>
#include "DFHack.h" #include "DFHack.h"
#include "Core.h" #include "PluginManager.h"
#include "Hooks.h" #include "Hooks.h"
#include <iostream> #include <iostream>

@ -28,7 +28,7 @@ distribution.
#include <stdint.h> #include <stdint.h>
#include <vector> #include <vector>
#include <string> #include <string>
#include "Core.h" #include "PluginManager.h"
#include "Hooks.h" #include "Hooks.h"
#include <stdio.h> #include <stdio.h>

@ -32,6 +32,8 @@ distribution.
#include "DataDefs.h" #include "DataDefs.h"
#include "MiscUtils.h" #include "MiscUtils.h"
#include "LuaWrapper.h"
using namespace DFHack; using namespace DFHack;
#include <string> #include <string>
@ -107,7 +109,7 @@ struct Plugin::RefLock
void lock_sub() void lock_sub()
{ {
mut->lock(); mut->lock();
refcount --; if (--refcount == 0)
wakeup->notify_one(); wakeup->notify_one();
mut->unlock(); mut->unlock();
} }
@ -130,6 +132,13 @@ struct Plugin::RefAutolock
~RefAutolock(){ lock->unlock(); }; ~RefAutolock(){ lock->unlock(); };
}; };
struct Plugin::RefAutoinc
{
RefLock * lock;
RefAutoinc(RefLock * lck):lock(lck){ lock->lock_add(); };
~RefAutoinc(){ lock->lock_sub(); };
};
Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _filename, PluginManager * pm) Plugin::Plugin(Core * core, const std::string & filepath, const std::string & _filename, PluginManager * pm)
{ {
filename = filepath; filename = filepath;
@ -210,6 +219,7 @@ bool Plugin::load(color_ostream &con)
plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown"); plugin_shutdown = (command_result (*)(color_ostream &)) LookupPlugin(plug, "plugin_shutdown");
plugin_onstatechange = (command_result (*)(color_ostream &, state_change_event)) LookupPlugin(plug, "plugin_onstatechange"); plugin_onstatechange = (command_result (*)(color_ostream &, state_change_event)) LookupPlugin(plug, "plugin_onstatechange");
plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect"); plugin_rpcconnect = (RPCService* (*)(color_ostream &)) LookupPlugin(plug, "plugin_rpcconnect");
index_lua(plug);
this->name = *plug_name; this->name = *plug_name;
plugin_lib = plug; plugin_lib = plug;
commands.clear(); commands.clear();
@ -222,6 +232,7 @@ bool Plugin::load(color_ostream &con)
else else
{ {
con.printerr("Plugin %s has failed to initialize properly.\n", filename.c_str()); con.printerr("Plugin %s has failed to initialize properly.\n", filename.c_str());
reset_lua();
ClosePlugin(plugin_lib); ClosePlugin(plugin_lib);
state = PS_BROKEN; state = PS_BROKEN;
return false; return false;
@ -235,13 +246,22 @@ bool Plugin::unload(color_ostream &con)
// if we are actually loaded // if we are actually loaded
if(state == PS_LOADED) if(state == PS_LOADED)
{ {
// notify the plugin about an attempt to shutdown
if (plugin_onstatechange &&
plugin_onstatechange(con, SC_BEGIN_UNLOAD) == CR_NOT_FOUND)
{
con.printerr("Plugin %s has refused to be unloaded.\n", name.c_str());
access->unlock();
return false;
}
// wait for all calls to finish
access->wait();
// notify plugin about shutdown, if it has a shutdown function // notify plugin about shutdown, if it has a shutdown function
command_result cr = CR_OK; command_result cr = CR_OK;
if(plugin_shutdown) if(plugin_shutdown)
cr = plugin_shutdown(con); cr = plugin_shutdown(con);
// wait for all calls to finish
access->wait();
// cleanup... // cleanup...
reset_lua();
parent->unregisterCommands(this); parent->unregisterCommands(this);
commands.clear(); commands.clear();
if(cr == CR_OK) if(cr == CR_OK)
@ -418,6 +438,90 @@ Plugin::plugin_state Plugin::getState() const
return state; return state;
} }
void Plugin::index_lua(DFLibrary *lib)
{
if (auto cmdlist = (CommandReg*)LookupPlugin(lib, "plugin_lua_commands"))
{
for (; cmdlist->name; ++cmdlist)
{
auto &cmd = lua_commands[cmdlist->name];
if (!cmd) cmd = new LuaCommand;
cmd->owner = this;
cmd->name = cmdlist->name;
cmd->command = cmdlist->command;
}
}
if (auto funlist = (FunctionReg*)LookupPlugin(lib, "plugin_lua_functions"))
{
for (; funlist->name; ++funlist)
{
auto &cmd = lua_functions[funlist->name];
if (!cmd) cmd = new LuaFunction;
cmd->owner = this;
cmd->name = funlist->name;
cmd->identity = funlist->identity;
}
}
}
void Plugin::reset_lua()
{
for (auto it = lua_commands.begin(); it != lua_commands.end(); ++it)
it->second->command = NULL;
for (auto it = lua_functions.begin(); it != lua_functions.end(); ++it)
it->second->identity = NULL;
}
int Plugin::lua_cmd_wrapper(lua_State *state)
{
auto cmd = (LuaCommand*)lua_touserdata(state, lua_upvalueindex(1));
RefAutoinc lock(cmd->owner->access);
if (!cmd->command)
luaL_error(state, "plugin command %s() has been unloaded",
(cmd->owner->name+"."+cmd->name).c_str());
return cmd->command(state);
}
int Plugin::lua_fun_wrapper(lua_State *state)
{
auto cmd = (LuaFunction*)lua_touserdata(state, UPVAL_CONTAINER_ID);
RefAutoinc lock(cmd->owner->access);
if (!cmd->identity)
luaL_error(state, "plugin function %s() has been unloaded",
(cmd->owner->name+"."+cmd->name).c_str());
return LuaWrapper::method_wrapper_core(state, cmd->identity);
}
void Plugin::open_lua(lua_State *state, int table)
{
table = lua_absindex(state, table);
RefAutolock lock(access);
for (auto it = lua_commands.begin(); it != lua_commands.end(); ++it)
{
lua_pushlightuserdata(state, it->second);
lua_pushcclosure(state, lua_cmd_wrapper, 1);
lua_setfield(state, table, it->first.c_str());
}
for (auto it = lua_functions.begin(); it != lua_functions.end(); ++it)
{
lua_rawgetp(state, LUA_REGISTRYINDEX, &LuaWrapper::DFHACK_TYPETABLE_TOKEN);
lua_pushlightuserdata(state, NULL);
lua_pushfstring(state, "%s.%s()", name.c_str(), it->second->name.c_str());
lua_pushlightuserdata(state, it->second);
lua_pushcclosure(state, lua_fun_wrapper, 4);
lua_setfield(state, table, it->first.c_str());
}
}
PluginManager::PluginManager(Core * core) PluginManager::PluginManager(Core * core)
{ {
#ifdef LINUX_BUILD #ifdef LINUX_BUILD

@ -61,6 +61,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "df/world.h" #include "df/world.h"
#include "df/world_data.h" #include "df/world_data.h"
#include "df/unit.h" #include "df/unit.h"
#include "df/unit_misc_trait.h"
#include "df/unit_soul.h" #include "df/unit_soul.h"
#include "df/unit_skill.h" #include "df/unit_skill.h"
#include "df/material.h" #include "df/material.h"
@ -316,6 +317,19 @@ void DFHack::describeUnit(BasicUnitInfo *info, df::unit *unit,
} }
} }
if (mask && mask->misc_traits())
{
auto &vec = unit -> status.misc_traits;
for (size_t i = 0; i < vec.size(); i++)
{
auto trait = vec[i];
auto item = info->add_misc_traits();
item->set_id(trait->id);
item->set_value(trait->value);
}
}
if (unit->curse.add_tags1.whole || if (unit->curse.add_tags1.whole ||
unit->curse.add_tags2.whole || unit->curse.add_tags2.whole ||
unit->curse.rem_tags1.whole || unit->curse.rem_tags1.whole ||
@ -614,6 +628,20 @@ static command_result ListSquads(color_ostream &stream,
return CR_OK; return CR_OK;
} }
static command_result SetUnitLabors(color_ostream &stream, const SetUnitLaborsIn *in)
{
for (size_t i = 0; i < in->change_size(); i++)
{
auto change = in->change(i);
auto unit = df::unit::find(change.unit_id());
if (unit)
unit->status.labors[change.labor()] = change.value();
}
return CR_OK;
}
CoreService::CoreService() { CoreService::CoreService() {
suspend_depth = 0; suspend_depth = 0;
@ -637,6 +665,8 @@ CoreService::CoreService() {
addFunction("ListMaterials", ListMaterials, SF_CALLED_ONCE); addFunction("ListMaterials", ListMaterials, SF_CALLED_ONCE);
addFunction("ListUnits", ListUnits); addFunction("ListUnits", ListUnits);
addFunction("ListSquads", ListSquads); addFunction("ListSquads", ListSquads);
addFunction("SetUnitLabors", SetUnitLabors);
} }
CoreService::~CoreService() CoreService::~CoreService()

@ -65,12 +65,6 @@ namespace DFHack
{ {
class df_window; class df_window;
} }
// anon type, pretty much
struct DFLibrary;
DFLibrary * OpenPlugin (const char * filename);
void * LookupPlugin (DFLibrary * plugin ,const char * function);
void ClosePlugin (DFLibrary * plugin);
// Core is a singleton. Why? Because it is closely tied to SDL calls. It tracks the global state of DF. // Core is a singleton. Why? Because it is closely tied to SDL calls. It tracks the global state of DF.
// There should never be more than one instance // There should never be more than one instance
@ -139,6 +133,8 @@ namespace DFHack
static void print(const char *format, ...); static void print(const char *format, ...);
static void printerr(const char *format, ...); static void printerr(const char *format, ...);
PluginManager *getPluginManager() { return plug_mgr; }
private: private:
DFHack::Console con; DFHack::Console con;

@ -32,10 +32,6 @@ distribution.
#include "DataIdentity.h" #include "DataIdentity.h"
#include "LuaWrapper.h" #include "LuaWrapper.h"
#ifndef BUILD_DFHACK_LIB
#error Due to export issues this header is internal to the main library.
#endif
namespace df { namespace df {
// A very simple and stupid implementation of some stuff from boost // A very simple and stupid implementation of some stuff from boost
template<class U, class V> struct is_same_type { static const bool value = false; }; template<class U, class V> struct is_same_type { static const bool value = false; };
@ -50,7 +46,7 @@ namespace df {
template<class T, bool isvoid = is_same_type<typename return_type<T>::type,void>::value> template<class T, bool isvoid = is_same_type<typename return_type<T>::type,void>::value>
struct function_wrapper {}; struct function_wrapper {};
class cur_lua_ostream_argument { class DFHACK_EXPORT cur_lua_ostream_argument {
DFHack::color_ostream *out; DFHack::color_ostream *out;
public: public:
cur_lua_ostream_argument(lua_State *state); cur_lua_ostream_argument(lua_State *state);

@ -160,8 +160,6 @@ namespace DFHack
}; };
} }
// Due to export issues, this stuff can only work in the main dll
#ifdef BUILD_DFHACK_LIB
namespace df namespace df
{ {
using DFHack::function_identity_base; using DFHack::function_identity_base;
@ -171,7 +169,7 @@ namespace df
using DFHack::ptr_container_identity; using DFHack::ptr_container_identity;
using DFHack::bit_container_identity; using DFHack::bit_container_identity;
class number_identity_base : public primitive_identity { class DFHACK_EXPORT number_identity_base : public primitive_identity {
const char *name; const char *name;
public: public:
@ -197,7 +195,7 @@ namespace df
virtual void write(void *ptr, double val) { *(T*)ptr = T(val); } virtual void write(void *ptr, double val) { *(T*)ptr = T(val); }
}; };
class bool_identity : public primitive_identity { class DFHACK_EXPORT bool_identity : public primitive_identity {
public: public:
bool_identity() : primitive_identity(sizeof(bool)) {}; bool_identity() : primitive_identity(sizeof(bool)) {};
@ -207,7 +205,7 @@ namespace df
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
}; };
class ptr_string_identity : public primitive_identity { class DFHACK_EXPORT ptr_string_identity : public primitive_identity {
public: public:
ptr_string_identity() : primitive_identity(sizeof(char*)) {}; ptr_string_identity() : primitive_identity(sizeof(char*)) {};
@ -217,7 +215,7 @@ namespace df
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
}; };
class stl_string_identity : public DFHack::constructed_identity { class DFHACK_EXPORT stl_string_identity : public DFHack::constructed_identity {
public: public:
stl_string_identity() stl_string_identity()
: constructed_identity(sizeof(std::string), &allocator_fn<std::string>) : constructed_identity(sizeof(std::string), &allocator_fn<std::string>)
@ -233,7 +231,7 @@ namespace df
virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index); virtual void lua_write(lua_State *state, int fname_idx, void *ptr, int val_index);
}; };
class stl_ptr_vector_identity : public ptr_container_identity { class DFHACK_EXPORT stl_ptr_vector_identity : public ptr_container_identity {
public: public:
typedef std::vector<void*> container; typedef std::vector<void*> container;
@ -276,6 +274,8 @@ namespace df
} }
}; };
// Due to export issues, this stuff can only work in the main dll
#ifdef BUILD_DFHACK_LIB
class buffer_container_identity : public container_identity { class buffer_container_identity : public container_identity {
int size; int size;
@ -370,8 +370,9 @@ namespace df
((container*)ptr)->set(idx, val); ((container*)ptr)->set(idx, val);
} }
}; };
#endif
class stl_bit_vector_identity : public bit_container_identity { class DFHACK_EXPORT stl_bit_vector_identity : public bit_container_identity {
public: public:
typedef std::vector<bool> container; typedef std::vector<bool> container;
@ -400,6 +401,7 @@ namespace df
} }
}; };
#ifdef BUILD_DFHACK_LIB
template<class T> template<class T>
class enum_list_attr_identity : public container_identity { class enum_list_attr_identity : public container_identity {
public: public:
@ -421,9 +423,10 @@ namespace df
return (void*)&((container*)ptr)->items[idx]; return (void*)&((container*)ptr)->items[idx];
} }
}; };
#endif
#define NUMBER_IDENTITY_TRAITS(type) \ #define NUMBER_IDENTITY_TRAITS(type) \
template<> struct identity_traits<type> { \ template<> struct DFHACK_EXPORT identity_traits<type> { \
static number_identity<type> identity; \ static number_identity<type> identity; \
static number_identity_base *get() { return &identity; } \ static number_identity_base *get() { return &identity; } \
}; };
@ -439,37 +442,37 @@ namespace df
NUMBER_IDENTITY_TRAITS(uint64_t); NUMBER_IDENTITY_TRAITS(uint64_t);
NUMBER_IDENTITY_TRAITS(float); NUMBER_IDENTITY_TRAITS(float);
template<> struct identity_traits<bool> { template<> struct DFHACK_EXPORT identity_traits<bool> {
static bool_identity identity; static bool_identity identity;
static bool_identity *get() { return &identity; } static bool_identity *get() { return &identity; }
}; };
template<> struct identity_traits<std::string> { template<> struct DFHACK_EXPORT identity_traits<std::string> {
static stl_string_identity identity; static stl_string_identity identity;
static stl_string_identity *get() { return &identity; } static stl_string_identity *get() { return &identity; }
}; };
template<> struct identity_traits<char*> { template<> struct DFHACK_EXPORT identity_traits<char*> {
static ptr_string_identity identity; static ptr_string_identity identity;
static ptr_string_identity *get() { return &identity; } static ptr_string_identity *get() { return &identity; }
}; };
template<> struct identity_traits<const char*> { template<> struct DFHACK_EXPORT identity_traits<const char*> {
static ptr_string_identity identity; static ptr_string_identity identity;
static ptr_string_identity *get() { return &identity; } static ptr_string_identity *get() { return &identity; }
}; };
template<> struct identity_traits<void*> { template<> struct DFHACK_EXPORT identity_traits<void*> {
static pointer_identity identity; static pointer_identity identity;
static pointer_identity *get() { return &identity; } static pointer_identity *get() { return &identity; }
}; };
template<> struct identity_traits<std::vector<void*> > { template<> struct DFHACK_EXPORT identity_traits<std::vector<void*> > {
static stl_ptr_vector_identity identity; static stl_ptr_vector_identity identity;
static stl_ptr_vector_identity *get() { return &identity; } static stl_ptr_vector_identity *get() { return &identity; }
}; };
template<> struct identity_traits<std::vector<bool> > { template<> struct DFHACK_EXPORT identity_traits<std::vector<bool> > {
static stl_bit_vector_identity identity; static stl_bit_vector_identity identity;
static stl_bit_vector_identity *get() { return &identity; } static stl_bit_vector_identity *get() { return &identity; }
}; };
@ -478,14 +481,17 @@ namespace df
// Container declarations // Container declarations
#ifdef BUILD_DFHACK_LIB
template<class Enum, class FT> struct identity_traits<enum_field<Enum,FT> > { template<class Enum, class FT> struct identity_traits<enum_field<Enum,FT> > {
static primitive_identity *get(); static primitive_identity *get();
}; };
#endif
template<class T> struct identity_traits<T *> { template<class T> struct identity_traits<T *> {
static pointer_identity *get(); static pointer_identity *get();
}; };
#ifdef BUILD_DFHACK_LIB
template<class T, int sz> struct identity_traits<T [sz]> { template<class T, int sz> struct identity_traits<T [sz]> {
static container_identity *get(); static container_identity *get();
}; };
@ -493,11 +499,13 @@ namespace df
template<class T> struct identity_traits<std::vector<T> > { template<class T> struct identity_traits<std::vector<T> > {
static container_identity *get(); static container_identity *get();
}; };
#endif
template<class T> struct identity_traits<std::vector<T*> > { template<class T> struct identity_traits<std::vector<T*> > {
static stl_ptr_vector_identity *get(); static stl_ptr_vector_identity *get();
}; };
#ifdef BUILD_DFHACK_LIB
template<class T> struct identity_traits<std::deque<T> > { template<class T> struct identity_traits<std::deque<T> > {
static container_identity *get(); static container_identity *get();
}; };
@ -518,13 +526,16 @@ namespace df
template<class T> struct identity_traits<enum_list_attr<T> > { template<class T> struct identity_traits<enum_list_attr<T> > {
static container_identity *get(); static container_identity *get();
}; };
#endif
// Container definitions // Container definitions
#ifdef BUILD_DFHACK_LIB
template<class Enum, class FT> template<class Enum, class FT>
inline primitive_identity *identity_traits<enum_field<Enum,FT> >::get() { inline primitive_identity *identity_traits<enum_field<Enum,FT> >::get() {
return identity_traits<FT>::get(); return identity_traits<FT>::get();
} }
#endif
template<class T> template<class T>
inline pointer_identity *identity_traits<T *>::get() { inline pointer_identity *identity_traits<T *>::get() {
@ -532,6 +543,7 @@ namespace df
return &identity; return &identity;
} }
#ifdef BUILD_DFHACK_LIB
template<class T, int sz> template<class T, int sz>
inline container_identity *identity_traits<T [sz]>::get() { inline container_identity *identity_traits<T [sz]>::get() {
static buffer_container_identity identity(sz, identity_traits<T>::get()); static buffer_container_identity identity(sz, identity_traits<T>::get());
@ -544,6 +556,7 @@ namespace df
static stl_container_identity<container> identity("vector", identity_traits<T>::get()); static stl_container_identity<container> identity("vector", identity_traits<T>::get());
return &identity; return &identity;
} }
#endif
template<class T> template<class T>
inline stl_ptr_vector_identity *identity_traits<std::vector<T*> >::get() { inline stl_ptr_vector_identity *identity_traits<std::vector<T*> >::get() {
@ -551,6 +564,7 @@ namespace df
return &identity; return &identity;
} }
#ifdef BUILD_DFHACK_LIB
template<class T> template<class T>
inline container_identity *identity_traits<std::deque<T> >::get() { inline container_identity *identity_traits<std::deque<T> >::get() {
typedef std::deque<T> container; typedef std::deque<T> container;
@ -576,5 +590,5 @@ namespace df
static enum_list_attr_identity<T> identity(identity_traits<T>::get()); static enum_list_attr_identity<T> identity(identity_traits<T>::get());
return &identity; return &identity;
} }
}
#endif #endif
}

@ -30,6 +30,7 @@ distribution.
#include <map> #include <map>
#include "DataDefs.h" #include "DataDefs.h"
#include "PluginManager.h"
#include <lua.h> #include <lua.h>
#include <lauxlib.h> #include <lauxlib.h>
@ -156,7 +157,7 @@ namespace DFHack { namespace LuaWrapper {
* Verify that the object is a DF ref with UPVAL_METATABLE. * Verify that the object is a DF ref with UPVAL_METATABLE.
* If everything ok, extract the address. * If everything ok, extract the address.
*/ */
uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode); DFHACK_EXPORT uint8_t *get_object_addr(lua_State *state, int obj, int field, const char *mode);
bool is_type_compatible(lua_State *state, type_identity *type1, int meta1, bool is_type_compatible(lua_State *state, type_identity *type1, int meta1,
type_identity *type2, int meta2, bool exact_equal); type_identity *type2, int meta2, bool exact_equal);
@ -221,16 +222,14 @@ namespace DFHack { namespace LuaWrapper {
*/ */
void AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum); void AttachEnumKeys(lua_State *state, int meta_idx, int ftable_idx, type_identity *ienum);
struct FunctionReg {
const char *name;
function_identity_base *identity;
};
/** /**
* Wrap functions and add them to the table on the top of the stack. * Wrap functions and add them to the table on the top of the stack.
*/ */
using DFHack::FunctionReg;
void SetFunctionWrappers(lua_State *state, const FunctionReg *reg); void SetFunctionWrappers(lua_State *state, const FunctionReg *reg);
int method_wrapper_core(lua_State *state, function_identity_base *id);
void IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct); void IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct);
void AttachDFGlobals(lua_State *state); void AttachDFGlobals(lua_State *state);

@ -33,7 +33,8 @@ distribution.
#include "RemoteClient.h" #include "RemoteClient.h"
struct DFLibrary; typedef struct lua_State lua_State;
namespace tthread namespace tthread
{ {
class mutex; class mutex;
@ -49,6 +50,17 @@ namespace DFHack
class PluginManager; class PluginManager;
class virtual_identity; class virtual_identity;
class RPCService; class RPCService;
class function_identity_base;
// anon type, pretty much
struct DFLibrary;
// Open a plugin library
DFLibrary * OpenPlugin (const char * filename);
// find a symbol inside plugin
void * LookupPlugin (DFLibrary * plugin ,const char * function);
// Close a plugin library
void ClosePlugin (DFLibrary * plugin);
enum state_change_event enum state_change_event
{ {
@ -56,7 +68,17 @@ namespace DFHack
SC_WORLD_UNLOADED, SC_WORLD_UNLOADED,
SC_MAP_LOADED, SC_MAP_LOADED,
SC_MAP_UNLOADED, SC_MAP_UNLOADED,
SC_VIEWSCREEN_CHANGED SC_VIEWSCREEN_CHANGED,
SC_CORE_INITIALIZED,
SC_BEGIN_UNLOAD
};
struct DFHACK_EXPORT CommandReg {
const char *name;
int (*command)(lua_State*);
};
struct DFHACK_EXPORT FunctionReg {
const char *name;
function_identity_base *identity;
}; };
struct DFHACK_EXPORT PluginCommand struct DFHACK_EXPORT PluginCommand
{ {
@ -102,6 +124,7 @@ namespace DFHack
{ {
struct RefLock; struct RefLock;
struct RefAutolock; struct RefAutolock;
struct RefAutoinc;
enum plugin_state enum plugin_state
{ {
PS_UNLOADED, PS_UNLOADED,
@ -138,6 +161,9 @@ namespace DFHack
{ {
return name; return name;
} }
void open_lua(lua_State *state, int table);
private: private:
RefLock * access; RefLock * access;
std::vector <PluginCommand> commands; std::vector <PluginCommand> commands;
@ -147,6 +173,26 @@ namespace DFHack
DFLibrary * plugin_lib; DFLibrary * plugin_lib;
PluginManager * parent; PluginManager * parent;
plugin_state state; plugin_state state;
struct LuaCommand {
Plugin *owner;
std::string name;
int (*command)(lua_State *state);
};
std::map<std::string, LuaCommand*> lua_commands;
static int lua_cmd_wrapper(lua_State *state);
struct LuaFunction {
Plugin *owner;
std::string name;
function_identity_base *identity;
};
std::map<std::string, LuaFunction*> lua_functions;
static int lua_fun_wrapper(lua_State *state);
void index_lua(DFLibrary *lib);
void reset_lua();
command_result (*plugin_init)(color_ostream &, std::vector <PluginCommand> &); command_result (*plugin_init)(color_ostream &, std::vector <PluginCommand> &);
command_result (*plugin_status)(color_ostream &, std::string &); command_result (*plugin_status)(color_ostream &, std::string &);
command_result (*plugin_shutdown)(color_ostream &); command_result (*plugin_shutdown)(color_ostream &);
@ -199,5 +245,15 @@ namespace DFHack
}; };
/// You have to have this in every plugin you write - just once. Ideally on top of the main file. /// You have to have this in every plugin you write - just once. Ideally on top of the main file.
#define DFHACK_PLUGIN(plugin_name) DFhackDataExport const char * version = DFHACK_VERSION;\ #define DFHACK_PLUGIN(plugin_name) \
DFhackDataExport const char * name = plugin_name; DFhackDataExport const char * version = DFHACK_VERSION;\
DFhackDataExport const char * name = plugin_name;
#define DFHACK_PLUGIN_LUA_COMMANDS \
DFhackCExport const DFHack::CommandReg plugin_lua_commands[] =
#define DFHACK_PLUGIN_LUA_FUNCTIONS \
DFhackCExport const DFHack::FunctionReg plugin_lua_functions[] =
#define DFHACK_LUA_COMMAND(name) { #name, name }
#define DFHACK_LUA_FUNCTION(name) { #name, df::wrap_function(name) }
#define DFHACK_LUA_END { NULL, NULL }

@ -55,6 +55,10 @@ function mkmodule(module,env)
error("Not a table in package.loaded["..module.."]") error("Not a table in package.loaded["..module.."]")
end end
end end
local plugname = string.match(module,'^plugins%.(%w+)$')
if plugname then
dfhack.open_plugin(pkg,plugname)
end
setmetatable(pkg, { __index = (env or _G) }) setmetatable(pkg, { __index = (env or _G) })
return pkg return pkg
end end

@ -130,6 +130,11 @@ message SkillInfo {
required int32 experience = 3; required int32 experience = 3;
}; };
message UnitMiscTrait {
required int32 id = 1;
required int32 value = 2;
};
message BasicUnitInfo { message BasicUnitInfo {
required int32 unit_id = 1; required int32 unit_id = 1;
@ -166,6 +171,9 @@ message BasicUnitInfo {
// IF mask.skills: // IF mask.skills:
repeated SkillInfo skills = 12; repeated SkillInfo skills = 12;
// IF mask.misc_traits:
repeated UnitMiscTrait misc_traits = 24;
optional UnitCurseInfo curse = 16; optional UnitCurseInfo curse = 16;
repeated int32 burrows = 21; repeated int32 burrows = 21;
@ -175,6 +183,7 @@ message BasicUnitInfoMask {
optional bool labors = 1 [default = false]; optional bool labors = 1 [default = false];
optional bool skills = 2 [default = false]; optional bool skills = 2 [default = false];
optional bool profession = 3 [default = false]; optional bool profession = 3 [default = false];
optional bool misc_traits = 4 [default = false];
}; };
message BasicSquadInfo { message BasicSquadInfo {
@ -188,3 +197,9 @@ message BasicSquadInfo {
// Member histfig ids: // Member histfig ids:
repeated sint32 members = 4; repeated sint32 members = 4;
}; };
message UnitLaborState {
required int32 unit_id = 1;
required int32 labor = 2;
required bool value = 3;
};

@ -99,4 +99,9 @@ message ListUnitsOut {
message ListSquadsIn {} message ListSquadsIn {}
message ListSquadsOut { message ListSquadsOut {
repeated BasicSquadInfo value = 1; repeated BasicSquadInfo value = 1;
} };
// RPC SetUnitLabors : SetUnitLaborsIn -> EmptyMessage
message SetUnitLaborsIn {
repeated UnitLaborState change = 1;
};

@ -1 +1 @@
Subproject commit 73cd75788fc45b13790b4e6bb4d3f33691224d30 Subproject commit a545167050fee9eedd5e319b518d961f933154a3

@ -36,6 +36,10 @@ if (BUILD_DWARFEXPORT)
add_subdirectory (dwarfexport) add_subdirectory (dwarfexport)
endif() endif()
install(DIRECTORY lua/
DESTINATION ${DFHACK_LUA_DESTINATION}/plugins
FILES_MATCHING PATTERN "*.lua")
# Protobuf # Protobuf
FILE(GLOB PROJECT_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto) FILE(GLOB PROJECT_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto)
@ -98,7 +102,8 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(feature feature.cpp) DFHACK_PLUGIN(feature feature.cpp)
DFHACK_PLUGIN(lair lair.cpp) DFHACK_PLUGIN(lair lair.cpp)
DFHACK_PLUGIN(zone zone.cpp) DFHACK_PLUGIN(zone zone.cpp)
DFHACK_PLUGIN(burrows burrows.cpp) # this one exports functions to lua
DFHACK_PLUGIN(burrows burrows.cpp LINK_LIBRARIES lua)
# not yet. busy with other crud again... # not yet. busy with other crud again...
#DFHACK_PLUGIN(versionosd versionosd.cpp) #DFHACK_PLUGIN(versionosd versionosd.cpp)
endif() endif()

@ -86,14 +86,15 @@ loadall(plugins)
dofile_silent("dfusion/initcustom.lua") dofile_silent("dfusion/initcustom.lua")
local args={...} local args={...}
for k,v in pairs(args) do
local f,err=load(v)
if f then local f,err=load(table.concat(args,' '))
if f then
f() f()
else else
Console.printerr(err) Console.printerr(err)
end
end end
if not INIT then if not INIT then
mainmenu(plugins) mainmenu(plugins)
end end

@ -274,19 +274,50 @@ function tools.changesite(names)
print(string.format("%x->%d",off,n2)) print(string.format("%x->%d",off,n2))
engine.poke(off,ptr_site.type,n2) engine.poke(off,ptr_site.type,n2)
end end
function tools.project(unit) function tools.project(unit,trg)
if unit==nil then if unit==nil then
unit=getSelectedUnit() unit=getCreatureAtPointer()
end
if unit==nil then
unit=getCreatureAtPos(getxyz())
end end
if unit==nil then if unit==nil then
error("Failed to project unit. Unit not selected/valid") error("Failed to project unit. Unit not selected/valid")
end end
-- todo: add projectile to world, point to unit, add flag to unit, add gen-ref to projectile. -- todo: add projectile to world, point to unit, add flag to unit, add gen-ref to projectile.
local p=df.proj_unitst:new()
local startpos={x=unit.pos.x,y=unit.pos.y,z=unit.pos.z}
p.origin_pos=startpos
p.target_pos=trg
p.cur_pos=startpos
p.prev_pos=startpos
p.unit=unit
--- wtf stuff
p.unk14=100
p.unk16=-1
p.unk23=-1
p.fall_delay=5
p.fall_counter=5
p.collided=true
-- end wtf
local citem=df.global.world.proj_list
local maxid=1
local newlink=df.proj_list_link:new()
newlink.item=p
while citem.item~= nil do
if citem.item.id>maxid then maxid=citem.item.id end
if citem.next ~= nil then
citem=citem.next
else
break
end
end
p.id=maxid+1
newlink.prev=citem
citem.next=newlink
local proj_ref=df.general_ref_projectile:new()
proj_ref.projectile_id=p.id
unit.refs:insert(#unit.refs,proj_ref)
unit.flags1.projectile=true
end end
function tools.empregnate(unit) function tools.empregnate(unit)
if unit==nil then if unit==nil then

@ -2,6 +2,9 @@
#include "Console.h" #include "Console.h"
#include "Export.h" #include "Export.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "Error.h"
#include "DataFuncs.h"
#include "modules/Gui.h" #include "modules/Gui.h"
#include "modules/Job.h" #include "modules/Job.h"
@ -420,6 +423,9 @@ static df::burrow *findByName(color_ostream &out, std::string name, bool silent
static void copyUnits(df::burrow *target, df::burrow *source, bool enable) static void copyUnits(df::burrow *target, df::burrow *source, bool enable)
{ {
CHECK_NULL_POINTER(target);
CHECK_NULL_POINTER(source);
if (source == target) if (source == target)
{ {
if (!enable) if (!enable)
@ -439,6 +445,9 @@ static void copyUnits(df::burrow *target, df::burrow *source, bool enable)
static void copyTiles(df::burrow *target, df::burrow *source, bool enable) static void copyTiles(df::burrow *target, df::burrow *source, bool enable)
{ {
CHECK_NULL_POINTER(target);
CHECK_NULL_POINTER(source);
if (source == target) if (source == target)
{ {
if (!enable) if (!enable)
@ -480,6 +489,8 @@ static void copyTiles(df::burrow *target, df::burrow *source, bool enable)
static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mask, static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mask,
df::tile_designation d_value, bool enable) df::tile_designation d_value, bool enable)
{ {
CHECK_NULL_POINTER(target);
auto &blocks = world->map.map_blocks; auto &blocks = world->map.map_blocks;
for (size_t i = 0; i < blocks.size(); i++) for (size_t i = 0; i < blocks.size(); i++)
@ -512,6 +523,8 @@ static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mas
static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable) static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable)
{ {
CHECK_NULL_POINTER(target);
df::tile_designation mask(0); df::tile_designation mask(0);
df::tile_designation value(0); df::tile_designation value(0);
@ -538,6 +551,14 @@ static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable)
return true; return true;
} }
DFHACK_PLUGIN_LUA_FUNCTIONS {
DFHACK_LUA_FUNCTION(findByName),
DFHACK_LUA_FUNCTION(copyUnits),
DFHACK_LUA_FUNCTION(copyTiles),
DFHACK_LUA_FUNCTION(setTilesByKeyword),
DFHACK_LUA_END
};
static command_result burrow(color_ostream &out, vector <string> &parameters) static command_result burrow(color_ostream &out, vector <string> &parameters)
{ {
CoreSuspender suspend; CoreSuspender suspend;

@ -0,0 +1,33 @@
local _ENV = mkmodule('plugins.burrows')
--[[
Native functions:
* findByName(name) -> burrow
* copyUnits(dest,src,enable)
* copyTiles(dest,src,enable)
* setTilesByKeyword(dest,kwd,enable) -> success
'enable' selects between add and remove modes
--]]
clearUnits = dfhack.units.clearBurrowMembers
function isBurrowUnit(burrow,unit)
return dfhack.units.isInBurrow(unit,burrow)
end
function setBurrowUnit(burrow,unit,enable)
return dfhack.units.setInBurrow(unit,burrow,enable)
end
clearTiles = dfhack.maps.clearBurrowTiles
listBlocks = dfhack.maps.listBurrowBlocks
isBurrowTile = dfhack.maps.isBurrowTile
setBurrowTile = dfhack.maps.setBurrowTile
isBlockBurrowTile = dfhack.maps.isBlockBurrowTile
setBlockBurrowTile = dfhack.maps.setBlockBurrowTile
return _ENV

@ -227,6 +227,10 @@ static command_result tweak(color_ostream &out, vector <string> &parameters)
unit->flags1.bits.forest = 0; unit->flags1.bits.forest = 0;
if(unit->civ_id != df::global::ui->civ_id) if(unit->civ_id != df::global::ui->civ_id)
unit->civ_id = df::global::ui->civ_id; unit->civ_id = df::global::ui->civ_id;
if(unit->profession == df::profession::MERCHANT)
unit->profession = df::profession::TRADER;
if(unit->profession2 == df::profession::MERCHANT)
unit->profession2 = df::profession::TRADER;
return fix_clothing_ownership(out, unit); return fix_clothing_ownership(out, unit);
} }
else else

@ -890,6 +890,8 @@ df::general_ref_building_civzone_assignedst * createCivzoneRef()
return newref; return newref;
} }
bool isInBuiltCage(df::unit* unit);
// check if assigned to pen, pit, (built) cage or chain // check if assigned to pen, pit, (built) cage or chain
// note: BUILDING_CAGED is not set for animals (maybe it's used for dwarves who get caged as sentence) // note: BUILDING_CAGED is not set for animals (maybe it's used for dwarves who get caged as sentence)
// animals in cages (no matter if built or on stockpile) get the ref CONTAINED_IN_ITEM instead // animals in cages (no matter if built or on stockpile) get the ref CONTAINED_IN_ITEM instead
@ -905,7 +907,7 @@ bool isAssigned(df::unit* unit)
if( rtype == df::general_ref_type::BUILDING_CIVZONE_ASSIGNED if( rtype == df::general_ref_type::BUILDING_CIVZONE_ASSIGNED
|| rtype == df::general_ref_type::BUILDING_CAGED || rtype == df::general_ref_type::BUILDING_CAGED
|| rtype == df::general_ref_type::BUILDING_CHAIN || rtype == df::general_ref_type::BUILDING_CHAIN
|| (rtype == df::general_ref_type::CONTAINED_IN_ITEM && isBuiltCageAtPos(unit->pos)) || (rtype == df::general_ref_type::CONTAINED_IN_ITEM && isInBuiltCage(unit))
) )
{ {
assigned = true; assigned = true;
@ -958,10 +960,10 @@ bool isInBuiltCage(df::unit* unit)
df::building* building = world->buildings.all[b]; df::building* building = world->buildings.all[b];
if( building->getType() == building_type::Cage) if( building->getType() == building_type::Cage)
{ {
df::building_cagest* oldcage = (df::building_cagest*) building; df::building_cagest* cage = (df::building_cagest*) building;
for(size_t oc=0; oc<oldcage->assigned_creature.size(); oc++) for(size_t c=0; c<cage->assigned_creature.size(); c++)
{ {
if(oldcage->assigned_creature[oc] == unit->id) if(cage->assigned_creature[c] == unit->id)
{ {
caged = true; caged = true;
break; break;
@ -2769,7 +2771,9 @@ command_result autoButcher( color_ostream &out, bool verbose = false )
|| !isTame(unit) || !isTame(unit)
|| isWar(unit) // ignore war dogs etc || isWar(unit) // ignore war dogs etc
|| isHunter(unit) // ignore hunting dogs etc || isHunter(unit) // ignore hunting dogs etc
|| (isContainedInItem(unit) && hasValidMapPos(unit) && isBuiltCageAtPos(unit->pos)) // ignore creatures in built cages to leave zoos alone
// (TODO: allow some kind of slaughter cages which you can place near the butcher)
|| (isContainedInItem(unit) && isInBuiltCage(unit))
|| unit->name.has_name || unit->name.has_name
) )
continue; continue;