First 'working' DFHack inside DF, for 'some' values of 'working'.
parent
da2fb1cb1a
commit
81d648dfa7
@ -0,0 +1,257 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2011 Petr Mrázek (peterix)
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "core.h"
|
||||
#include "DFHack.h"
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
#include "dfhack/Context.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#define DFhackCExport extern "C" __attribute__ ((visibility("default")))
|
||||
|
||||
int errorstate = 0;
|
||||
bool inited = 0;
|
||||
DFHack::VersionInfoFactory * vif = 0;
|
||||
DFHack::Process * p = 0;
|
||||
DFHack::Context * c = 0;
|
||||
DFHack::Gui * gui = 0;
|
||||
|
||||
uint32_t OS_getPID()
|
||||
{
|
||||
return getpid();
|
||||
}
|
||||
|
||||
void SHM_Init ( void )
|
||||
{
|
||||
// check that we do this only once per process
|
||||
if(inited)
|
||||
{
|
||||
std::cerr << "SDL_Init was called twice or more!" << std::endl;
|
||||
return;
|
||||
}
|
||||
vif = new DFHack::VersionInfoFactory("Memory.xml");
|
||||
p = new DFHack::Process(vif);
|
||||
if (!p->isIdentified())
|
||||
{
|
||||
std::cerr << "Couldn't identify this version of DF." << std::endl;
|
||||
errorstate = 1;
|
||||
}
|
||||
c = new DFHack::Context(p);
|
||||
gui = c->getGui();
|
||||
gui->Start();
|
||||
inited = true;
|
||||
}
|
||||
|
||||
int32_t x = 0,y = 0,z = 0;
|
||||
int32_t xo = 0,yo = 0,zo = 0;
|
||||
|
||||
void SHM_Act()
|
||||
{
|
||||
gui->getCursorCoords(x,y,z);
|
||||
if(x != xo || y!= yo || z != zo)
|
||||
{
|
||||
xo = x;
|
||||
yo = y;
|
||||
zo = z;
|
||||
std::cout << "Cursor: " << x << "/" << y << "/" << z << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
void SHM_Destroy ( void )
|
||||
{
|
||||
if(inited && !errorstate)
|
||||
{
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SDL part starts here *
|
||||
*******************************************************************************/
|
||||
DFhackCExport int SDL_NumJoysticks(void)
|
||||
{
|
||||
if(errorstate)
|
||||
return -1;
|
||||
if(!inited)
|
||||
{
|
||||
SHM_Init();
|
||||
return -2;
|
||||
}
|
||||
SHM_Act();
|
||||
return -3;
|
||||
}
|
||||
|
||||
// ptr to the real functions
|
||||
//static void (*_SDL_GL_SwapBuffers)(void) = 0;
|
||||
static void (*_SDL_Quit)(void) = 0;
|
||||
static int (*_SDL_Init)(uint32_t flags) = 0;
|
||||
//static int (*_SDL_Flip)(void * some_ptr) = 0;
|
||||
/*
|
||||
// hook - called every tick in OpenGL mode of DF
|
||||
DFhackCExport void SDL_GL_SwapBuffers(void)
|
||||
{
|
||||
if(_SDL_GL_SwapBuffers)
|
||||
{
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Act();
|
||||
}
|
||||
counter ++;
|
||||
_SDL_GL_SwapBuffers();
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
// hook - called every tick in the 2D mode of DF
|
||||
DFhackCExport int SDL_Flip(void * some_ptr)
|
||||
{
|
||||
if(_SDL_Flip)
|
||||
{
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Act();
|
||||
}
|
||||
counter ++;
|
||||
return _SDL_Flip(some_ptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
// hook - called at program exit
|
||||
DFhackCExport void SDL_Quit(void)
|
||||
{
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Destroy();
|
||||
errorstate = true;
|
||||
}
|
||||
if(_SDL_Quit)
|
||||
{
|
||||
_SDL_Quit();
|
||||
}
|
||||
}
|
||||
|
||||
// hook - called at program start, initialize some stuffs we'll use later
|
||||
DFhackCExport int SDL_Init(uint32_t flags)
|
||||
{
|
||||
// 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");
|
||||
|
||||
// check if we got them
|
||||
if(/*_SDL_GL_SwapBuffers &&*/ _SDL_Init && _SDL_Quit)
|
||||
{
|
||||
fprintf(stderr,"dfhack: hooking successful\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// bail, this would be a disaster otherwise
|
||||
fprintf(stderr,"dfhack: something went horribly wrong\n");
|
||||
errorstate = true;
|
||||
exit(1);
|
||||
}
|
||||
//SHM_Init();
|
||||
|
||||
return _SDL_Init(flags);
|
||||
}
|
||||
//*/
|
||||
/*******************************************************************************
|
||||
* NCURSES part starts here *
|
||||
*******************************************************************************/
|
||||
|
||||
static int (*_refresh)(void) = 0;
|
||||
//extern NCURSES_EXPORT(int) refresh (void);
|
||||
DFhackCExport int refresh (void)
|
||||
{
|
||||
if(_refresh)
|
||||
{
|
||||
/*
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Act();
|
||||
}
|
||||
counter ++;
|
||||
*/
|
||||
return _refresh();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*_endwin)(void) = 0;
|
||||
//extern NCURSES_EXPORT(int) endwin (void);
|
||||
DFhackCExport int endwin (void)
|
||||
{
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Destroy();
|
||||
errorstate = true;
|
||||
}
|
||||
if(_endwin)
|
||||
{
|
||||
return _endwin();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef void WINDOW;
|
||||
//extern NCURSES_EXPORT(WINDOW *) initscr (void);
|
||||
static WINDOW * (*_initscr)(void) = 0;
|
||||
DFhackCExport WINDOW * initscr (void)
|
||||
{
|
||||
// find real functions
|
||||
//_refresh = (int (*)( void )) dlsym(RTLD_NEXT, "refresh");
|
||||
_endwin = (int (*)( void )) dlsym(RTLD_NEXT, "endwin");
|
||||
_initscr = (WINDOW * (*)( void )) dlsym(RTLD_NEXT, "initscr");
|
||||
// check if we got them
|
||||
if(_refresh && _endwin && _initscr)
|
||||
{
|
||||
fprintf(stderr,"dfhack: hooking successful\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// bail, this would be a disaster otherwise
|
||||
fprintf(stderr,"dfhack: something went horribly wrong\n");
|
||||
exit(1);
|
||||
}
|
||||
//SHM_Init();
|
||||
return _initscr();
|
||||
}
|
@ -1,246 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "Internal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
#include "dfhack/DFProcess.h"
|
||||
#include "dfhack/DFProcessEnumerator.h"
|
||||
#include "dfhack/DFError.h"
|
||||
|
||||
#include "dfhack/DFContext.h"
|
||||
#include "dfhack/DFContextManager.h"
|
||||
#include "private/ContextShared.h"
|
||||
|
||||
using namespace DFHack;
|
||||
namespace DFHack
|
||||
{
|
||||
class ContextManager::Private
|
||||
{
|
||||
public:
|
||||
Private(){};
|
||||
~Private(){};
|
||||
string xml; // path to xml
|
||||
vector <Context *> contexts;
|
||||
ProcessEnumerator * pEnum;
|
||||
};
|
||||
}
|
||||
class DFHack::BadContexts::Private
|
||||
{
|
||||
public:
|
||||
Private(){};
|
||||
vector <Context *> bad;
|
||||
};
|
||||
|
||||
|
||||
BadContexts::BadContexts():d(new Private()){}
|
||||
|
||||
BadContexts::~BadContexts()
|
||||
{
|
||||
clear();
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool BadContexts::Contains(Process* p)
|
||||
{
|
||||
for(unsigned int i = 0; i < d->bad.size(); i++)
|
||||
{
|
||||
if((d->bad[i])->getProcess() == p)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BadContexts::Contains(Context* c)
|
||||
{
|
||||
for(unsigned int i = 0; i < d->bad.size(); i++)
|
||||
{
|
||||
if(d->bad[i] == c)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t BadContexts::size()
|
||||
{
|
||||
return d->bad.size();
|
||||
}
|
||||
|
||||
void BadContexts::clear()
|
||||
{
|
||||
for(unsigned int i = 0; i < d->bad.size(); i++)
|
||||
{
|
||||
// delete both Process and Context!
|
||||
// process has to be deleted after context, because Context does some
|
||||
// cleanup on delete (detach, etc.)
|
||||
Process * to_kill = d->bad[i]->getProcess();
|
||||
delete d->bad[i];
|
||||
delete to_kill;
|
||||
}
|
||||
d->bad.clear();
|
||||
}
|
||||
|
||||
void BadContexts::push_back(Context* c)
|
||||
{
|
||||
if(c)
|
||||
d->bad.push_back(c);
|
||||
}
|
||||
|
||||
Context * BadContexts::operator[](uint32_t index)
|
||||
{
|
||||
if(index < d->bad.size())
|
||||
return d->bad[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
ContextManager::ContextManager (const string path_to_xml) : d (new Private())
|
||||
{
|
||||
d->xml = MEMXML_DATA_PATH;
|
||||
d->xml += "/";
|
||||
d->xml += path_to_xml;
|
||||
d->pEnum = new ProcessEnumerator(d->xml);
|
||||
}
|
||||
|
||||
ContextManager::~ContextManager()
|
||||
{
|
||||
purge();
|
||||
// process enumerator has to be destroyed after we detach from processes
|
||||
// because it tracks and destroys them
|
||||
if(d->pEnum)
|
||||
{
|
||||
delete d->pEnum;
|
||||
d->pEnum = 0;
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
|
||||
uint32_t ContextManager::Refresh( BadContexts* bad_contexts )
|
||||
{
|
||||
// handle expired processes, remove stale Contexts
|
||||
{
|
||||
BadProcesses expired;
|
||||
// get new list od living and expired Process objects
|
||||
d->pEnum->Refresh(&expired);
|
||||
|
||||
// scan expired, kill contexts if necessary
|
||||
vector <Context*>::iterator it = d->contexts.begin();;
|
||||
while(it != d->contexts.end())
|
||||
{
|
||||
Process * test = (*it)->getProcess();
|
||||
if(expired.Contains(test))
|
||||
{
|
||||
// ok. we have an expired context here.
|
||||
if(!bad_contexts)
|
||||
{
|
||||
// with nowhere to put the context, we have to destroy it
|
||||
delete *it;
|
||||
// stop tracking it and advance the iterator
|
||||
it = d->contexts.erase(it);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we stuff the context into bad_contexts
|
||||
bad_contexts->push_back(*it);
|
||||
// stop tracking it and advance the iterator
|
||||
it = d->contexts.erase(it);
|
||||
// remove process from the 'expired' container, it is tracked by bad_contexts now
|
||||
// (which is responsible for freeing it).
|
||||
expired.excise(test);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else it++; // not expired, just advance to next one
|
||||
}
|
||||
// no expired contexts are in the d->contexts vector now
|
||||
// all processes remaining in 'expired' are now destroyed along with it
|
||||
}
|
||||
int numProcesses = d->pEnum->size();
|
||||
int numContexts = d->contexts.size();
|
||||
vector <Context *> newContexts;
|
||||
// enumerate valid processes
|
||||
for(int i = 0; i < numProcesses; i++)
|
||||
{
|
||||
Process * test = d->pEnum->operator[](i);
|
||||
bool exists = false;
|
||||
// scan context vector for this process
|
||||
for(int j = 0; j < numContexts; j++)
|
||||
{
|
||||
if((d->contexts[j])->getProcess() == test)
|
||||
{
|
||||
// already have that one, skip
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
if(!exists)
|
||||
{
|
||||
// new process needs a new context
|
||||
Context * c = new Context(d->pEnum->operator[](i));
|
||||
newContexts.push_back(c);
|
||||
}
|
||||
}
|
||||
d->contexts.insert(d->contexts.end(), newContexts.begin(), newContexts.end());
|
||||
return d->contexts.size();
|
||||
}
|
||||
|
||||
uint32_t ContextManager::size()
|
||||
{
|
||||
return d->contexts.size();
|
||||
}
|
||||
|
||||
Context * ContextManager::operator[](uint32_t index)
|
||||
{
|
||||
if (index < d->contexts.size())
|
||||
return d->contexts[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
Context * ContextManager::getSingleContext()
|
||||
{
|
||||
if(!d->contexts.size())
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
for(unsigned int i = 0; i < d->contexts.size();i++)
|
||||
{
|
||||
if(d->contexts[i]->isValid())
|
||||
{
|
||||
return d->contexts[i];
|
||||
}
|
||||
}
|
||||
throw DFHack::Error::NoProcess();
|
||||
}
|
||||
|
||||
void ContextManager::purge(void)
|
||||
{
|
||||
for(unsigned int i = 0; i < d->contexts.size();i++)
|
||||
delete d->contexts[i];
|
||||
d->contexts.clear();
|
||||
d->pEnum->purge();
|
||||
}
|
@ -1,366 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "dfhack/DFPragma.h"
|
||||
#include "dfhack/DFExport.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/DFIntegers.h"
|
||||
#include "dfhack/DFContextManager.h"
|
||||
#include "dfhack/DFContext.h"
|
||||
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
#include "dfhack-c/DFContext_C.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHackObject* ContextManager_Alloc(const char* path_to_xml)
|
||||
{
|
||||
DFHack::ContextManager* contextMgr = new DFHack::ContextManager(std::string(path_to_xml));
|
||||
return (DFHackObject*)contextMgr;
|
||||
}
|
||||
|
||||
//FIXME: X:\dfhack\DFHackContext_C.cpp:56: warning: deleting `DFHackObject* ' is undefined
|
||||
//DC: Yeah, I forgot that trying to delete a void pointer might be a bad idea. This works now.
|
||||
void ContextManager_Free(DFHackObject* contextMgr)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
DFHack::ContextManager* a = (DFHack::ContextManager*)contextMgr;
|
||||
delete a;
|
||||
|
||||
contextMgr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int ContextManager_Refresh(DFHackObject* contextMgr)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
return ((DFHack::ContextManager*)contextMgr)->Refresh();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ContextManager_size(DFHackObject* contextMgr, uint32_t* size)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
uint32_t result = ((DFHack::ContextManager*)contextMgr)->size();
|
||||
|
||||
*size = result;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ContextManager_purge(DFHackObject* contextMgr)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
((DFHack::ContextManager*)contextMgr)->purge();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
DFHackObject* ContextManager_getContext(DFHackObject* contextMgr, uint32_t index)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
DFHack::ContextManager* mgr = ((DFHack::ContextManager*)contextMgr);
|
||||
|
||||
if(index >= mgr->size())
|
||||
return NULL;
|
||||
|
||||
return (DFHackObject*)((DFHack::Context*)((*mgr)[index]));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* ContextManager_getSingleContext(DFHackObject* contextMgr)
|
||||
{
|
||||
if(contextMgr != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::ContextManager*)contextMgr)->getSingleContext();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Context_Free(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
DFHack::Context* c = (DFHack::Context*)context;
|
||||
delete c;
|
||||
|
||||
context = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int Context_Attach(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->Attach();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_Detach(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->Detach();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_isAttached(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->isAttached();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_Suspend(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->Suspend();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_Resume(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->Resume();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_isSuspended(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->isSuspended();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_ForceResume(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->ForceResume();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Context_AsyncSuspend(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return ((DFHack::Context*)context)->AsyncSuspend();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//module getters
|
||||
|
||||
DFHackObject* Context_getMemoryInfo(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getMemoryInfo();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getProcess(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getProcess();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getCreatures(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getCreatures();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getMaps(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getMaps();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getGui(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getGui();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getMaterials(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getMaterials();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getTranslation(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getTranslation();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getVegetation(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getVegetation();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getBuildings(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getBuildings();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getConstructions(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getConstructions();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getItems(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getItems();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getWorld(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getWorld();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DFHackObject* Context_getWindowIO(DFHackObject* context)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
return (DFHackObject*)((DFHack::Context*)context)->getWindowIO();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Context_ReadRaw(DFHackObject* context, const uint32_t offset, const uint32_t size, uint8_t* target)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
((DFHack::Context*)context)->ReadRaw(offset, size, target);
|
||||
}
|
||||
}
|
||||
|
||||
void Context_WriteRaw(DFHackObject* context, const uint32_t offset, const uint32_t size, uint8_t* source)
|
||||
{
|
||||
if(context != NULL)
|
||||
{
|
||||
((DFHack::Context*)context)->WriteRaw(offset, size, source);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,488 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
#include "Internal.h"
|
||||
#include "PlatformInternal.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
using namespace std;
|
||||
|
||||
#include "SHMProcess.h"
|
||||
#include "ProcessFactory.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include "shms.h"
|
||||
#include "mod-core.h"
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
Process* DFHack::createSHMProcess(uint32_t pid, VersionInfoFactory * factory)
|
||||
{
|
||||
return new SHMProcess(pid, factory);
|
||||
}
|
||||
|
||||
SHMProcess::SHMProcess(uint32_t PID, VersionInfoFactory * factory)
|
||||
: d(new Private(this))
|
||||
{
|
||||
d->process_ID = PID;
|
||||
// attach the SHM
|
||||
if(!attach())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Test bridge version, get PID, sync Yield
|
||||
bool bridgeOK;
|
||||
if(!d->Aux_Core_Attach(bridgeOK,d->process_ID))
|
||||
{
|
||||
detach();
|
||||
throw Error::SHMAttachFailure();
|
||||
}
|
||||
else if(!bridgeOK)
|
||||
{
|
||||
detach();
|
||||
throw Error::SHMVersionMismatch();
|
||||
}
|
||||
|
||||
// try to identify the DF version (md5 the binary, compare with known versions)
|
||||
d->validate(factory);
|
||||
// at this point, DF is attached and suspended, make it run
|
||||
detach();
|
||||
}
|
||||
|
||||
SHMProcess::~SHMProcess()
|
||||
{
|
||||
if(d->attached)
|
||||
{
|
||||
detach();
|
||||
}
|
||||
// destroy data model. this is assigned by processmanager
|
||||
if(d->memdescriptor)
|
||||
delete d->memdescriptor;
|
||||
delete d;
|
||||
}
|
||||
|
||||
VersionInfo * SHMProcess::getDescriptor()
|
||||
{
|
||||
return d->memdescriptor;
|
||||
}
|
||||
|
||||
int SHMProcess::getPID()
|
||||
{
|
||||
return d->process_ID;
|
||||
}
|
||||
|
||||
|
||||
bool SHMProcess::isSuspended()
|
||||
{
|
||||
return d->locked;
|
||||
}
|
||||
bool SHMProcess::isAttached()
|
||||
{
|
||||
return d->attached;
|
||||
}
|
||||
|
||||
bool SHMProcess::isIdentified()
|
||||
{
|
||||
return d->identified;
|
||||
}
|
||||
|
||||
bool SHMProcess::suspend()
|
||||
{
|
||||
if(!d->attached)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(d->locked)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//cerr << "suspend" << endl;// FIXME: throw
|
||||
// FIXME: this should be controlled on the server side
|
||||
// FIXME: IF server got CORE_RUN in this frame, interpret CORE_SUSPEND as CORE_STEP
|
||||
// did we just resume a moment ago?
|
||||
if(D_SHMCMD == CORE_RUN)
|
||||
{
|
||||
//fprintf(stderr,"%d invokes step\n",attachmentIdx);
|
||||
// wait for the next window
|
||||
/*
|
||||
if(!d->SetAndWait(CORE_STEP))
|
||||
{
|
||||
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_STEP))");
|
||||
}
|
||||
*/
|
||||
D_SHMCMD = CORE_STEP;
|
||||
}
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"%d invokes suspend\n",attachmentIdx);
|
||||
// lock now
|
||||
/*
|
||||
if(!d->SetAndWait(CORE_SUSPEND))
|
||||
{
|
||||
throw Error::SHMLockingError("if(!d->SetAndWait(CORE_SUSPEND))");
|
||||
}
|
||||
*/
|
||||
D_SHMCMD = CORE_SUSPEND;
|
||||
}
|
||||
//fprintf(stderr,"waiting for lock\n");
|
||||
// we wait for the server to give up our suspend lock (held by default)
|
||||
if(acquireSuspendLock())
|
||||
{
|
||||
d->locked = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: needs a good think-through
|
||||
bool SHMProcess::asyncSuspend()
|
||||
{
|
||||
if(!d->attached)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(d->locked)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//cerr << "async suspend" << endl;// FIXME: throw
|
||||
uint32_t cmd = D_SHMCMD;
|
||||
if(cmd == CORE_SUSPENDED)
|
||||
{
|
||||
// we have to hold the lock to be really suspended
|
||||
if(acquireSuspendLock())
|
||||
{
|
||||
d->locked = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// did we just resume a moment ago?
|
||||
if(cmd == CORE_STEP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(cmd == CORE_RUN)
|
||||
{
|
||||
D_SHMCMD = CORE_STEP;
|
||||
}
|
||||
else
|
||||
{
|
||||
D_SHMCMD = CORE_SUSPEND;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SHMProcess::forceresume()
|
||||
{
|
||||
return resume();
|
||||
}
|
||||
|
||||
// FIXME: wait for the server to advance a step!
|
||||
bool SHMProcess::resume()
|
||||
{
|
||||
if(!d->attached)
|
||||
return false;
|
||||
if(!d->locked)
|
||||
return true;
|
||||
//cerr << "resume" << endl;// FIXME: throw
|
||||
// unlock the suspend lock
|
||||
if(releaseSuspendLock())
|
||||
{
|
||||
d->locked = false;
|
||||
if(d->SetAndWait(CORE_RUN)) // we have to make sure the server responds!
|
||||
{
|
||||
return true;
|
||||
}
|
||||
throw Error::SHMLockingError("if(d->SetAndWait(CORE_RUN))");
|
||||
}
|
||||
throw Error::SHMLockingError("if(releaseSuspendLock())");
|
||||
return false;
|
||||
}
|
||||
|
||||
// get module index by name and version. bool 0 = error
|
||||
bool SHMProcess::getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(0xdeadbeef);
|
||||
|
||||
modulelookup * payload = D_SHMDATA(modulelookup);
|
||||
payload->version = version;
|
||||
|
||||
strncpy(payload->name,name,255);
|
||||
payload->name[255] = 0;
|
||||
|
||||
if(!SetAndWait(CORE_ACQUIRE_MODULE))
|
||||
{
|
||||
return false; // FIXME: throw a fatal exception instead
|
||||
}
|
||||
if(D_SHMHDR->error)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//fprintf(stderr,"%s v%d : %d\n", name, version, D_SHMHDR->value);
|
||||
OUTPUT = D_SHMHDR->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::Aux_Core_Attach(bool & versionOK, pid_t & PID)
|
||||
{
|
||||
if(!locked) throw Error::MemoryAccessDenied(0xdeadbeef);
|
||||
|
||||
SHMDATA(coreattach)->cl_affinity = OS_getAffinity();
|
||||
if(!SetAndWait(CORE_ATTACH)) return false;
|
||||
/*
|
||||
cerr <<"CORE_VERSION" << CORE_VERSION << endl;
|
||||
cerr <<"server CORE_VERSION" << SHMDATA(coreattach)->sv_version << endl;
|
||||
*/
|
||||
versionOK =( SHMDATA(coreattach)->sv_version == CORE_VERSION );
|
||||
PID = SHMDATA(coreattach)->sv_PID;
|
||||
useYield = SHMDATA(coreattach)->sv_useYield;
|
||||
#ifdef DEBUG
|
||||
if(useYield) cerr << "Using Yield!" << endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void SHMProcess::read (uint32_t src_address, uint32_t size, uint8_t *target_buffer)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(src_address);
|
||||
|
||||
// normal read under 1MB
|
||||
if(size <= SHM_BODY)
|
||||
{
|
||||
D_SHMHDR->address = src_address;
|
||||
D_SHMHDR->length = size;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ);
|
||||
memcpy (target_buffer, D_SHMDATA(void),size);
|
||||
}
|
||||
// a big read, we pull data over the shm in iterations
|
||||
else
|
||||
{
|
||||
// first read equals the size of the SHM window
|
||||
uint32_t to_read = SHM_BODY;
|
||||
while (size)
|
||||
{
|
||||
// read to_read bytes from src_cursor
|
||||
D_SHMHDR->address = src_address;
|
||||
D_SHMHDR->length = to_read;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ);
|
||||
memcpy (target_buffer, D_SHMDATA(void) ,to_read);
|
||||
// decrease size by bytes read
|
||||
size -= to_read;
|
||||
// move the cursors
|
||||
src_address += to_read;
|
||||
target_buffer += to_read;
|
||||
// check how much to write in the next iteration
|
||||
to_read = min(size, (uint32_t) SHM_BODY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SHMProcess::readByte (const uint32_t offset, uint8_t &val )
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_BYTE);
|
||||
val = D_SHMHDR->value;
|
||||
}
|
||||
|
||||
void SHMProcess::readWord (const uint32_t offset, uint16_t &val)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_WORD);
|
||||
val = D_SHMHDR->value;
|
||||
}
|
||||
|
||||
void SHMProcess::readDWord (const uint32_t offset, uint32_t &val)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_DWORD);
|
||||
val = D_SHMHDR->value;
|
||||
}
|
||||
|
||||
void SHMProcess::readQuad (const uint32_t offset, uint64_t &val)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_QUAD);
|
||||
val = D_SHMHDR->Qvalue;
|
||||
}
|
||||
|
||||
void SHMProcess::readFloat (const uint32_t offset, float &val)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_DWORD);
|
||||
val = reinterpret_cast<float&> (D_SHMHDR->value);
|
||||
}
|
||||
|
||||
/*
|
||||
* WRITING
|
||||
*/
|
||||
|
||||
void SHMProcess::writeQuad (uint32_t offset, uint64_t data)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
D_SHMHDR->Qvalue = data;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE_QUAD);
|
||||
}
|
||||
|
||||
void SHMProcess::writeDWord (uint32_t offset, uint32_t data)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
D_SHMHDR->value = data;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE_DWORD);
|
||||
}
|
||||
|
||||
// using these is expensive.
|
||||
void SHMProcess::writeWord (uint32_t offset, uint16_t data)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
D_SHMHDR->value = data;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE_WORD);
|
||||
}
|
||||
|
||||
void SHMProcess::writeByte (uint32_t offset, uint8_t data)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
D_SHMHDR->value = data;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE_BYTE);
|
||||
}
|
||||
|
||||
void SHMProcess::write (uint32_t dst_address, uint32_t size, uint8_t *source_buffer)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(dst_address);
|
||||
|
||||
// normal write under 1MB
|
||||
if(size <= SHM_BODY)
|
||||
{
|
||||
D_SHMHDR->address = dst_address;
|
||||
D_SHMHDR->length = size;
|
||||
memcpy(D_SHMDATA(void),source_buffer, size);
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE);
|
||||
}
|
||||
// a big write, we push this over the shm in iterations
|
||||
else
|
||||
{
|
||||
// first write equals the size of the SHM window
|
||||
uint32_t to_write = SHM_BODY;
|
||||
while (size)
|
||||
{
|
||||
// write to_write bytes to dst_cursor
|
||||
D_SHMHDR->address = dst_address;
|
||||
D_SHMHDR->length = to_write;
|
||||
memcpy(D_SHMDATA(void),source_buffer, to_write);
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE);
|
||||
// decrease size by bytes written
|
||||
size -= to_write;
|
||||
// move the cursors
|
||||
source_buffer += to_write;
|
||||
dst_address += to_write;
|
||||
// check how much to write in the next iteration
|
||||
to_write = min(size, (uint32_t) SHM_BODY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string SHMProcess::readCString (uint32_t offset)
|
||||
{
|
||||
std::string temp;
|
||||
int counter = 0;
|
||||
char r;
|
||||
while (1)
|
||||
{
|
||||
r = Process::readByte(offset+counter);
|
||||
if(!r) break;
|
||||
counter++;
|
||||
temp.append(1,r);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
const std::string SHMProcess::readSTLString(uint32_t offset)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_STL_STRING);
|
||||
return(string( D_SHMDATA(char) ));
|
||||
}
|
||||
|
||||
size_t SHMProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(offset);
|
||||
|
||||
D_SHMHDR->address = offset;
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_READ_STL_STRING);
|
||||
size_t length = D_SHMHDR->value;
|
||||
size_t fit = min(bufcapacity - 1, length);
|
||||
strncpy(buffer,D_SHMDATA(char),fit);
|
||||
buffer[fit] = 0;
|
||||
return fit;
|
||||
}
|
||||
|
||||
size_t SHMProcess::writeSTLString(const uint32_t address, const std::string writeString)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(address);
|
||||
|
||||
D_SHMHDR->address = address;
|
||||
strncpy(D_SHMDATA(char),writeString.c_str(),writeString.length()+1); // length + 1 for the null terminator
|
||||
full_barrier
|
||||
d->SetAndWait(CORE_WRITE_STL_STRING);
|
||||
return writeString.length();
|
||||
}
|
@ -1,421 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
#include "Internal.h"
|
||||
#include "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdio>
|
||||
using namespace std;
|
||||
|
||||
#include "SHMProcess.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <time.h>
|
||||
#include <shms.h>
|
||||
#include <mod-core.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <sched.h>
|
||||
#include <md5wrapper.h>
|
||||
using namespace DFHack;
|
||||
|
||||
SHMProcess::Private::Private(SHMProcess * self_)
|
||||
{
|
||||
memdescriptor = NULL;
|
||||
process_ID = 0;
|
||||
shm_ID = -1;
|
||||
attached = false;
|
||||
identified = false;
|
||||
useYield = false;
|
||||
server_lock = -1;
|
||||
client_lock = -1;
|
||||
suspend_lock = -1;
|
||||
locked = false;
|
||||
self = self_;
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::SetAndWait (uint32_t state)
|
||||
{
|
||||
uint32_t cnt = 0;
|
||||
if(!attached) return false;
|
||||
SHMCMD = state;
|
||||
|
||||
while (SHMCMD == state)
|
||||
{
|
||||
// yield the CPU, only on single-core CPUs
|
||||
if(useYield)
|
||||
{
|
||||
SCHED_YIELD
|
||||
}
|
||||
if(cnt == 10000)
|
||||
{
|
||||
if(!AreLocksOk())// DF not there anymore?
|
||||
{
|
||||
//detach the shared memory
|
||||
shmdt(shm_addr);
|
||||
FreeLocks();
|
||||
attached = locked = identified = false;
|
||||
// we aren't the current process anymore
|
||||
throw Error::SHMServerDisappeared();
|
||||
}
|
||||
else
|
||||
{
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
// server returned a generic error
|
||||
if(SHMCMD == CORE_ERROR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Yeah. with no way to synchronize things (locks are slow, the OS doesn't give us
|
||||
enough control over scheduling)
|
||||
we end up with this silly thing
|
||||
*/
|
||||
bool SHMProcess::SetAndWait (uint32_t state)
|
||||
{
|
||||
return d->SetAndWait(state);
|
||||
}
|
||||
|
||||
uint32_t OS_getAffinity()
|
||||
{
|
||||
cpu_set_t mask;
|
||||
sched_getaffinity(0,sizeof(cpu_set_t),&mask);
|
||||
// FIXME: truncation
|
||||
uint32_t affinity = *(uint32_t *) &mask;
|
||||
return affinity;
|
||||
}
|
||||
|
||||
void SHMProcess::Private::FreeLocks()
|
||||
{
|
||||
attachmentIdx = -1;
|
||||
if(client_lock != -1)
|
||||
{
|
||||
lockf(client_lock,F_ULOCK,0);
|
||||
close(client_lock);
|
||||
client_lock = -1;
|
||||
}
|
||||
if(server_lock != -1)
|
||||
{
|
||||
close(server_lock);
|
||||
server_lock = -1;
|
||||
}
|
||||
if(suspend_lock != -1)
|
||||
{
|
||||
close(suspend_lock);
|
||||
locked = false;
|
||||
suspend_lock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::GetLocks()
|
||||
{
|
||||
char name[256];
|
||||
// try to acquire locks
|
||||
// look at the server lock, if it's locked, the server is present
|
||||
sprintf(name, "/tmp/DFHack/%d/SVlock",process_ID);
|
||||
server_lock = open(name,O_WRONLY);
|
||||
if(server_lock == -1)
|
||||
{
|
||||
// cerr << "can't open sv lock" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(lockf( server_lock, F_TEST, 0 ) != -1)
|
||||
{
|
||||
cerr << "sv lock not locked" << endl;
|
||||
close(server_lock);
|
||||
server_lock = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < SHM_MAX_CLIENTS; i++)
|
||||
{
|
||||
// open the client suspend locked
|
||||
sprintf(name, "/tmp/DFHack/%d/CLSlock%d",process_ID,i);
|
||||
suspend_lock = open(name,O_WRONLY);
|
||||
if(suspend_lock == -1)
|
||||
{
|
||||
cerr << "can't open cl S-lock " << i << endl;
|
||||
// couldn't open lock
|
||||
continue;
|
||||
}
|
||||
|
||||
// open the client lock, try to lock it
|
||||
sprintf(name, "/tmp/DFHack/%d/CLlock%d",process_ID,i);
|
||||
client_lock = open(name,O_WRONLY);
|
||||
if(client_lock == -1)
|
||||
{
|
||||
cerr << "can't open cl lock " << i << endl;
|
||||
close(suspend_lock);
|
||||
locked = false;
|
||||
suspend_lock = -1;
|
||||
// couldn't open lock
|
||||
continue;
|
||||
}
|
||||
if(lockf(client_lock,F_TLOCK, 0) == -1)
|
||||
{
|
||||
// couldn't acquire lock
|
||||
cerr << "can't acquire cl lock " << i << endl;
|
||||
close(suspend_lock);
|
||||
locked = false;
|
||||
suspend_lock = -1;
|
||||
close(client_lock);
|
||||
client_lock = -1;
|
||||
continue;
|
||||
}
|
||||
// ok, we have all the locks we need!
|
||||
attachmentIdx = i;
|
||||
return true;
|
||||
}
|
||||
close(server_lock);
|
||||
server_lock = -1;
|
||||
cerr << "can't get any client locks" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// test if we have client and server locks and the server is present
|
||||
bool SHMProcess::Private::AreLocksOk()
|
||||
{
|
||||
// both locks are inited (we hold our lock)
|
||||
if(client_lock != -1 && server_lock != -1)
|
||||
{
|
||||
if(lockf(server_lock,F_TEST,0) == -1) // and server holds its lock
|
||||
{
|
||||
return true; // OK, locks are good
|
||||
}
|
||||
}
|
||||
// locks are bad
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SHMProcess::Private::validate(VersionInfoFactory * factory)
|
||||
{
|
||||
char exe_link_name [256];
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
// find the binary
|
||||
sprintf(exe_link_name,"/proc/%d/exe", process_ID);
|
||||
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
|
||||
if (target_result == -1)
|
||||
{
|
||||
perror("readlink");
|
||||
return false;
|
||||
}
|
||||
// make sure we have a null terminated string...
|
||||
// see http://www.opengroup.org/onlinepubs/000095399/functions/readlink.html
|
||||
target_name[target_result] = 0;
|
||||
|
||||
// get hash of the running DF process
|
||||
md5wrapper md5;
|
||||
string hash = md5.getHashFromFile(target_name);
|
||||
|
||||
// create linux process, add it to the vector
|
||||
VersionInfo * vinfo = factory->getVersionInfoByMD5(hash);
|
||||
if(vinfo)
|
||||
{
|
||||
memdescriptor = vinfo;
|
||||
// FIXME: BIG BAD BUG RIGHT HERE!!!!
|
||||
memdescriptor->setParentProcess(self);
|
||||
identified = true;
|
||||
vector_start = memdescriptor->getGroup("vector")->getOffset("start");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// there is only one we care about.
|
||||
bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
|
||||
{
|
||||
if(d->attached)
|
||||
{
|
||||
threads.clear();
|
||||
threads.push_back(d->process_ID);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//FIXME: cross-reference with ELF segment entries?
|
||||
void SHMProcess::getMemRanges( vector<t_memrange> & ranges )
|
||||
{
|
||||
char buffer[1024];
|
||||
char permissions[5]; // r/-, w/-, x/-, p/s, 0
|
||||
|
||||
sprintf(buffer, "/proc/%lu/maps", (long unsigned)d->process_ID);
|
||||
FILE *mapFile = ::fopen(buffer, "r");
|
||||
uint64_t offset, device1, device2, node;
|
||||
|
||||
while (fgets(buffer, 1024, mapFile))
|
||||
{
|
||||
t_memrange temp;
|
||||
temp.name[0] = 0;
|
||||
sscanf(buffer, "%zx-%zx %s %zx %2zu:%2zu %zu %s",
|
||||
&temp.start,
|
||||
&temp.end,
|
||||
(char*)&permissions,
|
||||
&offset, &device1, &device2, &node,
|
||||
(char*)&temp.name);
|
||||
temp.read = permissions[0] == 'r';
|
||||
temp.write = permissions[1] == 'w';
|
||||
temp.execute = permissions[2] == 'x';
|
||||
temp.valid = true;
|
||||
ranges.push_back(temp);
|
||||
}
|
||||
}
|
||||
|
||||
bool SHMProcess::acquireSuspendLock()
|
||||
{
|
||||
return (lockf(d->suspend_lock,F_LOCK,0) == 0);
|
||||
}
|
||||
|
||||
bool SHMProcess::releaseSuspendLock()
|
||||
{
|
||||
return (lockf(d->suspend_lock,F_ULOCK,0) == 0);
|
||||
}
|
||||
|
||||
|
||||
bool SHMProcess::attach()
|
||||
{
|
||||
if(d->attached)
|
||||
{
|
||||
if(!d->locked)
|
||||
return suspend();
|
||||
return true;
|
||||
}
|
||||
//cerr << "attach" << endl;// FIXME: throw
|
||||
if(!d->GetLocks())
|
||||
{
|
||||
//cerr << "server is full or not really there!" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate the segment.
|
||||
*/
|
||||
if ((d->shm_ID = shmget(SHM_KEY + d->process_ID, SHM_SIZE, 0666)) < 0)
|
||||
{
|
||||
d->FreeLocks();
|
||||
cerr << "can't find segment" << endl; // FIXME: throw
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach the segment
|
||||
*/
|
||||
if ((d->shm_addr = (char *) shmat(d->shm_ID, NULL, 0)) == (char *) -1)
|
||||
{
|
||||
d->FreeLocks();
|
||||
cerr << "can't attach segment" << endl; // FIXME: throw
|
||||
return false;
|
||||
}
|
||||
d->attached = true;
|
||||
if(!suspend())
|
||||
{
|
||||
shmdt(d->shm_addr);
|
||||
d->FreeLocks();
|
||||
cerr << "unable to suspend" << endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHMProcess::detach()
|
||||
{
|
||||
if(!d->attached) return true;
|
||||
if(d->locked)
|
||||
{
|
||||
resume();
|
||||
}
|
||||
// detach segment
|
||||
if(shmdt(d->shm_addr) != -1)
|
||||
{
|
||||
d->FreeLocks();
|
||||
d->locked = false;
|
||||
d->attached = false;
|
||||
d->shm_addr = 0;
|
||||
return true;
|
||||
}
|
||||
// fail if we can't detach
|
||||
// FIXME: throw exception here??
|
||||
perror("failed to detach shared segment");
|
||||
return false;
|
||||
}
|
||||
|
||||
void SHMProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
read(address + d->vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
void SHMProcess::writeSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
write(address + d->vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
|
||||
string SHMProcess::doReadClassName (uint32_t vptr)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(vptr);
|
||||
|
||||
int typeinfo = Process::readDWord(vptr - 0x4);
|
||||
int typestring = Process::readDWord(typeinfo + 0x4);
|
||||
string raw = readCString(typestring);
|
||||
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
|
||||
size_t end = raw.length();
|
||||
return raw.substr(start,end-start);
|
||||
}
|
||||
|
||||
string SHMProcess::getPath()
|
||||
{
|
||||
char cwd_name[256];
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
|
||||
sprintf(cwd_name,"/proc/%d/cwd", getPID());
|
||||
// resolve /proc/PID/exe link
|
||||
target_result = readlink(cwd_name, target_name, sizeof(target_name));
|
||||
target_name[target_result] = '\0';
|
||||
return(string(target_name));
|
||||
}
|
||||
|
||||
char * SHMProcess::getSHMStart (void)
|
||||
{
|
||||
if(!d->locked) return 0; //THROW HERE!
|
||||
|
||||
return d->shm_addr;
|
||||
}
|
@ -1,326 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
#include "Internal.h"
|
||||
#include "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdio>
|
||||
using namespace std;
|
||||
|
||||
#include "LinuxProcess.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
using namespace DFHack;
|
||||
|
||||
LinuxProcessBase::LinuxProcessBase(uint32_t pid)
|
||||
: my_pid(pid)
|
||||
{
|
||||
my_descriptor = NULL;
|
||||
attached = false;
|
||||
suspended = false;
|
||||
memFileHandle = 0;
|
||||
}
|
||||
|
||||
bool LinuxProcessBase::isSuspended()
|
||||
{
|
||||
return suspended;
|
||||
}
|
||||
bool LinuxProcessBase::isAttached()
|
||||
{
|
||||
return attached;
|
||||
}
|
||||
|
||||
bool LinuxProcessBase::isIdentified()
|
||||
{
|
||||
return identified;
|
||||
}
|
||||
|
||||
LinuxProcessBase::~LinuxProcessBase()
|
||||
{
|
||||
// destroy our copy of the memory descriptor
|
||||
if(my_descriptor)
|
||||
delete my_descriptor;
|
||||
}
|
||||
|
||||
VersionInfo * LinuxProcessBase::getDescriptor()
|
||||
{
|
||||
return my_descriptor;
|
||||
}
|
||||
|
||||
int LinuxProcessBase::getPID()
|
||||
{
|
||||
return my_pid;
|
||||
}
|
||||
|
||||
int getdir (string dir, vector<string> &files)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *dirp;
|
||||
if((dp = opendir(dir.c_str())) == NULL) {
|
||||
cout << "Error(" << errno << ") opening " << dir << endl;
|
||||
return errno;
|
||||
}
|
||||
|
||||
while ((dirp = readdir(dp)) != NULL) {
|
||||
files.push_back(string(dirp->d_name));
|
||||
}
|
||||
closedir(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool LinuxProcessBase::getThreadIDs(vector<uint32_t> & threads )
|
||||
{
|
||||
stringstream ss;
|
||||
vector<string> subdirs;
|
||||
ss << "/proc/" << my_pid << "/task/";
|
||||
if(getdir(ss.str(),subdirs) != 0)
|
||||
{
|
||||
//FIXME: needs exceptions. this is a fatal error
|
||||
cerr << "unable to enumerate threads. This is BAD!" << endl;
|
||||
return false;
|
||||
}
|
||||
threads.clear();
|
||||
for(size_t i = 0; i < subdirs.size();i++)
|
||||
{
|
||||
uint32_t tid;
|
||||
if(sscanf(subdirs[i].c_str(),"%d", &tid))
|
||||
{
|
||||
threads.push_back(tid);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//FIXME: cross-reference with ELF segment entries?
|
||||
void LinuxProcessBase::getMemRanges( vector<t_memrange> & ranges )
|
||||
{
|
||||
char buffer[1024];
|
||||
char permissions[5]; // r/-, w/-, x/-, p/s, 0
|
||||
|
||||
sprintf(buffer, "/proc/%lu/maps", (long unsigned)my_pid);
|
||||
FILE *mapFile = ::fopen(buffer, "r");
|
||||
size_t start, end, offset, device1, device2, node;
|
||||
|
||||
while (fgets(buffer, 1024, mapFile))
|
||||
{
|
||||
t_memrange temp;
|
||||
temp.name[0] = 0;
|
||||
sscanf(buffer, "%zx-%zx %s %zx %2zu:%2zu %zu %[^\n]s",
|
||||
&start,
|
||||
&end,
|
||||
(char*)&permissions,
|
||||
&offset, &device1, &device2, &node,
|
||||
(char*)&temp.name);
|
||||
temp.start = start;
|
||||
temp.end = end;
|
||||
temp.read = permissions[0] == 'r';
|
||||
temp.write = permissions[1] == 'w';
|
||||
temp.execute = permissions[2] == 'x';
|
||||
temp.shared = permissions[3] == 's';
|
||||
temp.valid = true;
|
||||
ranges.push_back(temp);
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxProcessBase::read (const uint32_t offset, const uint32_t size, uint8_t *target)
|
||||
{
|
||||
if(size == 0) return;
|
||||
|
||||
ssize_t result;
|
||||
ssize_t total = 0;
|
||||
ssize_t remaining = size;
|
||||
while (total != size)
|
||||
{
|
||||
result = pread(memFileHandle, target + total ,remaining,offset + total);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "pread failed: can't read " << size << " bytes at addres " << offset << endl;
|
||||
cerr << "errno: " << errno << endl;
|
||||
errno = 0;
|
||||
throw Error::MemoryAccessDenied(offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
total += result;
|
||||
remaining -= result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxProcessBase::readByte (const uint32_t offset, uint8_t &val )
|
||||
{
|
||||
read(offset, 1, &val);
|
||||
}
|
||||
|
||||
void LinuxProcessBase::readWord (const uint32_t offset, uint16_t &val)
|
||||
{
|
||||
read(offset, 2, (uint8_t *) &val);
|
||||
}
|
||||
|
||||
void LinuxProcessBase::readDWord (const uint32_t offset, uint32_t &val)
|
||||
{
|
||||
read(offset, 4, (uint8_t *) &val);
|
||||
}
|
||||
|
||||
void LinuxProcessBase::readFloat (const uint32_t offset, float &val)
|
||||
{
|
||||
read(offset, 4, (uint8_t *) &val);
|
||||
}
|
||||
|
||||
void LinuxProcessBase::readQuad (const uint32_t offset, uint64_t &val)
|
||||
{
|
||||
read(offset, 8, (uint8_t *) &val);
|
||||
}
|
||||
|
||||
/*
|
||||
* WRITING
|
||||
*/
|
||||
|
||||
void LinuxProcessBase::writeQuad (uint32_t offset, const uint64_t data)
|
||||
{
|
||||
#ifdef HAVE_64_BIT
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, data);
|
||||
#else
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, (uint32_t) data);
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset+4, (uint32_t) (data >> 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
void LinuxProcessBase::writeDWord (uint32_t offset, uint32_t data)
|
||||
{
|
||||
#ifdef HAVE_64_BIT
|
||||
uint64_t orig = Process::readQuad(offset);
|
||||
orig &= 0xFFFFFFFF00000000;
|
||||
orig |= data;
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
|
||||
#else
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, data);
|
||||
#endif
|
||||
}
|
||||
|
||||
// using these is expensive.
|
||||
void LinuxProcessBase::writeWord (uint32_t offset, uint16_t data)
|
||||
{
|
||||
#ifdef HAVE_64_BIT
|
||||
uint64_t orig = Process::readQuad(offset);
|
||||
orig &= 0xFFFFFFFFFFFF0000;
|
||||
orig |= data;
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
|
||||
#else
|
||||
uint32_t orig = Process::readDWord(offset);
|
||||
orig &= 0xFFFF0000;
|
||||
orig |= data;
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LinuxProcessBase::writeByte (uint32_t offset, uint8_t data)
|
||||
{
|
||||
#ifdef HAVE_64_BIT
|
||||
uint64_t orig = Process::readQuad(offset);
|
||||
orig &= 0xFFFFFFFFFFFFFF00;
|
||||
orig |= data;
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
|
||||
#else
|
||||
uint32_t orig = Process::readDWord(offset);
|
||||
orig &= 0xFFFFFF00;
|
||||
orig |= data;
|
||||
ptrace(PTRACE_POKEDATA,my_pid, offset, orig);
|
||||
#endif
|
||||
}
|
||||
|
||||
// blah. THIS IS RIDICULOUS
|
||||
void LinuxProcessBase::write (uint32_t offset, uint32_t size, uint8_t *source)
|
||||
{
|
||||
uint32_t indexptr = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
#ifdef HAVE_64_BIT
|
||||
// quad!
|
||||
if(size >= 8)
|
||||
{
|
||||
writeQuad(offset, *(uint64_t *) (source + indexptr));
|
||||
offset +=8;
|
||||
indexptr +=8;
|
||||
size -=8;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
// default: we push 4 bytes
|
||||
if(size >= 4)
|
||||
{
|
||||
writeDWord(offset, *(uint32_t *) (source + indexptr));
|
||||
offset +=4;
|
||||
indexptr +=4;
|
||||
size -=4;
|
||||
}
|
||||
// last is either three or 2 bytes
|
||||
else if(size >= 2)
|
||||
{
|
||||
writeWord(offset, *(uint16_t *) (source + indexptr));
|
||||
offset +=2;
|
||||
indexptr +=2;
|
||||
size -=2;
|
||||
}
|
||||
// finishing move
|
||||
else if(size == 1)
|
||||
{
|
||||
writeByte(offset, *(uint8_t *) (source + indexptr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string LinuxProcessBase::readCString (uint32_t offset)
|
||||
{
|
||||
std::string temp;
|
||||
int counter = 0;
|
||||
char r;
|
||||
while (1)
|
||||
{
|
||||
r = Process::readByte(offset+counter);
|
||||
if(!r) break;
|
||||
counter++;
|
||||
temp.append(1,r);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
string LinuxProcessBase::getPath()
|
||||
{
|
||||
char cwd_name[256];
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
|
||||
sprintf(cwd_name,"/proc/%d/cwd", getPID());
|
||||
// resolve /proc/PID/exe link
|
||||
target_result = readlink(cwd_name, target_name, sizeof(target_name));
|
||||
target_name[target_result] = '\0';
|
||||
return(string(target_name));
|
||||
}
|
@ -1,280 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
#include "Internal.h"
|
||||
#include "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
using namespace std;
|
||||
|
||||
#include "LinuxProcess.h"
|
||||
#include "ProcessFactory.h"
|
||||
#include "MicrosoftSTL.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
using namespace DFHack;
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#include <md5wrapper.h>
|
||||
|
||||
|
||||
namespace {
|
||||
class WineProcess : public LinuxProcessBase
|
||||
{
|
||||
private:
|
||||
uint8_t vector_start;
|
||||
MicrosoftSTL stl;
|
||||
public:
|
||||
WineProcess(uint32_t pid, VersionInfoFactory * factory);
|
||||
~WineProcess()
|
||||
{
|
||||
if(attached)
|
||||
{
|
||||
detach();
|
||||
}
|
||||
}
|
||||
bool attach();
|
||||
bool detach();
|
||||
|
||||
bool suspend();
|
||||
bool asyncSuspend();
|
||||
bool resume();
|
||||
bool forceresume();
|
||||
|
||||
void readSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
void writeSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
const std::string readSTLString (uint32_t offset);
|
||||
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
|
||||
size_t writeSTLString(const uint32_t address, const std::string writeString);
|
||||
// get class name of an object with rtti/type info
|
||||
std::string doReadClassName(uint32_t vptr);
|
||||
};
|
||||
}
|
||||
|
||||
Process* DFHack::createWineProcess(uint32_t pid, VersionInfoFactory * factory)
|
||||
{
|
||||
return new WineProcess(pid, factory);
|
||||
}
|
||||
|
||||
WineProcess::WineProcess(uint32_t pid, VersionInfoFactory * factory) : LinuxProcessBase(pid)
|
||||
{
|
||||
char dir_name [256];
|
||||
char exe_link_name [256];
|
||||
char mem_name [256];
|
||||
char cwd_name [256];
|
||||
char cmdline_name [256];
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
|
||||
identified = false;
|
||||
my_descriptor = 0;
|
||||
|
||||
sprintf(dir_name,"/proc/%d/", pid);
|
||||
sprintf(exe_link_name,"/proc/%d/exe", pid);
|
||||
sprintf(mem_name,"/proc/%d/mem", pid);
|
||||
memFile = mem_name;
|
||||
sprintf(cwd_name,"/proc/%d/cwd", pid);
|
||||
sprintf(cmdline_name,"/proc/%d/cmdline", pid);
|
||||
|
||||
// resolve /proc/PID/exe link
|
||||
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
|
||||
if (target_result == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// make sure we have a null terminated string...
|
||||
target_name[target_result] = 0;
|
||||
|
||||
// FIXME: this fails when the wine process isn't started from the 'current working directory'. strip path data from cmdline
|
||||
// is this windows version of Df running in wine?
|
||||
if(strstr(target_name, "wine-preloader")!= NULL)
|
||||
{
|
||||
// get working directory
|
||||
target_result = readlink(cwd_name, target_name, sizeof(target_name)-1);
|
||||
target_name[target_result] = 0;
|
||||
|
||||
// got path to executable, do the same for its name
|
||||
ifstream ifs ( cmdline_name , ifstream::in );
|
||||
string cmdline;
|
||||
getline(ifs,cmdline);
|
||||
if (cmdline.find("dwarfort-w.exe") != string::npos || cmdline.find("dwarfort.exe") != string::npos || cmdline.find("Dwarf Fortress.exe") != string::npos)
|
||||
{
|
||||
char exe_link[1024];
|
||||
// put executable name and path together
|
||||
sprintf(exe_link,"%s/%s",target_name,cmdline.c_str());
|
||||
|
||||
md5wrapper md5;
|
||||
// get hash of the running DF process
|
||||
string hash = md5.getHashFromFile(exe_link);
|
||||
// create linux process, add it to the vector
|
||||
VersionInfo * vinfo = factory->getVersionInfoByMD5(hash);
|
||||
if(vinfo)
|
||||
{
|
||||
my_descriptor = new VersionInfo(*vinfo);
|
||||
my_descriptor->setParentProcess(this);
|
||||
vector_start = my_descriptor->getGroup("vector")->getOffset("start");
|
||||
stl.init(this);
|
||||
identified = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WineProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
read(address + vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
void WineProcess::writeSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
write(address + vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
size_t WineProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
|
||||
{
|
||||
return stl.readSTLString(offset, buffer, bufcapacity);
|
||||
}
|
||||
|
||||
size_t WineProcess::writeSTLString(const uint32_t address, const std::string writeString)
|
||||
{
|
||||
return stl.writeSTLString(address,writeString);
|
||||
}
|
||||
|
||||
|
||||
const string WineProcess::readSTLString (uint32_t offset)
|
||||
{
|
||||
return stl.readSTLString(offset);
|
||||
}
|
||||
|
||||
string WineProcess::doReadClassName (uint32_t vptr)
|
||||
{
|
||||
return stl.readClassName(vptr);
|
||||
}
|
||||
|
||||
bool WineProcess::asyncSuspend()
|
||||
{
|
||||
return suspend();
|
||||
}
|
||||
|
||||
bool WineProcess::suspend()
|
||||
{
|
||||
int status;
|
||||
if(suspended)
|
||||
return true;
|
||||
// can we attach?
|
||||
if (ptrace(PTRACE_ATTACH , my_pid, NULL, NULL) == -1)
|
||||
{
|
||||
// no, we got an error
|
||||
perror("ptrace attach error");
|
||||
cerr << "attach failed on pid " << my_pid << endl;
|
||||
return false;
|
||||
}
|
||||
while(true)
|
||||
{
|
||||
// we wait on the pid
|
||||
pid_t w = waitpid(my_pid, &status, 0);
|
||||
if (w == -1)
|
||||
{
|
||||
// child died
|
||||
perror("wait inside attach()");
|
||||
return false;
|
||||
}
|
||||
// stopped -> let's continue
|
||||
if (WIFSTOPPED(status))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
int proc_pid_mem = open(memFile.c_str(),O_RDONLY);
|
||||
if(proc_pid_mem == -1)
|
||||
{
|
||||
ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
|
||||
cerr << memFile << endl;
|
||||
cerr << "couldn't open /proc/" << my_pid << "/mem" << endl;
|
||||
perror("open(memFile.c_str(),O_RDONLY)");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
attached = suspended = true;
|
||||
memFileHandle = proc_pid_mem;
|
||||
return true; // we are attached
|
||||
}
|
||||
}
|
||||
|
||||
bool WineProcess::forceresume()
|
||||
{
|
||||
return resume();
|
||||
}
|
||||
|
||||
bool WineProcess::resume()
|
||||
{
|
||||
if(!suspended)
|
||||
return true;
|
||||
int result = 0;
|
||||
// close /proc/PID/mem
|
||||
result = close(memFileHandle);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "couldn't close /proc/"<< my_pid <<"/mem" << endl;
|
||||
perror("mem file close");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// detach
|
||||
result = ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "couldn't detach from process pid" << my_pid << endl;
|
||||
perror("ptrace detach");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
attached = suspended = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool WineProcess::attach()
|
||||
{
|
||||
if(suspended) return true;
|
||||
return suspend();
|
||||
}
|
||||
|
||||
bool WineProcess::detach()
|
||||
{
|
||||
if(!suspended) return true;
|
||||
return resume();
|
||||
}
|
@ -1,410 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
#include "Internal.h"
|
||||
#include "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
using namespace std;
|
||||
|
||||
#include "LinuxProcess.h"
|
||||
#include "ProcessFactory.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <md5wrapper.h>
|
||||
using namespace DFHack;
|
||||
|
||||
namespace {
|
||||
class NormalProcess : public LinuxProcessBase
|
||||
{
|
||||
private:
|
||||
uint8_t vector_start;
|
||||
set <uint32_t> thread_ids;
|
||||
|
||||
void waitForSuspend(set<uint32_t> &threads);
|
||||
public:
|
||||
NormalProcess(uint32_t pid, VersionInfoFactory * known_versions);
|
||||
~NormalProcess()
|
||||
{
|
||||
if(attached)
|
||||
{
|
||||
detach();
|
||||
}
|
||||
}
|
||||
bool attach();
|
||||
bool detach();
|
||||
|
||||
bool suspend();
|
||||
bool asyncSuspend();
|
||||
bool resume();
|
||||
bool forceresume();
|
||||
|
||||
void readSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
void writeSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
const std::string readSTLString (uint32_t offset);
|
||||
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
|
||||
size_t writeSTLString(const uint32_t address, const std::string writeString);
|
||||
size_t copySTLString(const uint32_t address, const uint32_t target);
|
||||
// get class name of an object with rtti/type info
|
||||
std::string doReadClassName(uint32_t vptr);
|
||||
};
|
||||
}
|
||||
|
||||
Process* DFHack::createNormalProcess(uint32_t pid, VersionInfoFactory * known_versions)
|
||||
{
|
||||
return new NormalProcess(pid, known_versions);
|
||||
}
|
||||
|
||||
NormalProcess::NormalProcess(uint32_t pid, VersionInfoFactory * known_versions) : LinuxProcessBase(pid)
|
||||
{
|
||||
char dir_name [256];
|
||||
char exe_link_name [256];
|
||||
char mem_name [256];
|
||||
char cwd_name [256];
|
||||
char cmdline_name [256];
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
|
||||
identified = false;
|
||||
my_descriptor = 0;
|
||||
|
||||
sprintf(dir_name,"/proc/%d/", pid);
|
||||
sprintf(exe_link_name,"/proc/%d/exe", pid);
|
||||
sprintf(mem_name,"/proc/%d/mem", pid);
|
||||
memFile = mem_name;
|
||||
sprintf(cwd_name,"/proc/%d/cwd", pid);
|
||||
sprintf(cmdline_name,"/proc/%d/cmdline", pid);
|
||||
|
||||
// resolve /proc/PID/exe link
|
||||
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
|
||||
if (target_result == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// make sure we have a null terminated string...
|
||||
target_name[target_result] = 0;
|
||||
|
||||
// is this the regular linux DF?
|
||||
if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0)
|
||||
{
|
||||
md5wrapper md5;
|
||||
// get hash of the running DF process
|
||||
string hash = md5.getHashFromFile(target_name);
|
||||
// create linux process, add it to the vector
|
||||
VersionInfo * vinfo = known_versions->getVersionInfoByMD5(hash);
|
||||
if(vinfo)
|
||||
{
|
||||
my_descriptor = new VersionInfo(*vinfo);
|
||||
my_descriptor->setParentProcess(this);
|
||||
vector_start = my_descriptor->getGroup("vector")->getOffset("start");
|
||||
identified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct _Rep_base
|
||||
{
|
||||
uint32_t _M_length; // length of text stored, not including zero termination
|
||||
uint32_t _M_capacity; // capacity, not including zero termination
|
||||
int32_t _M_refcount; // reference count (two STL strings can share a common buffer, copy on write rules apply)
|
||||
};
|
||||
|
||||
size_t NormalProcess::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
|
||||
{
|
||||
_Rep_base header;
|
||||
offset = Process::readDWord(offset);
|
||||
read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
size_t read_real = min((size_t)header._M_length, bufcapacity-1);// keep space for null termination
|
||||
read(offset,read_real,(uint8_t * )buffer);
|
||||
buffer[read_real] = 0;
|
||||
return read_real;
|
||||
}
|
||||
|
||||
size_t NormalProcess::writeSTLString(const uint32_t address, const std::string writeString)
|
||||
{
|
||||
_Rep_base header;
|
||||
// get buffer location
|
||||
uint32_t start = Process::readDWord(address);
|
||||
// read the header
|
||||
read(start - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
|
||||
// the buffer has actual size = 1. no space for storing anything more than a zero byte
|
||||
if(header._M_capacity == 0)
|
||||
return 0;
|
||||
if(header._M_refcount > 0 ) // one ref or one non-shareable (-1) ref
|
||||
return 0;
|
||||
|
||||
// get writeable length (lesser of our string length and capacity of the target)
|
||||
uint32_t lstr = writeString.length();
|
||||
uint32_t allowed_copy = min(lstr, header._M_capacity);
|
||||
// write header with new length.
|
||||
header._M_length = allowed_copy;
|
||||
write(start - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
// write string, add a zero terminator, return bytes written
|
||||
write(start, allowed_copy, (uint8_t *) writeString.c_str());
|
||||
writeByte(start + allowed_copy, 0);
|
||||
return allowed_copy;
|
||||
}
|
||||
|
||||
void NormalProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
read(address + vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
void NormalProcess::writeSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
write(address + vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
const string NormalProcess::readSTLString (uint32_t offset)
|
||||
{
|
||||
_Rep_base header;
|
||||
|
||||
offset = Process::readDWord(offset);
|
||||
read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
|
||||
// FIXME: use char* everywhere, avoid string
|
||||
char * temp = new char[header._M_length+1];
|
||||
read(offset,header._M_length+1,(uint8_t * )temp);
|
||||
string ret(temp);
|
||||
delete temp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t NormalProcess::copySTLString (uint32_t offset, uint32_t target)
|
||||
{
|
||||
_Rep_base header;
|
||||
|
||||
offset = Process::readDWord(offset);
|
||||
uint32_t old_target = Process::readDWord(target);
|
||||
|
||||
if (offset == old_target)
|
||||
return 0;
|
||||
|
||||
read(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
|
||||
// destroying the leaked state
|
||||
if (header._M_refcount == -1)
|
||||
header._M_refcount = 1;
|
||||
else
|
||||
header._M_refcount++;
|
||||
|
||||
write(offset - sizeof(_Rep_base),sizeof(_Rep_base),(uint8_t *)&header);
|
||||
|
||||
writeDWord(target, offset);
|
||||
return header._M_length;
|
||||
}
|
||||
|
||||
string NormalProcess::doReadClassName (uint32_t vptr)
|
||||
{
|
||||
int typeinfo = Process::readDWord(vptr - 0x4);
|
||||
int typestring = Process::readDWord(typeinfo + 0x4);
|
||||
string raw = readCString(typestring);
|
||||
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
|
||||
size_t end = raw.length();
|
||||
return raw.substr(start,end-start);
|
||||
}
|
||||
|
||||
bool NormalProcess::asyncSuspend()
|
||||
{
|
||||
return suspend();
|
||||
}
|
||||
|
||||
bool NormalProcess::suspend()
|
||||
{
|
||||
if(!attached)
|
||||
return false;
|
||||
if(suspended)
|
||||
return true;
|
||||
|
||||
set<uint32_t> threads;
|
||||
|
||||
for (set<uint32_t>::iterator it = thread_ids.begin(); it != thread_ids.end(); ++it) {
|
||||
if (syscall(SYS_tgkill, my_pid, *it, SIGSTOP) == -1) {
|
||||
cerr << "couldn't stop thread " << *it << endl;
|
||||
perror("kill SIGSTOP error");
|
||||
} else {
|
||||
threads.insert(*it);
|
||||
}
|
||||
}
|
||||
|
||||
if (threads.empty()) {
|
||||
cerr << "couldn't suspend any of the threads";
|
||||
return false;
|
||||
}
|
||||
|
||||
waitForSuspend(threads);
|
||||
|
||||
if (!threads.empty())
|
||||
cerr << "couldn't suspend some of the threads";
|
||||
|
||||
suspended = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NormalProcess::forceresume()
|
||||
{
|
||||
return resume();
|
||||
}
|
||||
|
||||
bool NormalProcess::resume()
|
||||
{
|
||||
if(!attached)
|
||||
return false;
|
||||
if(!suspended)
|
||||
return true;
|
||||
|
||||
bool ok = true;
|
||||
for (set<uint32_t>::iterator it = thread_ids.begin(); it != thread_ids.end(); ++it) {
|
||||
int result = ptrace(PTRACE_CONT, *it, NULL, NULL);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "couldn't resume thread " << *it << endl;
|
||||
perror("ptrace resume error");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
suspended = false;
|
||||
return ok;
|
||||
}
|
||||
|
||||
void NormalProcess::waitForSuspend(set<uint32_t> &threads)
|
||||
{
|
||||
int status;
|
||||
while (!threads.empty()) {
|
||||
pid_t w = waitpid(-1, &status, __WALL);
|
||||
if (w == -1) {
|
||||
perror("waitpid");
|
||||
return;
|
||||
}
|
||||
if (threads.find(w) == threads.end()
|
||||
&& thread_ids.find(w) == thread_ids.end())
|
||||
continue;
|
||||
if (WIFSTOPPED(status)) {
|
||||
threads.erase(w);
|
||||
thread_ids.insert(w);
|
||||
} else if (WIFEXITED(status) || WIFSIGNALED(status)) {
|
||||
threads.erase(w);
|
||||
thread_ids.erase(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NormalProcess::attach()
|
||||
{
|
||||
if(attached)
|
||||
{
|
||||
if(!suspended)
|
||||
return suspend();
|
||||
return true;
|
||||
}
|
||||
|
||||
set<uint32_t> threads;
|
||||
vector<uint32_t> thread_vec;
|
||||
|
||||
if (!getThreadIDs(thread_vec))
|
||||
return false;
|
||||
|
||||
for (vector<uint32_t>::iterator it = thread_vec.begin(); it != thread_vec.end(); ++it) {
|
||||
if (ptrace(PTRACE_ATTACH, *it, NULL, NULL) == -1)
|
||||
{
|
||||
// no, we got an error
|
||||
perror("ptrace attach error");
|
||||
cerr << "attach failed on pid " << *it << endl;
|
||||
continue;
|
||||
}
|
||||
threads.insert(*it);
|
||||
}
|
||||
|
||||
thread_ids.clear();
|
||||
waitForSuspend(threads);
|
||||
|
||||
if (thread_ids.empty()) {
|
||||
cerr << "couldn't attach to any threads" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!threads.empty())
|
||||
cerr << "couldn't attach to some threads" << endl;
|
||||
|
||||
suspended = true;
|
||||
|
||||
int proc_pid_mem = open(memFile.c_str(),O_RDONLY);
|
||||
if(proc_pid_mem == -1)
|
||||
{
|
||||
ptrace(PTRACE_DETACH, my_pid, NULL, NULL);
|
||||
cerr << memFile << endl;
|
||||
cerr << "couldn't open /proc/" << my_pid << "/mem" << endl;
|
||||
perror("open(memFile.c_str(),O_RDONLY)");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
attached = true;
|
||||
|
||||
memFileHandle = proc_pid_mem;
|
||||
return true; // we are attached
|
||||
}
|
||||
}
|
||||
|
||||
bool NormalProcess::detach()
|
||||
{
|
||||
if(!attached) return true;
|
||||
if(!suspended) suspend();
|
||||
int result = 0;
|
||||
// close /proc/PID/mem
|
||||
result = close(memFileHandle);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "couldn't close /proc/"<< my_pid <<"/mem" << endl;
|
||||
perror("mem file close");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (set<uint32_t>::iterator it = thread_ids.begin(); it != thread_ids.end();) {
|
||||
// detach
|
||||
result = ptrace(PTRACE_DETACH, *it, NULL, NULL);
|
||||
if(result == -1)
|
||||
{
|
||||
cerr << "couldn't detach from process pid" << *it << endl;
|
||||
perror("ptrace detach");
|
||||
return false;;
|
||||
}
|
||||
thread_ids.erase(it++);
|
||||
}
|
||||
|
||||
attached = false;
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,428 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
#include "Internal.h"
|
||||
#include "PlatformInternal.h"
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
#include "SHMProcess.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/DFError.h"
|
||||
#include "shms.h"
|
||||
#include "mod-core.h"
|
||||
using namespace DFHack;
|
||||
|
||||
SHMProcess::Private::Private(SHMProcess * self_)
|
||||
{
|
||||
memdescriptor = NULL;
|
||||
process_ID = 0;
|
||||
attached = false;
|
||||
locked = false;
|
||||
identified = false;
|
||||
useYield = 0;
|
||||
DFSVMutex = 0;
|
||||
DFCLMutex = 0;
|
||||
DFCLSuspendMutex = 0;
|
||||
self = self_;
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::SetAndWait (uint32_t state)
|
||||
{
|
||||
uint32_t cnt = 0;
|
||||
if(!attached) return false;
|
||||
SHMCMD = state;
|
||||
|
||||
while (SHMCMD == state)
|
||||
{
|
||||
// yield the CPU, only on single-core CPUs
|
||||
if(useYield)
|
||||
{
|
||||
SCHED_YIELD
|
||||
}
|
||||
if(cnt == 10000)
|
||||
{
|
||||
if(!AreLocksOk())// DF not there anymore?
|
||||
{
|
||||
UnmapViewOfFile(shm_addr);
|
||||
FreeLocks();
|
||||
attached = locked = identified = false;
|
||||
// we aren't the current process anymore
|
||||
throw Error::SHMServerDisappeared();
|
||||
}
|
||||
else
|
||||
{
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
// server returned a generic error
|
||||
if(SHMCMD == CORE_ERROR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHMProcess::SetAndWait (uint32_t state)
|
||||
{
|
||||
return d->SetAndWait(state);
|
||||
}
|
||||
|
||||
uint32_t OS_getAffinity()
|
||||
{
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
DWORD dwProcessAffinityMask, dwSystemAffinityMask;
|
||||
GetProcessAffinityMask( hProcess, &dwProcessAffinityMask, &dwSystemAffinityMask );
|
||||
return dwProcessAffinityMask;
|
||||
}
|
||||
|
||||
void SHMProcess::Private::FreeLocks()
|
||||
{
|
||||
attachmentIdx = -1;
|
||||
if(DFCLMutex != 0)
|
||||
{
|
||||
ReleaseMutex(DFCLMutex);
|
||||
CloseHandle(DFCLMutex);
|
||||
DFCLMutex = 0;
|
||||
}
|
||||
if(DFSVMutex != 0)
|
||||
{
|
||||
CloseHandle(DFSVMutex);
|
||||
DFSVMutex = 0;
|
||||
}
|
||||
if(DFCLSuspendMutex != 0)
|
||||
{
|
||||
ReleaseMutex(DFCLSuspendMutex);
|
||||
CloseHandle(DFCLSuspendMutex);
|
||||
// FIXME: maybe also needs ReleaseMutex!
|
||||
DFCLSuspendMutex = 0;
|
||||
locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::GetLocks()
|
||||
{
|
||||
char name[256];
|
||||
// try to acquire locks
|
||||
// look at the server lock, if it's locked, the server is present
|
||||
sprintf(name,"DFSVMutex-%d",process_ID);
|
||||
DFSVMutex = OpenMutex(SYNCHRONIZE,0, name);
|
||||
if(DFSVMutex == 0)
|
||||
{
|
||||
// cerr << "can't open sv lock" << endl;
|
||||
return false;
|
||||
}
|
||||
// unlike the F_TEST of lockf, this one actually locks. we have to release
|
||||
if(WaitForSingleObject(DFSVMutex,0) == 0)
|
||||
{
|
||||
ReleaseMutex(DFSVMutex);
|
||||
// cerr << "sv lock not locked" << endl;
|
||||
CloseHandle(DFSVMutex);
|
||||
DFSVMutex = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i = 0; i < SHM_MAX_CLIENTS; i++)
|
||||
{
|
||||
// open the client suspend locked
|
||||
sprintf(name, "DFCLSuspendMutex-%d-%d",process_ID,i);
|
||||
DFCLSuspendMutex = OpenMutex(SYNCHRONIZE,0, name);
|
||||
if(DFCLSuspendMutex == 0)
|
||||
{
|
||||
//cerr << "can't open cl S-lock " << i << endl;
|
||||
// couldn't open lock
|
||||
continue;
|
||||
}
|
||||
|
||||
// open the client lock, try to lock it
|
||||
|
||||
sprintf(name,"DFCLMutex-%d-%d",process_ID,i);
|
||||
DFCLMutex = OpenMutex(SYNCHRONIZE,0,name);
|
||||
if(DFCLMutex == 0)
|
||||
{
|
||||
//cerr << "can't open cl lock " << i << endl;
|
||||
CloseHandle(DFCLSuspendMutex);
|
||||
locked = false;
|
||||
DFCLSuspendMutex = 0;
|
||||
continue;
|
||||
}
|
||||
uint32_t waitstate = WaitForSingleObject(DFCLMutex,0);
|
||||
if(waitstate == WAIT_FAILED || waitstate == WAIT_TIMEOUT )
|
||||
{
|
||||
//cerr << "can't acquire cl lock " << i << endl;
|
||||
CloseHandle(DFCLSuspendMutex);
|
||||
locked = false;
|
||||
DFCLSuspendMutex = 0;
|
||||
CloseHandle(DFCLMutex);
|
||||
DFCLMutex = 0;
|
||||
continue;
|
||||
}
|
||||
// ok, we have all the locks we need!
|
||||
attachmentIdx = i;
|
||||
return true;
|
||||
}
|
||||
CloseHandle(DFSVMutex);
|
||||
DFSVMutex = 0;
|
||||
// cerr << "can't get any client locks" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// is the other side still there?
|
||||
bool SHMProcess::Private::AreLocksOk()
|
||||
{
|
||||
// both locks are inited (we hold our lock)
|
||||
if(DFCLMutex != 0 && DFSVMutex != 0)
|
||||
{
|
||||
// try if CL mutex is free
|
||||
switch (WaitForSingleObject(DFSVMutex,0))
|
||||
{
|
||||
case WAIT_ABANDONED:
|
||||
case WAIT_OBJECT_0:
|
||||
{
|
||||
ReleaseMutex(DFSVMutex);
|
||||
return false;
|
||||
}
|
||||
case WAIT_TIMEOUT:
|
||||
{
|
||||
// mutex is held by DF
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
case WAIT_FAILED:
|
||||
{
|
||||
// TODO: now how do I respond to this?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHMProcess::Private::validate(VersionInfoFactory * factory)
|
||||
{
|
||||
// try to identify the DF version
|
||||
IMAGE_NT_HEADERS pe_header;
|
||||
IMAGE_SECTION_HEADER sections[16];
|
||||
HMODULE hmod = NULL;
|
||||
DWORD junk;
|
||||
HANDLE hProcess;
|
||||
bool found = false;
|
||||
identified = false;
|
||||
// open process, we only need the process open
|
||||
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, process_ID );
|
||||
if (NULL == hProcess)
|
||||
return false;
|
||||
|
||||
// try getting the first module of the process
|
||||
if(EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk) == 0)
|
||||
{
|
||||
CloseHandle(hProcess);
|
||||
// cout << "EnumProcessModules fail'd" << endl;
|
||||
return false;
|
||||
}
|
||||
// got base ;)
|
||||
uint32_t base = (uint32_t)hmod;
|
||||
|
||||
// read from this process
|
||||
uint32_t pe_offset = self->Process::readDWord(base+0x3C);
|
||||
self->read(base + pe_offset , sizeof(pe_header), (uint8_t *)&pe_header);
|
||||
self->read(base + pe_offset+ sizeof(pe_header), sizeof(sections) , (uint8_t *)§ions );
|
||||
|
||||
VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(pe_header.FileHeader.TimeDateStamp);
|
||||
if(vinfo)
|
||||
{
|
||||
VersionInfo *m = new VersionInfo(*vinfo);
|
||||
m->RebaseAll(base);
|
||||
memdescriptor = m;
|
||||
m->setParentProcess(self);
|
||||
identified = true;
|
||||
vector_start = memdescriptor->getGroup("vector")->getOffset("start");
|
||||
CloseHandle(hProcess);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SHMProcess::getThreadIDs(vector<uint32_t> & threads )
|
||||
{
|
||||
HANDLE AllThreads = INVALID_HANDLE_VALUE;
|
||||
THREADENTRY32 te32;
|
||||
|
||||
AllThreads = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
|
||||
if( AllThreads == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
te32.dwSize = sizeof(THREADENTRY32 );
|
||||
|
||||
if( !Thread32First( AllThreads, &te32 ) )
|
||||
{
|
||||
CloseHandle( AllThreads );
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if( te32.th32OwnerProcessID == d->process_ID )
|
||||
{
|
||||
threads.push_back(te32.th32ThreadID);
|
||||
}
|
||||
} while( Thread32Next(AllThreads, &te32 ) );
|
||||
|
||||
CloseHandle( AllThreads );
|
||||
return true;
|
||||
}
|
||||
|
||||
//FIXME: use VirtualQuery to probe for memory ranges, cross-reference with base-corrected PE segment entries
|
||||
void SHMProcess::getMemRanges( vector<t_memrange> & ranges )
|
||||
{
|
||||
// BLAH
|
||||
ranges.clear();
|
||||
}
|
||||
|
||||
bool SHMProcess::acquireSuspendLock()
|
||||
{
|
||||
return ( WaitForSingleObject(d->DFCLSuspendMutex,INFINITE) == 0 );
|
||||
}
|
||||
|
||||
bool SHMProcess::releaseSuspendLock()
|
||||
{
|
||||
return ( ReleaseMutex(d->DFCLSuspendMutex) != 0);
|
||||
}
|
||||
|
||||
|
||||
bool SHMProcess::attach()
|
||||
{
|
||||
if(d->attached)
|
||||
{
|
||||
if(!d->locked)
|
||||
return suspend();
|
||||
return true;
|
||||
}
|
||||
//cerr << "attach" << endl;// FIXME: throw
|
||||
if(!d->GetLocks())
|
||||
{
|
||||
//cerr << "server is full or not really there!" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate the segment.
|
||||
*/
|
||||
char shmname [256];
|
||||
sprintf(shmname,"DFShm-%d",d->process_ID);
|
||||
HANDLE shmHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS,false,shmname);
|
||||
if(!shmHandle)
|
||||
{
|
||||
d->FreeLocks();
|
||||
//ReleaseMutex(d->DFCLMutex);
|
||||
return false; // we couldn't lock it
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach the segment
|
||||
*/
|
||||
d->shm_addr = (char *) MapViewOfFile(shmHandle,FILE_MAP_ALL_ACCESS, 0,0, SHM_SIZE);
|
||||
if(!d->shm_addr)
|
||||
{
|
||||
CloseHandle(shmHandle);
|
||||
//ReleaseMutex(d->DFCLMutex);
|
||||
d->FreeLocks();
|
||||
return false; // we couldn't attach the mapping // FIXME: throw
|
||||
}
|
||||
// we close the handle right here - it's not needed anymore
|
||||
CloseHandle(shmHandle);
|
||||
|
||||
d->attached = true;
|
||||
if(!suspend())
|
||||
{
|
||||
UnmapViewOfFile(d->shm_addr);
|
||||
d->FreeLocks();
|
||||
//cerr << "unable to suspend" << endl;// FIXME: throw
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHMProcess::detach()
|
||||
{
|
||||
if(!d->attached) return true;
|
||||
if(d->locked)
|
||||
{
|
||||
resume();
|
||||
}
|
||||
// detach segment
|
||||
UnmapViewOfFile(d->shm_addr);
|
||||
// release it for some other client
|
||||
//ReleaseMutex(d->DFCLMutex); // we keep the mutex handles
|
||||
d->FreeLocks();
|
||||
d->attached = false;
|
||||
d->locked = false;
|
||||
d->shm_addr = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SHMProcess::readSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
read(address + d->vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
void SHMProcess::writeSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
write(address + d->vector_start, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
string SHMProcess::doReadClassName (uint32_t vptr)
|
||||
{
|
||||
int rtti = Process::readDWord(vptr - 0x4);
|
||||
int typeinfo = Process::readDWord(rtti + 0xC);
|
||||
string raw = readCString(typeinfo + 0xC); // skips the .?AV
|
||||
raw.resize(raw.length() - 2);// trim @@ from end
|
||||
return raw;
|
||||
}
|
||||
|
||||
string SHMProcess::getPath()
|
||||
{
|
||||
HMODULE hmod;
|
||||
DWORD junk;
|
||||
char String[255];
|
||||
HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, d->process_ID ); //get the handle from the process ID
|
||||
EnumProcessModules(hProcess, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle
|
||||
GetModuleFileNameEx(hProcess,hmod,String,sizeof(String)); //get the filename from the module
|
||||
string out(String);
|
||||
return(out.substr(0,out.find_last_of("\\")));
|
||||
}
|
||||
|
||||
char * SHMProcess::getSHMStart (void)
|
||||
{
|
||||
if(!d->locked) throw Error::MemoryAccessDenied(0xdeadbeef);
|
||||
|
||||
return d->shm_addr;
|
||||
}
|
@ -1,391 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "Internal.h"
|
||||
#include "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
using namespace std;
|
||||
|
||||
#include "ProcessFactory.h"
|
||||
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
#include "dfhack/DFProcessEnumerator.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
typedef std::vector<Process *> PROC_V;
|
||||
typedef std::map<ProcessID, Process*> PID2PROC;
|
||||
|
||||
class DFHack::ProcessEnumerator::Private
|
||||
{
|
||||
public:
|
||||
Private(){};
|
||||
VersionInfoFactory *meminfo;
|
||||
PROC_V Processes;
|
||||
PID2PROC ProcMap;
|
||||
Process *GetProcessObject(ProcessID ID);
|
||||
void EnumPIDs (vector <ProcessID> &PIDs);
|
||||
};
|
||||
|
||||
class DFHack::BadProcesses::Private
|
||||
{
|
||||
public:
|
||||
Private(){};
|
||||
PROC_V bad;
|
||||
};
|
||||
|
||||
BadProcesses::BadProcesses():d(new Private()){}
|
||||
|
||||
BadProcesses::~BadProcesses()
|
||||
{
|
||||
clear();
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool BadProcesses::Contains(Process* p)
|
||||
{
|
||||
for(unsigned int i = 0; i < d->bad.size(); i++)
|
||||
{
|
||||
if(d->bad[i] == p)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BadProcesses::excise(Process* p)
|
||||
{
|
||||
vector<Process*>::iterator it = d->bad.begin();
|
||||
while(it != d->bad.end())
|
||||
{
|
||||
if((*it) == p)
|
||||
{
|
||||
d->bad.erase(it);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t BadProcesses::size()
|
||||
{
|
||||
return d->bad.size();
|
||||
}
|
||||
|
||||
void BadProcesses::clear()
|
||||
{
|
||||
for(unsigned int i = 0; i < d->bad.size(); i++)
|
||||
{
|
||||
delete d->bad[i];
|
||||
}
|
||||
d->bad.clear();
|
||||
}
|
||||
|
||||
void BadProcesses::push_back(Process* p)
|
||||
{
|
||||
if(p)
|
||||
d->bad.push_back(p);
|
||||
}
|
||||
|
||||
Process * BadProcesses::operator[](uint32_t index)
|
||||
{
|
||||
if(index < d->bad.size())
|
||||
return d->bad[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
//FIXME: wasteful
|
||||
Process *ProcessEnumerator::Private::GetProcessObject(ProcessID ID)
|
||||
{
|
||||
Process *p2 = createNormalProcess(ID.pid, meminfo);
|
||||
if(p2->isIdentified())
|
||||
{
|
||||
return p2;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete p2;
|
||||
}
|
||||
#ifdef LINUX_BUILD
|
||||
Process *p3 = createWineProcess(ID.pid, meminfo);
|
||||
if(p3->isIdentified())
|
||||
return p3;
|
||||
else
|
||||
delete p3;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LINUX_BUILD
|
||||
void ProcessEnumerator::Private::EnumPIDs (vector <ProcessID> &PIDs)
|
||||
{
|
||||
DIR *dir_p;
|
||||
struct dirent *dir_entry_p;
|
||||
struct stat st;
|
||||
char fullname[512];
|
||||
fullname[0] = 0;
|
||||
PIDs.clear(); // make sure the vector is clear
|
||||
|
||||
// Open /proc/ directory
|
||||
dir_p = opendir("/proc/");
|
||||
// Reading /proc/ entries
|
||||
while(NULL != (dir_entry_p = readdir(dir_p)))
|
||||
{
|
||||
// Only PID folders (numbers)
|
||||
if (strspn(dir_entry_p->d_name, "0123456789") != strlen(dir_entry_p->d_name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sprintf(fullname, "/proc/%s", dir_entry_p->d_name);
|
||||
int ierr = stat (fullname, &st);
|
||||
if (ierr != 0)
|
||||
{
|
||||
printf("Cannot stat %s: ierr= %d\n", fullname, ierr);
|
||||
continue;
|
||||
}
|
||||
uint64_t Pnum = atoi(dir_entry_p->d_name);
|
||||
uint64_t ctime = st.st_ctime;
|
||||
PIDs.push_back(ProcessID(ctime,Pnum));
|
||||
}
|
||||
closedir(dir_p);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef LINUX_BUILD
|
||||
// some magic - will come in handy when we start doing debugger stuff on Windows
|
||||
bool EnableDebugPriv()
|
||||
{
|
||||
bool bRET = FALSE;
|
||||
TOKEN_PRIVILEGES tp;
|
||||
HANDLE hToken;
|
||||
|
||||
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid))
|
||||
{
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
|
||||
{
|
||||
if (hToken != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||
tp.PrivilegeCount = 1;
|
||||
if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, 0, 0))
|
||||
{
|
||||
bRET = TRUE;
|
||||
}
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bRET;
|
||||
}
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t LowDword;
|
||||
uint32_t HighDword;
|
||||
};
|
||||
uint64_t Quad;
|
||||
} TWO_DWORDS;
|
||||
|
||||
// Convert Windows FileTime structs to POSIX timestamp
|
||||
// from http://frenk.wordpress.com/2009/12/14/convert-filetime-to-unix-timestamp/
|
||||
uint64_t FileTime_to_POSIX(FILETIME ft)
|
||||
{
|
||||
// takes the last modified date
|
||||
TWO_DWORDS date, adjust;
|
||||
date.HighDword = ft.dwHighDateTime;
|
||||
date.LowDword = ft.dwLowDateTime;
|
||||
|
||||
// 100-nanoseconds = milliseconds * 10000
|
||||
adjust.Quad = 11644473600000LL * 10000LL;
|
||||
|
||||
// removes the diff between 1970 and 1601
|
||||
date.Quad -= adjust.Quad;
|
||||
|
||||
// converts back from 100-nanoseconds to seconds
|
||||
return date.Quad / 10000000LL;
|
||||
}
|
||||
|
||||
void ProcessEnumerator::Private::EnumPIDs (vector <ProcessID> &PIDs)
|
||||
{
|
||||
FILETIME ftCreate, ftExit, ftKernel, ftUser;
|
||||
|
||||
PIDs.clear(); // make sure the vector is clear
|
||||
|
||||
// Get the list of process identifiers.
|
||||
DWORD ProcArray[2048], memoryNeeded, numProccesses;
|
||||
if(!EnableDebugPriv())
|
||||
{
|
||||
cerr << "Failed to acquire debug privileges." << endl;
|
||||
}
|
||||
if ( !EnumProcesses( ProcArray, sizeof(ProcArray), &memoryNeeded ) )
|
||||
{
|
||||
cerr << "EnumProcesses fail'd" << endl;
|
||||
return;
|
||||
}
|
||||
// Calculate how many process identifiers were returned.
|
||||
numProccesses = memoryNeeded / sizeof(DWORD);
|
||||
//EnableDebugPriv();
|
||||
// iterate through processes
|
||||
for ( int i = 0; i < (int)numProccesses; i++ )
|
||||
{
|
||||
HANDLE proc = OpenProcess (PROCESS_QUERY_INFORMATION, false, ProcArray[i]);
|
||||
if(!proc)
|
||||
continue;
|
||||
if(GetProcessTimes(proc, &ftCreate, &ftExit, &ftKernel, &ftUser))
|
||||
{
|
||||
uint64_t ctime = FileTime_to_POSIX(ftCreate);
|
||||
uint64_t Pnum = ProcArray[i];
|
||||
PIDs.push_back(ProcessID(ctime,Pnum));
|
||||
}
|
||||
CloseHandle(proc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ProcessEnumerator::Refresh( BadProcesses* invalidated_processes )
|
||||
{
|
||||
// PIDs to process
|
||||
vector <ProcessID> PIDs;
|
||||
// this will be the new process map
|
||||
PID2PROC temporary;
|
||||
// clear the vector
|
||||
d->Processes.clear();
|
||||
if(invalidated_processes)
|
||||
invalidated_processes->clear();
|
||||
|
||||
d->EnumPIDs(PIDs);
|
||||
|
||||
for(uint64_t i = 0; i < PIDs.size();i++)
|
||||
{
|
||||
ProcessID & PID = PIDs[i];
|
||||
// check if we know about the OS process already
|
||||
PID2PROC::iterator found= d->ProcMap.find(PID);
|
||||
if( found != d->ProcMap.end())
|
||||
{
|
||||
// we do
|
||||
// check if it does have a DFHack Process object associated with it
|
||||
Process * p = (*found).second;
|
||||
if(p)
|
||||
{
|
||||
// add it back to the vector we export
|
||||
d->Processes.push_back(p);
|
||||
}
|
||||
// remove the OS Process from ProcMap
|
||||
d->ProcMap.erase(found);
|
||||
// add the OS Process to what will be the new ProcMap
|
||||
temporary[PID] = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// an OS process we don't know yet!
|
||||
// try to make a DFHack Process object for it
|
||||
if(Process*p = d->GetProcessObject(PID))
|
||||
{
|
||||
// allright. this is something that can be used
|
||||
d->Processes.push_back(p);
|
||||
temporary[PID] = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
// just a process. we track it anyway. Why not.
|
||||
temporary[PID] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// now the vector we export is filled again and a temporary map with valid processes is created.
|
||||
// we iterate over the old Process map and destroy all the processes that are dead.
|
||||
for(PID2PROC::const_iterator idx = d->ProcMap.begin(); idx != d->ProcMap.end();++idx)
|
||||
{
|
||||
Process * p = (*idx).second;
|
||||
if(p)
|
||||
{
|
||||
if(invalidated_processes)
|
||||
{
|
||||
invalidated_processes->push_back(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
}
|
||||
d->ProcMap.swap(temporary);
|
||||
// return value depends on if we found some DF processes
|
||||
if(d->Processes.size())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t ProcessEnumerator::size()
|
||||
{
|
||||
return d->Processes.size();
|
||||
}
|
||||
|
||||
|
||||
Process * ProcessEnumerator::operator[](uint32_t index)
|
||||
{
|
||||
assert(index < d->Processes.size());
|
||||
return d->Processes[index];
|
||||
}
|
||||
|
||||
|
||||
ProcessEnumerator::ProcessEnumerator( string path_to_xml )
|
||||
: d(new Private())
|
||||
{
|
||||
d->meminfo = new VersionInfoFactory(path_to_xml);
|
||||
}
|
||||
|
||||
void ProcessEnumerator::purge()
|
||||
{
|
||||
for(uint32_t i = 0;i < d->Processes.size();i++)
|
||||
{
|
||||
delete d->Processes[i];
|
||||
}
|
||||
d->ProcMap.clear();
|
||||
d->Processes.clear();
|
||||
}
|
||||
|
||||
ProcessEnumerator::~ProcessEnumerator()
|
||||
{
|
||||
// delete all processes
|
||||
purge();
|
||||
delete d->meminfo;
|
||||
delete d;
|
||||
}
|
@ -1,326 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <cstring>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/DFIntegers.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack-c/DFProcess_C.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PTR_CHECK if(p_Ptr == NULL) return -1;
|
||||
|
||||
int C_ProcessID_Compare(c_processID* left, c_processID* right)
|
||||
{
|
||||
if(left == NULL || right == NULL)
|
||||
return PROCESSID_C_NULL;
|
||||
else
|
||||
{
|
||||
if(left->time == right->time && left->pid == right->pid)
|
||||
return PROCESSID_C_EQ;
|
||||
else if(left->time < right->time || left->pid < right->pid)
|
||||
return PROCESSID_C_LT;
|
||||
else
|
||||
return PROCESSID_C_GT;
|
||||
}
|
||||
}
|
||||
|
||||
#define FUNCTION_FORWARD(func_name) \
|
||||
int Process_##func_name (DFHackObject* p_Ptr) \
|
||||
{ \
|
||||
if(p_Ptr == NULL) \
|
||||
return -1; \
|
||||
if(((DFHack::Process*)p_Ptr)->func_name()) \
|
||||
return 1; \
|
||||
else \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
FUNCTION_FORWARD(attach)
|
||||
FUNCTION_FORWARD(detach)
|
||||
FUNCTION_FORWARD(suspend)
|
||||
FUNCTION_FORWARD(asyncSuspend)
|
||||
FUNCTION_FORWARD(resume)
|
||||
FUNCTION_FORWARD(forceresume)
|
||||
FUNCTION_FORWARD(isSuspended)
|
||||
FUNCTION_FORWARD(isAttached)
|
||||
FUNCTION_FORWARD(isIdentified)
|
||||
FUNCTION_FORWARD(isSnapshot)
|
||||
|
||||
#define MEMREAD_FUNC_FORWARD(func_name, type) \
|
||||
int Process_##func_name(DFHackObject* p_Ptr, uint32_t address, type* value) \
|
||||
{ \
|
||||
PTR_CHECK \
|
||||
((DFHack::Process*)p_Ptr)->func_name(address, *value); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define MEMWRITE_FUNC_FORWARD(func_name, type) \
|
||||
int Process_##func_name(DFHackObject* p_Ptr, uint32_t address, type value) \
|
||||
{ \
|
||||
PTR_CHECK \
|
||||
((DFHack::Process*)p_Ptr)->func_name(address, value); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readQuad, uint64_t)
|
||||
MEMWRITE_FUNC_FORWARD(writeQuad, uint64_t)
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readDWord, uint32_t)
|
||||
MEMWRITE_FUNC_FORWARD(writeDWord, uint32_t)
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readWord, uint16_t)
|
||||
MEMWRITE_FUNC_FORWARD(writeWord, uint16_t)
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readFloat, float)
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readByte, uint8_t)
|
||||
MEMWRITE_FUNC_FORWARD(writeByte, uint8_t)
|
||||
|
||||
MEMREAD_FUNC_FORWARD(readSTLVector, t_vecTriplet);
|
||||
|
||||
uint8_t* Process_read(DFHackObject* p_Ptr, uint32_t address, uint32_t length)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_ubyte_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
uint8_t* buf;
|
||||
|
||||
((*alloc_ubyte_buffer_callback)(&buf, length));
|
||||
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
|
||||
((DFHack::Process*)p_Ptr)->read(address, length, buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void Process_write(DFHackObject* p_Ptr, uint32_t address, uint32_t length, uint8_t* buffer)
|
||||
{
|
||||
if(p_Ptr == NULL || buffer == NULL)
|
||||
return;
|
||||
|
||||
((DFHack::Process*)p_Ptr)->write(address, length, buffer);
|
||||
}
|
||||
|
||||
const char* Process_readString(DFHackObject* p_Ptr, uint32_t offset)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_char_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
std::string pString = ((DFHack::Process*)p_Ptr)->readSTLString(offset);
|
||||
|
||||
if(pString.length() > 0)
|
||||
{
|
||||
size_t length = pString.length();
|
||||
|
||||
char* buf;
|
||||
|
||||
//add 1 for the null terminator
|
||||
((*alloc_char_buffer_callback)(&buf, length + 1));
|
||||
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(buf, '\n', length + 1);
|
||||
|
||||
pString.copy(buf, length);
|
||||
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
const char* Process_getPath(DFHackObject* p_Ptr)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_char_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
std::string pString = ((DFHack::Process*)p_Ptr)->getPath();
|
||||
|
||||
if(pString.length() > 0)
|
||||
{
|
||||
size_t length = pString.length();
|
||||
|
||||
char* buf;
|
||||
|
||||
//add 1 for the null terminator
|
||||
((*alloc_char_buffer_callback)(&buf, length + 1));
|
||||
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(buf, '\0', length + 1);
|
||||
|
||||
pString.copy(buf, length);
|
||||
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
const char* Process_readClassName(DFHackObject* p_Ptr, uint32_t vptr)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_char_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
std::string cString = ((DFHack::Process*)p_Ptr)->readClassName(vptr);
|
||||
|
||||
if(cString.length() > 0)
|
||||
{
|
||||
size_t length = cString.length();
|
||||
|
||||
char* buf;
|
||||
|
||||
//add 1 for the null terminator
|
||||
((*alloc_char_buffer_callback)(&buf, length + 1));
|
||||
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(buf, '\0', length + 1);
|
||||
|
||||
cString.copy(buf, length);
|
||||
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
uint32_t* Process_getThreadIDs(DFHackObject* p_Ptr)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_uint_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
std::vector<uint32_t> threads;
|
||||
|
||||
if(((DFHack::Process*)p_Ptr)->getThreadIDs(threads))
|
||||
{
|
||||
uint32_t* buf;
|
||||
if(threads.size() > 0)
|
||||
{
|
||||
((*alloc_uint_buffer_callback)(&buf, threads.size()));
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
copy(threads.begin(), threads.end(), buf);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t_memrange* Process_getMemRanges(DFHackObject* p_Ptr)
|
||||
{
|
||||
if(p_Ptr == NULL || alloc_memrange_buffer_callback == NULL)
|
||||
return NULL;
|
||||
|
||||
std::vector<t_memrange> ranges;
|
||||
|
||||
((DFHack::Process*)p_Ptr)->getMemRanges(ranges);
|
||||
|
||||
if(ranges.size() > 0)
|
||||
{
|
||||
t_memrange* buf;
|
||||
uint32_t* rangeDescriptorBuf = (uint32_t*)calloc(ranges.size(), sizeof(uint32_t));
|
||||
|
||||
for(uint32_t i = 0; i < ranges.size(); i++)
|
||||
{
|
||||
t_memrange* r = &ranges[i];
|
||||
rangeDescriptorBuf[i] = (uint32_t)(r->end - r->start);
|
||||
}
|
||||
|
||||
((*alloc_memrange_buffer_callback)(&buf, rangeDescriptorBuf, ranges.size()));
|
||||
free(rangeDescriptorBuf);
|
||||
if(buf == NULL)
|
||||
return NULL;
|
||||
|
||||
for(uint32_t i = 0; i < ranges.size(); i++)
|
||||
{
|
||||
t_memrange* r = &ranges[i];
|
||||
buf[i].start = r->start;
|
||||
buf[i].end = r->end;
|
||||
memset(buf[i].name, '\0', 1024);
|
||||
strncpy(buf[i].name, r->name, 1024);
|
||||
buf[i].read = r->read;
|
||||
buf[i].write = r->write;
|
||||
buf[i].execute = r->execute;
|
||||
buf[i].shared = r->shared;
|
||||
buf[i].valid = r->valid;
|
||||
memcpy(buf[i].buffer, r->buffer, r->end - r->start);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int Process_getPID(DFHackObject* p_Ptr, int32_t* pid)
|
||||
{
|
||||
if(p_Ptr == NULL)
|
||||
{
|
||||
*pid = -1;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pid = ((DFHack::Process*)p_Ptr)->getPID();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int Process_getModuleIndex(DFHackObject* p_Ptr, char* name, uint32_t version, uint32_t* output)
|
||||
{
|
||||
PTR_CHECK
|
||||
|
||||
if(((DFHack::Process*)p_Ptr)->getModuleIndex(name, version, *output))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process_SetAndWait(DFHackObject* p_Ptr, uint32_t state)
|
||||
{
|
||||
PTR_CHECK
|
||||
|
||||
if(((DFHack::Process*)p_Ptr)->SetAndWait(state))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "Internal.h"
|
||||
#include "dfhack/DFTileTypes.h"
|
||||
#include "dfhack-c/DFTileTypes_C.h"
|
||||
|
||||
int DFHack_isWallTerrain(int in)
|
||||
{
|
||||
return DFHack::isWallTerrain(in);
|
||||
}
|
||||
|
||||
int DFHack_isFloorTerrain(int in)
|
||||
{
|
||||
return DFHack::isFloorTerrain(in);
|
||||
}
|
||||
|
||||
int DFHack_isRampTerrain(int in)
|
||||
{
|
||||
return DFHack::isRampTerrain(in);
|
||||
}
|
||||
|
||||
int DFHack_isStairTerrain(int in)
|
||||
{
|
||||
return DFHack::isStairTerrain(in);
|
||||
}
|
||||
|
||||
int DFHack_isOpenTerrain(int in)
|
||||
{
|
||||
return DFHack::isOpenTerrain(in);
|
||||
}
|
||||
|
||||
int DFHack_getVegetationType(int in)
|
||||
{
|
||||
return DFHack::tileShape(in);
|
||||
}
|
||||
|
||||
int DFHack_getTileType(int index, TileRow* tPtr)
|
||||
{
|
||||
if(index >= TILE_TYPE_ARRAY_LENGTH)
|
||||
return 0;
|
||||
|
||||
*tPtr = tileTypeTable[index];
|
||||
return 1;
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "Internal.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack/modules/Materials.h"
|
||||
using namespace DFHack;
|
||||
|
||||
/*
|
||||
I believe this is what they call "the bad kind of clever", but writing out registration functions for each callback just feels *so* wrong...
|
||||
|
||||
The output of this macro is something like this...
|
||||
|
||||
void RegisterByteBufferCallback(int(*fptr)(int8_t*, uint32_t))
|
||||
{
|
||||
alloc_byte_buffer_callback = fptr;
|
||||
}
|
||||
|
||||
*/
|
||||
#define BUILD(a) a ## BufferCallback
|
||||
#define REG_MACRO(type_name, type, callback) void BUILD(Register ## type_name) (int (*fptr)(type, uint32_t)) { callback = fptr; }
|
||||
|
||||
/*
|
||||
The output of this macro is something like this...
|
||||
|
||||
void UnregisterByteBufferCallback()
|
||||
{
|
||||
alloc_byte_buffer_callback = NULL;
|
||||
}
|
||||
|
||||
*/
|
||||
#define UNREG_MACRO(type_name, callback) void BUILD(Unregister ## type_name) () { callback = NULL; }
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int (*alloc_byte_buffer_callback)(int8_t**, uint32_t) = NULL;
|
||||
int (*alloc_short_buffer_callback)(int16_t**, uint32_t) = NULL;
|
||||
int (*alloc_int_buffer_callback)(int32_t**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_ubyte_buffer_callback)(uint8_t**, uint32_t) = NULL;
|
||||
int (*alloc_ushort_buffer_callback)(uint16_t**, uint32_t) = NULL;
|
||||
int (*alloc_uint_buffer_callback)(uint32_t**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_char_buffer_callback)(char**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_matgloss_buffer_callback)(t_matgloss**, uint32_t) = NULL;
|
||||
int (*alloc_descriptor_buffer_callback)(t_descriptor_color**, uint32_t) = NULL;
|
||||
int (*alloc_matgloss_other_buffer_callback)(t_matglossOther**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_feature_buffer_callback)(t_feature**, uint32_t) = NULL;
|
||||
int (*alloc_hotkey_buffer_callback)(t_hotkey**, uint32_t) = NULL;
|
||||
int (*alloc_screen_buffer_callback)(t_screen**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_tree_buffer_callback)(dfh_plant**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_memrange_buffer_callback)(t_memrange**, uint32_t*, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_customWorkshop_buffer_callback)(t_customWorkshop**, uint32_t) = NULL;
|
||||
int (*alloc_material_buffer_callback)(t_material**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_creaturetype_buffer_callback)(c_creaturetype**, c_creaturetype_descriptor*, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_vein_buffer_callback)(t_vein**, uint32_t) = NULL;
|
||||
int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein**, uint32_t) = NULL;
|
||||
int (*alloc_spattervein_buffer_callback)(t_spattervein**, uint32_t) = NULL;
|
||||
int (*alloc_grassvein_buffer_callback)(t_grassvein**, uint32_t) = NULL;
|
||||
int (*alloc_worldconstruction_buffer_callback)(t_worldconstruction**, uint32_t) = NULL;
|
||||
|
||||
int (*alloc_featuremap_buffer_callback)(c_featuremap_node**, uint32_t*, uint32_t) = NULL;
|
||||
|
||||
//int (*alloc_bodypart_buffer_callback)(t_bodypart**, uint32_t) = NULL;
|
||||
REG_MACRO(Byte, int8_t**, alloc_byte_buffer_callback)
|
||||
REG_MACRO(Short, int16_t**, alloc_short_buffer_callback)
|
||||
REG_MACRO(Int, int32_t**, alloc_int_buffer_callback)
|
||||
REG_MACRO(UByte, uint8_t**, alloc_ubyte_buffer_callback)
|
||||
REG_MACRO(UShort, uint16_t**, alloc_ushort_buffer_callback)
|
||||
REG_MACRO(UInt, uint32_t**, alloc_uint_buffer_callback)
|
||||
REG_MACRO(Char, char**, alloc_char_buffer_callback)
|
||||
REG_MACRO(Matgloss, t_matgloss**, alloc_matgloss_buffer_callback)
|
||||
REG_MACRO(DescriptorColor, t_descriptor_color**, alloc_descriptor_buffer_callback)
|
||||
REG_MACRO(MatglossOther, t_matglossOther**, alloc_matgloss_other_buffer_callback)
|
||||
REG_MACRO(Feature, t_feature**, alloc_feature_buffer_callback)
|
||||
REG_MACRO(Hotkey, t_hotkey**, alloc_hotkey_buffer_callback)
|
||||
REG_MACRO(Screen, t_screen**, alloc_screen_buffer_callback)
|
||||
REG_MACRO(Tree, dfh_plant**, alloc_tree_buffer_callback)
|
||||
REG_MACRO(CustomWorkshop, t_customWorkshop**, alloc_customWorkshop_buffer_callback)
|
||||
REG_MACRO(Material, t_material**, alloc_material_buffer_callback)
|
||||
|
||||
void RegisterMemRangeBufferCallback(int (*funcptr)(t_memrange**, uint32_t*, uint32_t))
|
||||
{
|
||||
alloc_memrange_buffer_callback = funcptr;
|
||||
}
|
||||
|
||||
UNREG_MACRO(Byte, alloc_byte_buffer_callback)
|
||||
UNREG_MACRO(Short, alloc_short_buffer_callback)
|
||||
UNREG_MACRO(Int, alloc_int_buffer_callback)
|
||||
UNREG_MACRO(UByte, alloc_ubyte_buffer_callback)
|
||||
UNREG_MACRO(UShort, alloc_ushort_buffer_callback)
|
||||
UNREG_MACRO(UInt, alloc_uint_buffer_callback)
|
||||
UNREG_MACRO(Char, alloc_char_buffer_callback)
|
||||
UNREG_MACRO(Matgloss, alloc_matgloss_buffer_callback)
|
||||
UNREG_MACRO(DescriptorColor, alloc_descriptor_buffer_callback)
|
||||
UNREG_MACRO(MatglossOther, alloc_matgloss_other_buffer_callback)
|
||||
UNREG_MACRO(Feature, alloc_feature_buffer_callback)
|
||||
UNREG_MACRO(Hotkey, alloc_hotkey_buffer_callback)
|
||||
UNREG_MACRO(Screen, alloc_screen_buffer_callback)
|
||||
UNREG_MACRO(Tree, alloc_tree_buffer_callback)
|
||||
UNREG_MACRO(MemRange, alloc_memrange_buffer_callback)
|
||||
UNREG_MACRO(CustomWorkshop, alloc_customWorkshop_buffer_callback)
|
||||
UNREG_MACRO(Material, alloc_material_buffer_callback)
|
||||
|
||||
void RegisterCreatureTypeBufferCallback(int (*funcptr)(c_creaturetype**, c_creaturetype_descriptor*, uint32_t))
|
||||
{
|
||||
alloc_creaturetype_buffer_callback = funcptr;
|
||||
}
|
||||
|
||||
UNREG_MACRO(CreatureType, alloc_creaturetype_buffer_callback)
|
||||
|
||||
REG_MACRO(Vein, t_vein**, alloc_vein_buffer_callback)
|
||||
REG_MACRO(FrozenLiquidVein, t_frozenliquidvein**, alloc_frozenliquidvein_buffer_callback)
|
||||
REG_MACRO(SpatterVein, t_spattervein**, alloc_spattervein_buffer_callback)
|
||||
REG_MACRO(GrassVein, t_grassvein**, alloc_grassvein_buffer_callback)
|
||||
REG_MACRO(WorldConstruction, t_worldconstruction**, alloc_worldconstruction_buffer_callback)
|
||||
|
||||
UNREG_MACRO(Vein, alloc_vein_buffer_callback)
|
||||
UNREG_MACRO(FrozenLiquidVein, alloc_frozenliquidvein_buffer_callback)
|
||||
UNREG_MACRO(SpatterVein, alloc_spattervein_buffer_callback)
|
||||
UNREG_MACRO(GrassVein, alloc_grassvein_buffer_callback)
|
||||
UNREG_MACRO(WorldConstruction, alloc_worldconstruction_buffer_callback)
|
||||
|
||||
void RegisterFeatureMapBufferCallback(int (*funcptr)(c_featuremap_node**, uint32_t*, uint32_t))
|
||||
{
|
||||
alloc_featuremap_buffer_callback = funcptr;
|
||||
}
|
||||
|
||||
UNREG_MACRO(FeatureMap, alloc_featuremap_buffer_callback)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
|
||||
#include "Internal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
using namespace std;
|
||||
|
||||
#include "MicrosoftSTL.h"
|
||||
#include "dfhack/DFProcess.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
|
||||
using namespace DFHack;
|
||||
|
||||
void MicrosoftSTL::init(Process* self)
|
||||
{
|
||||
p = self;
|
||||
OffsetGroup * strGrp = p->getDescriptor()->getGroup("string")->getGroup("MSVC");
|
||||
STLSTR_buf_off = strGrp->getOffset("buffer");
|
||||
STLSTR_size_off = strGrp->getOffset("size");
|
||||
STLSTR_cap_off = strGrp->getOffset("capacity");
|
||||
}
|
||||
|
||||
size_t MicrosoftSTL::readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
|
||||
{
|
||||
uint32_t start_offset = offset + STLSTR_buf_off;
|
||||
size_t length = p->readDWord(offset + STLSTR_size_off);
|
||||
size_t capacity = p->readDWord(offset + STLSTR_cap_off);
|
||||
|
||||
size_t read_real = min(length, bufcapacity-1);// keep space for null termination
|
||||
|
||||
// read data from inside the string structure
|
||||
if(capacity < 16)
|
||||
{
|
||||
p->read(start_offset, read_real , (uint8_t *)buffer);
|
||||
}
|
||||
else // read data from what the offset + 4 dword points to
|
||||
{
|
||||
start_offset = p->readDWord(start_offset);// dereference the start offset
|
||||
p->read(start_offset, read_real, (uint8_t *)buffer);
|
||||
}
|
||||
|
||||
buffer[read_real] = 0;
|
||||
return read_real;
|
||||
}
|
||||
|
||||
const string MicrosoftSTL::readSTLString (uint32_t offset)
|
||||
{
|
||||
uint32_t start_offset = offset + STLSTR_buf_off;
|
||||
size_t length = p->readDWord(offset + STLSTR_size_off);
|
||||
size_t capacity = p->readDWord(offset + STLSTR_cap_off);
|
||||
|
||||
char * temp = new char[capacity+1];
|
||||
|
||||
// read data from inside the string structure
|
||||
if(capacity < 16)
|
||||
{
|
||||
p->read(start_offset, capacity, (uint8_t *)temp);
|
||||
}
|
||||
else // read data from what the offset + 4 dword points to
|
||||
{
|
||||
start_offset = p->readDWord(start_offset);// dereference the start offset
|
||||
p->read(start_offset, capacity, (uint8_t *)temp);
|
||||
}
|
||||
|
||||
temp[length] = 0;
|
||||
string ret = temp;
|
||||
delete temp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
string MicrosoftSTL::readClassName (uint32_t vptr)
|
||||
{
|
||||
int rtti = p->readDWord(vptr - 0x4);
|
||||
int typeinfo = p->readDWord(rtti + 0xC);
|
||||
string raw = p->readCString(typeinfo + 0xC); // skips the .?AV
|
||||
raw.resize(raw.length() - 2);// trim @@ from end
|
||||
return raw;
|
||||
}
|
||||
|
||||
// FIXME: really, fix this.
|
||||
size_t MicrosoftSTL::writeSTLString(const uint32_t address, const std::string writeString)
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2011 Petr Mrázek (peterix)
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product documentation
|
||||
would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
*/
|
||||
#include "Internal.h"
|
||||
#include "PlatformInternal.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
using namespace std;
|
||||
|
||||
#include "dfhack/Process.h"
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
#include "dfhack/VersionInfo.h"
|
||||
#include "dfhack/Error.h"
|
||||
#include <errno.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <md5wrapper.h>
|
||||
using namespace DFHack;
|
||||
|
||||
Process::Process(VersionInfoFactory * known_versions)
|
||||
{
|
||||
const char * dir_name = "/proc/self/";
|
||||
const char * exe_link_name = "/proc/self/exe";
|
||||
const char * cwd_name = "/proc/self/cwd";
|
||||
const char * cmdline_name = "/proc/self/cmdline";
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
|
||||
identified = false;
|
||||
my_descriptor = 0;
|
||||
|
||||
// resolve /proc/self/exe link
|
||||
target_result = readlink(exe_link_name, target_name, sizeof(target_name)-1);
|
||||
if (target_result == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// make sure we have a null terminated string...
|
||||
target_name[target_result] = 0;
|
||||
|
||||
// is this the regular linux DF?
|
||||
if (strstr(target_name, "dwarfort.exe") != 0 || strstr(target_name,"Dwarf_Fortress") != 0)
|
||||
{
|
||||
md5wrapper md5;
|
||||
// get hash of the running DF process
|
||||
string hash = md5.getHashFromFile(target_name);
|
||||
// create linux process, add it to the vector
|
||||
VersionInfo * vinfo = known_versions->getVersionInfoByMD5(hash);
|
||||
if(vinfo)
|
||||
{
|
||||
my_descriptor = new VersionInfo(*vinfo);
|
||||
my_descriptor->setParentProcess(this);
|
||||
identified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Process::readSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
read(address, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
void Process::writeSTLVector(const uint32_t address, t_vecTriplet & triplet)
|
||||
{
|
||||
write(address, sizeof(triplet), (uint8_t *) &triplet);
|
||||
}
|
||||
|
||||
string Process::doReadClassName (uint32_t vptr)
|
||||
{
|
||||
int typeinfo = Process::readDWord(vptr - 0x4);
|
||||
int typestring = Process::readDWord(typeinfo + 0x4);
|
||||
string raw = readCString(typestring);
|
||||
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
|
||||
size_t end = raw.length();
|
||||
return raw.substr(start,end-start);
|
||||
}
|
||||
|
||||
//FIXME: cross-reference with ELF segment entries?
|
||||
void Process::getMemRanges( vector<t_memrange> & ranges )
|
||||
{
|
||||
char buffer[1024];
|
||||
char permissions[5]; // r/-, w/-, x/-, p/s, 0
|
||||
|
||||
FILE *mapFile = ::fopen("/proc/self/maps", "r");
|
||||
size_t start, end, offset, device1, device2, node;
|
||||
|
||||
while (fgets(buffer, 1024, mapFile))
|
||||
{
|
||||
t_memrange temp;
|
||||
temp.name[0] = 0;
|
||||
sscanf(buffer, "%zx-%zx %s %zx %2zu:%2zu %zu %[^\n]s",
|
||||
&start,
|
||||
&end,
|
||||
(char*)&permissions,
|
||||
&offset, &device1, &device2, &node,
|
||||
(char*)&temp.name);
|
||||
temp.start = start;
|
||||
temp.end = end;
|
||||
temp.read = permissions[0] == 'r';
|
||||
temp.write = permissions[1] == 'w';
|
||||
temp.execute = permissions[2] == 'x';
|
||||
temp.shared = permissions[3] == 's';
|
||||
temp.valid = true;
|
||||
ranges.push_back(temp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int getdir (string dir, vector<string> &files)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *dirp;
|
||||
if((dp = opendir(dir.c_str())) == NULL)
|
||||
{
|
||||
cout << "Error(" << errno << ") opening " << dir << endl;
|
||||
return errno;
|
||||
}
|
||||
while ((dirp = readdir(dp)) != NULL) {
|
||||
files.push_back(string(dirp->d_name));
|
||||
}
|
||||
closedir(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Process::getThreadIDs(vector<uint32_t> & threads )
|
||||
{
|
||||
stringstream ss;
|
||||
vector<string> subdirs;
|
||||
if(getdir("/proc/self/task/",subdirs) != 0)
|
||||
{
|
||||
//FIXME: needs exceptions. this is a fatal error
|
||||
cerr << "unable to enumerate threads. This is BAD!" << endl;
|
||||
return false;
|
||||
}
|
||||
threads.clear();
|
||||
for(size_t i = 0; i < subdirs.size();i++)
|
||||
{
|
||||
uint32_t tid;
|
||||
if(sscanf(subdirs[i].c_str(),"%d", &tid))
|
||||
{
|
||||
threads.push_back(tid);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string Process::getPath()
|
||||
{
|
||||
const char * cwd_name = "/proc/self/cwd";
|
||||
char target_name[1024];
|
||||
int target_result;
|
||||
target_result = readlink(cwd_name, target_name, sizeof(target_name));
|
||||
target_name[target_result] = '\0';
|
||||
return(string(target_name));
|
||||
}
|
||||
|
||||
int Process::getPID()
|
||||
{
|
||||
return getpid();
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// vim: sts=4 sta et shiftwidth=4:
|
||||
#include "dfhack/DFIntegers.h"
|
||||
#include "dfhack/DFTileTypes.h"
|
||||
#include "dfhack/DFExport.h"
|
||||
#include "dfhack/Integers.h"
|
||||
#include "dfhack/TileTypes.h"
|
||||
#include "dfhack/Export.h"
|
||||
|
||||
namespace DFHack
|
||||
{
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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
|
||||
#ifndef DFHACK_C_API
|
||||
#define DFHACK_C_API
|
||||
|
||||
#include "dfhack/DFPragma.h"
|
||||
|
||||
#include "dfhack/DFExport.h"
|
||||
#include "dfhack/DFIntegers.h"
|
||||
|
||||
typedef void DFHackObject;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace DFHack {};
|
||||
using namespace DFHack;
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
// some global stuff here
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* www.sourceforge.net/projects/dfhack
|
||||
* Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef DFHACK_C_API
|
||||
#define DFHACK_C_API
|
||||
|
||||
#define HBUILD(a) a ## BufferCallback
|
||||
#define HREG_MACRO(type_name, type) DFHACK_EXPORT void HBUILD(Register ## type_name) (int (*funcptr)(type, uint32_t));
|
||||
|
||||
#define HUNREG_MACRO(type_name) DFHACK_EXPORT void HBUILD(Unregister ## type_name) ();
|
||||
|
||||
#include "dfhack/DFPragma.h"
|
||||
|
||||
#include "dfhack/DFExport.h"
|
||||
#include "dfhack/DFIntegers.h"
|
||||
|
||||
typedef void DFHackObject;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
namespace DFHack {};
|
||||
using namespace DFHack;
|
||||
extern "C" {
|
||||
#endif
|
||||
// some global stuff here
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,157 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef DFHACK_C_CONTEXT
|
||||
#define DFHACK_C_CONTEXT
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Allocates a new ContextManager.
|
||||
@param path_to_xml A const string pointer containing the path to the Memory.xml file.
|
||||
@return A DFHackObject pointer that points to the allocated ContextManager.
|
||||
*/
|
||||
DFHACK_EXPORT DFHackObject* ContextManager_Alloc(const char* path_to_xml);
|
||||
|
||||
/**
|
||||
Frees a previously allocated ContextManager.
|
||||
@param contextMgr A DFHackObject pointer that points to a previously allocated ContextManager.
|
||||
@return None.
|
||||
*/
|
||||
DFHACK_EXPORT void ContextManager_Free(DFHackObject* contextMgr);
|
||||
|
||||
DFHACK_EXPORT int ContextManager_Refresh(DFHackObject* contextMgr);
|
||||
|
||||
/**
|
||||
Gets the number of active DF processes.
|
||||
@param contextMgr A pointer to an active ContextManager.
|
||||
@param size A pointer to an unsigned 32-bit integer that will contain the count of active DF processes.
|
||||
@return
|
||||
- 0: Failure.
|
||||
- 1: Success.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int ContextManager_size(DFHackObject* contextMgr, uint32_t* size);
|
||||
|
||||
DFHACK_EXPORT int ContextManager_purge(DFHackObject* contextMgr);
|
||||
DFHACK_EXPORT DFHackObject* ContextManager_getContext(DFHackObject* contextMgr, uint32_t index);
|
||||
DFHACK_EXPORT DFHackObject* ContextManager_getSingleContext(DFHackObject* contextMgr);
|
||||
|
||||
/**
|
||||
Frees a previously allocated Context.
|
||||
@param context A DFHackObject pointer that points to a previously allocated Context.
|
||||
@return None.
|
||||
*/
|
||||
DFHACK_EXPORT void Context_Free(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Attaches to a running DF process.
|
||||
@param context A pointer to an unattached Context.
|
||||
@return
|
||||
- 0: Failure.
|
||||
- 1: Success.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_Attach(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Detaches from a tracked DF process.
|
||||
@param context A pointer to an attached Context.
|
||||
@return
|
||||
- 0: Failure.
|
||||
- 1: Success.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_Detach(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Determines whether or not the given Context is attached to a running DF process.
|
||||
@param context A pointer to an attached Context.
|
||||
@return
|
||||
- 0: The supplied Context is not attached.
|
||||
- 1: The supplied Context is attached.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_isAttached(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Suspends a running DF process.
|
||||
@param context A pointer to an attached Context.
|
||||
@return
|
||||
- 0: The tracked process was not suspended.
|
||||
- 1: The tracked process was suspended.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_Suspend(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Resume a running DF process.
|
||||
@param context A pointer to an attached Context.
|
||||
@return
|
||||
- 0: The tracked process was not resumed.
|
||||
- 1: The tracked process was resumed.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_Resume(DFHackObject* context);
|
||||
|
||||
/**
|
||||
Determines whether or not the given Context's tracked process is suspended.
|
||||
@param context A pointer to an attached Context.
|
||||
@return
|
||||
- 0: The tracked process is not suspended.
|
||||
- 1: The tracked process is suspended.
|
||||
- -1: An invalid pointer was supplied.
|
||||
*/
|
||||
DFHACK_EXPORT int Context_isSuspended(DFHackObject* context);
|
||||
DFHACK_EXPORT int Context_ForceResume(DFHackObject* context);
|
||||
DFHACK_EXPORT int Context_AsyncSuspend(DFHackObject* context);
|
||||
|
||||
DFHACK_EXPORT DFHackObject* Context_getMemoryInfo(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getProcess(DFHackObject* context);
|
||||
|
||||
DFHACK_EXPORT DFHackObject* Context_getCreatures(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getMaps(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getGui(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getMaterials(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getTranslation(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getVegetation(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getBuildings(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getConstructions(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getItems(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getWorld(DFHackObject* context);
|
||||
DFHACK_EXPORT DFHackObject* Context_getWindowIO(DFHackObject* context);
|
||||
|
||||
//these are DANGEROUS...can crash/segfault DF, turn the seas to blood, call up the Antichrist, etc
|
||||
DFHACK_EXPORT void Context_ReadRaw(DFHackObject* context, const uint32_t offset, const uint32_t size, uint8_t* target);
|
||||
DFHACK_EXPORT void Context_WriteRaw(DFHackObject* context, const uint32_t offset, const uint32_t size, uint8_t* source);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef PROCESS_C_API
|
||||
#define PROCESS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFProcess.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct c_processID
|
||||
{
|
||||
uint64_t time;
|
||||
uint64_t pid;
|
||||
};
|
||||
|
||||
#define PROCESSID_C_NULL -2
|
||||
#define PROCESSID_C_LT -1
|
||||
#define PROCESSID_C_EQ 0
|
||||
#define PROCESSID_C_GT 1
|
||||
|
||||
DFHACK_EXPORT extern int C_ProcessID_Compare(c_processID* left, c_processID* right);
|
||||
|
||||
DFHACK_EXPORT int Process_attach(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_detach(DFHackObject* p_Ptr);
|
||||
|
||||
DFHACK_EXPORT int Process_suspend(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_asyncSuspend(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_resume(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_forceresume(DFHackObject* p_Ptr);
|
||||
|
||||
DFHACK_EXPORT int Process_readQuad(DFHackObject* p_Ptr, uint32_t address, uint64_t* value);
|
||||
DFHACK_EXPORT int Process_writeQuad(DFHackObject* p_Ptr, uint32_t address, uint64_t value);
|
||||
|
||||
DFHACK_EXPORT int Process_readDWord(DFHackObject* p_Ptr, uint32_t address, uint32_t* value);
|
||||
DFHACK_EXPORT int Process_writeDWord(DFHackObject* p_Ptr, uint32_t address, uint32_t value);
|
||||
|
||||
DFHACK_EXPORT int Process_readWord(DFHackObject* p_Ptr, uint32_t address, uint16_t* value);
|
||||
DFHACK_EXPORT int Process_writeWord(DFHackObject* p_Ptr, uint32_t address, uint16_t value);
|
||||
|
||||
DFHACK_EXPORT int Process_readFloat(DFHackObject* p_Ptr, uint32_t address, float* value);
|
||||
|
||||
DFHACK_EXPORT int Process_readByte(DFHackObject* p_Ptr, uint32_t address, uint8_t* value);
|
||||
DFHACK_EXPORT int Process_writeByte(DFHackObject* p_Ptr, uint32_t address, uint8_t value);
|
||||
|
||||
DFHACK_EXPORT uint8_t* Process_read(DFHackObject* p_Ptr, uint32_t address, uint32_t length);
|
||||
DFHACK_EXPORT void Process_write(DFHackObject* p_Ptr, uint32_t address, uint32_t length, uint8_t* buffer);
|
||||
|
||||
DFHACK_EXPORT int Process_readSTLVector(DFHackObject* p_Ptr, uint32_t address, t_vecTriplet* vector);
|
||||
|
||||
DFHACK_EXPORT const char* Process_readString(DFHackObject* p_Ptr, uint32_t offset);
|
||||
DFHACK_EXPORT const char* Process_getPath(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT const char* Process_readClassName(DFHackObject* p_Ptr, uint32_t vptr);
|
||||
|
||||
DFHACK_EXPORT int Process_isSuspended(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_isAttached(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_isIdentified(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_isSnapshot(DFHackObject* p_Ptr);
|
||||
|
||||
DFHACK_EXPORT uint32_t* Process_getThreadIDs(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT t_memrange* Process_getMemRanges(DFHackObject* p_Ptr);
|
||||
DFHACK_EXPORT int Process_getPID(DFHackObject* p_Ptr, int32_t* pid);
|
||||
|
||||
DFHACK_EXPORT int Process_getModuleIndex(DFHackObject* p_Ptr, char* name, uint32_t version, uint32_t* output);
|
||||
|
||||
DFHACK_EXPORT int Process_SetAndWait(DFHackObject* p_Ptr, uint32_t state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef TILETYPES_C_API
|
||||
#define TILETYPES_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTileTypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int DFHack_isWallTerrain(int in);
|
||||
DFHACK_EXPORT int DFHack_isFloorTerrain(int in);
|
||||
DFHACK_EXPORT int DFHack_isRampTerrain(int in);
|
||||
DFHACK_EXPORT int DFHack_isStairTerrain(int in);
|
||||
DFHACK_EXPORT int DFHack_isOpenTerrain(int in);
|
||||
DFHACK_EXPORT int DFHack_getVegetationType(int in);
|
||||
|
||||
DFHACK_EXPORT int DFHack_getTileType(int index, TileRow* tPtr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,262 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef TYPES_C_API
|
||||
#define TYPES_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "DFProcess_C.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Maps.h"
|
||||
#include "dfhack/modules/Materials.h"
|
||||
#include "dfhack/modules/Gui.h"
|
||||
|
||||
#define HBUILD(a) a ## BufferCallback
|
||||
#define HREG_MACRO(type_name, type) DFHACK_EXPORT void HBUILD(Register ## type_name) (int (*funcptr)(type, uint32_t));
|
||||
|
||||
#define HUNREG_MACRO(type_name) DFHACK_EXPORT void HBUILD(Unregister ## type_name) ();
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_byte_buffer_callback)(int8_t**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_short_buffer_callback)(int16_t**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_int_buffer_callback)(int32_t**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_ubyte_buffer_callback)(uint8_t**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_ushort_buffer_callback)(uint16_t**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_uint_buffer_callback)(uint32_t**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_char_buffer_callback)(char**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_matgloss_buffer_callback)(t_matgloss**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_descriptor_buffer_callback)(t_descriptor_color**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_matgloss_other_buffer_callback)(t_matglossOther**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_feature_buffer_callback)(t_feature**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_hotkey_buffer_callback)(t_hotkey**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_screen_buffer_callback)(t_screen**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_tree_buffer_callback)(dfh_plant**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_memrange_buffer_callback)(t_memrange**, uint32_t*, uint32_t);
|
||||
|
||||
DFHACK_EXPORT void RegisterByteBufferCallback(int (*funcptr)(int8_t**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterShortBufferCallback(int (*funcptr)(int16_t**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterIntBufferCallback(int (*funcptr)(int32_t**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterUByteBufferCallback(int (*funcptr)(uint8_t**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterUShortBufferCallback(int (*funcptr)(uint16_t**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterUIntBufferCallback(int (*funcptr)(uint32_t**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterCharBufferCallback(int (*funcptr)(char**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterMatglossBufferCallback(int (*funcptr)(t_matgloss**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterDescriptorColorBufferCallback(int (*funcptr)(t_descriptor_color**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterMatglossOtherBufferCallback(int (*funcptr)(t_matglossOther**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterFeatureBufferCallback(int (*funcptr)(t_feature**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterHotkeyBufferCallback(int (*funcptr)(t_hotkey**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterScreenBufferCallback(int (*funcptr)(t_screen**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterTreeBufferCallback(int (*funcptr)(dfh_plant**, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterMemRangeBufferCallback(int (*funcptr)(t_memrange**, uint32_t*, uint32_t));
|
||||
|
||||
HUNREG_MACRO(Byte)
|
||||
HUNREG_MACRO(Short)
|
||||
HUNREG_MACRO(Int)
|
||||
HUNREG_MACRO(UByte)
|
||||
HUNREG_MACRO(UShort)
|
||||
HUNREG_MACRO(UInt)
|
||||
|
||||
HUNREG_MACRO(Char)
|
||||
|
||||
HUNREG_MACRO(Matgloss)
|
||||
HUNREG_MACRO(DescriptorColor)
|
||||
HUNREG_MACRO(MatglossOther)
|
||||
|
||||
HUNREG_MACRO(Feature)
|
||||
HUNREG_MACRO(Hotkey)
|
||||
HUNREG_MACRO(Screen)
|
||||
|
||||
HUNREG_MACRO(Tree)
|
||||
HUNREG_MACRO(MemRange)
|
||||
|
||||
struct t_customWorkshop
|
||||
{
|
||||
uint32_t index;
|
||||
char name[256];
|
||||
};
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_customWorkshop_buffer_callback)(t_customWorkshop**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_material_buffer_callback)(t_material**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT void RegisterCustomWorkshopBufferCallback(int (*funcptr)(t_customWorkshop**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterMaterialBufferCallback(int (*funcptr)(t_material**, uint32_t));
|
||||
|
||||
HUNREG_MACRO(CustomWorkshop)
|
||||
HUNREG_MACRO(Material)
|
||||
|
||||
struct c_colormodifier
|
||||
{
|
||||
char part[128];
|
||||
uint32_t* colorlist;
|
||||
uint32_t colorlistLength;
|
||||
uint32_t startdate;
|
||||
uint32_t enddate;
|
||||
};
|
||||
|
||||
struct c_colormodifier_descriptor
|
||||
{
|
||||
uint32_t colorlistLength;
|
||||
};
|
||||
|
||||
struct c_creaturecaste
|
||||
{
|
||||
char rawname[128];
|
||||
char singular[128];
|
||||
char plural[128];
|
||||
char adjective[128];
|
||||
|
||||
c_colormodifier* colorModifier;
|
||||
uint32_t colorModifierLength;
|
||||
|
||||
t_bodypart* bodypart;
|
||||
uint32_t bodypartLength;
|
||||
|
||||
t_attrib strength;
|
||||
t_attrib agility;
|
||||
t_attrib toughness;
|
||||
t_attrib endurance;
|
||||
t_attrib recuperation;
|
||||
t_attrib disease_resistance;
|
||||
t_attrib analytical_ability;
|
||||
t_attrib focus;
|
||||
t_attrib willpower;
|
||||
t_attrib creativity;
|
||||
t_attrib intuition;
|
||||
t_attrib patience;
|
||||
t_attrib memory;
|
||||
t_attrib linguistic_ability;
|
||||
t_attrib spatial_sense;
|
||||
t_attrib musicality;
|
||||
t_attrib kinesthetic_sense;
|
||||
};
|
||||
|
||||
struct c_creaturecaste_descriptor
|
||||
{
|
||||
c_colormodifier_descriptor* color_descriptors;
|
||||
uint32_t colorModifierLength;
|
||||
uint32_t bodypartLength;
|
||||
};
|
||||
|
||||
struct c_creaturetype
|
||||
{
|
||||
char rawname[128];
|
||||
|
||||
c_creaturecaste* castes;
|
||||
uint32_t castesCount;
|
||||
|
||||
t_creatureextract* extract;
|
||||
uint32_t extractCount;
|
||||
|
||||
uint8_t tile_character;
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t fore;
|
||||
uint16_t back;
|
||||
uint16_t bright;
|
||||
} tilecolor;
|
||||
};
|
||||
|
||||
struct c_creaturetype_descriptor
|
||||
{
|
||||
c_creaturecaste_descriptor* caste_descriptors;
|
||||
uint32_t castesCount;
|
||||
uint32_t extractCount;
|
||||
};
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_creaturetype_buffer_callback)(c_creaturetype**, c_creaturetype_descriptor*, uint32_t);
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_vein_buffer_callback)(t_vein**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_frozenliquidvein_buffer_callback)(t_frozenliquidvein**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_spattervein_buffer_callback)(t_spattervein**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_grassvein_buffer_callback)(t_grassvein**, uint32_t);
|
||||
DFHACK_EXPORT extern int (*alloc_worldconstruction_buffer_callback)(t_worldconstruction**, uint32_t);
|
||||
|
||||
DFHACK_EXPORT void RegisterCreatureTypeBufferCallback(int (*funcptr)(c_creaturetype**, c_creaturetype_descriptor*, uint32_t));
|
||||
|
||||
DFHACK_EXPORT void RegisterVeinBufferCallback(int (*funcptr)(t_vein**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterFrozenLiquidVeinBufferCallback(int (*funcptr)(t_frozenliquidvein**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterSpatterVeinBufferCallback(int (*funcptr)(t_spattervein**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterGrassVeinBufferCallback(int (*funcptr)(t_grassvein**, uint32_t));
|
||||
DFHACK_EXPORT void RegisterWorldConstructionBufferCallback(int (*funcptr)(t_worldconstruction**, uint32_t));
|
||||
|
||||
HUNREG_MACRO(CreatureType)
|
||||
|
||||
HUNREG_MACRO(Vein)
|
||||
HUNREG_MACRO(FrozenLiquidVein)
|
||||
HUNREG_MACRO(SpatterVein)
|
||||
HUNREG_MACRO(GrassVein)
|
||||
HUNREG_MACRO(WorldConstruction)
|
||||
|
||||
struct c_mapcoord
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
uint32_t z;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
} dim;
|
||||
|
||||
uint64_t comparate;
|
||||
};
|
||||
};
|
||||
|
||||
struct c_featuremap_node
|
||||
{
|
||||
c_mapcoord coordinate;
|
||||
t_feature* features;
|
||||
uint32_t feature_length;
|
||||
};
|
||||
|
||||
DFHACK_EXPORT extern int (*alloc_featuremap_buffer_callback)(c_featuremap_node**, uint32_t*, uint32_t);
|
||||
|
||||
DFHACK_EXPORT void RegisterFeatureMapBufferCallback(int (*funcptr)(c_featuremap_node**, uint32_t*, uint32_t));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,133 +0,0 @@
|
||||
=======================================
|
||||
Introduction And Reasons For Existence
|
||||
=======================================
|
||||
|
||||
C++ is not an easy language to access from other languages. There are several "features" that make interoperability considerably more painful when trying to write bindings for Python, Ruby, Lua, or whatever. To that end, dfhack has a C translation layer to ease the process of making bindings for other languages. A shadow API, if you will.
|
||||
|
||||
.. contents::
|
||||
|
||||
|
||||
=================
|
||||
Getting DFHack-C
|
||||
=================
|
||||
The C shim is a part of the standard dfhack package. If you've installed dfhack, you've already got it. The dfhack source and binaries are hosted on github_, at http://github.com/peterix/dfhack
|
||||
|
||||
.. _github: http://www.github.com/
|
||||
|
||||
Packages
|
||||
=========
|
||||
The library and tools are packaged for Archlinux and are available both
|
||||
in AUR and the arch-games repository.
|
||||
|
||||
The package name is dfhack-git.
|
||||
|
||||
========
|
||||
Layout
|
||||
========
|
||||
The structure of the C shim mimics, as far as possible, the normal dfhack structure. Of course, since C lacks things like classes, templates, and function overloading, there are a few places where deviations are unavoidable.
|
||||
|
||||
Return Values
|
||||
=============
|
||||
Unless otherwise specified, functions that return an int return one of the following values:
|
||||
|
||||
- 0: The operation failed.
|
||||
- 1: The operation succeeded.
|
||||
- -1: An invalid module pointer was supplied.
|
||||
|
||||
Types
|
||||
=======
|
||||
Module objects are passed around as void pointers with the typedef name 'DFHackObject'. Wherever possible, the structures and enumerations defined by dfhack are used without redefinition.
|
||||
|
||||
Allocator Callbacks
|
||||
====================
|
||||
Wherever possible, the C shim eschews the native allocation of memory, as this would require language bindings to remember to free the memory later, and would, in my opinion, make the shim less flexible. So a number of function pointers are exposed to allow memory to be allocated in the language being used to wrap dfhack. In general, the allocations relate to arrays of dfhack structures, but there are a couple of corner cases.
|
||||
|
||||
The buffer callback functions should take a pointer to an array of the particular type, and a 32-bit unsigned integer (uint32_t) defining the length of the array needed. If the buffer was successfully created, the callback function should return 1. In case of failure, set the buffer pointer to NULL (or 0) and return 0.
|
||||
|
||||
All of the allocators are defined in dfhack/library/include/dfhack-c/DFTypes_C.h.
|
||||
|
||||
Buffer Callback List
|
||||
---------------------
|
||||
- alloc_byte_buffer_callback(int8_t**, uint32_t)
|
||||
- alloc_short_buffer_callback(int16_t**, uint32_t)
|
||||
- alloc_int_buffer_callback(int32_t**, uint32_t)
|
||||
- alloc_ubyte_buffer_callback(uint8_t**, uint32_t)
|
||||
- alloc_ushort_buffer_callback(uint16_t**, uint32_t)
|
||||
- alloc_uint_buffer_callback(uint32_t**, uint32_t)
|
||||
- alloc_char_buffer_callback(char** uint32_t)
|
||||
- alloc_matgloss_buffer_callback(t_matgloss**, uint32_t)
|
||||
- alloc_descriptor_buffer_callback(t_descriptor_color**, uint32_t)
|
||||
- alloc_matgloss_other_buffer_callback(t_matglossOther**, uint32_t)
|
||||
- alloc_t_feature_buffer_callback(t_feature**, uint32_t)
|
||||
- alloc_t_hotkey_buffer_callback(t_hotkey**, uint32_t)
|
||||
- alloc_t_screen_buffer_callback(t_screen**, uint32_t)
|
||||
- alloc_t_customWorkshop_buffer_callback(t_customWorkshop**, uint32_t)
|
||||
- alloc_t_material_buffer_callback(t_material**, uint32_t)
|
||||
- alloc_vein_buffer_callback(t_vein**, uint32_t)
|
||||
- alloc_frozenliquidvein_buffer_callback(t_frozenliquidvein**, uint32_t)
|
||||
- alloc_spattervein_buffer_callback(t_spattervein**, uint32_t)
|
||||
- alloc_grassvein_buffer_callback(t_grassvein**, uint32_t)
|
||||
- alloc_worldconstruction_buffer_callback(t_worldconstruction**, uint32_t)
|
||||
|
||||
|
||||
Templates Make My Life Harder
|
||||
-------------------------------
|
||||
Several dfhack structures contain vectors, which (obviously) don't work in C. Therefore, these structures have C versions that replace the vector with a buffer and length, but are otherwise identical to their C++ counterparts. For each structure, there are three associated callbacks. One initializes an empty instance of the structure (*alloc_empty_colormodifier_callback*, for instance), one initializes an instance with values passed in (*alloc_colormodifier_callback*), and one allocates a buffer in the same manner as the other allocators (*alloc_colormodifier_buffer_callback*).
|
||||
|
||||
The replaced structures and their callbacks are as follows.
|
||||
|
||||
- c_colormodifier
|
||||
* alloc_empty_colormodifier_callback(c_colormodifier*)
|
||||
* alloc_colormodifier_callback(c_colormodifier*, const char*, uint32_t)
|
||||
* alloc_colormodifier_buffer_callback(c_colormodifier*, uint32_t)
|
||||
- c_creaturecaste
|
||||
* alloc_empty_creaturecaste_callback(c_creaturecaste*)
|
||||
* alloc_creaturecaste_callback(c_creaturecaste*, const char*, const char*, const char*, const char*, uint32_t, uint32_t)
|
||||
* alloc_creaturecaste_buffer_callback(c_creaturecaste*, uint32_t)
|
||||
- c_creaturetype
|
||||
* alloc_empty_creaturetype_callback(c_creaturetype*)
|
||||
* alloc_creaturetype_callback(c_creaturetype*, const char*, uint32_t, uint32_t, uint8_t, uint16_t, uint16_t, uint16_t)
|
||||
* alloc_creaturetype_buffer_callback(c_creaturetype*, uint32_t)
|
||||
|
||||
A Small Callback Example In Python
|
||||
-------------------------------------
|
||||
The Python bindings for dfhack implement the unsigned integer allocator callback like this:
|
||||
|
||||
.. admonition:: util.py
|
||||
|
||||
| from ctypes import \*
|
||||
|
|
||||
| def _allocate_array(t_type, count):
|
||||
| arr_type = t_type * count
|
||||
| arr = arr_type()
|
||||
|
|
||||
| return arr
|
||||
|
|
||||
| def _alloc_uint_buffer(ptr, count):
|
||||
| a = _allocate_array(c_uint, count)
|
||||
|
|
||||
| p = cast(a, POINTER(c_uint))
|
||||
|
|
||||
| ptr[0] = p
|
||||
|
|
||||
| return 1
|
||||
|
|
||||
| _uint_functype = CFUNCTYPE(c_int, POINTER(c_uint), c_uint)
|
||||
| alloc_uint_buffer = _uint_functype(_alloc_uint_buffer)
|
||||
|
||||
.. admonition:: dftypes.py
|
||||
|
||||
| from ctypes import \*
|
||||
| from util import \*
|
||||
|
|
||||
| libdfhack = cdll.libdfhack
|
||||
|
|
||||
| def _register_callback(name, func):
|
||||
| ptr = c_void_p.in_dll(libdfhack, name)
|
||||
| ptr.value = cast(func, c_void_p).value
|
||||
|
|
||||
| _register_callback("alloc_uint_buffer_callback", alloc_uint_buffer)
|
||||
|
||||
Modules
|
||||
========
|
||||
Every dfhack module has a corresponding set of C functions. The functions are named <MODULE>_<FUNCTION>, as in 'Maps_Start', 'Materials_ReadOthers', etc. The first argument to any module function is a void pointer that points to an instance of the module object in question.
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef BUILDINGS_C_API
|
||||
#define BUILDINGS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Buildings.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Buildings_Start(DFHackObject* b_Ptr, uint32_t* numBuildings);
|
||||
DFHACK_EXPORT int Buildings_Finish(DFHackObject* b_Ptr);
|
||||
|
||||
DFHACK_EXPORT int Buildings_Read(DFHackObject* b_Ptr, const uint32_t index, t_building* building);
|
||||
|
||||
DFHACK_EXPORT t_customWorkshop* Buildings_ReadCustomWorkshopTypes(DFHackObject* b_Ptr);
|
||||
DFHACK_EXPORT int Buildings_GetCustomWorkshopType(DFHackObject* b_Ptr, t_building* building);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef CONSTRUCTIONS_C_API
|
||||
#define CONSTRUCTIONS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Constructions.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Constructions_Start(DFHackObject* c_Ptr, uint32_t* numConstructions);
|
||||
DFHACK_EXPORT int Constructions_Finish(DFHackObject* c_Ptr);
|
||||
|
||||
DFHACK_EXPORT int Constructions_Read(DFHackObject* c_Ptr, const uint32_t index, t_construction* construction);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef CREATURES_C_API
|
||||
#define CREATURES_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack/modules/Materials.h"
|
||||
#include "dfhack/modules/Creatures.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Creatures_Start(DFHackObject* cPtr, uint32_t* numCreatures);
|
||||
DFHACK_EXPORT int Creatures_Finish(DFHackObject* cPtr);
|
||||
|
||||
DFHACK_EXPORT int32_t Creatures_ReadCreatureInBox(DFHackObject* cPtr, const int32_t index, t_creature* furball,
|
||||
const uint16_t x1, const uint16_t y1, const uint16_t z1,
|
||||
const uint16_t x2, const uint16_t y2, const uint16_t z2);
|
||||
|
||||
DFHACK_EXPORT int Creatures_ReadCreature(DFHackObject* cPtr, const int32_t index, t_creature* furball);
|
||||
DFHACK_EXPORT t_material* Creatures_ReadJob(DFHackObject* cPtr, const t_creature* furball);
|
||||
|
||||
DFHACK_EXPORT uint32_t* Creatures_ReadInventoryIdx(DFHackObject* cPtr, const uint32_t index);
|
||||
DFHACK_EXPORT uint32_t* Creatures_ReadInventoryPtr(DFHackObject* cPtr, const uint32_t index);
|
||||
|
||||
DFHACK_EXPORT uint32_t Creatures_GetDwarfRaceIndex(DFHackObject* cPtr);
|
||||
DFHACK_EXPORT int32_t Creatures_GetDwarfCivId(DFHackObject* cPtr);
|
||||
|
||||
DFHACK_EXPORT int Creatures_WriteLabors(DFHackObject* cPtr, const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS]);
|
||||
DFHACK_EXPORT int Creatures_WriteHappiness(DFHackObject* cPtr, const uint32_t index, const uint32_t happiness_value);
|
||||
DFHACK_EXPORT int Creatures_WriteFlags(DFHackObject* cPtr, const uint32_t index, const uint32_t flags1, const uint32_t flags2);
|
||||
DFHACK_EXPORT int Creatures_WriteSkills(DFHackObject* cPtr, const uint32_t index, const t_soul* soul);
|
||||
DFHACK_EXPORT int Creatures_WriteAttributes(DFHackObject* cPtr, const uint32_t index, const t_creature* creature);
|
||||
DFHACK_EXPORT int Creatures_WriteSex(DFHackObject* cPtr, const uint32_t index, const uint8_t sex);
|
||||
DFHACK_EXPORT int Creatures_WriteTraits(DFHackObject* cPtr, const uint32_t index, const t_soul* soul);
|
||||
DFHACK_EXPORT int Creatures_WriteMood(DFHackObject* cPtr, const uint32_t index, const uint16_t mood);
|
||||
DFHACK_EXPORT int Creatures_WriteMoodSkill(DFHackObject* cPtr, const uint32_t index, const uint16_t moodSkill);
|
||||
DFHACK_EXPORT int Creatures_WriteJob(DFHackObject* cPtr, const t_creature* furball, const t_material* mat, const uint32_t mat_count);
|
||||
DFHACK_EXPORT int Creatures_WritePos(DFHackObject* cPtr, const uint32_t index, const t_creature* creature);
|
||||
DFHACK_EXPORT int Creatures_WriteCiv(DFHackObject* cPtr, const uint32_t index, const int32_t civ);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef GUI_C_API
|
||||
#define GUI_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Gui.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Gui_Start(DFHackObject* gui);
|
||||
DFHACK_EXPORT int Gui_Finish(DFHackObject* gui);
|
||||
|
||||
DFHACK_EXPORT int Gui_getViewCoords(DFHackObject* gui, int32_t* x, int32_t* y, int32_t* z);
|
||||
DFHACK_EXPORT int Gui_setViewCoords(DFHackObject* gui, int32_t x, int32_t y, int32_t z);
|
||||
|
||||
DFHACK_EXPORT int Gui_getCursorCoords(DFHackObject* gui, int32_t* x, int32_t* y, int32_t* z);
|
||||
DFHACK_EXPORT int Gui_setCursorCoords(DFHackObject* gui, int32_t x, int32_t y, int32_t z);
|
||||
|
||||
DFHACK_EXPORT t_hotkey* Gui_ReadHotkeys(DFHackObject* gui);
|
||||
|
||||
DFHACK_EXPORT int Gui_getWindowSize(DFHackObject* gui, int32_t* width, int32_t* height);
|
||||
|
||||
DFHACK_EXPORT t_screen* Gui_getScreenTiles(DFHackObject* gui, int32_t width, int32_t height);
|
||||
|
||||
DFHACK_EXPORT int Gui_ReadViewScreen(DFHackObject* gui, t_viewscreen* viewscreen);
|
||||
DFHACK_EXPORT int Gui_ReadMenuState(DFHackObject* gui, uint32_t* menuState);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef ITEMS_C_API
|
||||
#define ITEMS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFProcess.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack/modules/Items.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Items_Start(DFHackObject* items);
|
||||
DFHACK_EXPORT int Items_Finish(DFHackObject* items);
|
||||
|
||||
DFHACK_EXPORT char* Items_getItemDescription(DFHackObject* items, dfh_item* item, DFHackObject* mats);
|
||||
DFHACK_EXPORT char* Items_getItemClass(DFHackObject* items, int32_t index);
|
||||
DFHACK_EXPORT int Items_getItemData(DFHackObject* items, uint32_t itemptr, dfh_item* item);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MAPS_C_API
|
||||
#define MAPS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Maps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Maps_Start(DFHackObject* maps);
|
||||
DFHACK_EXPORT int Maps_Finish(DFHackObject* maps);
|
||||
|
||||
DFHACK_EXPORT uint16_t* Maps_ReadGeology(DFHackObject* maps);
|
||||
|
||||
DFHACK_EXPORT t_feature* Maps_ReadGlobalFeatures(DFHackObject* maps);
|
||||
DFHACK_EXPORT c_featuremap_node* Maps_ReadLocalFeatures(DFHackObject* maps);
|
||||
|
||||
DFHACK_EXPORT void Maps_getSize(DFHackObject* maps, uint32_t* x, uint32_t* y, uint32_t* z);
|
||||
DFHACK_EXPORT void Maps_getPosition(DFHackObject* maps, int32_t* x, int32_t* y, int32_t* z);
|
||||
|
||||
DFHACK_EXPORT int Maps_isValidBlock(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
|
||||
DFHACK_EXPORT uint32_t Maps_getBlockPtr(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadBlock40d(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, mapblock40d* buffer);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadTileTypes(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, tiletypes40d* buffer);
|
||||
DFHACK_EXPORT int Maps_WriteTileTypes(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, tiletypes40d* buffer);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadDesignations(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, designations40d* buffer);
|
||||
DFHACK_EXPORT int Maps_WriteDesignations(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, designations40d* buffer);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadTemperatures(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_temperatures* temp1, t_temperatures* temp2);
|
||||
DFHACK_EXPORT int Maps_WriteTemperatures(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_temperatures* temp1, t_temperatures* temp2);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadOccupancy(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, occupancies40d* buffer);
|
||||
DFHACK_EXPORT int Maps_WriteOccupancy(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, occupancies40d* buffer);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadDirtyBit(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int* dirtybit);
|
||||
DFHACK_EXPORT int Maps_WriteDirtyBit(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int dirtybit);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadFeatures(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int16_t* local, int16_t* global);
|
||||
DFHACK_EXPORT int Maps_WriteLocalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int16_t local);
|
||||
DFHACK_EXPORT int Maps_WriteEmptyLocalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
DFHACK_EXPORT int Maps_WriteGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, int16_t local);
|
||||
DFHACK_EXPORT int Maps_WriteEmptyGlobalFeature(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadBlockFlags(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_blockflags* blockflags);
|
||||
DFHACK_EXPORT int Maps_WriteBlockFlags(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, t_blockflags blockflags);
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadRegionOffsets(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, biome_indices40d* buffer);
|
||||
|
||||
DFHACK_EXPORT t_vein* Maps_ReadStandardVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
DFHACK_EXPORT t_frozenliquidvein* Maps_ReadFrozenVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
DFHACK_EXPORT t_spattervein* Maps_ReadSpatterVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
DFHACK_EXPORT t_grassvein* Maps_ReadGrassVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
DFHACK_EXPORT t_worldconstruction* Maps_ReadWorldConstructions(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
t_vein* veins;
|
||||
t_frozenliquidvein* frozen_veins;
|
||||
t_spattervein* spatter_veins;
|
||||
t_grassvein* grass_veins;
|
||||
t_worldconstruction* world_constructions;
|
||||
} c_allveins;
|
||||
|
||||
DFHACK_EXPORT int Maps_ReadAllVeins(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z, c_allveins* vein_struct);
|
||||
|
||||
DFHACK_EXPORT dfh_plant* Maps_ReadVegetation(DFHackObject* maps, uint32_t x, uint32_t y, uint32_t z);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MATERIALS_C_API
|
||||
#define MATERIALS_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack/modules/Materials.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Materials_ReadInorganicMaterials(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadOrganicMaterials(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadWoodMaterials(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadPlantMaterials(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadCreatureTypes(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadCreatureTypesEx(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadDescriptorColors(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_ReadOthers(DFHackObject* mat);
|
||||
|
||||
DFHACK_EXPORT void Materials_ReadAllMaterials(DFHackObject* mat);
|
||||
|
||||
DFHACK_EXPORT const char* Materials_getType(DFHackObject* mat, t_material* material);
|
||||
DFHACK_EXPORT const char* Materials_getDescription(DFHackObject* mat, t_material* material);
|
||||
|
||||
DFHACK_EXPORT int Materials_getInorganicSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getOrganicSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getTreeSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getPlantSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getRaceSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getRaceExSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getColorSize(DFHackObject* mat);
|
||||
DFHACK_EXPORT int Materials_getOtherSize(DFHackObject* mat);
|
||||
|
||||
DFHACK_EXPORT t_matgloss* Materials_getInorganic(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matgloss* Materials_getOrganic(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matgloss* Materials_getTree(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matgloss* Materials_getPlant(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matgloss* Materials_getRace(DFHackObject* mat);
|
||||
|
||||
DFHACK_EXPORT c_creaturetype* Materials_getRaceEx(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_descriptor_color* Materials_getColor(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matglossOther* Materials_getOther(DFHackObject* mat);
|
||||
DFHACK_EXPORT t_matgloss* Materials_getAllDesc(DFHackObject* mat);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef TRANSLATION_C_API
|
||||
#define TRANSLATION_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack-c/DFTypes_C.h"
|
||||
#include "dfhack/modules/Translation.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Translation_Start(DFHackObject* trans);
|
||||
DFHACK_EXPORT int Translation_Finish(DFHackObject* trans);
|
||||
|
||||
DFHACK_EXPORT char* Translation_TranslateNameEnglish(DFHackObject* trans, const DFHack::t_name* name);
|
||||
DFHACK_EXPORT char* Translation_TranslateNameNonEnglish(DFHackObject* trans, const DFHack::t_name* name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef VEGETATION_C_API
|
||||
#define VEGETATION_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/DFTypes.h"
|
||||
#include "dfhack/modules/Vegetation.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int Vegetation_Start(DFHackObject* veg, uint32_t* numTrees);
|
||||
DFHACK_EXPORT int Vegetation_Finish(DFHackObject* veg);
|
||||
|
||||
DFHACK_EXPORT int Vegetation_Read(DFHackObject* veg, const uint32_t index, dfh_plant* shrubbery);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef WINDOWIO_C_API
|
||||
#define WINDOWIO_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/modules/WindowIO.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int WindowIO_TypeStr(DFHackObject* window, const char* input, uint32_t delay, int8_t useShift);
|
||||
|
||||
DFHACK_EXPORT int WindowIO_TypeSpecial(DFHackObject* window, t_special command, uint32_t count, uint32_t delay);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef WORLD_C_API
|
||||
#define WORLD_C_API
|
||||
|
||||
#include "dfhack-c/Common.h"
|
||||
#include "dfhack/modules/World.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DFHACK_EXPORT int World_Start(DFHackObject* world);
|
||||
DFHACK_EXPORT int World_Finish(DFHackObject* world);
|
||||
|
||||
DFHACK_EXPORT int World_ReadCurrentTick(DFHackObject* world, uint32_t* tick);
|
||||
DFHACK_EXPORT int World_ReadCurrentYear(DFHackObject* world, uint32_t* year);
|
||||
DFHACK_EXPORT int World_ReadCurrentMonth(DFHackObject* world, uint32_t* month);
|
||||
DFHACK_EXPORT int World_ReadCurrentDay(DFHackObject* world, uint32_t* day);
|
||||
|
||||
DFHACK_EXPORT int World_ReadCurrentWeather(DFHackObject* world, uint8_t* weather);
|
||||
DFHACK_EXPORT int World_WriteCurrentWeather(DFHackObject* world, uint8_t weather);
|
||||
|
||||
DFHACK_EXPORT int World_ReadGameMode(DFHackObject* world, t_gamemodes*);
|
||||
DFHACK_EXPORT int World_WriteGameMode(DFHackObject* world, t_gamemodes);
|
||||
|
||||
DFHACK_EXPORT int World_ReadPauseState(DFHackObject* gui);
|
||||
DFHACK_EXPORT int World_SetPauseState(DFHackObject* gui, int8_t paused);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,149 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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
|
||||
|
||||
#ifndef CONTEXTMANAGER_H_INCLUDED
|
||||
#define CONTEXTMANAGER_H_INCLUDED
|
||||
|
||||
|
||||
#include "DFPragma.h"
|
||||
#include "DFExport.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
class Context;
|
||||
class BadContexts;
|
||||
class Process;
|
||||
/**
|
||||
* Used to enumerate, create and destroy Contexts. The very base of DFHack.
|
||||
* @see DFHack::Context
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
class DFHACK_EXPORT ContextManager
|
||||
{
|
||||
class Private;
|
||||
Private * const d;
|
||||
public:
|
||||
/**
|
||||
* Constructs the ContextManager.
|
||||
* @param path_to_xml the path to the file that defines memory offsets. (Memory.xml)
|
||||
*/
|
||||
ContextManager(const std::string path_to_xml);
|
||||
|
||||
/**
|
||||
* Destroys the ContextManager.
|
||||
*/
|
||||
~ContextManager();
|
||||
|
||||
/**
|
||||
* Refresh the internal list of valid Context objects.
|
||||
* @param bad_contexts pointer to a BadContexts object. Not required. All contexts are automatically destroyed if the object is not provided.
|
||||
* @see DFHack::BadContexts
|
||||
* @return Number of tracked contexts
|
||||
*/
|
||||
uint32_t Refresh(BadContexts* bad_contexts = 0);
|
||||
|
||||
/**
|
||||
* Get the number of tracked contexts.
|
||||
* @return Number of tracked contexts
|
||||
*/
|
||||
uint32_t size();
|
||||
|
||||
/**
|
||||
* Get a context by index
|
||||
* @param index index of the context to be returned
|
||||
* @return pointer to a Context. 0 if the index is out of range.
|
||||
*/
|
||||
Context * operator[](uint32_t index);
|
||||
|
||||
/**
|
||||
* Convenience method to return a single valid Context
|
||||
* @return pointer to a Context. The Context isn't attached!
|
||||
*/
|
||||
Context * getSingleContext();
|
||||
|
||||
/**
|
||||
* Destroy all tracked Context objects
|
||||
* Normally called during object destruction. Calling this from outside ContextManager is nasty.
|
||||
*/
|
||||
void purge(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* Class used for holding a set of invalidated Context AND Process objects temporarily and destroy them safely.
|
||||
* @see DFHack::Context
|
||||
* @see DFHack::Process
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
class DFHACK_EXPORT BadContexts
|
||||
{
|
||||
class Private;
|
||||
Private * const d;
|
||||
void push_back(Context * c);
|
||||
friend class ContextManager;
|
||||
void clear();
|
||||
public:
|
||||
BadContexts();
|
||||
/**
|
||||
* Destructor.
|
||||
* All Processes and Contexts tracked by the BadContexts object will be destroyed also.
|
||||
*/
|
||||
~BadContexts();
|
||||
|
||||
/**
|
||||
* Test if a Context is among the invalidated Contexts
|
||||
* @param c pointer to a Context to be checked
|
||||
* @return true if the Context is among the invalidated. false otherwise.
|
||||
*/
|
||||
bool Contains(Context* c);
|
||||
|
||||
/**
|
||||
* Test if a Process is among the invalidated Processes/Contexts
|
||||
* @param p pointer to a Process to be checked
|
||||
* @see DFHack::Process
|
||||
* @return true if the Process is among the invalidated. false otherwise.
|
||||
*/
|
||||
bool Contains(Process* p);
|
||||
|
||||
// TODO: Add excise(Context *) method
|
||||
|
||||
/**
|
||||
* Get the number of tracked invalid contexts.
|
||||
* @return Number of tracked invalid contexts
|
||||
*/
|
||||
uint32_t size();
|
||||
|
||||
/**
|
||||
* Get an invalid Context by index
|
||||
* @param index index of the invalid Context to be returned
|
||||
* @return pointer to an invalid Context
|
||||
*/
|
||||
Context * operator[](uint32_t index);
|
||||
};
|
||||
} // namespace DFHack
|
||||
#endif // CONTEXTMANAGER_H_INCLUDED
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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
|
||||
|
||||
#ifndef PROCESSMANAGER_H_INCLUDED
|
||||
#define PROCESSMANAGER_H_INCLUDED
|
||||
|
||||
#include "DFPragma.h"
|
||||
#include "DFExport.h"
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
class VersionInfo;
|
||||
class Process;
|
||||
class BadProcesses;
|
||||
/**
|
||||
* Process enumerator
|
||||
* Used to enumerate, create and destroy Processes.
|
||||
* @see DFHack::Process
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
class DFHACK_EXPORT ProcessEnumerator
|
||||
{
|
||||
class Private;
|
||||
Private * const d;
|
||||
public:
|
||||
/**
|
||||
* Constructs the ProcessEnumerator.
|
||||
* @param path_to_xml the path to the file that defines memory offsets. (Memory.xml)
|
||||
*/
|
||||
ProcessEnumerator( string path_to_xml );
|
||||
|
||||
/**
|
||||
* Destroys the ProcessEnumerator.
|
||||
*/
|
||||
~ProcessEnumerator();
|
||||
|
||||
/**
|
||||
* Refresh the internal list of valid Process objects.
|
||||
* @param invalidated_processes pointer to a BadProcesses object. Not required. All processes are automatically destroyed if the object is not provided.
|
||||
* @see DFHack::BadProcesses
|
||||
* @return true if there's at least one valit Process
|
||||
*/
|
||||
bool Refresh(BadProcesses * invalidated_processes = 0);
|
||||
|
||||
/**
|
||||
* @return Number of tracked processes
|
||||
*/
|
||||
uint32_t size();
|
||||
|
||||
/**
|
||||
* Get a Process by index
|
||||
* @param index index of the Process to be returned
|
||||
* @return pointer to a Process. 0 if the index is out of range.
|
||||
*/
|
||||
Process * operator[](uint32_t index);
|
||||
|
||||
/**
|
||||
* Destroy all tracked Process objects
|
||||
* Normally called during object destruction. Calling this from outside ProcessManager is nasty.
|
||||
*/
|
||||
void purge(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* Class used for holding a set of invalidated Process objects temporarily and destroy them safely.
|
||||
* @see DFHack::Process
|
||||
* \ingroup grp_context
|
||||
*/
|
||||
class DFHACK_EXPORT BadProcesses
|
||||
{
|
||||
class Private;
|
||||
Private * const d;
|
||||
void push_back(Process * p);
|
||||
friend class ProcessEnumerator;
|
||||
void clear();
|
||||
public:
|
||||
BadProcesses();
|
||||
/**
|
||||
* Destructor.
|
||||
* All Processes tracked by the BadProcesses object will be destroyed also.
|
||||
*/
|
||||
~BadProcesses();
|
||||
|
||||
/**
|
||||
* Test if a Process is among the invalidated Processes
|
||||
* @param p pointer to a Process to be checked
|
||||
* @return true if the Process is among the invalidated. false otherwise.
|
||||
*/
|
||||
bool Contains(Process* p);
|
||||
|
||||
/**
|
||||
* Remove a Process from the tracked invalidated Processes. Used by BadContexts.
|
||||
* @param p pointer to a Process to be excised
|
||||
* @see DFHack::BadContexts
|
||||
* @return true if the Process was among the invalidated. false otherwise.
|
||||
*/
|
||||
bool excise (Process* p);
|
||||
|
||||
/**
|
||||
* Get the number of tracked invalid contexts.
|
||||
* @return Number of tracked invalid contexts
|
||||
*/
|
||||
uint32_t size();
|
||||
|
||||
/**
|
||||
* Get an invalid Process by index
|
||||
* @param index index of the invalid Process to be returned
|
||||
* @return pointer to an invalid Process
|
||||
*/
|
||||
Process * operator[](uint32_t index);
|
||||
};
|
||||
}
|
||||
#endif // PROCESSMANAGER_H_INCLUDED
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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
|
||||
|
||||
#ifndef LINUX_PROCESS_H_INCLUDED
|
||||
#define LINUX_PROCESS_H_INCLUDED
|
||||
|
||||
#include "dfhack/DFProcess.h"
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
class LinuxProcessBase : public Process
|
||||
{
|
||||
protected:
|
||||
VersionInfo * my_descriptor;
|
||||
pid_t my_pid;
|
||||
string memFile;
|
||||
int memFileHandle;
|
||||
bool attached:1;
|
||||
bool suspended:1;
|
||||
bool identified:1;
|
||||
public:
|
||||
LinuxProcessBase(uint32_t pid);
|
||||
~LinuxProcessBase();
|
||||
|
||||
void readQuad(const uint32_t address, uint64_t & value);
|
||||
void writeQuad(const uint32_t address, const uint64_t value);
|
||||
|
||||
void readDWord(const uint32_t address, uint32_t & value);
|
||||
void writeDWord(const uint32_t address, const uint32_t value);
|
||||
|
||||
void readFloat(const uint32_t address, float & value);
|
||||
|
||||
void readWord(const uint32_t address, uint16_t & value);
|
||||
void writeWord(const uint32_t address, const uint16_t value);
|
||||
|
||||
void readByte(const uint32_t address, uint8_t & value);
|
||||
void writeByte(const uint32_t address, const uint8_t value);
|
||||
|
||||
void read( uint32_t address, uint32_t length, uint8_t* buffer);
|
||||
void write(uint32_t address, uint32_t length, uint8_t* buffer);
|
||||
|
||||
const std::string readCString (uint32_t offset);
|
||||
|
||||
bool isSuspended();
|
||||
bool isAttached();
|
||||
bool isIdentified();
|
||||
|
||||
VersionInfo *getDescriptor();
|
||||
int getPID();
|
||||
std::string getPath();
|
||||
|
||||
bool getThreadIDs(std::vector<uint32_t> & threads );
|
||||
void getMemRanges(std::vector<t_memrange> & ranges );
|
||||
// get module index by name and version. bool 1 = error
|
||||
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT) { OUTPUT=0; return false;};
|
||||
// get the SHM start if available
|
||||
char * getSHMStart (void){return 0;};
|
||||
// set a SHM command and wait for a response
|
||||
bool SetAndWait (uint32_t state){return false;};
|
||||
};
|
||||
}
|
||||
#endif
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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
|
||||
|
||||
namespace DFHack {
|
||||
class Process;
|
||||
class MicrosoftSTL
|
||||
{
|
||||
private:
|
||||
uint32_t STLSTR_buf_off;
|
||||
uint32_t STLSTR_size_off;
|
||||
uint32_t STLSTR_cap_off;
|
||||
|
||||
Process* p;
|
||||
public:
|
||||
void init(Process* p);
|
||||
|
||||
const std::string readSTLString (uint32_t offset);
|
||||
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
|
||||
size_t writeSTLString(const uint32_t address, const std::string writeString);
|
||||
// get class name of an object with rtti/type info
|
||||
std::string readClassName(uint32_t vptr);
|
||||
};
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef PROCESS_FACTORY_H_INCLUDED
|
||||
#define PROCESS_FACTORY_H_INCLUDED
|
||||
|
||||
#include "dfhack/DFProcess.h"
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
Process* createNormalProcess(uint32_t pid, VersionInfoFactory * factory);
|
||||
Process* createSHMProcess(uint32_t pid, VersionInfoFactory * factory);
|
||||
#ifdef LINUX_BUILD
|
||||
Process* createWineProcess(uint32_t pid, VersionInfoFactory * factory);
|
||||
#endif
|
||||
}
|
||||
#endif
|
@ -1,152 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
|
||||
|
||||
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
|
||||
|
||||
#ifndef SHM_PROCESS_H_INCLUDED
|
||||
#define SHM_PROCESS_H_INCLUDED
|
||||
|
||||
#include "dfhack/DFProcess.h"
|
||||
#include "dfhack/DFIntegers.h"
|
||||
#include "dfhack/VersionInfoFactory.h"
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
class DFHACK_EXPORT SHMProcess : public Process
|
||||
{
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
|
||||
public:
|
||||
SHMProcess(uint32_t PID, VersionInfoFactory * factory);
|
||||
~SHMProcess();
|
||||
// Set up stuff so we can read memory
|
||||
bool attach();
|
||||
bool detach();
|
||||
|
||||
bool suspend();
|
||||
bool asyncSuspend();
|
||||
bool resume();
|
||||
bool forceresume();
|
||||
|
||||
void readQuad(const uint32_t address, uint64_t & value);
|
||||
void writeQuad(const uint32_t address, const uint64_t value);
|
||||
|
||||
void readDWord(const uint32_t address, uint32_t & value);
|
||||
void writeDWord(const uint32_t address, const uint32_t value);
|
||||
|
||||
void readFloat(const uint32_t address, float & value);
|
||||
|
||||
void readWord(const uint32_t address, uint16_t & value);
|
||||
void writeWord(const uint32_t address, const uint16_t value);
|
||||
|
||||
void readByte(const uint32_t address, uint8_t & value);
|
||||
void writeByte(const uint32_t address, const uint8_t value);
|
||||
|
||||
void read( uint32_t address, uint32_t length, uint8_t* buffer);
|
||||
void write(uint32_t address, uint32_t length, uint8_t* buffer);
|
||||
|
||||
const std::string readSTLString (uint32_t offset);
|
||||
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity);
|
||||
size_t writeSTLString(const uint32_t address, const std::string writeString);
|
||||
|
||||
void readSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
void writeSTLVector(const uint32_t address, t_vecTriplet & triplet);
|
||||
// get class name of an object with rtti/type info
|
||||
std::string doReadClassName(uint32_t vptr);
|
||||
|
||||
const std::string readCString (uint32_t offset);
|
||||
|
||||
bool isSuspended();
|
||||
bool isAttached();
|
||||
bool isIdentified();
|
||||
|
||||
bool getThreadIDs(std::vector<uint32_t> & threads );
|
||||
void getMemRanges(std::vector<t_memrange> & ranges );
|
||||
VersionInfo *getDescriptor();
|
||||
int getPID();
|
||||
std::string getPath();
|
||||
// get module index by name and version. bool 1 = error
|
||||
bool getModuleIndex (const char * name, const uint32_t version, uint32_t & OUTPUT);
|
||||
// get the SHM start if available
|
||||
char * getSHMStart (void);
|
||||
bool SetAndWait (uint32_t state);
|
||||
private:
|
||||
bool acquireSuspendLock();
|
||||
bool releaseSuspendLock();
|
||||
};
|
||||
|
||||
class SHMProcess::Private
|
||||
{
|
||||
public:
|
||||
Private(SHMProcess * self_);
|
||||
~Private(){}
|
||||
VersionInfo * memdescriptor;
|
||||
SHMProcess * self;
|
||||
char *shm_addr;
|
||||
int attachmentIdx;
|
||||
|
||||
bool attached;
|
||||
bool locked;
|
||||
bool identified;
|
||||
bool useYield;
|
||||
|
||||
uint8_t vector_start;
|
||||
|
||||
#ifdef LINUX_BUILD
|
||||
pid_t process_ID;
|
||||
int shm_ID;
|
||||
int server_lock;
|
||||
int client_lock;
|
||||
int suspend_lock;
|
||||
#else
|
||||
typedef uint32_t pid_t;
|
||||
uint32_t process_ID;
|
||||
HANDLE DFSVMutex;
|
||||
HANDLE DFCLMutex;
|
||||
HANDLE DFCLSuspendMutex;
|
||||
#endif
|
||||
|
||||
bool validate(VersionInfoFactory * factory);
|
||||
|
||||
bool Aux_Core_Attach(bool & versionOK, pid_t& PID);
|
||||
bool SetAndWait (uint32_t state);
|
||||
bool GetLocks();
|
||||
bool AreLocksOk();
|
||||
void FreeLocks();
|
||||
};
|
||||
}
|
||||
|
||||
// some helpful macros to keep the code bloat in check
|
||||
#define SHMCMD ( (uint32_t *) shm_addr)[attachmentIdx]
|
||||
#define D_SHMCMD ( (uint32_t *) (d->shm_addr))[d->attachmentIdx]
|
||||
|
||||
#define SHMHDR ((shm_core_hdr *)shm_addr)
|
||||
#define D_SHMHDR ((shm_core_hdr *)(d->shm_addr))
|
||||
|
||||
#define SHMDATA(type) ((type *)(shm_addr + SHM_HEADER))
|
||||
#define D_SHMDATA(type) ((type *)(d->shm_addr + SHM_HEADER))
|
||||
|
||||
#endif
|
@ -1,56 +0,0 @@
|
||||
################################################################################
|
||||
# DFCONNECT
|
||||
###
|
||||
SET(DFCONNECT_HDRS
|
||||
shms.h
|
||||
mod-core.h
|
||||
mod-maps.h
|
||||
)
|
||||
|
||||
SET(PROJECT_SRCS
|
||||
mod-core.cpp
|
||||
mod-maps.cpp
|
||||
#mod-creature40d.cpp
|
||||
)
|
||||
|
||||
SET(PROJECT_HDRS_LINUX
|
||||
)
|
||||
|
||||
SET(PROJECT_HDRS_WINDOWS
|
||||
)
|
||||
|
||||
SET(PROJECT_SRCS_LINUX
|
||||
shms-linux.cpp
|
||||
)
|
||||
|
||||
SET(PROJECT_SRCS_WINDOWS
|
||||
shms-windows.cpp
|
||||
)
|
||||
|
||||
IF(UNIX)
|
||||
LIST(APPEND PROJECT_HDRS ${PROJECT_HDRS_LINUX})
|
||||
LIST(APPEND PROJECT_SRCS ${PROJECT_SRCS_LINUX})
|
||||
ELSE(UNIX)
|
||||
LIST(APPEND PROJECT_HDRS ${PROJECT_HDRS_WINDOWS})
|
||||
LIST(APPEND PROJECT_SRCS ${PROJECT_SRCS_WINDOWS})
|
||||
ENDIF(UNIX)
|
||||
|
||||
|
||||
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE )
|
||||
|
||||
LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS})
|
||||
|
||||
#IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
add_definitions(-DBUILD_SHM)
|
||||
IF(UNIX)
|
||||
add_definitions(-DLINUX_BUILD)
|
||||
SET(PROJECT_LIBS rt)
|
||||
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden")
|
||||
ADD_LIBRARY(dfconnect SHARED ${PROJECT_SRCS})
|
||||
TARGET_LINK_LIBRARIES(dfconnect ${PROJECT_LIBS})
|
||||
ELSE(UNIX)
|
||||
# SET(PROJECT_LIBS psapi)
|
||||
ADD_LIBRARY(SDL SHARED ${PROJECT_SRCS})
|
||||
TARGET_LINK_LIBRARIES(SDL ${PROJECT_LIBS})
|
||||
ENDIF(UNIX)
|
||||
#ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
@ -1,364 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is the source for the DF <-> dfhack shm bridge's core module.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "dfhack/DFIntegers.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define SHM_INTERNAL // for things only visible to the SHM
|
||||
|
||||
#include "shms.h"
|
||||
#include "mod-core.h"
|
||||
#include "mod-maps.h"
|
||||
#include "mod-creature40d.h"
|
||||
|
||||
std::vector <DFPP_module> module_registry;
|
||||
|
||||
// shared by shms_OS
|
||||
extern int errorstate;
|
||||
extern char *shm;
|
||||
extern int shmid;
|
||||
|
||||
// file-globals
|
||||
bool useYield = 0;
|
||||
int currentClient = -1;
|
||||
|
||||
#define SHMHDR ((shm_core_hdr *)shm)
|
||||
#define SHMCMD ((uint32_t *)shm )[currentClient]
|
||||
#define SHMDATA(type) ((type *)(shm + SHM_HEADER))
|
||||
|
||||
void ReadRaw (void * data)
|
||||
{
|
||||
memcpy(SHMDATA(void), (void *) SHMHDR->address,SHMHDR->length);
|
||||
}
|
||||
|
||||
void ReadQuad (void * data)
|
||||
{
|
||||
SHMHDR->Qvalue = *((uint64_t*) SHMHDR->address);
|
||||
}
|
||||
|
||||
void ReadDWord (void * data)
|
||||
{
|
||||
SHMHDR->value = *((uint32_t*) SHMHDR->address);
|
||||
}
|
||||
|
||||
void ReadWord (void * data)
|
||||
{
|
||||
SHMHDR->value = *((uint16_t*) SHMHDR->address);
|
||||
}
|
||||
|
||||
void ReadByte (void * data)
|
||||
{
|
||||
SHMHDR->value = *((uint8_t*) SHMHDR->address);
|
||||
}
|
||||
|
||||
void WriteRaw (void * data)
|
||||
{
|
||||
memcpy((void *)SHMHDR->address, SHMDATA(void),SHMHDR->length);
|
||||
}
|
||||
|
||||
void WriteQuad (void * data)
|
||||
{
|
||||
(*(uint64_t*)SHMHDR->address) = SHMHDR->Qvalue;
|
||||
}
|
||||
|
||||
void WriteDWord (void * data)
|
||||
{
|
||||
(*(uint32_t*)SHMHDR->address) = SHMHDR->value;
|
||||
}
|
||||
|
||||
void WriteWord (void * data)
|
||||
{
|
||||
(*(uint16_t*)SHMHDR->address) = SHMHDR->value;
|
||||
}
|
||||
|
||||
void WriteByte (void * data)
|
||||
{
|
||||
(*(uint8_t*)SHMHDR->address) = SHMHDR->value;
|
||||
}
|
||||
|
||||
void ReadSTLString (void * data)
|
||||
{
|
||||
std::string * myStringPtr = (std::string *) SHMHDR->address;
|
||||
unsigned int l = myStringPtr->length();
|
||||
SHMHDR->value = l;
|
||||
// FIXME: there doesn't have to be a null terminator!
|
||||
strncpy( SHMDATA(char),myStringPtr->c_str(),l+1);
|
||||
}
|
||||
|
||||
void WriteSTLString (void * data)
|
||||
{
|
||||
std::string * myStringPtr = (std::string *) SHMHDR->address;
|
||||
// here we DO expect a 0 terminator
|
||||
myStringPtr->assign( SHMDATA(const char) );
|
||||
}
|
||||
|
||||
// MIT HAKMEM bitcount
|
||||
int bitcount(uint32_t n)
|
||||
{
|
||||
register uint32_t tmp;
|
||||
|
||||
tmp = n - ((n >> 1) & 033333333333) - ((n >> 2) & 011111111111);
|
||||
return ((tmp + (tmp >> 3)) & 030707070707) % 63;
|
||||
}
|
||||
|
||||
// get local and remote affinity, set up yield if required (single core available)
|
||||
void CoreAttach (void * data)
|
||||
{
|
||||
// sync affinity
|
||||
uint32_t local = OS_getAffinity();
|
||||
uint32_t remote = SHMDATA(coreattach)->cl_affinity;
|
||||
uint32_t pool = local | remote;
|
||||
SHMDATA(coreattach)->sv_useYield = useYield = (bitcount(pool) == 1);
|
||||
// return our PID
|
||||
SHMDATA(coreattach)->sv_PID = OS_getPID();
|
||||
// return core version
|
||||
SHMDATA(coreattach)->sv_version = module_registry[0].version;
|
||||
}
|
||||
|
||||
void FindModule (void * data)
|
||||
{
|
||||
bool found = false;
|
||||
modulelookup * payload = SHMDATA(modulelookup);
|
||||
std::string test = payload->name;
|
||||
uint32_t version = payload->version;
|
||||
for(unsigned int i = 0; i < module_registry.size();i++)
|
||||
{
|
||||
if(module_registry[i].name == test && module_registry[i].version == version)
|
||||
{
|
||||
// gotcha
|
||||
SHMHDR->value = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SHMHDR->error = !found;
|
||||
}
|
||||
|
||||
void FindCommand (void * data)
|
||||
{
|
||||
bool found = false;
|
||||
commandlookup * payload = SHMDATA(commandlookup);
|
||||
std::string modname = payload->module;
|
||||
std::string cmdname = payload->name;
|
||||
uint32_t version = payload->version;
|
||||
for(unsigned int i = 0; i < module_registry.size();i++)
|
||||
{
|
||||
if(module_registry[i].name == modname && module_registry[i].version == version)
|
||||
{
|
||||
for(unsigned int j = 0 ; j < module_registry[i].commands.size();j++)
|
||||
{
|
||||
if(module_registry[i].commands[j].name == cmdname)
|
||||
{
|
||||
// gotcha
|
||||
SHMHDR->value = j + (i << 16);
|
||||
SHMHDR->error = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SHMHDR->error = true;
|
||||
}
|
||||
|
||||
void ReleaseSuspendLock( void * data )
|
||||
{
|
||||
OS_releaseSuspendLock(currentClient);
|
||||
}
|
||||
|
||||
void AcquireSuspendLock( void * data )
|
||||
{
|
||||
OS_lockSuspendLock(currentClient);
|
||||
}
|
||||
|
||||
|
||||
DFPP_module InitCore(void)
|
||||
{
|
||||
DFPP_module core;
|
||||
core.name = "Core";
|
||||
core.version = CORE_VERSION;
|
||||
core.modulestate = 0; // this one is dumb and has no real state
|
||||
|
||||
core.reserve(NUM_CORE_CMDS);
|
||||
// basic states
|
||||
core.set_command(CORE_RUNNING, CANCELLATION, "Running");
|
||||
//core.set_command(CORE_RUN, FUNCTION, "Run!",AcquireSuspendLock,CORE_RUNNING);
|
||||
core.set_command(CORE_RUN, CANCELLATION, "Run!",0,CORE_RUNNING);
|
||||
core.set_command(CORE_STEP, CANCELLATION, "Suspend on next step",0,CORE_SUSPEND);// set command to CORE_SUSPEND, check next client
|
||||
core.set_command(CORE_SUSPEND, FUNCTION, "Suspend", ReleaseSuspendLock , CORE_SUSPENDED, LOCKING_LOCKS);
|
||||
core.set_command(CORE_SUSPENDED, CLIENT_WAIT, "Suspended");
|
||||
core.set_command(CORE_ERROR, CANCELLATION, "Error");
|
||||
|
||||
// utility commands
|
||||
core.set_command(CORE_ATTACH, FUNCTION,"Core attach",CoreAttach, CORE_SUSPENDED);
|
||||
core.set_command(CORE_ACQUIRE_MODULE, FUNCTION, "Module lookup", FindModule, CORE_SUSPENDED);
|
||||
core.set_command(CORE_ACQUIRE_COMMAND, FUNCTION, "Command lookup", FindCommand, CORE_SUSPENDED);
|
||||
|
||||
// raw reads
|
||||
core.set_command(CORE_READ, FUNCTION,"Raw read",ReadRaw, CORE_SUSPENDED);
|
||||
core.set_command(CORE_READ_QUAD, FUNCTION,"Read QUAD",ReadQuad, CORE_SUSPENDED);
|
||||
core.set_command(CORE_READ_DWORD, FUNCTION,"Read DWORD",ReadDWord, CORE_SUSPENDED);
|
||||
core.set_command(CORE_READ_WORD, FUNCTION,"Read WORD",ReadWord, CORE_SUSPENDED);
|
||||
core.set_command(CORE_READ_BYTE, FUNCTION,"Read BYTE",ReadByte, CORE_SUSPENDED);
|
||||
|
||||
// raw writes
|
||||
core.set_command(CORE_WRITE, FUNCTION, "Raw write", WriteRaw, CORE_SUSPENDED);
|
||||
core.set_command(CORE_WRITE_QUAD, FUNCTION, "Write QUAD", WriteQuad, CORE_SUSPENDED);
|
||||
core.set_command(CORE_WRITE_DWORD, FUNCTION, "Write DWORD", WriteDWord, CORE_SUSPENDED);
|
||||
core.set_command(CORE_WRITE_WORD, FUNCTION, "Write WORD", WriteWord, CORE_SUSPENDED);
|
||||
core.set_command(CORE_WRITE_BYTE, FUNCTION, "Write BYTE", WriteByte, CORE_SUSPENDED);
|
||||
|
||||
// stl string commands
|
||||
core.set_command(CORE_READ_STL_STRING, FUNCTION, "Read STL string", ReadSTLString, CORE_SUSPENDED);
|
||||
core.set_command(CORE_READ_C_STRING, CLIENT_WAIT, "RESERVED");
|
||||
core.set_command(CORE_WRITE_STL_STRING, FUNCTION, "Write STL string", WriteSTLString, CORE_SUSPENDED);
|
||||
return core;
|
||||
}
|
||||
|
||||
void InitModules (void)
|
||||
{
|
||||
// create the core module
|
||||
module_registry.push_back(InitCore());
|
||||
module_registry.push_back(DFHack::Server::Maps::Init());
|
||||
//module_registry.push_back(DFHack::Server::Creatures::Init());
|
||||
for(int i = 0; i < module_registry.size();i++)
|
||||
{
|
||||
fprintf(stderr,"Initialized module %s, version %d\n",module_registry[i].name.c_str(),module_registry[i].version);
|
||||
}
|
||||
// TODO: dynamic module init
|
||||
}
|
||||
|
||||
void KillModules (void)
|
||||
{
|
||||
for(unsigned int i = 0; i < module_registry.size();i++)
|
||||
{
|
||||
if(module_registry[i].modulestate)
|
||||
free(module_registry[i].modulestate);
|
||||
}
|
||||
module_registry.clear();
|
||||
}
|
||||
|
||||
void SHM_Act (void)
|
||||
{
|
||||
volatile uint32_t atomic = 0;
|
||||
if(errorstate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//static uint oldcl = 88;
|
||||
for(currentClient = 0; currentClient < SHM_MAX_CLIENTS;currentClient++)
|
||||
{
|
||||
// set the offset for the shared memory used for the client
|
||||
uint32_t numwaits = 0;
|
||||
check_again: // goto target!!!
|
||||
if(numwaits == 10000)
|
||||
{
|
||||
// this tests if there's a process on the other side
|
||||
if(isValidSHM(currentClient))
|
||||
{
|
||||
numwaits = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
full_barrier
|
||||
SHMCMD = CORE_RUNNING;
|
||||
fprintf(stderr,"dfhack: Broke out of loop, other process disappeared.\n");
|
||||
}
|
||||
}
|
||||
full_barrier // I don't want the compiler to reorder my code.
|
||||
|
||||
|
||||
//fprintf(stderr,"%d: %x %x\n",currentClient, (uint) SHMHDR, (uint) &(SHMHDR->cmd[currentClient]));
|
||||
|
||||
// this is very important! copying two words separately from the command variable leads to inconsistency.
|
||||
// Always copy the thing in one go.
|
||||
// Also, this whole SHM thing probably only works on intel processors
|
||||
atomic = SHMCMD;
|
||||
full_barrier
|
||||
|
||||
DFPP_module & mod = module_registry[ ((shm_cmd)atomic).parts.module ];
|
||||
DFPP_command & cmd = mod.commands[ ((shm_cmd)atomic).parts.command ];
|
||||
/*
|
||||
if(atomic == CORE_RUNNING)
|
||||
{
|
||||
// we are running again for this process
|
||||
// reaquire the suspend lock
|
||||
OS_lockSuspendLock(currentClient);
|
||||
continue;
|
||||
}
|
||||
full_barrier
|
||||
*/
|
||||
// set next state BEFORE we act on the command - good for locks
|
||||
if(cmd.locking == LOCKING_LOCKS)
|
||||
{
|
||||
if(cmd.nextState != -1) SHMCMD = cmd.nextState;
|
||||
}
|
||||
|
||||
if(cmd._function)
|
||||
{
|
||||
cmd._function(mod.modulestate);
|
||||
}
|
||||
full_barrier
|
||||
|
||||
// set next state AFTER we act on the command - good for busy waits
|
||||
if(cmd.locking == LOCKING_BUSY)
|
||||
{
|
||||
/*
|
||||
char text [512];
|
||||
char text2 [512];
|
||||
sprintf (text,"Client %d invoked %d:%d = %x = %s\n",currentClient,((shm_cmd)atomic).parts.module,((shm_cmd)atomic).parts.command, cmd._function,cmd.name.c_str());
|
||||
sprintf(text2, "Server set %d\n",cmd.nextState);
|
||||
*/
|
||||
// FIXME: WHAT HAPPENS WHEN A 'NEXTSTATE' IS FROM A DIFFERENT MODULE THAN 'CORE'? Yeah. It doesn't work.
|
||||
if(cmd.nextState != -1) SHMCMD = cmd.nextState;
|
||||
//MessageBox(0,text,text2, MB_OK);
|
||||
|
||||
//fflush(stderr); // make sure this finds its way to the terminal!
|
||||
|
||||
}
|
||||
full_barrier
|
||||
|
||||
if(cmd.type != CANCELLATION)
|
||||
{
|
||||
if(useYield)
|
||||
{
|
||||
SCHED_YIELD
|
||||
}
|
||||
numwaits ++; // watchdog timeout
|
||||
goto check_again;
|
||||
}
|
||||
full_barrier
|
||||
|
||||
// we are running again for this process
|
||||
// reaquire the suspend lock
|
||||
OS_lockSuspendLock(currentClient);
|
||||
}
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SHMS_CORE_H
|
||||
#define SHMS_CORE_H
|
||||
|
||||
// increment on every core change
|
||||
#define CORE_VERSION 10
|
||||
|
||||
typedef struct
|
||||
{
|
||||
shm_cmd cmd[SHM_MAX_CLIENTS]; // MANDATORY!
|
||||
uint32_t address;
|
||||
uint32_t value;
|
||||
uint32_t length;
|
||||
uint32_t error;
|
||||
uint64_t Qvalue;
|
||||
} shm_core_hdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t version;
|
||||
char name[256];
|
||||
} modulelookup;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t version;
|
||||
char module[256];
|
||||
char name[256];
|
||||
} commandlookup;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t sv_version; // output
|
||||
uint32_t cl_affinity; // input
|
||||
uint32_t sv_PID; // output
|
||||
uint32_t sv_useYield; // output
|
||||
} coreattach;
|
||||
|
||||
enum CORE_COMMAND
|
||||
{
|
||||
// basic states
|
||||
CORE_RUNNING = 0, // no command, normal server execution
|
||||
CORE_RUN, // sent by the client to restart the server execution
|
||||
CORE_STEP, // client suspend sets step
|
||||
CORE_SUSPEND, // client notifies server to wait for commands (server is stalled in busy wait)
|
||||
CORE_SUSPENDED, // response to WAIT, server is stalled in busy wait
|
||||
CORE_ERROR, // there was a server error
|
||||
|
||||
// utility commands
|
||||
CORE_ATTACH, // compare affinity, get core version and process ID
|
||||
CORE_ACQUIRE_MODULE, // get index of a loaded module by name and version
|
||||
CORE_ACQUIRE_COMMAND, // get module::command callsign by module name, command name and module version
|
||||
|
||||
// raw reads
|
||||
CORE_READ, // cl -> sv, read some data
|
||||
CORE_READ_QUAD, // cl -> sv, read a quad
|
||||
CORE_READ_DWORD, // cl -> sv, read a dword
|
||||
CORE_READ_WORD, // cl -> sv, read a word
|
||||
CORE_READ_BYTE, // cl -> sv, read a byte
|
||||
|
||||
// raw writes
|
||||
CORE_WRITE,// client writes to server
|
||||
CORE_WRITE_QUAD,// client writes a QUAD to server
|
||||
CORE_WRITE_DWORD,// client writes a DWORD to server
|
||||
CORE_WRITE_WORD,// client writes a WORD to server
|
||||
CORE_WRITE_BYTE,// client writes a BYTE to server
|
||||
|
||||
// string functions
|
||||
CORE_READ_STL_STRING,// client requests contents of STL string at address
|
||||
CORE_READ_C_STRING,// client requests contents of a C string at address, max length (0 means zero terminated)
|
||||
CORE_WRITE_STL_STRING,// client wants to set STL string at address to something
|
||||
|
||||
// total commands
|
||||
NUM_CORE_CMDS
|
||||
};
|
||||
#endif
|
||||
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MOD_CREATURES2010_H
|
||||
#define MOD_CREATURES2010_H
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
namespace Creatures2010
|
||||
{
|
||||
|
||||
#define CREATURES2010_VERSION 1
|
||||
typedef struct
|
||||
{
|
||||
// creature offsets
|
||||
uint32_t vector;
|
||||
uint32_t pos_offset;
|
||||
uint32_t profession_offset;
|
||||
uint32_t custom_profession_offset;
|
||||
uint32_t race_offset;
|
||||
int32_t civ_offset;
|
||||
uint32_t flags1_offset;
|
||||
uint32_t flags2_offset;
|
||||
uint32_t name_offset;
|
||||
uint32_t sex_offset;
|
||||
uint32_t caste_offset;
|
||||
uint32_t id_offset;
|
||||
uint32_t labors_offset;
|
||||
uint32_t happiness_offset;
|
||||
uint32_t artifact_name_offset;
|
||||
uint32_t physical_offset;
|
||||
uint32_t mood_offset;
|
||||
uint32_t mood_skill_offset;
|
||||
uint32_t pickup_equipment_bit;
|
||||
uint32_t soul_vector_offset;
|
||||
uint32_t default_soul_offset;
|
||||
uint32_t current_job_offset;
|
||||
// soul offsets
|
||||
uint32_t soul_skills_vector_offset;
|
||||
// name offsets (needed for reading creature names)
|
||||
uint32_t name_firstname_offset;
|
||||
uint32_t name_nickname_offset;
|
||||
uint32_t name_words_offset;
|
||||
uint32_t soul_mental_offset;
|
||||
uint32_t soul_traits_offset;
|
||||
uint32_t appearance_vector_offset;
|
||||
uint32_t birth_year_offset;
|
||||
uint32_t birth_time_offset;
|
||||
uint32_t inventory_offset;
|
||||
} creature_offsets;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool inited;
|
||||
creature_offsets offsets;
|
||||
} creature_modulestate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
shm_cmd cmd[SHM_MAX_CLIENTS]; // MANDATORY!
|
||||
// box
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t z;
|
||||
uint32_t x2;
|
||||
uint32_t y2;
|
||||
uint32_t z2;
|
||||
// starting index
|
||||
int32_t index;
|
||||
} shm_creature_hdr;
|
||||
|
||||
enum CREATURE_COMMAND
|
||||
{
|
||||
CREATURE_INIT = 0, // initialization
|
||||
CREATURE_FIND_IN_BOX,
|
||||
CREATURE_AT_INDEX,
|
||||
NUM_CREATURE_CMDS
|
||||
};
|
||||
DFPP_module Init(void);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,197 +0,0 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <DFIntegers.h>
|
||||
|
||||
#include "shms.h"
|
||||
#include "mod-core.h"
|
||||
#include "mod-creature40d.h"
|
||||
#include <DFTypes.h>
|
||||
#include <modules/Creatures.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
|
||||
extern char *shm;
|
||||
|
||||
namespace DFHack{
|
||||
namespace Server{
|
||||
namespace Creatures{ // start of namespace
|
||||
|
||||
#define SHMHDR ((shm_creature_hdr *)shm)
|
||||
#define SHMDATA(type) ((type *)(shm + SHM_HEADER))
|
||||
|
||||
void readName(t_name & name, char * address, creature_offsets & offsets)
|
||||
{
|
||||
// custom profession
|
||||
std::string * fname = (std::string *) (address + offsets.name_firstname_offset);
|
||||
strncpy(name.first_name,fname->c_str(),127);
|
||||
name.first_name[127] = 0;
|
||||
|
||||
std::string * nname = (std::string *) (address + offsets.name_nickname_offset);
|
||||
strncpy(name.nickname,nname->c_str(),127);
|
||||
name.nickname[127] = 0;
|
||||
|
||||
memcpy(name.words, (void *)(address + offsets.name_words_offset), 48);
|
||||
}
|
||||
|
||||
void InitOffsets (void* data)
|
||||
{
|
||||
creature_modulestate * state = (creature_modulestate *) data;
|
||||
memcpy((void *) &(state->offsets), SHMDATA(void), sizeof(creature_offsets));
|
||||
((creature_modulestate *) data)->inited = true;
|
||||
}
|
||||
|
||||
void ReadCreatureAtIndex(void *data)
|
||||
{
|
||||
creature_modulestate * state = (creature_modulestate *) data;
|
||||
creature_offsets & offsets = state->offsets;
|
||||
std::vector<char *> * creaturev = (std::vector<char *> *) (offsets.creature_vector + offsets.vector_correct);
|
||||
uint32_t length = creaturev->size();
|
||||
int32_t index = SHMHDR->index;
|
||||
|
||||
// read pointer from vector at position
|
||||
char * temp = (char *) creaturev->at (index);
|
||||
t_creature *furball = SHMDATA(t_creature);
|
||||
furball->origin = (uint32_t) temp;
|
||||
//read creature from memory
|
||||
memcpy(&(furball->x),temp + offsets.creature_pos_offset,3* sizeof(uint16_t));
|
||||
furball->type = *(uint32_t *) (temp + offsets.creature_type_offset);
|
||||
furball->flags1.whole = *(uint32_t *) (temp + offsets.creature_flags1_offset);
|
||||
furball->flags2.whole = *(uint32_t *) (temp + offsets.creature_flags2_offset);
|
||||
// names
|
||||
|
||||
readName(furball->name,temp + offsets.creature_name_offset, offsets);
|
||||
readName(furball->squad_name, temp + offsets.creature_squad_name_offset, offsets);
|
||||
readName(furball->artifact_name, temp + offsets.creature_artifact_name_offset, offsets);
|
||||
|
||||
// custom profession
|
||||
std::string * custprof = (std::string *) (temp + offsets.creature_custom_profession_offset);
|
||||
strncpy(furball->custom_profession,custprof->c_str(),127);
|
||||
furball->custom_profession[127] = 0;
|
||||
|
||||
// labors
|
||||
memcpy(furball->labors, temp + offsets.creature_labors_offset, NUM_CREATURE_LABORS);
|
||||
|
||||
// traits
|
||||
memcpy(furball->traits, temp + offsets.creature_traits_offset, sizeof (uint16_t) * NUM_CREATURE_TRAITS);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t id;
|
||||
junk_fill <3> fill1;
|
||||
uint8_t rating;
|
||||
junk_fill <3> fill2;
|
||||
uint16_t experience;
|
||||
} raw_skill;
|
||||
// learned skills
|
||||
std::vector <void *> * skillv = (std::vector <void *> *) (temp + offsets.creature_skills_offset + offsets.vector_correct);
|
||||
furball->numSkills = skillv->size();
|
||||
for (uint32_t i = 0; i < furball->numSkills;i++)
|
||||
{
|
||||
//skills.read(i, (uint8_t *) &temp2);
|
||||
// a byte: this gives us 256 skills maximum.
|
||||
furball->skills[i].id = ( (raw_skill*) skillv->at(i))->id;
|
||||
furball->skills[i].rating = ( (raw_skill*) skillv->at(i))->rating;
|
||||
furball->skills[i].experience = ( (raw_skill*) skillv->at(i))->experience;
|
||||
}
|
||||
// profession
|
||||
furball->profession = *(uint8_t *) (temp + offsets.creature_profession_offset);
|
||||
// current job HACK: the job object isn't cleanly represented here
|
||||
uint32_t jobIdAddr = *(uint32_t *) (temp + offsets.creature_current_job_offset);
|
||||
|
||||
if (jobIdAddr)
|
||||
{
|
||||
furball->current_job.active = true;
|
||||
furball->current_job.jobId = *(uint8_t *) (jobIdAddr + offsets.creature_current_job_id_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
furball->current_job.active = false;
|
||||
}
|
||||
|
||||
//likes
|
||||
std::vector <t_like *> * likev = (std::vector <t_like *> *) (temp + offsets.creature_likes_offset + offsets.vector_correct);
|
||||
furball->numLikes = likev->size();
|
||||
for(uint32_t i = 0;i<furball->numLikes;i++)
|
||||
{
|
||||
memcpy(&furball->likes[i], likev->at(i), sizeof(t_skill));
|
||||
}
|
||||
|
||||
furball->mood = *(int16_t *) (temp + offsets.creature_mood_offset);
|
||||
|
||||
|
||||
furball->happiness = *(uint32_t *) (temp + offsets.creature_happiness_offset);
|
||||
furball->id = *(uint32_t *) (temp + offsets.creature_id_offset);
|
||||
furball->agility = *(uint32_t *) (temp + offsets.creature_agility_offset);
|
||||
furball->strength = *(uint32_t *) (temp + offsets.creature_strength_offset);
|
||||
furball->toughness = *(uint32_t *) (temp + offsets.creature_toughness_offset);
|
||||
furball->money = *(uint32_t *) (temp + offsets.creature_money_offset);
|
||||
furball->squad_leader_id = *(int32_t*) (temp + offsets.creature_squad_leader_id_offset);
|
||||
furball->sex = *(uint8_t*) (temp + offsets.creature_sex_offset);
|
||||
|
||||
furball->pregnancy_timer = *(uint32_t *)(temp+offsets.creature_pregnancy_offset);
|
||||
furball->blood_max = *(int32_t*) (temp+offsets.creature_blood_max_offset);
|
||||
furball->blood_current = *(int32_t*) (temp+offsets.creature_blood_current_offset);
|
||||
furball->bleed_rate = *(uint32_t*) (temp+offsets.creature_bleed_offset);
|
||||
}
|
||||
|
||||
void FindNextCreatureInBox (void * data)
|
||||
{
|
||||
int32_t index = SHMHDR->index;
|
||||
// sanity
|
||||
if(index == -1) return;
|
||||
|
||||
creature_modulestate * state = (creature_modulestate *) data;
|
||||
creature_offsets & offsets = state->offsets;
|
||||
uint32_t x,y,z,x2,y2,z2;
|
||||
|
||||
x = SHMHDR->x; x2 = SHMHDR->x2;
|
||||
y = SHMHDR->y; y2 = SHMHDR->y2;
|
||||
z = SHMHDR->z; z2 = SHMHDR->x2;
|
||||
|
||||
std::vector<char *> * creaturev = (std::vector<char *> *) (offsets.creature_vector + offsets.vector_correct);
|
||||
|
||||
uint32_t length = creaturev->size();
|
||||
typedef uint16_t coords[3];
|
||||
|
||||
// look at all creatures, starting at index
|
||||
// if you find one in the specified 'box', return the creature in the data
|
||||
// section and the index in the header
|
||||
for(;index < length;index++)
|
||||
{
|
||||
coords& coo = *(coords*) (creaturev->at(index) + offsets.creature_pos_offset);
|
||||
if(coo[0] >=x && coo[0] < x2
|
||||
&& coo[1] >=y && coo[1] < y2
|
||||
&& coo[2] >=z && coo[2] < z2)
|
||||
{
|
||||
// we found a creature!
|
||||
SHMHDR->index = index;
|
||||
ReadCreatureAtIndex(data);
|
||||
return; // we're done here
|
||||
}
|
||||
}
|
||||
// nothing found
|
||||
SHMHDR->index = -1;
|
||||
}
|
||||
|
||||
DFPP_module Init( void )
|
||||
{
|
||||
DFPP_module creatures;
|
||||
creatures.name = "Creatures40d";
|
||||
creatures.version = CREATURES40D_VERSION;
|
||||
// freed by the core
|
||||
creatures.modulestate = malloc(sizeof(creature_modulestate)); // we store a flag
|
||||
memset(creatures.modulestate,0,sizeof(creature_modulestate));
|
||||
|
||||
creatures.reserve(NUM_CREATURE_CMDS);
|
||||
|
||||
creatures.set_command(CREATURE_INIT, FUNCTION, "Supply the Creature40d module with offsets",InitOffsets,CORE_SUSPENDED);
|
||||
creatures.set_command(CREATURE_FIND_IN_BOX, FUNCTION, "Get next creature in a box, return new index or -1", FindNextCreatureInBox, CORE_SUSPENDED);
|
||||
creatures.set_command(CREATURE_AT_INDEX, FUNCTION, "Get creature at index", ReadCreatureAtIndex, CORE_SUSPENDED);
|
||||
|
||||
return creatures;
|
||||
}
|
||||
|
||||
}}} // end of namespace
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MOD_CREATURES40D_H
|
||||
#define MOD_CREATURES40D_H
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
namespace Server
|
||||
{
|
||||
namespace Creatures
|
||||
{
|
||||
|
||||
#define CREATURES40D_VERSION 1
|
||||
typedef struct
|
||||
{
|
||||
// creature offsets
|
||||
uint32_t creature_vector;
|
||||
uint32_t creature_pos_offset;
|
||||
uint32_t creature_type_offset;
|
||||
uint32_t creature_flags1_offset;
|
||||
uint32_t creature_flags2_offset;
|
||||
uint32_t creature_name_offset;
|
||||
uint32_t creature_custom_profession_offset;
|
||||
uint32_t creature_profession_offset;
|
||||
uint32_t creature_sex_offset;
|
||||
uint32_t creature_id_offset;
|
||||
uint32_t creature_squad_name_offset;
|
||||
uint32_t creature_squad_leader_id_offset;
|
||||
uint32_t creature_money_offset;
|
||||
uint32_t creature_current_job_offset;
|
||||
uint32_t creature_current_job_id_offset;
|
||||
uint32_t creature_strength_offset;
|
||||
uint32_t creature_agility_offset;
|
||||
uint32_t creature_toughness_offset;
|
||||
uint32_t creature_skills_offset;
|
||||
uint32_t creature_labors_offset;
|
||||
uint32_t creature_happiness_offset;
|
||||
uint32_t creature_traits_offset;
|
||||
uint32_t creature_likes_offset;
|
||||
uint32_t creature_artifact_name_offset;
|
||||
uint32_t creature_mood_offset;
|
||||
uint32_t creature_pregnancy_offset;
|
||||
uint32_t creature_blood_max_offset;
|
||||
uint32_t creature_blood_current_offset;
|
||||
uint32_t creature_bleed_offset;
|
||||
// name offsets (needed for reading creature names)
|
||||
uint32_t name_firstname_offset;
|
||||
uint32_t name_nickname_offset;
|
||||
uint32_t name_words_offset;
|
||||
// HACK: vector address correction for SHM server
|
||||
int32_t vector_correct;
|
||||
} creature_offsets;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool inited;
|
||||
creature_offsets offsets;
|
||||
} creature_modulestate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
shm_cmd cmd[SHM_MAX_CLIENTS]; // MANDATORY!
|
||||
// box
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t z;
|
||||
uint32_t x2;
|
||||
uint32_t y2;
|
||||
uint32_t z2;
|
||||
// starting index
|
||||
int32_t index;
|
||||
} shm_creature_hdr;
|
||||
|
||||
enum CREATURE_COMMAND
|
||||
{
|
||||
CREATURE_INIT = 0, // initialization
|
||||
CREATURE_FIND_IN_BOX,
|
||||
CREATURE_AT_INDEX,
|
||||
NUM_CREATURE_CMDS
|
||||
};
|
||||
DFPP_module Init(void);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,130 +0,0 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <dfhack/DFIntegers.h>
|
||||
|
||||
#include "shms.h"
|
||||
#include "mod-core.h"
|
||||
#include "mod-maps.h"
|
||||
#include <dfhack/DFTypes.h>
|
||||
#include <dfhack/modules/Maps.h>
|
||||
using namespace DFHack;
|
||||
using namespace DFHack::Server::Maps;
|
||||
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
extern char *shm;
|
||||
|
||||
//TODO: circular buffer streaming primitives required
|
||||
//TODO: commands can fail without the proper offsets. Hot to handle that?
|
||||
|
||||
namespace DFHack{
|
||||
namespace Server{ // start of namespace
|
||||
namespace Maps{ // start of namespace
|
||||
|
||||
#define SHMHDR ((shm_maps_hdr *)shm)
|
||||
#define SHMCMD ((shm_cmd *)shm)->pingpong
|
||||
#define SHMDATA(type) ((type *)(shm + SHM_HEADER))
|
||||
|
||||
void NullCommand (void* data)
|
||||
{
|
||||
};
|
||||
|
||||
void InitOffsets (void* data)
|
||||
{
|
||||
maps_modulestate * state = (maps_modulestate *) data;
|
||||
memcpy((void *) &(state->offsets), SHMDATA(void), sizeof(maps_offsets));
|
||||
((maps_modulestate *) data)->inited = true;
|
||||
}
|
||||
|
||||
void GetMapSize (void *data)
|
||||
{
|
||||
maps_modulestate * state = (maps_modulestate *) data;
|
||||
if(state->inited)
|
||||
{
|
||||
SHMHDR->x = *(uint32_t *) (state->offsets.x_count_offset);
|
||||
SHMHDR->y = *(uint32_t *) (state->offsets.y_count_offset);
|
||||
SHMHDR->z = *(uint32_t *) (state->offsets.z_count_offset);
|
||||
SHMHDR->error = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
SHMHDR->error = true;
|
||||
}
|
||||
}
|
||||
|
||||
struct mblock
|
||||
{
|
||||
uint32_t * ptr_to_dirty;
|
||||
};
|
||||
|
||||
inline void ReadBlockByAddress (void * data)
|
||||
{
|
||||
maps_modulestate * state = (maps_modulestate *) data;
|
||||
maps_offsets & offsets = state->offsets;
|
||||
mblock * block = (mblock *) SHMHDR->address;
|
||||
if(block)
|
||||
{
|
||||
memcpy(&(SHMDATA(mapblock40d)->tiletypes), ((char *) block) + offsets.tile_type_offset, sizeof(SHMDATA(mapblock40d)->tiletypes));
|
||||
memcpy(&(SHMDATA(mapblock40d)->designation), ((char *) block) + offsets.designation_offset, sizeof(SHMDATA(mapblock40d)->designation));
|
||||
memcpy(&(SHMDATA(mapblock40d)->occupancy), ((char *) block) + offsets.occupancy_offset, sizeof(SHMDATA(mapblock40d)->occupancy));
|
||||
memcpy(&(SHMDATA(mapblock40d)->biome_indices), ((char *) block) + offsets.biome_stuffs, sizeof(SHMDATA(mapblock40d)->biome_indices));
|
||||
SHMDATA(mapblock40d)->blockflags.whole = *block->ptr_to_dirty;
|
||||
|
||||
SHMDATA(mapblock40d)->local_feature = *(int16_t *)((char*) block + offsets.local_feature_offset);
|
||||
SHMDATA(mapblock40d)->global_feature = *(int16_t *)((char*) block + offsets.global_feature_offset);
|
||||
|
||||
SHMDATA(mapblock40d)->origin = (uint32_t)(uint64_t)block; // this is STUPID
|
||||
SHMHDR->error = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
SHMHDR->error = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadBlockByCoords (void * data)
|
||||
{
|
||||
maps_modulestate * state = (maps_modulestate *) data;
|
||||
maps_offsets & offsets = state->offsets;
|
||||
/* map_offset is a pointer to
|
||||
a pointer to
|
||||
an X block of pointers to
|
||||
an Y blocks of pointers to
|
||||
a Z blocks of pointers to
|
||||
map blocks
|
||||
only Z blocks can have NULL pointers? TODO: verify
|
||||
*/
|
||||
mblock * *** mapArray = *(mblock * ****)offsets.map_offset;
|
||||
SHMHDR->address = (uint32_t) (uint64_t) mapArray[SHMHDR->x][SHMHDR->y][SHMHDR->z];// this is STUPID
|
||||
ReadBlockByAddress(data); // I wonder... will this inline properly?
|
||||
}
|
||||
|
||||
DFPP_module Init( void )
|
||||
{
|
||||
DFPP_module maps;
|
||||
maps.name = "Maps";
|
||||
maps.version = MAPS_VERSION;
|
||||
// freed by the core
|
||||
maps.modulestate = malloc(sizeof(maps_modulestate)); // we store a flag
|
||||
memset(maps.modulestate,0,sizeof(maps_modulestate));
|
||||
|
||||
maps.reserve(NUM_MAPS_CMDS);
|
||||
|
||||
// client sends a maps_offsets struct -> inited = true;
|
||||
maps.set_command(MAP_INIT, FUNCTION, "Supply the module with offsets",InitOffsets,CORE_SUSPENDED);
|
||||
maps.set_command(MAP_GET_SIZE, FUNCTION, "Get map size in 16x16x1 tile blocks", GetMapSize, CORE_SUSPENDED);
|
||||
maps.set_command(MAP_READ_BLOCK_BY_COORDS, FUNCTION, "Read the whole block with specified coords", ReadBlockByCoords, CORE_SUSPENDED);
|
||||
maps.set_command(MAP_READ_BLOCK_BY_ADDRESS, FUNCTION, "Read the whole block from an address", ReadBlockByAddress, CORE_SUSPENDED);
|
||||
|
||||
// will it fit into 1MB? We shouldn't assume this is the case
|
||||
maps.set_command(MAP_READ_BLOCKTREE, FUNCTION,"Get the tree of block pointers as a single structure", NullCommand, CORE_SUSPENDED);
|
||||
|
||||
// really doesn't fit into 1MB, there should be a streaming variant to better utilize context switches
|
||||
maps.set_command(MAP_READ_BLOCKS_3D, FUNCTION, "Read a range of blocks between two sets of coords", NullCommand, CORE_SUSPENDED);
|
||||
|
||||
return maps;
|
||||
}
|
||||
|
||||
}}} // end of namespace
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef MOD_MAPS_H
|
||||
#define MOD_MAPS_H
|
||||
|
||||
#include "dfhack/DFTypes.h"
|
||||
|
||||
namespace DFHack
|
||||
{
|
||||
namespace Server
|
||||
{
|
||||
namespace Maps
|
||||
{
|
||||
// increment on every change
|
||||
#define MAPS_VERSION 5
|
||||
typedef struct
|
||||
{
|
||||
uint32_t map_offset;// = d->offset_descriptor->getAddress ("map_data");
|
||||
uint32_t x_count_offset;// = d->offset_descriptor->getAddress ("x_count");
|
||||
uint32_t y_count_offset;// = d->offset_descriptor->getAddress ("y_count");
|
||||
uint32_t z_count_offset;// = d->offset_descriptor->getAddress ("z_count");
|
||||
/*
|
||||
Block
|
||||
*/
|
||||
uint32_t tile_type_offset;// = d->offset_descriptor->getOffset ("type");
|
||||
uint32_t designation_offset;// = d->offset_descriptor->getOffset ("designation");
|
||||
uint32_t occupancy_offset;// = d->offset_descriptor->getOffset ("occupancy");
|
||||
uint32_t biome_stuffs;// = d->offset_descriptor->getOffset ("biome_stuffs");
|
||||
uint32_t veinvector;// = d->offset_descriptor->getOffset ("v_vein");
|
||||
uint32_t vegvector;
|
||||
uint32_t temperature1_offset;
|
||||
uint32_t temperature2_offset;
|
||||
uint32_t global_feature_offset;
|
||||
uint32_t local_feature_offset;
|
||||
|
||||
uint32_t vein_mineral_vptr;
|
||||
uint32_t vein_ice_vptr;
|
||||
uint32_t vein_spatter_vptr;
|
||||
uint32_t vein_grass_vptr;
|
||||
uint32_t vein_worldconstruction_vptr;
|
||||
/*
|
||||
GEOLOGY
|
||||
*/
|
||||
uint32_t region_x_offset;// = minfo->getAddress ("region_x");
|
||||
uint32_t region_y_offset;// = minfo->getAddress ("region_y");
|
||||
uint32_t region_z_offset;// = minfo->getAddress ("region_z");
|
||||
|
||||
uint32_t world_regions;// mem->getAddress ("ptr2_region_array");
|
||||
uint32_t region_size;// = minfo->getHexValue ("region_size");
|
||||
uint32_t region_geo_index_offset;// = minfo->getOffset ("region_geo_index_off");
|
||||
uint32_t world_geoblocks_vector;// = minfo->getOffset ("geoblock_vector");
|
||||
uint32_t world_size_x;// = minfo->getOffset ("world_size_x");
|
||||
uint32_t world_size_y;// = minfo->getOffset ("world_size_y");
|
||||
uint32_t geolayer_geoblock_offset;// = minfo->getOffset ("geolayer_geoblock_offset");
|
||||
uint32_t type_inside_geolayer;// = mem->getOffset ("type_inside_geolayer");
|
||||
|
||||
/*
|
||||
FEATURES
|
||||
*/
|
||||
uint32_t world_data;
|
||||
uint32_t local_f_start; // offset from world_data or absolute address.
|
||||
uint32_t local_material;
|
||||
uint32_t local_submaterial;
|
||||
uint32_t global_vector; // offset from world_data or absolute address.
|
||||
uint32_t global_funcptr;
|
||||
uint32_t global_material;
|
||||
uint32_t global_submaterial;
|
||||
/*
|
||||
* Vegetation
|
||||
*/
|
||||
uint32_t tree_desc_offset;
|
||||
} maps_offsets;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool inited;
|
||||
maps_offsets offsets;
|
||||
} maps_modulestate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
shm_cmd cmd[SHM_MAX_CLIENTS]; // MANDATORY!
|
||||
uint32_t x;
|
||||
uint32_t y;
|
||||
uint32_t z;
|
||||
uint32_t x2;
|
||||
uint32_t y2;
|
||||
uint32_t z2;
|
||||
uint32_t address;
|
||||
uint32_t error;
|
||||
} shm_maps_hdr;
|
||||
|
||||
enum MAPS_COMMAND
|
||||
{
|
||||
MAP_INIT = 0, // initialization
|
||||
MAP_PROBE, // check if the map is still there
|
||||
MAP_GET_SIZE, // get the map size in 16x16x1 blocks
|
||||
MAP_READ_BLOCKTREE, // read the structure of pointers to blocks
|
||||
MAP_READ_BLOCK_BY_COORDS, // read block by cords
|
||||
MAP_READ_BLOCK_BY_ADDRESS, // read block by address
|
||||
MAP_WRITE_BLOCK,
|
||||
MAP_READ_BLOCKS_3D, // read blocks between two coords (volumetric)
|
||||
MAP_READ_ALL_BLOCKS, // read the entire map
|
||||
MAP_REVEAL, // reveal the whole map
|
||||
NUM_MAPS_CMDS
|
||||
};
|
||||
DFPP_module Init(void);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,14 +0,0 @@
|
||||
Using the shm server:
|
||||
copy files to DF/libs folder
|
||||
g++ -fPIC -c dfconnect.c -o dfconnect.o
|
||||
g++ -shared -o dfconnect.so dfconnect.o -ldl
|
||||
|
||||
edit DF/df script and add this line just before DF is called:
|
||||
export LD_PRELOAD="./libs/dfconnect.so" # Hack DF!
|
||||
|
||||
save and run the script!
|
||||
|
||||
Has to be compiled for 32bit arch, otherwise the library isn't recognised. Client can be any arch.
|
||||
|
||||
Precompiled dfconnect library is made available. dfconnect.so goes in DF/libs, df-hacked script goes in DF/
|
||||
Run ./df-hacked to use the shared memory API
|
@ -1,402 +0,0 @@
|
||||
/*
|
||||
www.sourceforge.net/projects/dfhack
|
||||
Copyright (c) 2009 Petr Mrázek (peterix)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is the source for the DF <-> dfhack shm bridge
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "shms.h"
|
||||
#include "mod-core.h"
|
||||
#include <sched.h>
|
||||
|
||||
#define DFhackCExport extern "C" __attribute__ ((visibility("default")))
|
||||
|
||||
// various crud
|
||||
int counter = 0;
|
||||
int errorstate = 0;
|
||||
char *shm = 0;
|
||||
int shmid = 0;
|
||||
bool inited = 0;
|
||||
|
||||
int fd_svlock = -1;
|
||||
int fd_cllock[SHM_MAX_CLIENTS];
|
||||
int fd_clSlock[SHM_MAX_CLIENTS];
|
||||
int held_clSlock[SHM_MAX_CLIENTS];
|
||||
int numheld = SHM_MAX_CLIENTS;
|
||||
|
||||
/*******************************************************************************
|
||||
* SHM part starts here *
|
||||
*******************************************************************************/
|
||||
// is the other side still there?
|
||||
bool isValidSHM(int which)
|
||||
{
|
||||
// if we get the client lock here, the client process failed and we need to reclaim our suspend lock
|
||||
if(lockf(fd_cllock[which],F_TLOCK,0) == 0)
|
||||
{
|
||||
// we get back our suspend lock from the cold, dead hands of the former client :P
|
||||
OS_lockSuspendLock(which);
|
||||
// free the client lock again
|
||||
lockf(fd_cllock[which],F_ULOCK,0);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t OS_getPID()
|
||||
{
|
||||
return getpid();
|
||||
}
|
||||
|
||||
uint32_t OS_getAffinity()
|
||||
{
|
||||
cpu_set_t mask;
|
||||
sched_getaffinity(0,sizeof(cpu_set_t),&mask);
|
||||
// FIXME: truncation
|
||||
uint32_t affinity = *(uint32_t *) &mask;
|
||||
return affinity;
|
||||
}
|
||||
|
||||
void OS_lockSuspendLock(int which)
|
||||
{
|
||||
if(numheld == SHM_MAX_CLIENTS)
|
||||
return;
|
||||
// lock not held by server and can be picked up. OK.
|
||||
if(held_clSlock[which] == 0 && lockf(fd_clSlock[which],F_LOCK,0) == 0)
|
||||
{
|
||||
held_clSlock[which] = 1;
|
||||
numheld++;
|
||||
}
|
||||
// lock couldn't be picked up!
|
||||
else if (held_clSlock[which] == 0)
|
||||
{
|
||||
fprintf(stderr,"lock %d failed to lock\n", which);
|
||||
}
|
||||
}
|
||||
|
||||
void OS_releaseSuspendLock(int which)
|
||||
{
|
||||
/*
|
||||
if(which >=0 && which < SHM_MAX_CLIENTS)
|
||||
return;
|
||||
*/
|
||||
if(numheld != SHM_MAX_CLIENTS)
|
||||
{
|
||||
fprintf(stderr,"TOTAL FAILURE OF LOCKING SYSTEM\n");
|
||||
return;
|
||||
}
|
||||
// lock hel by server and can be released -> OK
|
||||
if(held_clSlock[which] == 1 && lockf(fd_clSlock[which],F_ULOCK,0) == 0)
|
||||
{
|
||||
numheld--;
|
||||
held_clSlock[which] = 0;
|
||||
}
|
||||
// locked and not can't be released? FAIL!
|
||||
else if (held_clSlock[which] == 1)
|
||||
fprintf(stderr,"lock %d failed to unlock\n", which);
|
||||
}
|
||||
|
||||
void SHM_Init ( void )
|
||||
{
|
||||
// check that we do this only once per process
|
||||
if(inited)
|
||||
{
|
||||
fprintf(stderr, "SDL_Init was called twice or more!\n");
|
||||
return;
|
||||
}
|
||||
inited = true;
|
||||
char name[256];
|
||||
char name2[256];
|
||||
// make folder structure for our lock files
|
||||
sprintf(name, "/tmp/DFHack/%d",OS_getPID());
|
||||
mode_t createmode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
|
||||
mkdir("/tmp/DFHack", createmode);
|
||||
mkdir(name, createmode);
|
||||
|
||||
// create and lock the server lock file
|
||||
sprintf(name2, "%s/SVlock",name);
|
||||
fd_svlock = open(name2,O_WRONLY | O_CREAT, createmode);
|
||||
lockf( fd_svlock, F_LOCK, 0 );
|
||||
|
||||
for(int i = 0; i < SHM_MAX_CLIENTS; i++)
|
||||
{
|
||||
// create the client lock file
|
||||
sprintf(name2, "%s/CLlock%d",name,i);
|
||||
fd_cllock[i] = open(name2,O_WRONLY | O_CREAT, createmode);
|
||||
// get and lock the suspend locks
|
||||
sprintf(name2, "%s/CLSlock%d",name,i);
|
||||
fd_clSlock[i] = open(name2,O_WRONLY | O_CREAT, createmode);
|
||||
lockf(fd_clSlock[i],F_LOCK,0);
|
||||
held_clSlock[i] = 1;
|
||||
}
|
||||
|
||||
// name for the segment, an accident waiting to happen
|
||||
key_t key = SHM_KEY + OS_getPID();
|
||||
|
||||
// find previous segment, check if it's used by some processes.
|
||||
// if it isn't, kill it with fire
|
||||
if ((shmid = shmget(key, SHM_SIZE, 0600)) != -1)
|
||||
{
|
||||
shmid_ds descriptor;
|
||||
shmctl(shmid, IPC_STAT, &descriptor);
|
||||
if(descriptor.shm_nattch == 0)
|
||||
{
|
||||
shmctl(shmid,IPC_RMID,NULL);
|
||||
fprintf(stderr,"dfhack: killed dangling resources from crashed DF.\n");
|
||||
}
|
||||
}
|
||||
// create the segment, make sure only ww are really creating it
|
||||
if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0600)) < 0)
|
||||
{
|
||||
perror("shmget");
|
||||
errorstate = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// attach the segment
|
||||
if ((shm = (char *) shmat(shmid, 0, 0)) == (char *) -1)
|
||||
{
|
||||
perror("shmat");
|
||||
errorstate = 1;
|
||||
return;
|
||||
}
|
||||
full_barrier
|
||||
// make sure we don't stall or do crazy stuff
|
||||
for(int i = 0; i < SHM_MAX_CLIENTS;i++)
|
||||
{
|
||||
((uint32_t *)shm)[i] = CORE_RUNNING;
|
||||
}
|
||||
InitModules();
|
||||
}
|
||||
|
||||
void SHM_Destroy ( void )
|
||||
{
|
||||
if(inited && !errorstate)
|
||||
{
|
||||
KillModules();
|
||||
shmid_ds descriptor;
|
||||
shmctl(shmid, IPC_STAT, &descriptor);
|
||||
shmdt(shm);
|
||||
while(descriptor.shm_nattch != 0)
|
||||
{
|
||||
shmctl(shmid, IPC_STAT, &descriptor);
|
||||
}
|
||||
shmctl(shmid,IPC_RMID,NULL);
|
||||
|
||||
char name[256];
|
||||
char name2[256];
|
||||
sprintf(name, "/tmp/DFHack/%d",OS_getPID());
|
||||
|
||||
// unlock and close server lock, close client lock, destroy files
|
||||
lockf(fd_svlock,F_ULOCK,0);
|
||||
for(int i = 0; i < SHM_MAX_CLIENTS; i++)
|
||||
{
|
||||
close(fd_cllock[i]);
|
||||
fd_cllock[i] = 0;
|
||||
close(fd_clSlock[i]);
|
||||
fd_clSlock[i] = 0;
|
||||
held_clSlock[i] = 0;
|
||||
sprintf(name2, "%s/CLlock%d",name,i);
|
||||
unlink(name2);
|
||||
sprintf(name2, "%s/CLSlock%d",name,i);
|
||||
unlink(name2);
|
||||
}
|
||||
close(fd_svlock);
|
||||
fd_svlock = 0;
|
||||
sprintf(name2, "%s/SVlock",name);
|
||||
unlink(name2);
|
||||
// remove the PID folder
|
||||
rmdir(name);
|
||||
fprintf(stderr,"dfhack: destroyed shared segment.\n");
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* SDL part starts here *
|
||||
*******************************************************************************/
|
||||
// this is supported from 0.31.04 forward
|
||||
DFhackCExport int SDL_NumJoysticks(void)
|
||||
{
|
||||
if(errorstate)
|
||||
return -1;
|
||||
if(!inited)
|
||||
{
|
||||
SHM_Init();
|
||||
return -2;
|
||||
}
|
||||
SHM_Act();
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
||||
// ptr to the real functions
|
||||
//static void (*_SDL_GL_SwapBuffers)(void) = 0;
|
||||
static void (*_SDL_Quit)(void) = 0;
|
||||
static int (*_SDL_Init)(uint32_t flags) = 0;
|
||||
//static int (*_SDL_Flip)(void * some_ptr) = 0;
|
||||
/*
|
||||
// hook - called every tick in OpenGL mode of DF
|
||||
DFhackCExport void SDL_GL_SwapBuffers(void)
|
||||
{
|
||||
if(_SDL_GL_SwapBuffers)
|
||||
{
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Act();
|
||||
}
|
||||
counter ++;
|
||||
_SDL_GL_SwapBuffers();
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
// hook - called every tick in the 2D mode of DF
|
||||
DFhackCExport int SDL_Flip(void * some_ptr)
|
||||
{
|
||||
if(_SDL_Flip)
|
||||
{
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Act();
|
||||
}
|
||||
counter ++;
|
||||
return _SDL_Flip(some_ptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
// hook - called at program exit
|
||||
DFhackCExport void SDL_Quit(void)
|
||||
{
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Destroy();
|
||||
errorstate = true;
|
||||
}
|
||||
if(_SDL_Quit)
|
||||
{
|
||||
_SDL_Quit();
|
||||
}
|
||||
}
|
||||
|
||||
// hook - called at program start, initialize some stuffs we'll use later
|
||||
DFhackCExport int SDL_Init(uint32_t flags)
|
||||
{
|
||||
// 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");
|
||||
|
||||
// check if we got them
|
||||
if(/*_SDL_GL_SwapBuffers &&*/ _SDL_Init && _SDL_Quit)
|
||||
{
|
||||
fprintf(stderr,"dfhack: hooking successful\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// bail, this would be a disaster otherwise
|
||||
fprintf(stderr,"dfhack: something went horribly wrong\n");
|
||||
errorstate = true;
|
||||
exit(1);
|
||||
}
|
||||
//SHM_Init();
|
||||
|
||||
return _SDL_Init(flags);
|
||||
}
|
||||
//*/
|
||||
/*******************************************************************************
|
||||
* NCURSES part starts here *
|
||||
*******************************************************************************/
|
||||
|
||||
static int (*_refresh)(void) = 0;
|
||||
//extern NCURSES_EXPORT(int) refresh (void);
|
||||
DFhackCExport int refresh (void)
|
||||
{
|
||||
if(_refresh)
|
||||
{
|
||||
/*
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Act();
|
||||
}
|
||||
counter ++;
|
||||
*/
|
||||
return _refresh();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*_endwin)(void) = 0;
|
||||
//extern NCURSES_EXPORT(int) endwin (void);
|
||||
DFhackCExport int endwin (void)
|
||||
{
|
||||
if(!errorstate)
|
||||
{
|
||||
SHM_Destroy();
|
||||
errorstate = true;
|
||||
}
|
||||
if(_endwin)
|
||||
{
|
||||
return _endwin();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef void WINDOW;
|
||||
//extern NCURSES_EXPORT(WINDOW *) initscr (void);
|
||||
static WINDOW * (*_initscr)(void) = 0;
|
||||
DFhackCExport WINDOW * initscr (void)
|
||||
{
|
||||
// find real functions
|
||||
//_refresh = (int (*)( void )) dlsym(RTLD_NEXT, "refresh");
|
||||
_endwin = (int (*)( void )) dlsym(RTLD_NEXT, "endwin");
|
||||
_initscr = (WINDOW * (*)( void )) dlsym(RTLD_NEXT, "initscr");
|
||||
// check if we got them
|
||||
if(_refresh && _endwin && _initscr)
|
||||
{
|
||||
fprintf(stderr,"dfhack: hooking successful\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// bail, this would be a disaster otherwise
|
||||
fprintf(stderr,"dfhack: something went horribly wrong\n");
|
||||
exit(1);
|
||||
}
|
||||
//SHM_Init();
|
||||
return _initscr();
|
||||
}
|
Loading…
Reference in New Issue