Hotkey UI for linux.

develop
Petr Mrázek 2011-07-09 11:33:58 +02:00
parent 65d7278f53
commit d894ef0ffa
16 changed files with 380 additions and 123 deletions

@ -803,8 +803,8 @@
<Group name="GUI" description="Offsets used by the GUI module."> <Group name="GUI" description="Offsets used by the GUI module.">
<Address name="pause_state" description="a flag that determines if the game is paused."/> <Address name="pause_state" description="a flag that determines if the game is paused."/>
<Address name="current_cursor_creature" description="A vector? of creatures currently under the cursor."/> <Address name="current_cursor_creature" description="A vector? of creatures currently under the cursor."/>
<Address name="interface" description="Pointer to the global interfacest object (gview symbol on Linux)."/>
<Address name="current_menu_state" description="A numeric value that describes the state of the current GUI element (switching between menus will change this)."/> <Address name="current_menu_state" description="A numeric value that describes the state of the current GUI element (switching between menus will change this)."/>
<Address name="view_screen" description="Pointer to the current view screen object (GUI screen)."/>
<Address name="hotkeys" description="Address where the array of hotkeys starts." /> <Address name="hotkeys" description="Address where the array of hotkeys starts." />
</Group> </Group>
<Group name="Maps" description="Offsets used by the Maps module."> <Group name="Maps" description="Offsets used by the Maps module.">
@ -1127,8 +1127,6 @@
<Group name="GUI"> <Group name="GUI">
<Address name="pause_state" value="0x146e45f" /> <Address name="pause_state" value="0x146e45f" />
<Address name="current_cursor_creature" value="0xae82cc" valid="false" /> <Address name="current_cursor_creature" value="0xae82cc" valid="false" />
<Address name="current_menu_state" value="0x017f6f38" />
<Address name="view_screen" value="0xae82cc" valid="false" />
<Address name="hotkeys" value="0x01476ecc" /> <Address name="hotkeys" value="0x01476ecc" />
</Group> </Group>
<Group name="Maps"> <Group name="Maps">
@ -1307,7 +1305,6 @@
constructions 0xffffffff constructions 0xffffffff
creatures 0x0166eccc creatures 0x0166eccc
current_cursor_creature 0x00ae82cc current_cursor_creature 0x00ae82cc
current_menu_state 0x017f6f38
cursor_xyz 0x0166ecd4 cursor_xyz 0x0166ecd4
effects_vector 0x017f6da0 effects_vector 0x017f6da0
hotkey_start 0x01476ecc hotkey_start 0x01476ecc
@ -1323,7 +1320,6 @@
settlement_current 0xffffffff settlement_current 0xffffffff
settlements 0x016af4a4 settlements 0x016af4a4
translation_vector 0x016b0010 translation_vector 0x016b0010
view_screen 0xffffffff
window_dims 0x017f5abc window_dims 0x017f5abc
window_x 0x00e32798 window_x 0x00e32798
window_y 0x00e60838 window_y 0x00e60838
@ -3019,6 +3015,8 @@
WORLD: 0x93f77a0 WORLD: 0x93f77a0
<Group name="GUI"> <Group name="GUI">
<Address name="hotkeys" value="0x93f740c" /> <Address name="hotkeys" value="0x93f740c" />
<Address name="interface" value="0x8C3E900" />
<Address name="current_menu_state" value="0x93F756C" />
</Group> </Group>
<Group name="Creatures"> <Group name="Creatures">
Maybe, possibly. Maybe, possibly.

@ -20,6 +20,7 @@ SET(PROJECT_HDRS
include/DFHack.h include/DFHack.h
include/dfhack/Error.h include/dfhack/Error.h
include/dfhack/Export.h include/dfhack/Export.h
include/dfhack/Virtual.h
include/dfhack/MiscUtils.h include/dfhack/MiscUtils.h
include/dfhack/Module.h include/dfhack/Module.h
include/dfhack/Pragma.h include/dfhack/Pragma.h
@ -53,6 +54,7 @@ PluginManager.cpp
VersionInfo.cpp VersionInfo.cpp
VersionInfoFactory.cpp VersionInfoFactory.cpp
TileTypes.cpp TileTypes.cpp
Virtual.cpp
depends/md5/md5.cpp depends/md5/md5.cpp
depends/md5/md5wrapper.cpp depends/md5/md5wrapper.cpp

@ -38,14 +38,14 @@ using namespace std;
#include "dfhack/Process.h" #include "dfhack/Process.h"
#include "dfhack/Core.h" #include "dfhack/Core.h"
#include "dfhack/Console.h" #include "dfhack/Console.h"
#include "dfhack/Module.h"
#include "dfhack/VersionInfoFactory.h" #include "dfhack/VersionInfoFactory.h"
#include "dfhack/PluginManager.h" #include "dfhack/PluginManager.h"
#include "ModuleFactory.h" #include "ModuleFactory.h"
#include "dfhack/modules/Gui.h" #include "dfhack/modules/Gui.h"
#include "dfhack/modules/Vegetation.h"
#include "dfhack/modules/Maps.h" #include "dfhack/SDL_fakes/events.h"
#include "dfhack/modules/World.h"
#include <stdio.h> #include <stdio.h>
#include <iomanip> #include <iomanip>
using namespace DFHack; using namespace DFHack;
@ -63,11 +63,41 @@ struct IODATA
PluginManager * plug_mgr; PluginManager * plug_mgr;
}; };
// A thread function... for handling hotkeys. This is needed because
// all the plugin commands are expected to be run from foreign threads.
// Running them from one of the main DF threads will result in deadlock!
int fHKthread(void * iodata)
{
Core * core = ((IODATA*) iodata)->core;
PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr;
if(plug_mgr == 0 || core == 0)
{
cerr << "Hotkey thread has croaked." << endl;
return 0;
}
while(1)
{
std::string stuff = core->getHotkeyCmd(); // waits on mutex!
if(!stuff.empty())
{
vector <string> crap;
plug_mgr->InvokeCommand(stuff, crap);
}
}
}
// A thread function... for the interactive console.
static bool flip0 = false;
int fIOthread(void * iodata) int fIOthread(void * iodata)
{ {
if(!flip0)
{
std::cerr << "Console from Thread " << SDL_ThreadID() << std::endl;
flip0 = true;
}
Core * core = ((IODATA*) iodata)->core; Core * core = ((IODATA*) iodata)->core;
PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr; PluginManager * plug_mgr = ((IODATA*) iodata)->plug_mgr;
if(plug_mgr == 0) if(plug_mgr == 0 || core == 0)
{ {
dfout << "Something horrible happened to the plugin manager in Core's constructor..." << std::endl; dfout << "Something horrible happened to the plugin manager in Core's constructor..." << std::endl;
return 0; return 0;
@ -140,8 +170,34 @@ int fIOthread(void * iodata)
Core::Core() Core::Core()
{ {
// init the console. This must be always the first step! // init the console. This must be always the first step!
con = new Console(); con = 0;
plug_mgr = 0; plug_mgr = 0;
vif = 0;
p = 0;
errorstate = false;
vinfo = 0;
started = false;
memset(&(s_mods), 0, sizeof(s_mods));
// create mutex for syncing with interactive tasks
AccessMutex = 0;
// set up hotkey capture
memset(hotkey_states,0,sizeof(hotkey_states));
hotkey_set = false;
HotkeyMutex = 0;
HotkeyCond = 0;
};
static bool flip1 = 0;
bool Core::Init()
{
// init the console. This must be always the first step!
con = new Console();
if(!flip1)
{
std::cerr << "Construct from Thread " << SDL_ThreadID() << std::endl;
flip1 = true;
}
// find out what we are... // find out what we are...
vif = new DFHack::VersionInfoFactory("Memory.xml"); vif = new DFHack::VersionInfoFactory("Memory.xml");
p = new DFHack::Process(vif); p = new DFHack::Process(vif);
@ -151,36 +207,71 @@ Core::Core()
errorstate = true; errorstate = true;
delete p; delete p;
p = NULL; p = NULL;
return; return false;
} }
vinfo = p->getDescriptor(); vinfo = p->getDescriptor();
// init module storage
allModules.clear();
memset(&(s_mods), 0, sizeof(s_mods));
// create mutex for syncing with interactive tasks // create mutex for syncing with interactive tasks
AccessMutex = SDL_CreateMutex(); AccessMutex = SDL_CreateMutex();
if(!AccessMutex) if(!AccessMutex)
{ {
dfout << "Mutex creation failed." << std::endl; dfout << "Mutex creation failed." << std::endl;
errorstate = true; errorstate = true;
return; return false;
} }
// all OK
errorstate = false;
// lock mutex // lock mutex
SDL_mutexP(AccessMutex); SDL_mutexP(AccessMutex);
// create plugin manager
plug_mgr = new PluginManager(this); plug_mgr = new PluginManager(this);
if(!plug_mgr)
{
dfout << "Failed to create the Plugin Manager." << std::endl;
errorstate = true;
return false;
}
// look for all plugins, // look for all plugins,
// create IO thread // create IO thread
IODATA *temp = new IODATA; IODATA *temp = new IODATA;
temp->core = this; temp->core = this;
temp->plug_mgr = plug_mgr; temp->plug_mgr = plug_mgr;
DFThread * IO = SDL_CreateThread(fIOthread, (void *) temp); SDL::Thread * IO = SDL_CreateThread(fIOthread, (void *) temp);
delete temp; // set up hotkey capture
// and let DF do its thing. HotkeyMutex = SDL_CreateMutex();
}; HotkeyCond = SDL_CreateCond();
SDL::Thread * HK = SDL_CreateThread(fHKthread, (void *) temp);
started = true;
return true;
}
/// sets the current hotkey command
bool Core::setHotkeyCmd( std::string cmd )
{
// access command
SDL_mutexP(HotkeyMutex);
{
hotkey_set = true;
hotkey_cmd = cmd;
SDL_CondSignal(HotkeyCond);
}
SDL_mutexV(HotkeyMutex);
return true;
}
/// removes the hotkey command and gives it to the caller thread
std::string Core::getHotkeyCmd( void )
{
string returner;
SDL_mutexP(HotkeyMutex);
while ( ! hotkey_set )
{
SDL_CondWait(HotkeyCond, HotkeyMutex);
}
hotkey_set = false;
returner = hotkey_cmd;
hotkey_cmd.clear();
SDL_mutexV(HotkeyMutex);
return returner;
}
void Core::Suspend() void Core::Suspend()
{ {
@ -198,10 +289,18 @@ void Core::Resume()
SDL_mutexV(AccessMutex); SDL_mutexV(AccessMutex);
} }
// should always be from simulation thread!
static bool flip2 = false;
int Core::Update() int Core::Update()
{ {
if(!started) Init();
if(errorstate) if(errorstate)
return -1; return -1;
if(!flip2)
{
std::cerr << "Update from Thread " << SDL_ThreadID() << std::endl;
flip2 = true;
}
// notify all the plugins that a game tick is finished // notify all the plugins that a game tick is finished
plug_mgr->OnUpdate(); plug_mgr->OnUpdate();
SDL_mutexV(AccessMutex); SDL_mutexV(AccessMutex);
@ -228,20 +327,58 @@ int Core::Shutdown ( void )
memset(&(s_mods), 0, sizeof(s_mods)); memset(&(s_mods), 0, sizeof(s_mods));
dfout << std::endl; dfout << std::endl;
// kill the console object // kill the console object
delete con; if(con)
delete con;
con = 0; con = 0;
return -1; return -1;
} }
void Core::SDL_Event(FakeSDL::Event* event) static bool flip3 = 0;
int Core::SDL_Event(SDL::Event* ev, int orig_return)
{ {
if(!event) // do NOT process events before we are ready.
return; if(!started) return orig_return;
if(event->type == FakeSDL::ET_KEYDOWN) if(!flip3)
{
std::cerr << "Event from Thread " << SDL_ThreadID() << std::endl;
flip3 = true;
}
if(!ev)
return orig_return;
if(ev && ev->type == SDL::ET_KEYDOWN || ev->type == SDL::ET_KEYUP)
{ {
FakeSDL::KeyboardEvent * kev = (FakeSDL::KeyboardEvent *) event; SDL::KeyboardEvent * ke = (SDL::KeyboardEvent *)ev;
cerr << "Key " << kev->ksym.sym << std::endl; bool shift = ke->ksym.mod & SDL::KMOD_SHIFT;
// consuming F1 .. F8
int idx = ke->ksym.sym - SDL::K_F1;
if(idx < 0 || idx > 7)
return orig_return;
idx += 8*shift;
// now we have the real index...
if(ke->state == SDL::BTN_PRESSED && !hotkey_states[idx])
{
hotkey_states[idx] = 1;
Gui * g = getGui();
if(g->hotkeys && g->interface && g->menu_state)
{
t_viewscreen * ws = g->GetCurrentScreen();
if(ws->getClassName() == "viewscreen_dwarfmodest" && *g->menu_state == 0x23)
return orig_return;
else
{
std::cerr << "Hotkey " << idx << " triggered. Thread " << SDL_ThreadID() << std::endl;
t_hotkey & hotkey = (*g->hotkeys)[idx];
setHotkeyCmd(hotkey.name);
}
}
}
else if(ke->state == SDL::BTN_RELEASED)
{
hotkey_states[idx] = 0;
}
} }
return orig_return;
// do stuff with the events...
} }
/******************************************************************************* /*******************************************************************************

@ -85,7 +85,7 @@ DFhackCExport int SDL_NumJoysticks(void)
//static void (*_SDL_GL_SwapBuffers)(void) = 0; //static void (*_SDL_GL_SwapBuffers)(void) = 0;
static void (*_SDL_Quit)(void) = 0; static void (*_SDL_Quit)(void) = 0;
static int (*_SDL_Init)(uint32_t flags) = 0; static int (*_SDL_Init)(uint32_t flags) = 0;
static DFThread * (*_SDL_CreateThread)(int (*fn)(void *), void *data) = 0; static SDL::Thread * (*_SDL_CreateThread)(int (*fn)(void *), void *data) = 0;
//static int (*_SDL_Flip)(void * some_ptr) = 0; //static int (*_SDL_Flip)(void * some_ptr) = 0;
/* /*
// hook - called every tick in OpenGL mode of DF // hook - called every tick in OpenGL mode of DF
@ -119,26 +119,26 @@ DFhackCExport int SDL_Flip(void * some_ptr)
} }
*/ */
static DFMutex * (*_SDL_CreateMutex)(void) = 0; static SDL::Mutex * (*_SDL_CreateMutex)(void) = 0;
DFhackCExport DFMutex * SDL_CreateMutex(void) DFhackCExport SDL::Mutex * SDL_CreateMutex(void)
{ {
return _SDL_CreateMutex(); return _SDL_CreateMutex();
} }
static int (*_SDL_mutexP)(DFMutex * mutex) = 0; static int (*_SDL_mutexP)(SDL::Mutex * mutex) = 0;
DFhackCExport int SDL_mutexP(DFMutex * mutex) DFhackCExport int SDL_mutexP(SDL::Mutex * mutex)
{ {
return _SDL_mutexP(mutex); return _SDL_mutexP(mutex);
} }
static int (*_SDL_mutexV)(DFMutex * mutex) = 0; static int (*_SDL_mutexV)(SDL::Mutex * mutex) = 0;
DFhackCExport int SDL_mutexV(DFMutex * mutex) DFhackCExport int SDL_mutexV(SDL::Mutex * mutex)
{ {
return _SDL_mutexV(mutex); return _SDL_mutexV(mutex);
} }
static void (*_SDL_DestroyMutex)(DFMutex * mutex) = 0; static void (*_SDL_DestroyMutex)(SDL::Mutex * mutex) = 0;
DFhackCExport void SDL_DestroyMutex(DFMutex * mutex) DFhackCExport void SDL_DestroyMutex(SDL::Mutex * mutex)
{ {
_SDL_DestroyMutex(mutex); _SDL_DestroyMutex(mutex);
} }
@ -155,41 +155,77 @@ DFhackCExport void SDL_Quit(void)
} }
// called by DF to check input events // called by DF to check input events
static int (*_SDL_PollEvent)(FakeSDL::Event* event) = 0; static int (*_SDL_PollEvent)(SDL::Event* event) = 0;
DFhackCExport int SDL_PollEvent(FakeSDL::Event* event) DFhackCExport int SDL_PollEvent(SDL::Event* event)
{ {
int ret = _SDL_PollEvent(event); int orig_return = _SDL_PollEvent(event);
// only send events to Core after we get first SDL_NumJoysticks call // only send events to Core after we get first SDL_NumJoysticks call
// DF event loop is possibly polling for SDL events before things get inited properly // DF event loop is possibly polling for SDL events before things get inited properly
// SDL handles it. We don't, because we use some other parts of SDL too. // SDL handles it. We don't, because we use some other parts of SDL too.
if(inited && event != 0) if(inited && event != 0)
{ {
DFHack::Core & c = DFHack::Core::getInstance(); DFHack::Core & c = DFHack::Core::getInstance();
c.SDL_Event(event); return c.SDL_Event(event, orig_return);
} }
return ret; return orig_return;
}
static uint32_t (*_SDL_ThreadID)(void) = 0;
DFhackCExport uint32_t SDL_ThreadID()
{
return _SDL_ThreadID();
} }
static SDL::Cond * (*_SDL_CreateCond)(void) = 0;
DFhackCExport SDL::Cond *SDL_CreateCond(void)
{
return _SDL_CreateCond();
}
static void (*_SDL_DestroyCond)(SDL::Cond *) = 0;
DFhackCExport void SDL_DestroyCond(SDL::Cond *cond)
{
_SDL_DestroyCond(cond);
}
static int (*_SDL_CondSignal)(SDL::Cond *) = 0;
DFhackCExport int SDL_CondSignal(SDL::Cond *cond)
{
return _SDL_CondSignal(cond);
}
static int (*_SDL_CondWait)(SDL::Cond *, SDL::Mutex *) = 0;
DFhackCExport int SDL_CondWait(SDL::Cond *cond, SDL::Mutex * mut)
{
return _SDL_CondWait(cond, mut);
}
// hook - called at program start, initialize some stuffs we'll use later // hook - called at program start, initialize some stuffs we'll use later
DFhackCExport int SDL_Init(uint32_t flags) DFhackCExport int SDL_Init(uint32_t flags)
{ {
freopen("stdout.log", "w", stdout); freopen("stdout.log", "w", stdout);
freopen("stderr.log", "w", stderr); freopen("stderr.log", "w", stderr);
// horrible casts not supported by the C or C++ standards. Only POSIX. Damn you, POSIX.
// find real functions // find real functions
//_SDL_GL_SwapBuffers = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_GL_SwapBuffers"); //_SDL_GL_SwapBuffers = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_GL_SwapBuffers");
_SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init"); _SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init");
//_SDL_Flip = (int (*)( void * )) dlsym(RTLD_NEXT, "SDL_Flip"); //_SDL_Flip = (int (*)( void * )) dlsym(RTLD_NEXT, "SDL_Flip");
_SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit"); _SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit");
_SDL_CreateThread = (DFThread* (*)(int (*fn)(void *), void *data))dlsym(RTLD_NEXT, "SDL_CreateThread"); _SDL_CreateThread = (SDL::Thread* (*)(int (*fn)(void *), void *data))dlsym(RTLD_NEXT, "SDL_CreateThread");
_SDL_CreateMutex = (DFMutex*(*)())dlsym(RTLD_NEXT,"SDL_CreateMutex"); _SDL_CreateMutex = (SDL::Mutex*(*)())dlsym(RTLD_NEXT,"SDL_CreateMutex");
_SDL_DestroyMutex = (void (*)(DFMutex*))dlsym(RTLD_NEXT,"SDL_DestroyMutex"); _SDL_DestroyMutex = (void (*)(SDL::Mutex*))dlsym(RTLD_NEXT,"SDL_DestroyMutex");
_SDL_mutexP = (int (*)(DFMutex*))dlsym(RTLD_NEXT,"SDL_mutexP"); _SDL_mutexP = (int (*)(SDL::Mutex*))dlsym(RTLD_NEXT,"SDL_mutexP");
_SDL_mutexV = (int (*)(DFMutex*))dlsym(RTLD_NEXT,"SDL_mutexV"); _SDL_mutexV = (int (*)(SDL::Mutex*))dlsym(RTLD_NEXT,"SDL_mutexV");
_SDL_PollEvent = (int (*)(FakeSDL::Event*))dlsym(RTLD_NEXT,"SDL_PollEvent"); _SDL_PollEvent = (int (*)(SDL::Event*))dlsym(RTLD_NEXT,"SDL_PollEvent");
_SDL_ThreadID = (uint32_t (*)())dlsym(RTLD_NEXT,"SDL_ThreadID");
_SDL_CreateCond = (SDL::Cond * (*)())dlsym(RTLD_NEXT,"SDL_CreateCond");
_SDL_DestroyCond = (void(*)(SDL::Cond *))dlsym(RTLD_NEXT,"SDL_DestroyCond");
_SDL_CondSignal = (int (*)(SDL::Cond *))dlsym(RTLD_NEXT,"SDL_CondSignal");
_SDL_CondWait = (int (*)(SDL::Cond *, SDL::Mutex *))dlsym(RTLD_NEXT,"SDL_CondWait");
// check if we got them // check if we got them
if(_SDL_Init && _SDL_Quit && _SDL_CreateThread && _SDL_CreateMutex && _SDL_DestroyMutex && _SDL_mutexP && _SDL_mutexV) if(_SDL_Init && _SDL_Quit && _SDL_CreateThread
&& _SDL_CreateMutex && _SDL_DestroyMutex && _SDL_mutexP
&& _SDL_mutexV && _SDL_PollEvent && _SDL_ThreadID
&& _SDL_CondSignal && _SDL_CondWait && _SDL_CreateCond && _SDL_DestroyCond)
{ {
fprintf(stderr,"dfhack: hooking successful\n"); fprintf(stderr,"dfhack: hooking successful\n");
} }

@ -170,7 +170,7 @@ PluginManager::~PluginManager()
all_plugins.clear(); all_plugins.clear();
} }
Plugin *PluginManager::getPluginByName (const std::string & name) const Plugin *PluginManager::getPluginByName (const std::string & name)
{ {
for(int i = 0; i < all_plugins.size(); i++) for(int i = 0; i < all_plugins.size(); i++)
{ {

@ -53,6 +53,9 @@ namespace DFHack
class Console; class Console;
class PluginManager; class PluginManager;
class Core; class Core;
class Hotkey;
// anon type, pretty much
struct DFLibrary;
DFLibrary * OpenPlugin (const char * filename); DFLibrary * OpenPlugin (const char * filename);
void * LookupPlugin (DFLibrary * plugin ,const char * function); void * LookupPlugin (DFLibrary * plugin ,const char * function);
@ -65,7 +68,7 @@ namespace DFHack
{ {
friend int ::SDL_NumJoysticks(void); friend int ::SDL_NumJoysticks(void);
friend void ::SDL_Quit(void); friend void ::SDL_Quit(void);
friend int ::SDL_PollEvent(FakeSDL::Event *); friend int ::SDL_PollEvent(SDL::Event *);
public: public:
/// Get the single Core instance or make one. /// Get the single Core instance or make one.
static Core& getInstance() static Core& getInstance()
@ -103,20 +106,25 @@ namespace DFHack
Buildings * getBuildings(); Buildings * getBuildings();
/// get the constructions module /// get the constructions module
Constructions * getConstructions(); Constructions * getConstructions();
/// sets the current hotkey command
bool setHotkeyCmd( std::string cmd );
/// removes the hotkey command and gives it to the caller thread
std::string getHotkeyCmd( void );
DFHack::Process * p; DFHack::Process * p;
DFHack::VersionInfo * vinfo; DFHack::VersionInfo * vinfo;
DFHack::Console * con; DFHack::Console * con;
private: private:
Core(); Core();
bool Init();
int Update (void); int Update (void);
int Shutdown (void); int Shutdown (void);
void SDL_Event(FakeSDL::Event* event); int SDL_Event(SDL::Event* event, int orig_return);
Core(Core const&); // Don't Implement Core(Core const&); // Don't Implement
void operator=(Core const&); // Don't implement void operator=(Core const&); // Don't implement
bool errorstate; bool errorstate;
// mutex for access to DF // mutex for access to DF
DFMutex * AccessMutex; SDL::Mutex * AccessMutex;
// FIXME: shouldn't be kept around like this // FIXME: shouldn't be kept around like this
DFHack::VersionInfoFactory * vif; DFHack::VersionInfoFactory * vif;
// Module storage // Module storage
@ -136,5 +144,13 @@ namespace DFHack
} s_mods; } s_mods;
std::vector <Module *> allModules; std::vector <Module *> allModules;
DFHack::PluginManager * plug_mgr; DFHack::PluginManager * plug_mgr;
// hotkey-related stuff
int hotkey_states[16];
std::string hotkey_cmd;
bool hotkey_set;
SDL::Mutex * HotkeyMutex;
SDL::Cond * HotkeyCond;
// Very important!
bool started;
}; };
} }

@ -32,29 +32,37 @@ distribution.
#include "dfhack/Export.h" #include "dfhack/Export.h"
#include <string> #include <string>
#include <stdint.h> #include <stdint.h>
#include "dfhack/SDL_fakes/events.h"
#include "dfhack/SDL_fakes/keyboard.h"
#include "dfhack/SDL_fakes/keysym.h"
// function and variable pointer... we don't try to understand what SDL does here // function and variable pointer... we don't try to understand what SDL does here
typedef void * fPtr; typedef void * fPtr;
typedef void * vPtr; typedef void * vPtr;
struct DFMutex; namespace SDL
struct DFThread; {
struct DFLibrary; union Event;
struct Thread;
struct Mutex;
struct Cond;
}
// mutex and thread functions. We can call these. // mutex stuff
DFhackCExport DFMutex * SDL_CreateMutex(void); DFhackCExport SDL::Mutex * SDL_CreateMutex(void);
DFhackCExport int SDL_mutexP(DFMutex *); DFhackCExport int SDL_mutexP(SDL::Mutex *);
DFhackCExport int SDL_mutexV(DFMutex *); DFhackCExport int SDL_mutexV(SDL::Mutex *);
DFhackCExport void SDL_DestroyMutex(DFMutex *); DFhackCExport void SDL_DestroyMutex(SDL::Mutex *);
DFhackCExport DFThread *SDL_CreateThread(int (*fn)(void *), void *data); // thread stuff
DFhackCExport SDL::Thread *SDL_CreateThread(int (*fn)(void *), void *data);
DFhackCExport uint32_t SDL_ThreadID();
// condition variables
DFhackCExport SDL::Cond *SDL_CreateCond(void);
DFhackCExport void SDL_DestroyCond(SDL::Cond *cond);
DFhackCExport int SDL_CondSignal(SDL::Cond *cond);
DFhackCExport int SDL_CondWait(SDL::Cond *cond, SDL::Mutex * mut);
// these functions are here because they call into DFHack::Core and therefore need to // these functions are here because they call into DFHack::Core and therefore need to
// be declared as friend functions/known // be declared as friend functions/known
DFhackCExport int SDL_NumJoysticks(void); DFhackCExport int SDL_NumJoysticks(void);
DFhackCExport void SDL_Quit(void); DFhackCExport void SDL_Quit(void);
DFhackCExport int SDL_PollEvent(FakeSDL::Event* event); DFhackCExport int SDL_PollEvent(SDL::Event* event);
/* /*
// not yet. // not yet.
DFhackCExport int SDL_Init(uint32_t flags); DFhackCExport int SDL_Init(uint32_t flags);

@ -92,13 +92,15 @@ namespace DFHack
}; };
class DFHACK_EXPORT PluginManager class DFHACK_EXPORT PluginManager
{ {
public: // PRIVATE METHODS
friend class Core;
PluginManager(Core * core); PluginManager(Core * core);
~PluginManager(); ~PluginManager();
Plugin *getPluginByName (const std::string & name);
command_result InvokeCommand( std::string & command, std::vector <std::string> & parameters);
void OnUpdate( void ); void OnUpdate( void );
//FIXME: how do we deal with errors inside DF? Unhandled exceptions are deadly. // PUBLIC METHODS
public:
const Plugin *getPluginByName (const std::string & name);
command_result InvokeCommand( std::string & command, std::vector <std::string> & parameters );
const Plugin* operator[] (std::size_t index) const Plugin* operator[] (std::size_t index)
{ {
if(index >= all_plugins.size()) if(index >= all_plugins.size())
@ -109,6 +111,7 @@ namespace DFHack
{ {
return all_plugins.size(); return all_plugins.size();
} }
// DATA
private: private:
std::map <std::string, const PluginCommand *> commands; std::map <std::string, const PluginCommand *> commands;
std::vector <Plugin *> all_plugins; std::vector <Plugin *> all_plugins;

@ -20,10 +20,13 @@
slouken@libsdl.org slouken@libsdl.org
*/ */
// Fake - only structs. Shamelessly pilfered from the SDL library.
// Needed for processing its event types without polluting our namespaces with C garbage
#pragma once #pragma once
#include "keyboard.h" #include "keyboard.h"
namespace FakeSDL namespace SDL
{ {
enum ButtonState enum ButtonState
{ {

@ -27,7 +27,7 @@
#include "keysym.h" #include "keysym.h"
#include <stdint.h> #include <stdint.h>
namespace FakeSDL namespace SDL
{ {
/** Keysym structure /** Keysym structure
* *

@ -20,9 +20,12 @@
slouken@libsdl.org slouken@libsdl.org
*/ */
// Fake - only structs. Shamelessly pilfered from the SDL library.
// Needed for processing its event types without polluting our namespaces with C garbage
#pragma once #pragma once
namespace FakeSDL namespace SDL
{ {
/** What we really want is a mapping of every raw key on the keyboard. /** What we really want is a mapping of every raw key on the keyboard.
* To support international keyboards, we use the range 0xA1 - 0xFF * To support international keyboards, we use the range 0xA1 - 0xFF

@ -0,0 +1,35 @@
/*
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>
namespace DFHack
{
/// very generic representation of a virtual class... just the pointer to the vtable.
struct t_virtual
{
void * vptr;
std::string getClassName();
};
}

@ -28,6 +28,8 @@ distribution.
#include "dfhack/Export.h" #include "dfhack/Export.h"
#include "dfhack/Module.h" #include "dfhack/Module.h"
#include "dfhack/Virtual.h"
#include <string>
/** /**
* \defgroup grp_gui query DF's GUI state * \defgroup grp_gui query DF's GUI state
@ -40,13 +42,27 @@ namespace DFHack
/** /**
* \ingroup grp_gui * \ingroup grp_gui
*/ */
struct t_viewscreen struct t_viewscreen : public t_virtual
{ {
int32_t type; t_viewscreen * child;
//There is more info in these objects, but I don't know what it is yet t_viewscreen * parent;
char unk1; // varies
char unk2; // state?
}; };
/**
* \ingroup grp_gui
*/
struct t_interface
{
int fps;
t_viewscreen view;
unsigned int flags; // ?
// more crud this way ...
};
#define NUM_HOTKEYS 16 #define NUM_HOTKEYS 16
/** /**
* The hotkey structure
* \ingroup grp_gui * \ingroup grp_gui
*/ */
struct t_hotkey struct t_hotkey
@ -57,8 +73,10 @@ namespace DFHack
int32_t y; int32_t y;
int32_t z; int32_t z;
}; };
typedef t_hotkey hotkey_array[16]; typedef t_hotkey hotkey_array[NUM_HOTKEYS];
/** /**
* One tile of the screen. Possibly outdated.
* \ingroup grp_gui * \ingroup grp_gui
*/ */
struct t_screen struct t_screen
@ -70,6 +88,7 @@ namespace DFHack
uint8_t gtile; uint8_t gtile;
uint8_t grayscale; uint8_t grayscale;
}; };
/** /**
* The Gui module * The Gui module
* \ingroup grp_modules * \ingroup grp_modules
@ -91,6 +110,16 @@ namespace DFHack
bool getCursorCoords (int32_t &x, int32_t &y, int32_t &z); bool getCursorCoords (int32_t &x, int32_t &y, int32_t &z);
bool setCursorCoords (const int32_t x, const int32_t y, const int32_t z); bool setCursorCoords (const int32_t x, const int32_t y, const int32_t z);
/*
* Gui screens
*/
/// handle to the interface object
t_interface * interface;
/// Get the current top-level view-screen
t_viewscreen * GetCurrentScreen();
/// The DF menu state (designation menu ect)
uint32_t * menu_state;
/* /*
* Hotkeys (DF's zoom locations) * Hotkeys (DF's zoom locations)
*/ */
@ -106,11 +135,6 @@ namespace DFHack
*/ */
bool getScreenTiles(int32_t width, int32_t height, t_screen screen[]); bool getScreenTiles(int32_t width, int32_t height, t_screen screen[]);
/// read the DF menu view state (stock screen, unit screen, other screens
bool ReadViewScreen(t_viewscreen &);
/// read the DF menu state (designation menu ect)
uint32_t ReadMenuState();
private: private:
struct Private; struct Private;
Private *d; Private *d;

@ -34,6 +34,7 @@ distribution.
#include "dfhack/Module.h" #include "dfhack/Module.h"
#include "dfhack/modules/Vegetation.h" #include "dfhack/modules/Vegetation.h"
#include <vector> #include <vector>
#include "dfhack/Virtual.h"
/** /**
* \defgroup grp_maps Maps module and its types * \defgroup grp_maps Maps module and its types
@ -145,10 +146,6 @@ namespace DFHack
uint32_t origin; uint32_t origin;
}; };
struct t_virtual
{
void * vptr;
};
/** /**
* mineral vein object - bitmap with a material type * mineral vein object - bitmap with a material type
* \ingroup grp_maps * \ingroup grp_maps

@ -48,14 +48,9 @@ struct Gui::Private
{ {
Private() Private()
{ {
Started = ViewScreeInited = MenuStateInited = false; Started = false;
StartedScreen = false; StartedScreen = false;
} }
bool ViewScreeInited;
uint32_t view_screen_offset;
bool MenuStateInited;
uint32_t current_menu_state_offset;
bool Started; bool Started;
uint32_t window_x_offset; uint32_t window_x_offset;
@ -77,6 +72,8 @@ Gui::Gui()
d->owner = c.p; d->owner = c.p;
VersionInfo * mem = c.vinfo; VersionInfo * mem = c.vinfo;
OffsetGroup * OG_Gui = mem->getGroup("GUI"); OffsetGroup * OG_Gui = mem->getGroup("GUI");
// Setting up hotkeys
try try
{ {
hotkeys = (hotkey_array *) OG_Gui->getAddress("hotkeys"); hotkeys = (hotkey_array *) OG_Gui->getAddress("hotkeys");
@ -85,18 +82,27 @@ Gui::Gui()
{ {
hotkeys = 0; hotkeys = 0;
}; };
// Setting up menu state
try try
{ {
d->current_menu_state_offset = OG_Gui->getAddress("current_menu_state"); menu_state = (uint32_t *) OG_Gui->getAddress("current_menu_state");
d->MenuStateInited = true;
} }
catch(exception &){}; catch(Error::All &)
{
menu_state = 0;
};
// Setting up the view screen stuff
try try
{ {
d->view_screen_offset = OG_Gui->getAddress ("view_screen"); interface = (t_interface *) OG_Gui->getAddress ("interface");
d->ViewScreeInited = true;
} }
catch(exception &){}; catch(exception &)
{
interface = 0;
};
OffsetGroup * OG_Position; OffsetGroup * OG_Position;
try try
{ {
@ -132,30 +138,19 @@ bool Gui::Finish()
return true; return true;
} }
uint32_t Gui::ReadMenuState() t_viewscreen * Gui::GetCurrentScreen()
{
if(d->MenuStateInited)
return(d->owner->readDWord(d->current_menu_state_offset));
return false;
}
// FIXME: variable screenAddr set but not used [-Wunused-but-set-variable]
bool Gui::ReadViewScreen (t_viewscreen &screen)
{ {
if (!d->ViewScreeInited) return false; if(!interface)
Process * p = d->owner; return 0;
t_viewscreen * ws = &interface->view;
uint32_t last = p->readDWord (d->view_screen_offset); while(ws)
uint32_t screenAddr = p->readDWord (last);
uint32_t nextScreenPtr = p->readDWord (last + 4);
while (nextScreenPtr != 0)
{ {
last = nextScreenPtr; if(ws->child)
screenAddr = p->readDWord (nextScreenPtr); ws = ws->child;
nextScreenPtr = p->readDWord (nextScreenPtr + 4); else
return ws;
} }
Core & c = Core::getInstance(); return 0;
return c.vinfo->resolveObjectToClassID (last, screen.type);
} }
bool Gui::getViewCoords (int32_t &x, int32_t &y, int32_t &z) bool Gui::getViewCoords (int32_t &x, int32_t &y, int32_t &z)

@ -97,7 +97,7 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
DFhackCExport command_result reveal(DFHack::Core * c, std::vector<std::string> & params) DFhackCExport command_result reveal(DFHack::Core * c, std::vector<std::string> & params)
{ {
bool no_hell = false; bool no_hell = false;
if(params[0] == "safe") if(params.size() && params[0] == "safe")
{ {
no_hell = true; no_hell = true;
} }
@ -177,7 +177,7 @@ DFhackCExport command_result reveal(DFHack::Core * c, std::vector<std::string> &
c->Resume(); c->Resume();
dfout << "Map revealed." << std::endl; dfout << "Map revealed." << std::endl;
if(!no_hell) if(!no_hell)
dfout << "Unpausing can unleash the forces of hell, so it has been temporarily disabled!" << std::endl; dfout << "Unpausing can unleash the forces of hell, so it has been temporarily disabled." << std::endl;
dfout << "Run 'unreveal' to revert to previous state." << std::endl; dfout << "Run 'unreveal' to revert to previous state." << std::endl;
return CR_OK; return CR_OK;
} }