diff --git a/Memory.xml b/Memory.xml index 1639ff148..f3dff230b 100644 --- a/Memory.xml +++ b/Memory.xml @@ -803,8 +803,8 @@
+
-
@@ -1127,8 +1127,6 @@
-
-
@@ -1307,7 +1305,6 @@ constructions 0xffffffff creatures 0x0166eccc current_cursor_creature 0x00ae82cc - current_menu_state 0x017f6f38 cursor_xyz 0x0166ecd4 effects_vector 0x017f6da0 hotkey_start 0x01476ecc @@ -1323,7 +1320,6 @@ settlement_current 0xffffffff settlements 0x016af4a4 translation_vector 0x016b0010 - view_screen 0xffffffff window_dims 0x017f5abc window_x 0x00e32798 window_y 0x00e60838 @@ -3019,6 +3015,8 @@ WORLD: 0x93f77a0
+
+
Maybe, possibly. diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 3a5b4a4b7..eb6136312 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -20,6 +20,7 @@ SET(PROJECT_HDRS include/DFHack.h include/dfhack/Error.h include/dfhack/Export.h +include/dfhack/Virtual.h include/dfhack/MiscUtils.h include/dfhack/Module.h include/dfhack/Pragma.h @@ -53,6 +54,7 @@ PluginManager.cpp VersionInfo.cpp VersionInfoFactory.cpp TileTypes.cpp +Virtual.cpp depends/md5/md5.cpp depends/md5/md5wrapper.cpp diff --git a/library/Core.cpp b/library/Core.cpp index b67c207c2..761122939 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -38,14 +38,14 @@ using namespace std; #include "dfhack/Process.h" #include "dfhack/Core.h" #include "dfhack/Console.h" +#include "dfhack/Module.h" #include "dfhack/VersionInfoFactory.h" #include "dfhack/PluginManager.h" #include "ModuleFactory.h" - #include "dfhack/modules/Gui.h" -#include "dfhack/modules/Vegetation.h" -#include "dfhack/modules/Maps.h" -#include "dfhack/modules/World.h" + +#include "dfhack/SDL_fakes/events.h" + #include #include using namespace DFHack; @@ -63,11 +63,41 @@ struct IODATA 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 crap; + plug_mgr->InvokeCommand(stuff, crap); + } + } +} + +// A thread function... for the interactive console. +static bool flip0 = false; int fIOthread(void * iodata) { + if(!flip0) + { + std::cerr << "Console from Thread " << SDL_ThreadID() << std::endl; + flip0 = true; + } Core * core = ((IODATA*) iodata)->core; 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; return 0; @@ -140,8 +170,34 @@ int fIOthread(void * iodata) Core::Core() { // init the console. This must be always the first step! - con = new Console(); + con = 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... vif = new DFHack::VersionInfoFactory("Memory.xml"); p = new DFHack::Process(vif); @@ -151,36 +207,71 @@ Core::Core() errorstate = true; delete p; p = NULL; - return; + return false; } vinfo = p->getDescriptor(); - // init module storage - allModules.clear(); - memset(&(s_mods), 0, sizeof(s_mods)); - // create mutex for syncing with interactive tasks AccessMutex = SDL_CreateMutex(); if(!AccessMutex) { dfout << "Mutex creation failed." << std::endl; errorstate = true; - return; + return false; } - // all OK - errorstate = false; // lock mutex SDL_mutexP(AccessMutex); + + // create plugin manager 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, // create IO thread IODATA *temp = new IODATA; temp->core = this; temp->plug_mgr = plug_mgr; - DFThread * IO = SDL_CreateThread(fIOthread, (void *) temp); - delete temp; - // and let DF do its thing. -}; + SDL::Thread * IO = SDL_CreateThread(fIOthread, (void *) temp); + // set up hotkey capture + 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() { @@ -198,10 +289,18 @@ void Core::Resume() SDL_mutexV(AccessMutex); } +// should always be from simulation thread! +static bool flip2 = false; int Core::Update() { + if(!started) Init(); if(errorstate) 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 plug_mgr->OnUpdate(); SDL_mutexV(AccessMutex); @@ -228,20 +327,58 @@ int Core::Shutdown ( void ) memset(&(s_mods), 0, sizeof(s_mods)); dfout << std::endl; // kill the console object - delete con; + if(con) + delete con; con = 0; 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) - return; - if(event->type == FakeSDL::ET_KEYDOWN) + // do NOT process events before we are ready. + if(!started) return orig_return; + 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; - cerr << "Key " << kev->ksym.sym << std::endl; + SDL::KeyboardEvent * ke = (SDL::KeyboardEvent *)ev; + 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... } /******************************************************************************* diff --git a/library/FakeSDL-linux.cpp b/library/FakeSDL-linux.cpp index cef9557c3..484970dc0 100644 --- a/library/FakeSDL-linux.cpp +++ b/library/FakeSDL-linux.cpp @@ -85,7 +85,7 @@ DFhackCExport int SDL_NumJoysticks(void) //static void (*_SDL_GL_SwapBuffers)(void) = 0; static void (*_SDL_Quit)(void) = 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; /* // 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; -DFhackCExport DFMutex * SDL_CreateMutex(void) +static SDL::Mutex * (*_SDL_CreateMutex)(void) = 0; +DFhackCExport SDL::Mutex * SDL_CreateMutex(void) { return _SDL_CreateMutex(); } -static int (*_SDL_mutexP)(DFMutex * mutex) = 0; -DFhackCExport int SDL_mutexP(DFMutex * mutex) +static int (*_SDL_mutexP)(SDL::Mutex * mutex) = 0; +DFhackCExport int SDL_mutexP(SDL::Mutex * mutex) { return _SDL_mutexP(mutex); } -static int (*_SDL_mutexV)(DFMutex * mutex) = 0; -DFhackCExport int SDL_mutexV(DFMutex * mutex) +static int (*_SDL_mutexV)(SDL::Mutex * mutex) = 0; +DFhackCExport int SDL_mutexV(SDL::Mutex * mutex) { return _SDL_mutexV(mutex); } -static void (*_SDL_DestroyMutex)(DFMutex * mutex) = 0; -DFhackCExport void SDL_DestroyMutex(DFMutex * mutex) +static void (*_SDL_DestroyMutex)(SDL::Mutex * mutex) = 0; +DFhackCExport void SDL_DestroyMutex(SDL::Mutex * mutex) { _SDL_DestroyMutex(mutex); } @@ -155,41 +155,77 @@ DFhackCExport void SDL_Quit(void) } // called by DF to check input events -static int (*_SDL_PollEvent)(FakeSDL::Event* event) = 0; -DFhackCExport int SDL_PollEvent(FakeSDL::Event* event) +static int (*_SDL_PollEvent)(SDL::Event* event) = 0; +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 // 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. if(inited && event != 0) { 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 DFhackCExport int SDL_Init(uint32_t flags) { freopen("stdout.log", "w", stdout); freopen("stderr.log", "w", stderr); + // horrible casts not supported by the C or C++ standards. Only POSIX. Damn you, POSIX. // find real functions //_SDL_GL_SwapBuffers = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_GL_SwapBuffers"); _SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init"); //_SDL_Flip = (int (*)( void * )) dlsym(RTLD_NEXT, "SDL_Flip"); _SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit"); - _SDL_CreateThread = (DFThread* (*)(int (*fn)(void *), void *data))dlsym(RTLD_NEXT, "SDL_CreateThread"); - _SDL_CreateMutex = (DFMutex*(*)())dlsym(RTLD_NEXT,"SDL_CreateMutex"); - _SDL_DestroyMutex = (void (*)(DFMutex*))dlsym(RTLD_NEXT,"SDL_DestroyMutex"); - _SDL_mutexP = (int (*)(DFMutex*))dlsym(RTLD_NEXT,"SDL_mutexP"); - _SDL_mutexV = (int (*)(DFMutex*))dlsym(RTLD_NEXT,"SDL_mutexV"); - _SDL_PollEvent = (int (*)(FakeSDL::Event*))dlsym(RTLD_NEXT,"SDL_PollEvent"); + _SDL_CreateThread = (SDL::Thread* (*)(int (*fn)(void *), void *data))dlsym(RTLD_NEXT, "SDL_CreateThread"); + _SDL_CreateMutex = (SDL::Mutex*(*)())dlsym(RTLD_NEXT,"SDL_CreateMutex"); + _SDL_DestroyMutex = (void (*)(SDL::Mutex*))dlsym(RTLD_NEXT,"SDL_DestroyMutex"); + _SDL_mutexP = (int (*)(SDL::Mutex*))dlsym(RTLD_NEXT,"SDL_mutexP"); + _SDL_mutexV = (int (*)(SDL::Mutex*))dlsym(RTLD_NEXT,"SDL_mutexV"); + _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 - 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"); } diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp index 85d48a564..be57ca1bd 100644 --- a/library/PluginManager.cpp +++ b/library/PluginManager.cpp @@ -170,7 +170,7 @@ PluginManager::~PluginManager() 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++) { diff --git a/library/include/dfhack/Core.h b/library/include/dfhack/Core.h index cdc192193..7cab16960 100644 --- a/library/include/dfhack/Core.h +++ b/library/include/dfhack/Core.h @@ -53,6 +53,9 @@ namespace DFHack class Console; class PluginManager; class Core; + class Hotkey; + // anon type, pretty much + struct DFLibrary; DFLibrary * OpenPlugin (const char * filename); void * LookupPlugin (DFLibrary * plugin ,const char * function); @@ -65,7 +68,7 @@ namespace DFHack { friend int ::SDL_NumJoysticks(void); friend void ::SDL_Quit(void); - friend int ::SDL_PollEvent(FakeSDL::Event *); + friend int ::SDL_PollEvent(SDL::Event *); public: /// Get the single Core instance or make one. static Core& getInstance() @@ -103,20 +106,25 @@ namespace DFHack Buildings * getBuildings(); /// get the constructions module 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::VersionInfo * vinfo; DFHack::Console * con; private: Core(); + bool Init(); int Update (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 void operator=(Core const&); // Don't implement bool errorstate; // mutex for access to DF - DFMutex * AccessMutex; + SDL::Mutex * AccessMutex; // FIXME: shouldn't be kept around like this DFHack::VersionInfoFactory * vif; // Module storage @@ -136,5 +144,13 @@ namespace DFHack } s_mods; std::vector allModules; 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; }; } \ No newline at end of file diff --git a/library/include/dfhack/FakeSDL.h b/library/include/dfhack/FakeSDL.h index 5ca3662d4..029ee4484 100644 --- a/library/include/dfhack/FakeSDL.h +++ b/library/include/dfhack/FakeSDL.h @@ -32,29 +32,37 @@ distribution. #include "dfhack/Export.h" #include #include -#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 typedef void * fPtr; typedef void * vPtr; -struct DFMutex; -struct DFThread; -struct DFLibrary; +namespace SDL +{ + union Event; + struct Thread; + struct Mutex; + struct Cond; +} -// mutex and thread functions. We can call these. -DFhackCExport DFMutex * SDL_CreateMutex(void); -DFhackCExport int SDL_mutexP(DFMutex *); -DFhackCExport int SDL_mutexV(DFMutex *); -DFhackCExport void SDL_DestroyMutex(DFMutex *); -DFhackCExport DFThread *SDL_CreateThread(int (*fn)(void *), void *data); +// mutex stuff +DFhackCExport SDL::Mutex * SDL_CreateMutex(void); +DFhackCExport int SDL_mutexP(SDL::Mutex *); +DFhackCExport int SDL_mutexV(SDL::Mutex *); +DFhackCExport void SDL_DestroyMutex(SDL::Mutex *); +// 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 // be declared as friend functions/known DFhackCExport int SDL_NumJoysticks(void); DFhackCExport void SDL_Quit(void); -DFhackCExport int SDL_PollEvent(FakeSDL::Event* event); +DFhackCExport int SDL_PollEvent(SDL::Event* event); /* // not yet. DFhackCExport int SDL_Init(uint32_t flags); diff --git a/library/include/dfhack/PluginManager.h b/library/include/dfhack/PluginManager.h index 398c62e2f..13ce3484a 100644 --- a/library/include/dfhack/PluginManager.h +++ b/library/include/dfhack/PluginManager.h @@ -92,13 +92,15 @@ namespace DFHack }; class DFHACK_EXPORT PluginManager { - public: + // PRIVATE METHODS + friend class Core; PluginManager(Core * core); ~PluginManager(); - Plugin *getPluginByName (const std::string & name); - command_result InvokeCommand( std::string & command, std::vector & parameters); 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 & parameters ); const Plugin* operator[] (std::size_t index) { if(index >= all_plugins.size()) @@ -109,6 +111,7 @@ namespace DFHack { return all_plugins.size(); } + // DATA private: std::map commands; std::vector all_plugins; diff --git a/library/include/dfhack/SDL_fakes/events.h b/library/include/dfhack/SDL_fakes/events.h index 33a337ed2..b8b8b1eb6 100644 --- a/library/include/dfhack/SDL_fakes/events.h +++ b/library/include/dfhack/SDL_fakes/events.h @@ -20,10 +20,13 @@ 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 #include "keyboard.h" -namespace FakeSDL +namespace SDL { enum ButtonState { diff --git a/library/include/dfhack/SDL_fakes/keyboard.h b/library/include/dfhack/SDL_fakes/keyboard.h index 42cb93763..a49cf2517 100644 --- a/library/include/dfhack/SDL_fakes/keyboard.h +++ b/library/include/dfhack/SDL_fakes/keyboard.h @@ -27,7 +27,7 @@ #include "keysym.h" #include -namespace FakeSDL +namespace SDL { /** Keysym structure * diff --git a/library/include/dfhack/SDL_fakes/keysym.h b/library/include/dfhack/SDL_fakes/keysym.h index 013a462c6..4f01cfa9c 100644 --- a/library/include/dfhack/SDL_fakes/keysym.h +++ b/library/include/dfhack/SDL_fakes/keysym.h @@ -20,9 +20,12 @@ 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 -namespace FakeSDL +namespace SDL { /** What we really want is a mapping of every raw key on the keyboard. * To support international keyboards, we use the range 0xA1 - 0xFF diff --git a/library/include/dfhack/Virtual.h b/library/include/dfhack/Virtual.h new file mode 100644 index 000000000..11d8bc78d --- /dev/null +++ b/library/include/dfhack/Virtual.h @@ -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 +namespace DFHack +{ + /// very generic representation of a virtual class... just the pointer to the vtable. + struct t_virtual + { + void * vptr; + std::string getClassName(); + }; +} \ No newline at end of file diff --git a/library/include/dfhack/modules/Gui.h b/library/include/dfhack/modules/Gui.h index 71263eef7..e11e046c0 100644 --- a/library/include/dfhack/modules/Gui.h +++ b/library/include/dfhack/modules/Gui.h @@ -28,6 +28,8 @@ distribution. #include "dfhack/Export.h" #include "dfhack/Module.h" +#include "dfhack/Virtual.h" +#include /** * \defgroup grp_gui query DF's GUI state @@ -40,13 +42,27 @@ namespace DFHack /** * \ingroup grp_gui */ - struct t_viewscreen + struct t_viewscreen : public t_virtual { - int32_t type; - //There is more info in these objects, but I don't know what it is yet + t_viewscreen * child; + 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 /** + * The hotkey structure * \ingroup grp_gui */ struct t_hotkey @@ -57,8 +73,10 @@ namespace DFHack int32_t y; 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 */ struct t_screen @@ -70,6 +88,7 @@ namespace DFHack uint8_t gtile; uint8_t grayscale; }; + /** * The Gui module * \ingroup grp_modules @@ -91,6 +110,16 @@ namespace DFHack 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); + /* + * 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) */ @@ -105,11 +134,6 @@ namespace DFHack * Screen tiles */ 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: struct Private; diff --git a/library/include/dfhack/modules/Maps.h b/library/include/dfhack/modules/Maps.h index ba4c44ad3..e88795e47 100644 --- a/library/include/dfhack/modules/Maps.h +++ b/library/include/dfhack/modules/Maps.h @@ -34,6 +34,7 @@ distribution. #include "dfhack/Module.h" #include "dfhack/modules/Vegetation.h" #include +#include "dfhack/Virtual.h" /** * \defgroup grp_maps Maps module and its types @@ -145,10 +146,6 @@ namespace DFHack uint32_t origin; }; - struct t_virtual - { - void * vptr; - }; /** * mineral vein object - bitmap with a material type * \ingroup grp_maps diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 6992b9978..1a29e5d43 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -48,14 +48,9 @@ struct Gui::Private { Private() { - Started = ViewScreeInited = MenuStateInited = false; + Started = false; StartedScreen = false; } - bool ViewScreeInited; - uint32_t view_screen_offset; - - bool MenuStateInited; - uint32_t current_menu_state_offset; bool Started; uint32_t window_x_offset; @@ -77,6 +72,8 @@ Gui::Gui() d->owner = c.p; VersionInfo * mem = c.vinfo; OffsetGroup * OG_Gui = mem->getGroup("GUI"); + + // Setting up hotkeys try { hotkeys = (hotkey_array *) OG_Gui->getAddress("hotkeys"); @@ -85,18 +82,27 @@ Gui::Gui() { hotkeys = 0; }; + + // Setting up menu state try { - d->current_menu_state_offset = OG_Gui->getAddress("current_menu_state"); - d->MenuStateInited = true; + menu_state = (uint32_t *) OG_Gui->getAddress("current_menu_state"); } - catch(exception &){}; + catch(Error::All &) + { + menu_state = 0; + }; + + // Setting up the view screen stuff try { - d->view_screen_offset = OG_Gui->getAddress ("view_screen"); - d->ViewScreeInited = true; + interface = (t_interface *) OG_Gui->getAddress ("interface"); } - catch(exception &){}; + catch(exception &) + { + interface = 0; + }; + OffsetGroup * OG_Position; try { @@ -132,30 +138,19 @@ bool Gui::Finish() return true; } -uint32_t Gui::ReadMenuState() -{ - 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) +t_viewscreen * Gui::GetCurrentScreen() { - if (!d->ViewScreeInited) return false; - Process * p = d->owner; - - uint32_t last = p->readDWord (d->view_screen_offset); - uint32_t screenAddr = p->readDWord (last); - uint32_t nextScreenPtr = p->readDWord (last + 4); - while (nextScreenPtr != 0) + if(!interface) + return 0; + t_viewscreen * ws = &interface->view; + while(ws) { - last = nextScreenPtr; - screenAddr = p->readDWord (nextScreenPtr); - nextScreenPtr = p->readDWord (nextScreenPtr + 4); + if(ws->child) + ws = ws->child; + else + return ws; } - Core & c = Core::getInstance(); - return c.vinfo->resolveObjectToClassID (last, screen.type); + return 0; } bool Gui::getViewCoords (int32_t &x, int32_t &y, int32_t &z) diff --git a/plugins/reveal.cpp b/plugins/reveal.cpp index 1f1165ac6..d3f910712 100644 --- a/plugins/reveal.cpp +++ b/plugins/reveal.cpp @@ -97,7 +97,7 @@ DFhackCExport command_result plugin_shutdown ( Core * c ) DFhackCExport command_result reveal(DFHack::Core * c, std::vector & params) { bool no_hell = false; - if(params[0] == "safe") + if(params.size() && params[0] == "safe") { no_hell = true; } @@ -177,7 +177,7 @@ DFhackCExport command_result reveal(DFHack::Core * c, std::vector & c->Resume(); dfout << "Map revealed." << std::endl; 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; return CR_OK; }