Merge branch 'develop' of https://github.com/DFHack/dfhack into develop
commit
2f86683d37
@ -1,11 +0,0 @@
|
|||||||
include_directories(include)
|
|
||||||
|
|
||||||
FILE(GLOB DFUSION_CPPS src/*.c*)
|
|
||||||
set(
|
|
||||||
DFUSION_CPPS_ALL
|
|
||||||
dfusion.cpp
|
|
||||||
${DFUSION_CPPS}
|
|
||||||
)
|
|
||||||
FILE(GLOB DFUSION_HS include/*)
|
|
||||||
SET_SOURCE_FILES_PROPERTIES( ${DFUSION_HS} PROPERTIES HEADER_FILE_ONLY TRUE )
|
|
||||||
DFHACK_PLUGIN(dfusion ${DFUSION_CPPS_ALL} ${DFUSION_HS} LINK_LIBRARIES lua dfhack-tinythread)
|
|
@ -1,88 +0,0 @@
|
|||||||
#include "Core.h"
|
|
||||||
#include "Export.h"
|
|
||||||
#include "PluginManager.h"
|
|
||||||
#include "MemAccess.h"
|
|
||||||
#include "MiscUtils.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "luamain.h"
|
|
||||||
#include "lua_Process.h"
|
|
||||||
#include "lua_Hexsearch.h"
|
|
||||||
#include "lua_Misc.h"
|
|
||||||
|
|
||||||
#include "DataDefs.h"
|
|
||||||
#include "LuaTools.h"
|
|
||||||
|
|
||||||
using std::vector;
|
|
||||||
using std::string;
|
|
||||||
using namespace DFHack;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DFHACK_PLUGIN("dfusion")
|
|
||||||
|
|
||||||
static int loadObjectFile(lua_State* L)
|
|
||||||
{
|
|
||||||
std::string path;
|
|
||||||
|
|
||||||
path=luaL_checkstring(L,1);
|
|
||||||
|
|
||||||
OutFile::File f(path);
|
|
||||||
lua_newtable(L);
|
|
||||||
int table_pos=lua_gettop(L);
|
|
||||||
size_t size=f.GetTextSize();
|
|
||||||
Lua::Push(L,size);
|
|
||||||
lua_setfield(L,table_pos,"data_size");
|
|
||||||
char* buf=new char[size];
|
|
||||||
f.GetText(buf);
|
|
||||||
|
|
||||||
//Lua::PushDFObject(L,DFHack::,buf);
|
|
||||||
//Lua::Push(L,buf);
|
|
||||||
lua_pushlightuserdata(L,buf);
|
|
||||||
lua_setfield(L,table_pos,"data");
|
|
||||||
const OutFile::vSymbol &symbols=f.GetSymbols();
|
|
||||||
lua_newtable(L);
|
|
||||||
for(size_t i=0;i<symbols.size();i++)
|
|
||||||
{
|
|
||||||
Lua::Push(L,i);
|
|
||||||
lua_newtable(L);
|
|
||||||
Lua::Push(L,symbols[i].name);
|
|
||||||
lua_setfield(L,-2,"name");
|
|
||||||
Lua::Push(L,symbols[i].pos);
|
|
||||||
lua_setfield(L,-2,"pos");
|
|
||||||
|
|
||||||
|
|
||||||
lua_settable(L,-3);
|
|
||||||
}
|
|
||||||
lua_setfield(L,table_pos,"symbols");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int markAsExecutable(lua_State* L)
|
|
||||||
{
|
|
||||||
unsigned addr=luaL_checkunsigned(L,1);
|
|
||||||
std::vector<DFHack::t_memrange> ranges;
|
|
||||||
DFHack::Core::getInstance().p->getMemRanges(ranges);
|
|
||||||
for(size_t i=0;i<ranges.size();i++)
|
|
||||||
{
|
|
||||||
if(ranges[i].isInRange((void*)addr))
|
|
||||||
{
|
|
||||||
DFHack::t_memrange newperm=ranges[i];
|
|
||||||
newperm.execute=true;
|
|
||||||
DFHack::Core::getInstance().p->setPermisions(ranges[i],newperm);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lua_pushlstring(L,"Memory range not found",23);
|
|
||||||
lua_error(L);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
DFHACK_PLUGIN_LUA_COMMANDS {
|
|
||||||
DFHACK_LUA_COMMAND(loadObjectFile),
|
|
||||||
DFHACK_LUA_COMMAND(markAsExecutable),
|
|
||||||
DFHACK_LUA_END
|
|
||||||
};
|
|
||||||
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
|
|
||||||
{
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
#ifndef OUTFILE_H
|
|
||||||
#define OUTFILE_H
|
|
||||||
#include <string>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
namespace OutFile
|
|
||||||
{
|
|
||||||
struct Header
|
|
||||||
{
|
|
||||||
unsigned short machinetype;
|
|
||||||
unsigned short sectioncount;
|
|
||||||
unsigned long time;
|
|
||||||
unsigned long symbolptr;
|
|
||||||
unsigned long symbolcount;
|
|
||||||
unsigned short opthead;
|
|
||||||
unsigned short flags;
|
|
||||||
void PrintData()
|
|
||||||
{
|
|
||||||
std::cout<<"Symbol start:"<<symbolptr<<"\n";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
struct Section
|
|
||||||
{
|
|
||||||
char name[8];
|
|
||||||
unsigned long Vsize;
|
|
||||||
unsigned long Vstart;
|
|
||||||
unsigned long size;
|
|
||||||
unsigned long start;
|
|
||||||
unsigned long ptrRel;
|
|
||||||
unsigned long ptrLine;
|
|
||||||
unsigned short numRel;
|
|
||||||
unsigned short numLine;
|
|
||||||
unsigned long flags;
|
|
||||||
void PrintData()
|
|
||||||
{
|
|
||||||
std::cout<<name<<" size:"<<size<<" start:"<<start<<"\n";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
struct Symbol
|
|
||||||
{
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
unsigned long pos;
|
|
||||||
unsigned short sectnumb;
|
|
||||||
unsigned short type;
|
|
||||||
unsigned char storageclass;
|
|
||||||
unsigned char auxsymbs;
|
|
||||||
//char unk2[6];
|
|
||||||
void Read(std::iostream &s,unsigned long strptr)
|
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
char buf[8];
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned long zeros;
|
|
||||||
unsigned long strptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
}data;
|
|
||||||
|
|
||||||
s.read((char*)&data,8);
|
|
||||||
s.read((char*)&pos,4);
|
|
||||||
s.read((char*)§numb,2);
|
|
||||||
s.read((char*)&type,2);
|
|
||||||
s.read((char*)&storageclass,1);
|
|
||||||
s.read((char*)&auxsymbs,1);
|
|
||||||
if(data.zeros!=0)
|
|
||||||
{
|
|
||||||
name=data.buf;
|
|
||||||
name=name.substr(0,8);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//name="";
|
|
||||||
//std::cout<<"Name in symbol table\n";
|
|
||||||
char buf[256];
|
|
||||||
s.seekg(strptr+data.strptr);
|
|
||||||
s.get(buf,256,'\0');
|
|
||||||
name=buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
//s.seekp(6,std::ios::cur);
|
|
||||||
}
|
|
||||||
void PrintData()
|
|
||||||
{
|
|
||||||
std::cout<<name<<" section:"<<sectnumb<<" pos:"<<pos<<"\n";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
struct Relocation
|
|
||||||
{
|
|
||||||
unsigned long ptr;
|
|
||||||
unsigned long tblIndex;
|
|
||||||
unsigned short type;
|
|
||||||
};
|
|
||||||
typedef std::vector<Symbol> vSymbol;
|
|
||||||
class File
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
File(std::string path);
|
|
||||||
virtual ~File();
|
|
||||||
|
|
||||||
void GetText(char *ptr);
|
|
||||||
size_t GetTextSize();
|
|
||||||
void LoadSymbols();
|
|
||||||
const vSymbol& GetSymbols(){LoadSymbols();return symbols;};
|
|
||||||
void PrintSymbols();
|
|
||||||
void PrintRelocations();
|
|
||||||
protected:
|
|
||||||
private:
|
|
||||||
typedef std::map<std::string,Section> secMap;
|
|
||||||
|
|
||||||
secMap sections;
|
|
||||||
vSymbol symbols;
|
|
||||||
Section &GetSection(std::string name);
|
|
||||||
|
|
||||||
std::fstream mystream;
|
|
||||||
Header myhead;
|
|
||||||
// Section Text;
|
|
||||||
//Section Data;
|
|
||||||
// Section Bss;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif // OUTFILE_H
|
|
@ -1,37 +0,0 @@
|
|||||||
#ifndef HEXSEARCH_H
|
|
||||||
#define HEXSEARCH_H
|
|
||||||
#include <vector>
|
|
||||||
#include "Core.h" //for some reason process.h needs core
|
|
||||||
#include "MemAccess.h"
|
|
||||||
|
|
||||||
//(not yet)implemented using Boyer-Moore algorithm
|
|
||||||
|
|
||||||
class Hexsearch
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::vector<int> SearchArgType;
|
|
||||||
enum SearchConst //TODO add more
|
|
||||||
{
|
|
||||||
ANYBYTE=0x101,DWORD_,ANYDWORD,ADDRESS
|
|
||||||
};
|
|
||||||
|
|
||||||
Hexsearch(const SearchArgType &args,char * startpos,char * endpos);
|
|
||||||
~Hexsearch();
|
|
||||||
|
|
||||||
void Reset(){pos_=startpos_;};
|
|
||||||
void SetStart(char * pos){pos_=pos;};
|
|
||||||
|
|
||||||
void * FindNext();
|
|
||||||
std::vector<void *> FindAll();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool Compare(int a,int b);
|
|
||||||
void ReparseArgs();
|
|
||||||
SearchArgType args_;
|
|
||||||
char * pos_,* startpos_,* endpos_;
|
|
||||||
std::vector<int> BadCharShifts,GoodSuffixShift;
|
|
||||||
void PrepareGoodSuffixTable();
|
|
||||||
void PrepareBadCharShift();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,33 +0,0 @@
|
|||||||
#ifndef LUA_HEXSEARCH_H
|
|
||||||
#define LUA_HEXSEARCH_H
|
|
||||||
#include "hexsearch.h"
|
|
||||||
|
|
||||||
#include "luamain.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace lua
|
|
||||||
{
|
|
||||||
|
|
||||||
class Hexsearch
|
|
||||||
{
|
|
||||||
int tblid;
|
|
||||||
::Hexsearch *p;
|
|
||||||
public:
|
|
||||||
Hexsearch(lua_State *L,int id);
|
|
||||||
~Hexsearch();
|
|
||||||
|
|
||||||
int GetTableId(){return tblid;};
|
|
||||||
|
|
||||||
int find(lua_State *L);
|
|
||||||
int findall(lua_State *L);
|
|
||||||
int reset(lua_State *L);
|
|
||||||
|
|
||||||
DEF_LUNE(Hexsearch);
|
|
||||||
};
|
|
||||||
void RegisterHexsearch(lua::state &st);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,46 +0,0 @@
|
|||||||
#ifndef LUA_MISC_H
|
|
||||||
#define LUA_MISC_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "Core.h"
|
|
||||||
#include <MemAccess.h>
|
|
||||||
#include "luamain.h"
|
|
||||||
#include "OutFile.h"
|
|
||||||
#include "LuaTools.h"
|
|
||||||
|
|
||||||
namespace lua
|
|
||||||
{
|
|
||||||
|
|
||||||
typedef std::map<std::string,void *> mapPlugs;
|
|
||||||
|
|
||||||
class PlugManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
mapPlugs GetList(){return plugs;};
|
|
||||||
uint32_t AddNewPlug(std::string name,uint32_t size,uint32_t loc=0);
|
|
||||||
uint32_t FindPlugin(std::string name);
|
|
||||||
|
|
||||||
static PlugManager &GetInst()
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
p=DFHack::Core::getInstance().GetData("dfusion_manager");
|
|
||||||
if(p==0)
|
|
||||||
{
|
|
||||||
p=new PlugManager;
|
|
||||||
DFHack::Core::getInstance().RegisterData(p,"dfusion_manager");
|
|
||||||
}
|
|
||||||
return *static_cast<PlugManager*>(p);
|
|
||||||
};
|
|
||||||
protected:
|
|
||||||
private:
|
|
||||||
PlugManager(){};
|
|
||||||
mapPlugs plugs;
|
|
||||||
};
|
|
||||||
|
|
||||||
void RegisterMisc(lua::state &st);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,13 +0,0 @@
|
|||||||
#ifndef LUA_PROCESS_H
|
|
||||||
#define LUA_PROCESS_H
|
|
||||||
|
|
||||||
#include "Core.h"
|
|
||||||
#include <MemAccess.h>
|
|
||||||
|
|
||||||
#include "luamain.h"
|
|
||||||
|
|
||||||
namespace lua
|
|
||||||
{
|
|
||||||
void RegisterProcess(lua::state &st);
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,40 +0,0 @@
|
|||||||
#ifndef LUAMAIN_H
|
|
||||||
#define LUAMAIN_H
|
|
||||||
#include <string>
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
#include "lualib.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include "lune.h"
|
|
||||||
#include "luaxx.hpp"
|
|
||||||
|
|
||||||
namespace lua
|
|
||||||
{
|
|
||||||
//global lua state singleton
|
|
||||||
class glua
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static state &Get();
|
|
||||||
private:
|
|
||||||
glua();
|
|
||||||
static glua *ptr;
|
|
||||||
state mystate;
|
|
||||||
};
|
|
||||||
//registers basic lua commands
|
|
||||||
void RegBasics(lua::state &L);
|
|
||||||
//dumps lua function trace, useless unless called from lua.
|
|
||||||
string DebugDump(lua::state &L);
|
|
||||||
//register functions, first registers into global scope, second into current table
|
|
||||||
void RegFunctions(lua::state &L,luaL_Reg const *arr);
|
|
||||||
void RegFunctionsLocal(lua::state &L,luaL_Reg const *arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // LUAMAIN_H
|
|
@ -1,530 +0,0 @@
|
|||||||
/* vim: set et sw=3 tw=0 fo=croqlaw cino=t0:
|
|
||||||
*
|
|
||||||
* Luaxx, the C++ Lua wrapper library.
|
|
||||||
* Copyright (c) 2006-2008 Matthew Nicholson
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to
|
|
||||||
* deal in the Software without restriction, including without limitation the
|
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
* IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LUAXX_H
|
|
||||||
#define LUAXX_H
|
|
||||||
|
|
||||||
#define lua_Integer_long 1
|
|
||||||
#define lua_Integer_int 1
|
|
||||||
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
#include "lualib.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <new>
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
/** @file
|
|
||||||
* Luaxx header file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @mainpage Luaxx
|
|
||||||
*
|
|
||||||
* Luaxx is a thin wrapper around the Lua C API. The wrapper adds some
|
|
||||||
* convenience functions and integrates well with modern C++.
|
|
||||||
*
|
|
||||||
* Luaxx is not designed like toLua, instead Luaxx is more of a 1 to 1
|
|
||||||
* logical mapping of the lua API in C++. For example: in C you would write
|
|
||||||
* 'lua_pushnumber(L, 3)', in C++ with Luaxx you would write
|
|
||||||
* 'L.push(3)'.
|
|
||||||
*
|
|
||||||
* Every thing is contained in the 'lua' namespace and exceptions are thrown
|
|
||||||
* when a lua API function returns an error. Most of the functionality is
|
|
||||||
* contained in the lua::state class, which can be passed directly to lua C API
|
|
||||||
* functions (the compiler will automatically use the internal lua_State
|
|
||||||
* pointer). See the documentation for that class for more information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace lua
|
|
||||||
{
|
|
||||||
void StackDump(lua_State *L);
|
|
||||||
/** A generic lua exception.
|
|
||||||
*/
|
|
||||||
class exception : public std::exception {
|
|
||||||
public:
|
|
||||||
/// Constructor.
|
|
||||||
exception() : std::exception() { }
|
|
||||||
/// Constructor.
|
|
||||||
explicit exception(const char* desc) : std::exception(), description(desc) { }
|
|
||||||
virtual ~exception() throw() { }
|
|
||||||
/** Get a description of the error.
|
|
||||||
* @returns a C-string describing the error
|
|
||||||
*/
|
|
||||||
virtual const char* what() const throw() {
|
|
||||||
return description.c_str();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::string description;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** A lua runtime error.
|
|
||||||
* This is thrown when there was an error executing some lua code.
|
|
||||||
* @note This is not an std::runtime error.
|
|
||||||
*/
|
|
||||||
class runtime_error : public exception {
|
|
||||||
public:
|
|
||||||
/// Constructor.
|
|
||||||
runtime_error() : exception() { }
|
|
||||||
/// Constructor.
|
|
||||||
explicit runtime_error(const char* desc) : exception(desc) { }
|
|
||||||
virtual ~runtime_error() throw() { }
|
|
||||||
};
|
|
||||||
|
|
||||||
/** A syntax error.
|
|
||||||
*/
|
|
||||||
class syntax_error : public exception {
|
|
||||||
public:
|
|
||||||
/// Constructor.
|
|
||||||
syntax_error() : exception() { }
|
|
||||||
/// Constructor.
|
|
||||||
explicit syntax_error(const char* desc) : exception(desc) { }
|
|
||||||
virtual ~syntax_error() throw() { }
|
|
||||||
};
|
|
||||||
|
|
||||||
/** An error loading a lua file.
|
|
||||||
* This is thrown when a call to lua::loadfile failed because the file could
|
|
||||||
* not be opened or read.
|
|
||||||
*/
|
|
||||||
class file_error : public exception {
|
|
||||||
public:
|
|
||||||
/// Constructor.
|
|
||||||
file_error() : exception() { }
|
|
||||||
/// Constructor.
|
|
||||||
explicit file_error(const char* desc) : exception(desc) { }
|
|
||||||
virtual ~file_error() throw() { }
|
|
||||||
};
|
|
||||||
|
|
||||||
/** A memory allocation error.
|
|
||||||
*/
|
|
||||||
class bad_alloc : public exception, std::bad_alloc {
|
|
||||||
public:
|
|
||||||
/// Constructor.
|
|
||||||
bad_alloc() : lua::exception(), std::bad_alloc() { }
|
|
||||||
/// Constructor.
|
|
||||||
explicit bad_alloc(const char* desc) : lua::exception(desc), std::bad_alloc() { }
|
|
||||||
virtual ~bad_alloc() throw() { }
|
|
||||||
};
|
|
||||||
|
|
||||||
/** An error converting a lua type.
|
|
||||||
*/
|
|
||||||
class bad_conversion : public exception {
|
|
||||||
public:
|
|
||||||
/// Constructor.
|
|
||||||
bad_conversion() : exception() { }
|
|
||||||
/// Constructor.
|
|
||||||
explicit bad_conversion(const char* desc) : exception(desc) { }
|
|
||||||
virtual ~bad_conversion() throw() { }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A Lua table (this class does not have any data).
|
|
||||||
class table { };
|
|
||||||
/// A Lua nil (this class does not have any data).
|
|
||||||
class nil { };
|
|
||||||
/// A lua function (not a cfunction).
|
|
||||||
class function { };
|
|
||||||
/// A lua userdatum
|
|
||||||
class userdata { };
|
|
||||||
/// A lua light userdatum
|
|
||||||
class lightuserdata { };
|
|
||||||
|
|
||||||
typedef lua_CFunction cfunction; ///< A cfunction on the lua statck
|
|
||||||
typedef lua_Integer integer; ///< The default lua integer type
|
|
||||||
typedef lua_Number number; ///< The default lua number type
|
|
||||||
typedef lua_Reader reader; ///< The type of function used by lua_load
|
|
||||||
const int multiret = LUA_MULTRET; ///< LUA_MULTIRET
|
|
||||||
|
|
||||||
/** This is the Luaxx equivalent of lua_State.
|
|
||||||
* The functions provided by this class, closely resemble those of the Lua C
|
|
||||||
* API.
|
|
||||||
*/
|
|
||||||
void StackDump(lua_State *L);
|
|
||||||
class state {
|
|
||||||
public:
|
|
||||||
state();
|
|
||||||
state(lua_State* L);
|
|
||||||
state(const state& t)
|
|
||||||
{
|
|
||||||
managed=false;
|
|
||||||
L=t.L;
|
|
||||||
}
|
|
||||||
state& operator = (const state& t);
|
|
||||||
~state();
|
|
||||||
|
|
||||||
operator lua_State*();
|
|
||||||
|
|
||||||
state& push();
|
|
||||||
state& push(nil);
|
|
||||||
state& push(bool boolean);
|
|
||||||
template<typename T> state& push(T number);
|
|
||||||
state& push(const char* s, size_t length);
|
|
||||||
state& push(const char* s);
|
|
||||||
state& push(const std::string& s);
|
|
||||||
state& push(cfunction f);
|
|
||||||
state& push(table);
|
|
||||||
state& push(void* p);
|
|
||||||
template<typename T> state& pushlightuserdata(T p);
|
|
||||||
|
|
||||||
template<typename T> state& to(T& number, int index = -1);
|
|
||||||
template<typename T> state& touserdata(T& p, int index = -1);
|
|
||||||
|
|
||||||
template<typename T> T as(T default_value, int index = -1);
|
|
||||||
template<typename T> T as(int index = -1);
|
|
||||||
template<typename T> T vpop()
|
|
||||||
{
|
|
||||||
T ret;
|
|
||||||
ret=as<T>();
|
|
||||||
pop();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
template<typename T> bool is(int index = -1);
|
|
||||||
|
|
||||||
state& check(int narg);
|
|
||||||
#ifndef lua_Integer_int
|
|
||||||
state& check(int& i, int narg);
|
|
||||||
#endif
|
|
||||||
state& check(integer& i, int narg);
|
|
||||||
#ifndef lua_Integer_long
|
|
||||||
state& check(long& l, int narg);
|
|
||||||
#endif
|
|
||||||
state& check(std::string& s, int narg);
|
|
||||||
state& check(number& n, int narg);
|
|
||||||
|
|
||||||
template<typename msg_t> void error(msg_t message);
|
|
||||||
#if 0
|
|
||||||
template<> void error(const std::string& message);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
state& pcall(int nargs = 0, int nresults = 0, int on_error = 0);
|
|
||||||
state& call(int nargs = 0, int nresults = 0);
|
|
||||||
|
|
||||||
state& checkstack(int size);
|
|
||||||
state& settop(int index);
|
|
||||||
int gettop();
|
|
||||||
int size();
|
|
||||||
bool empty();
|
|
||||||
|
|
||||||
state& insert(int index);
|
|
||||||
state& replace(int index);
|
|
||||||
state& remove(int index);
|
|
||||||
state& pop(int elements = 1);
|
|
||||||
|
|
||||||
state& pushvalue(int index);
|
|
||||||
|
|
||||||
state& newtable();
|
|
||||||
bool newmetatable(const std::string& tname);
|
|
||||||
template<typename userdata_t> userdata_t* newuserdata();
|
|
||||||
void* newuserdata(size_t nbytes);
|
|
||||||
|
|
||||||
state& gettable(int index = -2);
|
|
||||||
state& getfield(const std::string& k, int index = -1);
|
|
||||||
state& settable(int index = -3);
|
|
||||||
state& setfield(const std::string& k, int index = -2);
|
|
||||||
state& getmetatable(const std::string& tname);
|
|
||||||
bool getmetatable(int index);
|
|
||||||
|
|
||||||
bool next(int index = -2);
|
|
||||||
|
|
||||||
state& getglobal(const std::string& name);
|
|
||||||
state& setglobal(const std::string& name);
|
|
||||||
|
|
||||||
state& loadfile(const std::string& filename);
|
|
||||||
state& loadstring(const std::string& s);
|
|
||||||
|
|
||||||
template<typename iterator_t> state& load(iterator_t begin, iterator_t end);
|
|
||||||
|
|
||||||
size_t objlen(int index = -1);
|
|
||||||
|
|
||||||
private:
|
|
||||||
lua_State* L;
|
|
||||||
bool managed;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int throw_error(int code);
|
|
||||||
};
|
|
||||||
|
|
||||||
// template functions
|
|
||||||
|
|
||||||
/** Push a number onto the stack.
|
|
||||||
* @tparam T the numeric type to push (should be automatically determined,
|
|
||||||
* if there is no specialization for the desired type, lua_pushnumber() will
|
|
||||||
* be used, and may fail)
|
|
||||||
* @param number the number to push
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
state& state::push(T number) {
|
|
||||||
lua_pushnumber(L, number);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Push a light userdatum on to the stack.
|
|
||||||
* @tparam T the type of data to push (should be automatically determined)
|
|
||||||
* @param p the pointer to push
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
state& state::pushlightuserdata(T p) {
|
|
||||||
lua_pushlightuserdata(L, p);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if the given index is of the given type (defaults to using
|
|
||||||
* lua_isnumber()).
|
|
||||||
* @tparam T the type to check for (the default, if no specializations
|
|
||||||
* match, does lua_isnumber())
|
|
||||||
* @param index the index to check
|
|
||||||
* @note the default version (used if no specialization is matched) will
|
|
||||||
* check if the given value is a number
|
|
||||||
* @returns whether the value at the given index is a nil
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
bool state::is(int index) {
|
|
||||||
return lua_isnumber(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the value at index as the given numeric type.
|
|
||||||
* @tparam T they numeric type to static_cast<T>() the numeric value on the
|
|
||||||
* stack to
|
|
||||||
* @param number where to store the value
|
|
||||||
* @param index the index to get
|
|
||||||
* @note This function does \em not pop the value from the stack.
|
|
||||||
* @todo Instead of throwing an exception here, we may just return an
|
|
||||||
* error code.
|
|
||||||
* @throws lua::bad_conversion if the value on the stack could not be
|
|
||||||
* converted to the indicated type
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
state& state::to(T& number, int index) {
|
|
||||||
if (lua_isnumber(L, index))
|
|
||||||
number = static_cast<T>(lua_tonumber(L, index));
|
|
||||||
else
|
|
||||||
throw bad_conversion("Cannot convert non 'number' value to number");
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the value at index as (light) userdata.
|
|
||||||
* @tparam T the type of data pointed to (pointer is returned as
|
|
||||||
* reinterpret_cast<T>())
|
|
||||||
* @param p the pointer to store the value in
|
|
||||||
* @param index the index to get
|
|
||||||
* @note This function does \em not pop the value from the stack.
|
|
||||||
* @todo Instead of throwing an exception here, we may just return an
|
|
||||||
* error code.
|
|
||||||
* @throws lua::bad_conversion if the value on the stack could not be
|
|
||||||
* converted to the indicated type
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
state& state::touserdata(T& p, int index) {
|
|
||||||
if (lua_isuserdata(L, index))
|
|
||||||
p = reinterpret_cast<T>(lua_touserdata(L, index));
|
|
||||||
else
|
|
||||||
throw bad_conversion("Cannot convert non 'userdata' or 'lightuserdata' value to userdata");
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the value at index as the given type.
|
|
||||||
* @tparam T the type to retrieve the value on the stack as (the default
|
|
||||||
* template function uses lua_tonumber(), specializations may cause
|
|
||||||
* different behavior)
|
|
||||||
* @param default_value this value is returned if the conversion fails
|
|
||||||
* @param index the index to get
|
|
||||||
* @note This function does \em not pop the value from the stack.
|
|
||||||
* @returns the indicated value from the stack or the default value if
|
|
||||||
* the conversion fails
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
T state::as(T default_value, int index) {
|
|
||||||
if (lua_isnumber(L, index))
|
|
||||||
return static_cast<T>(lua_tonumber(L, index));
|
|
||||||
else
|
|
||||||
return default_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the value at index as the given type.
|
|
||||||
* @tparam T the expected type of the value
|
|
||||||
* @param index the index to get
|
|
||||||
*
|
|
||||||
* @note This function does \em not pop the value from the stack.
|
|
||||||
* @note The default version of this function uses lua_tonumber() but
|
|
||||||
* specializations may cause different behavior.
|
|
||||||
*
|
|
||||||
* @todo Instead of throwing an exception here, we may just return an
|
|
||||||
* error code.
|
|
||||||
*
|
|
||||||
* @throws lua::bad_conversion if the value on the stack could not be
|
|
||||||
* converted to the indicated type
|
|
||||||
*
|
|
||||||
* This function will return the value on the stack as the given type. If
|
|
||||||
* the value is not of the given type <em>no conversion will be
|
|
||||||
* performed</em> and lua::bad_conversion will be thrown. There are some
|
|
||||||
* exceptions to this rule, for example, numbers will be converted to
|
|
||||||
* strings and vice-versa (conversion is only performed if the matching
|
|
||||||
* lua_is*() function returns true). The state::to() function should be
|
|
||||||
* used to perform automatic conversion.
|
|
||||||
*
|
|
||||||
* @returns the indicated value as the given type if possible
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
T state::as(int index) {
|
|
||||||
if (lua_isnumber(L, index))
|
|
||||||
return static_cast<T>(lua_tonumber(L, index));
|
|
||||||
else
|
|
||||||
throw bad_conversion("Cannot convert non 'number' value to number");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a new userdatum on the stack.
|
|
||||||
* @tparam userdata_t the type of the userdata (will be passed to sizeof())
|
|
||||||
*
|
|
||||||
* This function creates a new userdatum on the stack the size of
|
|
||||||
* userdata_t and return a pointer to it.
|
|
||||||
* @returns a pointer to the new userdatum
|
|
||||||
*/
|
|
||||||
template<typename userdata_t>
|
|
||||||
userdata_t* state::newuserdata() {
|
|
||||||
return reinterpret_cast<userdata_t*>(lua_newuserdata(L, sizeof(userdata_t)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Generate a Lua error.
|
|
||||||
* @tparam msg_t the type of error message data (should be automatically
|
|
||||||
* determined)
|
|
||||||
* @param message the error message/value
|
|
||||||
* @note This function is used to raise errors from lua::cfunctions.
|
|
||||||
* @note This function never returns, instead it throws an exception
|
|
||||||
* caught by the intepreter.
|
|
||||||
*/
|
|
||||||
template<typename msg_t>
|
|
||||||
void state::error(msg_t message) {
|
|
||||||
push(message);
|
|
||||||
lua_error(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Load a sequence of data as a Lua chunk.
|
|
||||||
* @tparam iterator_t the type of iterator to use (should be automatically
|
|
||||||
* determined)
|
|
||||||
* @param begin an iterator to the start of the sequence
|
|
||||||
* @param end an iterator to the end of the sequence (one past the
|
|
||||||
* end)
|
|
||||||
*
|
|
||||||
* This function takes a sequence of data and attempts to convert it
|
|
||||||
* into a Lua chunk. The type of data passed must be able to be
|
|
||||||
* converted into an 8-bit char.
|
|
||||||
*
|
|
||||||
* @note This function should automatically detect if the data is text
|
|
||||||
* or binary.
|
|
||||||
*
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
template<typename iterator_t>
|
|
||||||
state& state::load(iterator_t begin, iterator_t end) {
|
|
||||||
// convert the data to characters
|
|
||||||
std::vector<char> chunk(begin, end);
|
|
||||||
|
|
||||||
// Here we use the address of the first element of our vector.
|
|
||||||
// This works because the data in std::vectors is contiguous.
|
|
||||||
throw_error(luaL_loadbuffer(L, &(*chunk.begin()), chunk.size(), NULL));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// template specializations
|
|
||||||
template<> state& state::to(bool& boolean, int index);
|
|
||||||
template<> state& state::to(std::string& string, int index);
|
|
||||||
|
|
||||||
template<> bool state::as(bool default_value, int index);
|
|
||||||
template<> std::string state::as(std::string default_value, int index);
|
|
||||||
template<> bool state::as(int index);
|
|
||||||
template<> std::string state::as(int index);
|
|
||||||
|
|
||||||
template<> bool state::is<nil>(int index);
|
|
||||||
template<> bool state::is<bool>(int index);
|
|
||||||
template<> bool state::is<std::string>(int index);
|
|
||||||
template<> bool state::is<table>(int index);
|
|
||||||
template<> bool state::is<cfunction>(int index);
|
|
||||||
template<> bool state::is<function>(int index);
|
|
||||||
template<> bool state::is<userdata>(int index);
|
|
||||||
template<> bool state::is<lightuserdata>(int index);
|
|
||||||
|
|
||||||
|
|
||||||
// inline functions
|
|
||||||
|
|
||||||
/** Convert a lua::state to a lua_State*.
|
|
||||||
* This operator allows lua::state to behave like a lua_State
|
|
||||||
* pointer.
|
|
||||||
*
|
|
||||||
* @note This should be used as a last result to interoperate with C
|
|
||||||
* code. This may be removed in future versions of Luaxx.
|
|
||||||
*/
|
|
||||||
inline state::operator lua_State*() {
|
|
||||||
return L;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Throws exceptions for error return codes.
|
|
||||||
* @param code the return code
|
|
||||||
*
|
|
||||||
* This function throws an exception based on the error it was passed.
|
|
||||||
* If it is passed a 0 it will not throw anything.
|
|
||||||
*
|
|
||||||
* @todo In the future this function may check an exception mask
|
|
||||||
* before throwing an error.
|
|
||||||
*
|
|
||||||
* @returns the code it was passed
|
|
||||||
*/
|
|
||||||
inline int state::throw_error(int code) {
|
|
||||||
std::string error;
|
|
||||||
|
|
||||||
// below, we package lua errors into exceptions
|
|
||||||
switch (code) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case LUA_ERRSYNTAX:
|
|
||||||
to(error).pop();
|
|
||||||
throw syntax_error(error.c_str());
|
|
||||||
case LUA_ERRMEM:
|
|
||||||
to(error).pop();
|
|
||||||
throw bad_alloc(error.c_str());
|
|
||||||
case LUA_ERRRUN:
|
|
||||||
to(error).pop();
|
|
||||||
throw runtime_error(error.c_str());
|
|
||||||
case LUA_ERRFILE:
|
|
||||||
to(error).pop();
|
|
||||||
throw file_error(error.c_str());
|
|
||||||
default:
|
|
||||||
to(error).pop();
|
|
||||||
throw exception(error.c_str());
|
|
||||||
}
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,360 +0,0 @@
|
|||||||
#ifndef LUNE_H
|
|
||||||
#define LUNE_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
|
||||||
#include "lualib.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include "luaxx.hpp"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace lua
|
|
||||||
{
|
|
||||||
class object
|
|
||||||
{
|
|
||||||
state &myst;
|
|
||||||
int myref;
|
|
||||||
public:
|
|
||||||
object(state &myst):myst(myst)
|
|
||||||
{
|
|
||||||
myref=luaL_ref(myst,LUA_REGISTRYINDEX);
|
|
||||||
}
|
|
||||||
~object()
|
|
||||||
{
|
|
||||||
luaL_unref(myst,LUA_REGISTRYINDEX,myref);
|
|
||||||
}
|
|
||||||
void Get()
|
|
||||||
{
|
|
||||||
lua_rawgeti(myst,LUA_REGISTRYINDEX,myref);
|
|
||||||
}
|
|
||||||
state &GetState(){return myst;};
|
|
||||||
};
|
|
||||||
|
|
||||||
class local_object
|
|
||||||
{
|
|
||||||
state myst;
|
|
||||||
int myref;
|
|
||||||
static object *mytbl;
|
|
||||||
public:
|
|
||||||
local_object(lua_State *L)
|
|
||||||
{
|
|
||||||
|
|
||||||
myst=state(L);
|
|
||||||
//LOG<<"Creating local object...\n";
|
|
||||||
//StackDump(L);
|
|
||||||
if(!mytbl)
|
|
||||||
{
|
|
||||||
//LOG<<" Metable...\n";
|
|
||||||
myst.newtable(); //2
|
|
||||||
if(myst.newmetatable("WEAKTABLE"))//3
|
|
||||||
{
|
|
||||||
//StackDump(L);
|
|
||||||
myst.push("kv"); //4
|
|
||||||
myst.setfield("__mode");//3
|
|
||||||
//LOG<<" Setting Metable...\n";
|
|
||||||
//StackDump(L);
|
|
||||||
}
|
|
||||||
//LOG<<" Attaching to holder...\n";
|
|
||||||
|
|
||||||
//myst.setfield("__metatable");//2
|
|
||||||
lua_setmetatable(myst,-1);
|
|
||||||
mytbl=new object(myst);
|
|
||||||
//StackDump(L);
|
|
||||||
//LOG<<" Done Metatable...\n";
|
|
||||||
}
|
|
||||||
//StackDump(L);
|
|
||||||
mytbl->Get();
|
|
||||||
//LOG<<" Got my table...\n";
|
|
||||||
//StackDump(L);
|
|
||||||
myst.insert(-2);
|
|
||||||
myref=luaL_ref(myst,-2);
|
|
||||||
//LOG<<"Before pop:";
|
|
||||||
//StackDump(L);
|
|
||||||
myst.pop(1);
|
|
||||||
GetTable();
|
|
||||||
//LOG<<"========Done...\n"<<"Ref="<<myref<<"\n";
|
|
||||||
//mytbl->Get();
|
|
||||||
//StackDump(L);
|
|
||||||
//LOG<<"===========================\n";
|
|
||||||
}
|
|
||||||
~local_object()
|
|
||||||
{
|
|
||||||
//LOG<<"Deleting local object...\n";
|
|
||||||
ReleaseTable();
|
|
||||||
}
|
|
||||||
void ReleaseTable()
|
|
||||||
{
|
|
||||||
mytbl->Get();
|
|
||||||
int pos=myst.gettop();
|
|
||||||
luaL_unref(myst,pos,myref);
|
|
||||||
myst.remove(pos);
|
|
||||||
}
|
|
||||||
state GetState(){return myst;}
|
|
||||||
void GetTable()
|
|
||||||
{
|
|
||||||
//LOG<<"Getting ref="<<myref<<"\n";
|
|
||||||
//StackDump(myst);
|
|
||||||
//LOG<<"Tbl preget\n";
|
|
||||||
mytbl->Get();
|
|
||||||
int pos=myst.gettop();
|
|
||||||
//StackDump(myst);
|
|
||||||
//LOG<<"Tbl get\n";
|
|
||||||
//int pos=myst.gettop();
|
|
||||||
lua_rawgeti(myst,pos,myref);
|
|
||||||
//StackDump(myst);
|
|
||||||
//LOG<<"Done\n";
|
|
||||||
myst.remove(pos);
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T,bool GC=true>
|
|
||||||
class Lune
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
T *pT;
|
|
||||||
int tableref;
|
|
||||||
} userdataType;
|
|
||||||
|
|
||||||
typedef int (T::*mfp)(lua_State *L);
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
const char *name;
|
|
||||||
mfp mfunc;
|
|
||||||
} RegType;
|
|
||||||
|
|
||||||
static void Register(lua_State *L)
|
|
||||||
{
|
|
||||||
lua_newtable(L);
|
|
||||||
int methods = lua_gettop(L);
|
|
||||||
|
|
||||||
luaL_newmetatable(L, T::className);
|
|
||||||
int metatable = lua_gettop(L);
|
|
||||||
|
|
||||||
// store method table in globals so that
|
|
||||||
// scripts can add functions written in Lua.
|
|
||||||
lua_pushvalue(L, methods);
|
|
||||||
lua_setglobal(L, T::className);
|
|
||||||
|
|
||||||
lua_pushliteral(L, "__metatable");
|
|
||||||
lua_pushvalue(L, methods);
|
|
||||||
lua_settable(L, metatable); // hide metatable from Lua getmetatable()
|
|
||||||
|
|
||||||
lua_pushliteral(L, "__index");
|
|
||||||
lua_pushcfunction(L, index_T);
|
|
||||||
lua_settable(L, metatable);
|
|
||||||
|
|
||||||
//lua_pushliteral(L, "__name");
|
|
||||||
//lua_pushstring(L, T::className);
|
|
||||||
//lua_settable(L, metatable);
|
|
||||||
|
|
||||||
lua_pushliteral(L, "__newindex");
|
|
||||||
lua_pushcfunction(L, newindex_T);
|
|
||||||
lua_settable(L, metatable);
|
|
||||||
|
|
||||||
lua_pushliteral(L, "__instances");
|
|
||||||
lua_newtable(L);
|
|
||||||
lua_settable(L, metatable);
|
|
||||||
if(GC)
|
|
||||||
{
|
|
||||||
lua_pushliteral(L, "__gc");
|
|
||||||
lua_pushcfunction(L, gc_T);
|
|
||||||
lua_settable(L, metatable);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
lua_newtable(L); // metatable for method table
|
|
||||||
int mt = lua_gettop(L);
|
|
||||||
lua_pushliteral(L, "__call");
|
|
||||||
lua_pushcfunction(L, new_T);
|
|
||||||
lua_pushliteral(L, "new");
|
|
||||||
lua_pushvalue(L, -2); // dup new_T function
|
|
||||||
lua_settable(L, methods); // add new_T to method table
|
|
||||||
lua_settable(L, mt); // mt.__call = new_T
|
|
||||||
lua_setmetatable(L, methods);
|
|
||||||
//LOG<<"lune: registered class \""<<T::className<<"\"\n";
|
|
||||||
// fill method table with methods from class T
|
|
||||||
for (RegType *l = T::methods; l->name; l++)
|
|
||||||
{
|
|
||||||
/* edited by Snaily: shouldn't it be const RegType *l ... ? */
|
|
||||||
lua_pushstring(L, l->name);
|
|
||||||
lua_pushlightuserdata(L, (void*)l);
|
|
||||||
lua_pushcclosure(L, thunk, 1);
|
|
||||||
lua_settable(L, methods);
|
|
||||||
//LOG<<"lune: method \""<<l->name<<"\"\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_pop(L, 2); // drop metatable and method table
|
|
||||||
};
|
|
||||||
static void GetTable(lua_State *L,T *p)
|
|
||||||
{
|
|
||||||
GetTableEx(L,p->GetTableId());
|
|
||||||
}
|
|
||||||
static void GetTableEx(lua_State *L,int id)
|
|
||||||
{
|
|
||||||
lua::state s(L);
|
|
||||||
s.getmetatable(T::className);
|
|
||||||
s.getfield("__instances");
|
|
||||||
int ins=s.gettop();
|
|
||||||
lua_rawgeti(L, ins, id);
|
|
||||||
s.insert(-3);
|
|
||||||
s.pop(2);
|
|
||||||
}
|
|
||||||
static T *check(lua_State *L, int narg)
|
|
||||||
{
|
|
||||||
userdataType *ud =
|
|
||||||
static_cast<userdataType*>(luaL_checkudata(L, narg, T::className)); //TODO FIX THIs..
|
|
||||||
//(lua_touserdata(L, narg));//
|
|
||||||
if(!ud) luaL_error(L, "Bad argument %d: expected type %s", narg, T::className);
|
|
||||||
return ud->pT; // pointer to T object
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
private:
|
|
||||||
|
|
||||||
static int RegTable(lua_State *L)
|
|
||||||
{
|
|
||||||
// LOG<<"Regging....\n";
|
|
||||||
//lua::StackDump(L);
|
|
||||||
|
|
||||||
lua::state s(L);
|
|
||||||
int ssize=s.gettop();
|
|
||||||
//s.getglobal(T::className);
|
|
||||||
s.getmetatable(T::className);
|
|
||||||
s.getfield("__instances");
|
|
||||||
int ins=s.gettop();
|
|
||||||
s.newtable();
|
|
||||||
int id=luaL_ref(L,ins);
|
|
||||||
//LOG<<"After reg:\n";
|
|
||||||
//lua::StackDump(L);
|
|
||||||
s.settop(ssize);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
static void UnregTable(lua_State *L,int id)
|
|
||||||
{
|
|
||||||
lua::state s(L);
|
|
||||||
s.getmetatable(T::className);
|
|
||||||
s.getfield("__instances");
|
|
||||||
int ins=s.gettop();
|
|
||||||
//LOG<<"Unreg table id:"<<id<<"stack dump:\n";
|
|
||||||
//lua::StackDump(L);
|
|
||||||
luaL_unref(L,ins,id);
|
|
||||||
}
|
|
||||||
static int index_T(lua_State *L) // calls with (table, key), return value
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
std::string key=st.as<std::string>(-1);
|
|
||||||
T *p=check(L,1);
|
|
||||||
GetTable(L,p);
|
|
||||||
st.insert(-2);
|
|
||||||
//LOG<<"Index:\n";
|
|
||||||
//lua::StackDump(L);
|
|
||||||
lua_rawget(L,-2); //try getting from normal table
|
|
||||||
if(st.is<lua::nil>()) //failed
|
|
||||||
{
|
|
||||||
st.pop(2);
|
|
||||||
st.getglobal(T::className); //try class tables then
|
|
||||||
st.push(key);
|
|
||||||
st.gettable();
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int newindex_T(lua_State *L)
|
|
||||||
{
|
|
||||||
//LOG<<"New index....\n";
|
|
||||||
//lua::StackDump(L);
|
|
||||||
|
|
||||||
lua::state st(L);
|
|
||||||
T *p=check(L,1);
|
|
||||||
GetTable(L,p);
|
|
||||||
//st.insert(-3);
|
|
||||||
//LOG<<"Before set:\n";
|
|
||||||
st.insert(-3);
|
|
||||||
//lua::StackDump(L);
|
|
||||||
lua_rawset(L,-3);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int thunk(lua_State *L)
|
|
||||||
{
|
|
||||||
//LOG<<"Size of stack:"<<lua_gettop(L)<<"\n";
|
|
||||||
//lua::StackDump(L);
|
|
||||||
if(lua_gettop(L)<1)
|
|
||||||
luaL_error(L,"Member function called without 'self'");
|
|
||||||
//LOG<<"Size of stack after:"<<lua_gettop(L)<<"\n";
|
|
||||||
// stack has userdata, followed by method args
|
|
||||||
T *obj = check(L, 1); // get 'self', or if you prefer, 'this'
|
|
||||||
//T *obj=static_cast<userdataType*>(lua_touserdata(L,1))->pT;
|
|
||||||
lua_remove(L, 1); // remove self so member function args start at index 1
|
|
||||||
// get member function from upvalue
|
|
||||||
RegType *l = static_cast<RegType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
|
||||||
return (obj->*(l->mfunc))(L); // call member function
|
|
||||||
}
|
|
||||||
static int gc_T(lua_State *L)
|
|
||||||
{
|
|
||||||
//lua_getfield(L,,"__ud");
|
|
||||||
//LOG<<"Garbage collecting.\n";
|
|
||||||
//lua::StackDump(L);
|
|
||||||
userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
|
|
||||||
T *obj = ud->pT;
|
|
||||||
|
|
||||||
delete obj; // call destructor for T objects
|
|
||||||
UnregTable(L,ud->tableref);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int new_T(lua_State *L)
|
|
||||||
{
|
|
||||||
//LOG<<"Pre build:"<<lua_gettop(L)<<"\n";
|
|
||||||
//lua::StackDump(L);
|
|
||||||
lua_remove(L, 1); // use classname:new(), instead of classname.new()
|
|
||||||
//lua_newtable(L);
|
|
||||||
int id=RegTable(L);
|
|
||||||
//LOG<<"Registred as:"<<id<<"\n";
|
|
||||||
//int ssize=lua_gettop(L);
|
|
||||||
T *obj = new T(L,id); // call constructor for T objects
|
|
||||||
lua_settop(L,0); //no need for parameters later.
|
|
||||||
//LOG<<"Post build:"<<lua_gettop(L)<<"\t";
|
|
||||||
//lua::StackDump(L);
|
|
||||||
//LOG<<"TSOP\n";
|
|
||||||
|
|
||||||
userdataType *ud =
|
|
||||||
static_cast<userdataType*>(lua_newuserdata(L, sizeof(userdataType)));
|
|
||||||
//lua::StackDump(L);
|
|
||||||
luaL_getmetatable(L, T::className); // lookup metatable in Lua registry
|
|
||||||
lua_setmetatable(L,-2);
|
|
||||||
//LOG<<"metatable set\n";
|
|
||||||
|
|
||||||
//lua::StackDump(L);
|
|
||||||
GetTable(L,obj);
|
|
||||||
lua_pushliteral(L,"__obj");
|
|
||||||
lua_pushvalue(L,-3);
|
|
||||||
lua_settable(L,-3);
|
|
||||||
lua_pop(L,1);
|
|
||||||
//LOG<<"Object referenced\n";
|
|
||||||
//lua::StackDump(L);
|
|
||||||
//T *p = new(ud) T(L); // call constructor for T objects
|
|
||||||
//lua::StackDump(L);
|
|
||||||
ud->pT = obj; // store pointer to object in userdata
|
|
||||||
ud->tableref=id;
|
|
||||||
//luaL_getmetatable(L, T::className); // lookup metatable in Lua registry
|
|
||||||
//lua_setmetatable(L, tableindex);
|
|
||||||
//lua::StackDump(L);
|
|
||||||
//LOG<<"Push done\n";
|
|
||||||
return 1; // userdata containing pointer to T object
|
|
||||||
}
|
|
||||||
Lune() {}; //non constructable...
|
|
||||||
};
|
|
||||||
#define method(class, name) {#name, &class::name}
|
|
||||||
#define DEF_LUNE(class) static const char className[];\
|
|
||||||
static Lune<class>::RegType methods[];
|
|
||||||
#define DEF_LUNE_NOGC(class) static const char className[];\
|
|
||||||
static Lune<class,false>::RegType methods[];
|
|
||||||
#define IMP_LUNE(class,lua_name) const char class::className[]=#lua_name;
|
|
||||||
#define LUNE_METHODS_START(class) Lune<class>::RegType class::methods[] = {
|
|
||||||
#define LUNE_METHODS_START_NOGC(class) Lune<class,false>::RegType class::methods[] = {
|
|
||||||
#define LUNE_METHODS_END() {0,0}}
|
|
||||||
#endif // LUNE_H
|
|
@ -1,12 +0,0 @@
|
|||||||
Dfusion plugin offers four DFhack commands: 'dfusion', 'dfuse' and 'lua', 'runlua'.
|
|
||||||
lua:
|
|
||||||
Runs an interactive lua console. For more on lua commands see [http://www.lua.org/manual/5.1/manual.html Lua reference manual] or google "lua". Also this command could be ran with filepath as an argument. Then it runs that file as a lua script file. E.g. ''lua dfusion/temp.lua'' runs a file <your df path>/dfusion/temp.lua.
|
|
||||||
runlua:
|
|
||||||
Similar to ''lua <filename>'' but not interactive, to be used with hotkeys
|
|
||||||
dfusion:
|
|
||||||
First this command runs all plugins' init.lua part then show a menu. Type number to run specified plugin.
|
|
||||||
dfuse:
|
|
||||||
Similar to dfusion but not interactive. To be used with hotkeys (later will have command support).
|
|
||||||
|
|
||||||
Also dfuse/dfusion runs an init script located at 'save directory/dfusion/init.lua'. And 'initcustom.lua' if it exists
|
|
||||||
More info http://dwarffortresswiki.org/index.php/Utility:DFusion
|
|
@ -1,102 +0,0 @@
|
|||||||
#include "OutFile.h"
|
|
||||||
#include <stdexcept>
|
|
||||||
using namespace OutFile;
|
|
||||||
File::File(std::string path)
|
|
||||||
{
|
|
||||||
//mystream.exceptions ( std::fstream::eofbit | std::fstream::failbit | std::fstream::badbit );
|
|
||||||
mystream.open(path.c_str(),std::fstream::binary|std::ios::in|std::ios::out);
|
|
||||||
|
|
||||||
|
|
||||||
if(mystream)
|
|
||||||
{
|
|
||||||
mystream.read((char*)&myhead,sizeof(myhead));
|
|
||||||
for(unsigned i=0;i<myhead.sectioncount;i++)
|
|
||||||
{
|
|
||||||
Section x;
|
|
||||||
mystream.read((char*)&x,sizeof(Section));
|
|
||||||
sections[x.name]=x;
|
|
||||||
}
|
|
||||||
//std::cout<<"Sizeof:"<<sizeof(Section)<<"\n";
|
|
||||||
/*myhead.PrintData();
|
|
||||||
for(auto it=sections.begin();it!=sections.end();it++)
|
|
||||||
{
|
|
||||||
it->second.PrintData();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Error opening file!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Section &File::GetSection(std::string name)
|
|
||||||
{
|
|
||||||
return sections[name];
|
|
||||||
}
|
|
||||||
void File::GetText(char *ptr)
|
|
||||||
{
|
|
||||||
Section &s=GetSection(".text");
|
|
||||||
mystream.seekg(s.start);
|
|
||||||
|
|
||||||
mystream.read(ptr,s.size);
|
|
||||||
}
|
|
||||||
size_t File::GetTextSize()
|
|
||||||
{
|
|
||||||
Section &s=GetSection(".text");
|
|
||||||
return s.size;
|
|
||||||
}
|
|
||||||
void File::PrintRelocations()
|
|
||||||
{
|
|
||||||
for(auto it=sections.begin();it!=sections.end();it++)
|
|
||||||
{
|
|
||||||
std::cout<<it->first<<":\n";
|
|
||||||
for(unsigned i=0;i<it->second.numRel;i++)
|
|
||||||
{
|
|
||||||
Relocation r;
|
|
||||||
mystream.seekg(it->second.ptrRel+10*i);
|
|
||||||
mystream.read((char*)&r,10);
|
|
||||||
std::cout<<r.ptr<<" -- "<<r.tblIndex<<":"<</*symbols[r.tblIndex].name<<*/" type:"<<r.type<<"\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void File::PrintSymbols()
|
|
||||||
{
|
|
||||||
|
|
||||||
std::cout<<"Sizeof symbol:"<<sizeof(Symbol)<<std::endl;
|
|
||||||
std::cout<<"Symbol count:"<<myhead.symbolcount<<std::endl;
|
|
||||||
for(unsigned i=0;i<myhead.symbolcount;i++)
|
|
||||||
{
|
|
||||||
mystream.seekg(myhead.symbolptr+i*18);
|
|
||||||
Symbol s;
|
|
||||||
std::cout<<i<<"\t";
|
|
||||||
s.Read(mystream,myhead.symbolptr+18*myhead.symbolcount);
|
|
||||||
|
|
||||||
//mystream.read((char*)&s,sizeof(Symbol));
|
|
||||||
s.PrintData();
|
|
||||||
symbols.push_back(s);
|
|
||||||
if(s.auxsymbs>0)
|
|
||||||
{
|
|
||||||
i+=s.auxsymbs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
void File::LoadSymbols()
|
|
||||||
{
|
|
||||||
symbols.clear();
|
|
||||||
for(unsigned i=0;i<myhead.symbolcount;i++)
|
|
||||||
{
|
|
||||||
mystream.seekg(myhead.symbolptr+i*18);
|
|
||||||
Symbol s;
|
|
||||||
s.Read(mystream,myhead.symbolptr+18*myhead.symbolcount);
|
|
||||||
symbols.push_back(s);
|
|
||||||
if(s.auxsymbs>0)
|
|
||||||
{
|
|
||||||
i+=s.auxsymbs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File::~File()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
#include "hexsearch.h"
|
|
||||||
|
|
||||||
|
|
||||||
Hexsearch::Hexsearch(const SearchArgType &args,char * startpos,char * endpos):args_(args),pos_(startpos),startpos_(startpos),endpos_(endpos)
|
|
||||||
{
|
|
||||||
ReparseArgs();
|
|
||||||
}
|
|
||||||
Hexsearch::~Hexsearch()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
inline bool Hexsearch::Compare(int a,int b)
|
|
||||||
{
|
|
||||||
if(b==Hexsearch::ANYBYTE)
|
|
||||||
return true;
|
|
||||||
if(a==b)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void Hexsearch::ReparseArgs()
|
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
uint32_t val;
|
|
||||||
uint8_t bytes[4];
|
|
||||||
}B;
|
|
||||||
SearchArgType targ;
|
|
||||||
targ=args_;
|
|
||||||
args_.clear();
|
|
||||||
for(size_t i=0;i<targ.size();)
|
|
||||||
{
|
|
||||||
if(targ[i]==DWORD_)
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
B.val=targ[i];
|
|
||||||
for(int j=0;j<4;j++)
|
|
||||||
{
|
|
||||||
args_.push_back(B.bytes[j]);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
else if (targ[i]==ANYDWORD)
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
for(int j=0;j<4;j++)
|
|
||||||
args_.push_back(ANYBYTE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
args_.push_back(targ[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void * Hexsearch::FindNext() //TODO rewrite using Boyer-Moore algorithm
|
|
||||||
{
|
|
||||||
DFHack::Core &inst=DFHack::Core::getInstance();
|
|
||||||
DFHack::Process *p=inst.p;
|
|
||||||
uint8_t *buf;
|
|
||||||
buf=new uint8_t[args_.size()];
|
|
||||||
while(pos_<endpos_)
|
|
||||||
{
|
|
||||||
bool found=true;
|
|
||||||
p->readByte(pos_,buf[0]);
|
|
||||||
if(Compare(buf[0],args_[0]))
|
|
||||||
{
|
|
||||||
p->read(pos_,args_.size(),buf);
|
|
||||||
for(size_t i=0;i<args_.size();i++)
|
|
||||||
{
|
|
||||||
if(!Compare(buf[i],args_[i]))
|
|
||||||
{
|
|
||||||
pos_+=i;
|
|
||||||
found=false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(found)
|
|
||||||
{
|
|
||||||
pos_+=args_.size();
|
|
||||||
delete [] buf;
|
|
||||||
return pos_-args_.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pos_ = pos_ + 1;
|
|
||||||
}
|
|
||||||
delete [] buf;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<void *> Hexsearch::FindAll()
|
|
||||||
{
|
|
||||||
std::vector<void *> ret;
|
|
||||||
void * cpos=pos_;
|
|
||||||
while(cpos!=0)
|
|
||||||
{
|
|
||||||
cpos=FindNext();
|
|
||||||
if(cpos!=0)
|
|
||||||
ret.push_back(cpos);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
void Hexsearch::PrepareBadCharShift()
|
|
||||||
{
|
|
||||||
BadCharShifts.resize(256,-1);
|
|
||||||
int i=0;
|
|
||||||
for(SearchArgType::reverse_iterator it=args_.rbegin();it!=args_.rend();it++)
|
|
||||||
{
|
|
||||||
BadCharShifts[*it]=i;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Hexsearch::PrepareGoodSuffixTable()
|
|
||||||
{
|
|
||||||
GoodSuffixShift.resize(args_.size()+1,0);
|
|
||||||
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
#include "lua_Hexsearch.h"
|
|
||||||
int lua::Hexsearch::find(lua_State *L)
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
void * pos=p->FindNext();
|
|
||||||
st.push(reinterpret_cast<size_t>(pos));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
int lua::Hexsearch::findall(lua_State *L)
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
std::vector<void *> pos=p->FindAll();
|
|
||||||
st.newtable();
|
|
||||||
for(unsigned i=0;i<pos.size();i++)
|
|
||||||
{
|
|
||||||
st.push(i+1);
|
|
||||||
st.push(reinterpret_cast<size_t>(pos[i]));
|
|
||||||
st.settable();
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
lua::Hexsearch::Hexsearch(lua_State *L,int id):tblid(id)
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
char * start,* end;
|
|
||||||
::Hexsearch::SearchArgType args;
|
|
||||||
start= (char *)st.as<uint32_t>(1);
|
|
||||||
end=(char *)st.as<uint32_t>(2);
|
|
||||||
for(int i=3;i<=st.gettop();i++)
|
|
||||||
{
|
|
||||||
args.push_back(st.as<int>(i));
|
|
||||||
}
|
|
||||||
p=new ::Hexsearch(args,start,end);
|
|
||||||
}
|
|
||||||
lua::Hexsearch::~Hexsearch()
|
|
||||||
{
|
|
||||||
delete p;
|
|
||||||
}
|
|
||||||
int lua::Hexsearch::reset(lua_State *L)
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
p->Reset();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
IMP_LUNE(lua::Hexsearch,hexsearch);
|
|
||||||
LUNE_METHODS_START(lua::Hexsearch)
|
|
||||||
method(lua::Hexsearch,find),
|
|
||||||
method(lua::Hexsearch,findall),
|
|
||||||
method(lua::Hexsearch,reset),
|
|
||||||
LUNE_METHODS_END();
|
|
||||||
#define __ADDCONST(name) st.push(::Hexsearch:: name); st.setglobal(#name)
|
|
||||||
void lua::RegisterHexsearch(lua::state &st)
|
|
||||||
{
|
|
||||||
|
|
||||||
Lune<lua::Hexsearch>::Register(st);
|
|
||||||
__ADDCONST(ANYBYTE);
|
|
||||||
__ADDCONST(ANYDWORD);
|
|
||||||
__ADDCONST(DWORD_);
|
|
||||||
}
|
|
||||||
#undef __ADDCONST
|
|
@ -1,154 +0,0 @@
|
|||||||
#include "lua_Misc.h"
|
|
||||||
uint32_t lua::PlugManager::AddNewPlug(std::string name,uint32_t size,uint32_t loc)
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
if(size!=0)
|
|
||||||
p=new unsigned char[size];
|
|
||||||
else
|
|
||||||
p=(void*)loc;
|
|
||||||
plugs[name]=p;
|
|
||||||
return (uint32_t)p;
|
|
||||||
}
|
|
||||||
uint32_t lua::PlugManager::FindPlugin(std::string name)
|
|
||||||
{
|
|
||||||
mapPlugs::iterator it=plugs.find(name);
|
|
||||||
if(it!=plugs.end())
|
|
||||||
return (uint32_t)it->second;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int LoadMod(lua_State *L)
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
std::string modfile=st.as<std::string>(1);
|
|
||||||
std::string modname=st.as<std::string>(2);
|
|
||||||
uint32_t size_add=st.as<uint32_t>(0,3);
|
|
||||||
OutFile::File f(modfile);
|
|
||||||
uint32_t size=f.GetTextSize();
|
|
||||||
uint32_t pos=lua::PlugManager::GetInst().AddNewPlug(modname,size+size_add);
|
|
||||||
char *buf;
|
|
||||||
buf=new char[size];
|
|
||||||
f.GetText(buf);
|
|
||||||
//std::cout<<"poking @:"<<std::hex<<pos<<"size :"<<size<<std::endl;
|
|
||||||
DFHack::Core::getInstance().p->write((void *) pos,size,(uint8_t*)buf);
|
|
||||||
delete [] buf;
|
|
||||||
st.push(pos);
|
|
||||||
st.push(size);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
static int LoadObj(lua_State *L)
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
std::string modfile=st.as<std::string>(1);
|
|
||||||
OutFile::File f(modfile);
|
|
||||||
size_t s=f.GetTextSize();
|
|
||||||
void *p=st.newuserdata(s); //TODO does it leak memory??
|
|
||||||
f.GetText((char*)p);
|
|
||||||
st.push(s);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
static int FindMarker(lua_State *L) // marker, void ptr, size, start
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
union
|
|
||||||
{
|
|
||||||
unsigned char bytes[4];
|
|
||||||
size_t mark;
|
|
||||||
}M;
|
|
||||||
M.mark=st.as<size_t>(1);
|
|
||||||
unsigned char *p=(unsigned char *)lua_touserdata(L, 2);//st.as<lua::userdata>(2);
|
|
||||||
size_t size=st.as<size_t>(3);
|
|
||||||
size_t start=st.as<size_t>(4);
|
|
||||||
for(size_t i=start;i<size;i++)
|
|
||||||
{
|
|
||||||
bool ok;
|
|
||||||
ok=true;
|
|
||||||
if(p[i]==M.bytes[0])
|
|
||||||
{
|
|
||||||
for(size_t j=0;j<4;j++)
|
|
||||||
{
|
|
||||||
if(p[i+j]!=M.bytes[j])
|
|
||||||
{
|
|
||||||
ok=false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(ok)
|
|
||||||
{
|
|
||||||
st.push(i);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int LoadObjSymbols(lua_State *L)
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
std::string modfile=st.as<std::string>(1);
|
|
||||||
OutFile::File f(modfile);
|
|
||||||
OutFile::vSymbol vec=f.GetSymbols();
|
|
||||||
OutFile::Symbol S;
|
|
||||||
|
|
||||||
st.newtable();
|
|
||||||
for(size_t i=0;i<vec.size();i++)
|
|
||||||
{
|
|
||||||
st.push(i);
|
|
||||||
S=vec[i];
|
|
||||||
st.newtable();
|
|
||||||
st.push(S.name);
|
|
||||||
st.setfield("name");
|
|
||||||
st.push(S.pos);
|
|
||||||
st.setfield("pos");
|
|
||||||
st.settable();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int NewMod(lua_State *L)
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
std::string modname=st.as<std::string>(1);
|
|
||||||
size_t size=st.as<size_t>(2);
|
|
||||||
size_t loc=st.as<size_t>(3,0);
|
|
||||||
uint32_t pos=lua::PlugManager::GetInst().AddNewPlug(modname,size,loc);
|
|
||||||
st.push(pos);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int GetMod(lua_State *L)
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
std::string modname=st.as<std::string>(1);
|
|
||||||
uint32_t pos=lua::PlugManager::GetInst().FindPlugin(modname);
|
|
||||||
if(pos==0)
|
|
||||||
st.push();
|
|
||||||
else
|
|
||||||
st.push(pos);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const luaL_Reg lua_misc_func[]=
|
|
||||||
{
|
|
||||||
{"loadmod",LoadMod},
|
|
||||||
{"getmod",GetMod},
|
|
||||||
{"loadobj",LoadObj},
|
|
||||||
{"loadobjsymbols",LoadObjSymbols},
|
|
||||||
{"findmarker",FindMarker},
|
|
||||||
{"newmod",NewMod},
|
|
||||||
{NULL,NULL}
|
|
||||||
};
|
|
||||||
void lua::RegisterMisc(lua::state &st)
|
|
||||||
{
|
|
||||||
st.getglobal("engine");
|
|
||||||
if(st.is<lua::nil>())
|
|
||||||
{
|
|
||||||
st.pop();
|
|
||||||
st.newtable();
|
|
||||||
}
|
|
||||||
lua::RegFunctionsLocal(st, lua_misc_func);
|
|
||||||
st.setglobal("engine");
|
|
||||||
}
|
|
@ -1,269 +0,0 @@
|
|||||||
#include "lua_Process.h"
|
|
||||||
|
|
||||||
static DFHack::Process* GetProcessPtr(lua::state &st)
|
|
||||||
{
|
|
||||||
return DFHack::Core::getInstance().p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lua_Process_readDWord(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
uint32_t ret=c->readDWord( (void *) st.as<uint32_t>(1));
|
|
||||||
st.push(ret);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int lua_Process_writeDWord(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
c->writeDWord((void *) st.as<uint32_t>(1),st.as<uint32_t>(2));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int lua_Process_readFloat(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
float ret=c->readFloat((void *) st.as<uint32_t>(1));
|
|
||||||
st.push(ret);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lua_Process_readWord(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
uint16_t ret=c->readWord((void *) st.as<uint32_t>(1));
|
|
||||||
st.push(ret);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lua_Process_writeWord(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
c->writeWord((void *) st.as<uint32_t>(1),st.as<uint16_t>(2));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int lua_Process_readByte(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
uint8_t ret=c->readByte((void *) st.as<uint32_t>(1));
|
|
||||||
st.push(ret);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lua_Process_writeByte(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
c->writeByte((void *) st.as<uint32_t>(1),st.as<uint8_t>(2));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int lua_Process_read(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
size_t len=st.as<uint32_t>(2);
|
|
||||||
uint8_t* buf;
|
|
||||||
|
|
||||||
if(!st.is<lua::nil>(3))
|
|
||||||
buf=(uint8_t*)lua_touserdata(st,3);
|
|
||||||
else
|
|
||||||
buf=new uint8_t[len];
|
|
||||||
c->read((void *) st.as<uint32_t>(1),len,buf);
|
|
||||||
st.pushlightuserdata(buf);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int lua_Process_write(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
c-> write((void *) st.as<uint32_t>(1),st.as<uint32_t>(2),static_cast<uint8_t*>(lua_touserdata(st,3)));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int lua_Process_readSTLString (lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
std::string r=c->readSTLString((void *) st.as<uint32_t>(1));
|
|
||||||
st.push(r);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lua_Process_writeSTLString(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
c->writeSTLString((void *) st.as<uint32_t>(1),st.as<std::string>(2));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int lua_Process_copySTLString(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
c->copySTLString((void *) st.as<uint32_t>(1),st.as<uint32_t>(2));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
static int lua_Process_doReadClassName(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
std::string r=c->doReadClassName((void*)st.as<size_t>(1));
|
|
||||||
st.push(r);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int lua_Process_readClassName(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
std::string r=c->readClassName((void*)st.as<size_t>(1));
|
|
||||||
st.push(r);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int lua_Process_readCString (lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
std::string r=c->readCString((void *) st.as<uint32_t>(1));
|
|
||||||
st.push(r);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int lua_Process_isSuspended(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
st.push(c->isSuspended());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int lua_Process_isIdentified(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
st.push(c->isIdentified());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int lua_Process_getMemRanges(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
std::vector<DFHack::t_memrange> ranges;
|
|
||||||
c->getMemRanges(ranges);
|
|
||||||
st.newtable();
|
|
||||||
for(size_t i=0;i<ranges.size();i++)
|
|
||||||
{
|
|
||||||
st.push(i);
|
|
||||||
st.newtable();
|
|
||||||
st.push((uint32_t)ranges[i].start); // WARNING!! lua has only 32bit numbers, possible loss of data!!
|
|
||||||
st.setfield("start");
|
|
||||||
st.push((uint32_t)ranges[i].end);
|
|
||||||
st.setfield("end");
|
|
||||||
st.push(std::string(ranges[i].name));
|
|
||||||
st.setfield("name");
|
|
||||||
st.push(ranges[i].read);
|
|
||||||
st.setfield("read");
|
|
||||||
st.push(ranges[i].write);
|
|
||||||
st.setfield("write");
|
|
||||||
st.push(ranges[i].execute);
|
|
||||||
st.setfield("execute");
|
|
||||||
st.push(ranges[i].shared);
|
|
||||||
st.setfield("shared");
|
|
||||||
st.push(ranges[i].valid);
|
|
||||||
st.setfield("valid");
|
|
||||||
st.settable();
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int lua_Process_getBase(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
uint32_t base=c->getBase();
|
|
||||||
st.push(base);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/*static int lua_Process_getPID(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
int ret=c->getPID();
|
|
||||||
st.push(ret);
|
|
||||||
return 1;
|
|
||||||
}*/
|
|
||||||
static int lua_Process_getPath(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
std::string ret=c->getPath();
|
|
||||||
st.push(ret);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
static int lua_Process_setPermisions(lua_State *S)
|
|
||||||
{
|
|
||||||
lua::state st(S);
|
|
||||||
DFHack::Process* c=GetProcessPtr(st);
|
|
||||||
DFHack::t_memrange range,trange;
|
|
||||||
|
|
||||||
st.getfield("start",1);
|
|
||||||
range.start= (void *)st.as<uint64_t>();
|
|
||||||
st.pop();
|
|
||||||
st.getfield("end",1);
|
|
||||||
range.end= (void *)st.as<uint64_t>();
|
|
||||||
st.pop();
|
|
||||||
|
|
||||||
st.getfield("read",2);
|
|
||||||
trange.read=st.as<bool>();
|
|
||||||
st.pop();
|
|
||||||
st.getfield("write",2);
|
|
||||||
trange.write=st.as<bool>();
|
|
||||||
st.pop();
|
|
||||||
st.getfield("execute",2);
|
|
||||||
trange.execute=st.as<bool>();
|
|
||||||
st.pop();
|
|
||||||
|
|
||||||
c->setPermisions(range,trange);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#define PROC_FUNC(name) {#name,lua_Process_ ## name}
|
|
||||||
const luaL_Reg lua_process_func[]=
|
|
||||||
{
|
|
||||||
PROC_FUNC(readDWord),
|
|
||||||
PROC_FUNC(writeDWord),
|
|
||||||
PROC_FUNC(readFloat),
|
|
||||||
PROC_FUNC(readWord),
|
|
||||||
PROC_FUNC(writeWord),
|
|
||||||
PROC_FUNC(readByte),
|
|
||||||
PROC_FUNC(writeByte),
|
|
||||||
PROC_FUNC(read),
|
|
||||||
PROC_FUNC(write),
|
|
||||||
PROC_FUNC(readSTLString),
|
|
||||||
PROC_FUNC(writeSTLString),
|
|
||||||
PROC_FUNC(copySTLString),
|
|
||||||
PROC_FUNC(doReadClassName),
|
|
||||||
PROC_FUNC(readClassName),
|
|
||||||
PROC_FUNC(readCString ),
|
|
||||||
PROC_FUNC(isSuspended),
|
|
||||||
PROC_FUNC(isIdentified),
|
|
||||||
PROC_FUNC(getMemRanges),
|
|
||||||
PROC_FUNC(getBase),
|
|
||||||
//PROC_FUNC(getPID), //not implemented
|
|
||||||
PROC_FUNC(getPath),
|
|
||||||
PROC_FUNC(setPermisions),
|
|
||||||
{NULL,NULL}
|
|
||||||
};
|
|
||||||
#undef PROC_FUNC
|
|
||||||
void lua::RegisterProcess(lua::state &st)
|
|
||||||
{
|
|
||||||
st.getglobal("Process");
|
|
||||||
if(st.is<lua::nil>())
|
|
||||||
{
|
|
||||||
st.pop();
|
|
||||||
st.newtable();
|
|
||||||
}
|
|
||||||
|
|
||||||
lua::RegFunctionsLocal(st, lua_process_func);
|
|
||||||
|
|
||||||
st.setglobal("Process");
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
#include "luamain.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
lua::glua* lua::glua::ptr=0;
|
|
||||||
lua::glua::glua()
|
|
||||||
{
|
|
||||||
RegBasics(mystate);
|
|
||||||
}
|
|
||||||
lua::state &lua::glua::Get()
|
|
||||||
{
|
|
||||||
if(!glua::ptr)
|
|
||||||
glua::ptr=new glua();
|
|
||||||
return glua::ptr->mystate;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int lua_Ver_Lua(lua_State *L)
|
|
||||||
{
|
|
||||||
lua::state st(L);
|
|
||||||
st.push(LUA_RELEASE);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const struct luaL_Reg lua_basic_lib [] =
|
|
||||||
{
|
|
||||||
{"getluaver", lua_Ver_Lua},
|
|
||||||
{NULL, NULL} /* sentinel */
|
|
||||||
};
|
|
||||||
void lua::RegBasics(lua::state &L)
|
|
||||||
{
|
|
||||||
luaL_openlibs(L);
|
|
||||||
RegFunctions(L,lua_basic_lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
void lua::RegFunctions(lua::state &L,luaL_Reg const*arr)
|
|
||||||
{
|
|
||||||
luaL_Reg const *cur=arr;
|
|
||||||
while(cur->name!=NULL)
|
|
||||||
{
|
|
||||||
lua_pushcfunction(L, cur->func);
|
|
||||||
lua_setglobal(L, cur->name);
|
|
||||||
|
|
||||||
cur++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void lua::RegFunctionsLocal(lua::state &L,luaL_Reg const*arr)
|
|
||||||
{
|
|
||||||
luaL_Reg const *cur=arr;
|
|
||||||
while(cur->name!=NULL)
|
|
||||||
{
|
|
||||||
lua_pushcfunction(L, cur->func);
|
|
||||||
//lua_setglobal(L, cur->name);
|
|
||||||
L.setfield(cur->name);
|
|
||||||
|
|
||||||
cur++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string lua::DebugDump(lua::state &L)
|
|
||||||
{
|
|
||||||
L.getglobal("debug");
|
|
||||||
L.getfield("traceback");
|
|
||||||
L.call(0,1);
|
|
||||||
string ret=L.as<string>();
|
|
||||||
//cout<<"StackTrace:"<<ret<<endl;
|
|
||||||
L.settop(0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
@ -1,836 +0,0 @@
|
|||||||
/* vim: set et sw=3 tw=0 fo=croqlaw cino=t0:
|
|
||||||
*
|
|
||||||
* Luaxx, the C++ Lua wrapper library.
|
|
||||||
* Copyright (c) 2006-2008 Matthew Nicholson
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to
|
|
||||||
* deal in the Software without restriction, including without limitation the
|
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
* IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <luaxx.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#define LOG std::cout
|
|
||||||
/** @file
|
|
||||||
* Luaxx implementation file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace lua
|
|
||||||
{
|
|
||||||
void StackDump(lua_State *L)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int top = lua_gettop(L);
|
|
||||||
for (i = 1; i <= top; i++) /* repeat for each level */
|
|
||||||
{
|
|
||||||
int t = lua_type(L, i);
|
|
||||||
LOG<<i<<":";
|
|
||||||
switch (t)
|
|
||||||
{
|
|
||||||
|
|
||||||
case LUA_TSTRING: /* strings */
|
|
||||||
LOG<<"str ="<<lua_tostring(L, i)<<"\n";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LUA_TBOOLEAN: /* booleans */
|
|
||||||
LOG<<"bool="<<(lua_toboolean(L, i) ? "true" : "false")<<"\n";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LUA_TNUMBER: /* numbers */
|
|
||||||
LOG<<"num ="<<lua_tonumber(L, i)<<"\n";
|
|
||||||
break;
|
|
||||||
case LUA_TTABLE:
|
|
||||||
|
|
||||||
LOG<<lua_typename(L, t);
|
|
||||||
{
|
|
||||||
//LOG<<"PRE TOP:"<< lua_gettop(L)<<"\n";
|
|
||||||
lua_getglobal(L,"PrintTable");
|
|
||||||
//lua_insert(L,-2);
|
|
||||||
lua_pushvalue(L,i);
|
|
||||||
lua_pcall(L,1,0,0);
|
|
||||||
//LOG<<"POST TOP:"<< lua_gettop(L)<<"\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
default: /* other values */
|
|
||||||
LOG<<lua_typename(L, t);
|
|
||||||
{
|
|
||||||
//LOG<<"PRE TOP:"<< lua_gettop(L)<<"\n";
|
|
||||||
lua_getglobal(L,"tostring");
|
|
||||||
//lua_insert(L,-2);
|
|
||||||
lua_pushvalue(L,i);
|
|
||||||
lua_pcall(L,1,1,0);
|
|
||||||
LOG<<"=";
|
|
||||||
LOG<<lua_tostring(L,-1)<<"\n";
|
|
||||||
lua_pop(L,1);
|
|
||||||
//LOG<<"POST TOP:"<< lua_gettop(L)<<"\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
LOG<<"\n"; /* end the listing */
|
|
||||||
LOG<<"==============================\n";
|
|
||||||
}
|
|
||||||
#undef LOG
|
|
||||||
/// Construct our lua environment.
|
|
||||||
state::state() : L(luaL_newstate()), managed(true) {
|
|
||||||
if (L == NULL)
|
|
||||||
throw bad_alloc("Error creating lua state");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Construct our lua environment from an existing lua_State.
|
|
||||||
* @param L the existing state to use.
|
|
||||||
*
|
|
||||||
* This function differs from the normal constructor as it sets a flag
|
|
||||||
* that prevents lua_close() from being called when this class is
|
|
||||||
* destroyed.
|
|
||||||
*/
|
|
||||||
state::state(lua_State* L) :
|
|
||||||
L(L), managed(false) {
|
|
||||||
}
|
|
||||||
state& state::operator = (const state& t)
|
|
||||||
{
|
|
||||||
if(managed)
|
|
||||||
lua_close(L);
|
|
||||||
managed=false;
|
|
||||||
L=t.L;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
/// Destroy our lua environment.
|
|
||||||
state::~state() {
|
|
||||||
if (managed)
|
|
||||||
lua_close(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Push a nil onto the stack.
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::push() {
|
|
||||||
lua_pushnil(L);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Push a nil onto the stack.
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::push(nil) {
|
|
||||||
lua_pushnil(L);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Push a boolean onto the stack.
|
|
||||||
* @param boolean the value to push
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::push(bool boolean) {
|
|
||||||
lua_pushboolean(L, boolean);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Push a C-style string onto the stack.
|
|
||||||
* @param s the string to push
|
|
||||||
* @param length the length of the string
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::push(const char* s, size_t length) {
|
|
||||||
lua_pushlstring(L, s, length);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Push a C-style string onto the stack.
|
|
||||||
* @param s the string to push
|
|
||||||
* @note This must be a '0' terminated string.
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::push(const char* s) {
|
|
||||||
lua_pushstring(L, s);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Push an std::string onto the stack.
|
|
||||||
* @param s the string to push
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::push(const std::string& s) {
|
|
||||||
lua_pushlstring(L, s.c_str(), s.size());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Push an C function onto the stack.
|
|
||||||
* @param f the function to push
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::push(cfunction f) {
|
|
||||||
lua_pushcfunction(L, f);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a new table on to the stack.
|
|
||||||
* @see state::newtable()
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::push(table) {
|
|
||||||
lua_newtable(L);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Push a light userdatum on to the stack.
|
|
||||||
* @param p the pointer to push
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::push(void* p) {
|
|
||||||
lua_pushlightuserdata(L, p);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the value at index as a string.
|
|
||||||
* @param default_value this value is returned if the conversion fails
|
|
||||||
* @param index the index to get
|
|
||||||
* @note This function does \em not pop the value from the stack.
|
|
||||||
*
|
|
||||||
* @note lua::state::as(std::string()) will convert the value at the
|
|
||||||
* indicated index to a string <em>on the stack</em>. This can
|
|
||||||
* confuse lua::state::next();
|
|
||||||
*
|
|
||||||
* @returns the indicated value from the stack or the default value if the
|
|
||||||
* conversion fails
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
std::string state::as(std::string default_value, int index) {
|
|
||||||
if (lua_isstring(L, index))
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
const char *str = lua_tolstring(L, index, &len);
|
|
||||||
return std::string(str, len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return default_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check an argument of the current function.
|
|
||||||
* @param narg the argument number to check
|
|
||||||
*
|
|
||||||
* This function will throw a lua error if there is no argument at the
|
|
||||||
* given position.
|
|
||||||
*
|
|
||||||
* @note This function is meant to be called from with in a lua::cfunction.
|
|
||||||
* The error throw is internal to the lua interpreter. When compiled as
|
|
||||||
* C++, a C++ exception is thrown, so the stack is properly unwound. This
|
|
||||||
* exception is not meant to be caught.
|
|
||||||
*/
|
|
||||||
state& state::check(int narg) {
|
|
||||||
luaL_checkany(L, narg);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef lua_Integer_int
|
|
||||||
/** Check an argument of the current function.
|
|
||||||
* @param i the int to hold the returned value
|
|
||||||
* @param narg the argument number to check
|
|
||||||
*
|
|
||||||
* This function checks if the given argument number is an int.
|
|
||||||
*
|
|
||||||
* @note This function is meant to be called from with in a
|
|
||||||
* lua::cfunction. The error throw is internal to the lua intrepeter.
|
|
||||||
* When compiled as C++, a C++ exception is thrown, so the stack is
|
|
||||||
* properly unwound. This exception is not meant to be caught.
|
|
||||||
*/
|
|
||||||
state& state::check(int& i, int narg) {
|
|
||||||
i = luaL_checkint(L, narg);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Check an argument of the current function.
|
|
||||||
* @param i the lua::integer (lua_Integer) to hold the returned value
|
|
||||||
* @param narg the argument number to check
|
|
||||||
*
|
|
||||||
* This function checks if the given argument number is an integer.
|
|
||||||
*
|
|
||||||
* @note This is different from lua::check(int(), ...). It returns a
|
|
||||||
* lua::integer (lua_Integer), which may not be an int.
|
|
||||||
*
|
|
||||||
* @note This function is meant to be called from with in a
|
|
||||||
* lua::cfunction. The error throw is internal to the lua intrepeter.
|
|
||||||
* When compiled as C++, a C++ exception is thrown, so the stack is
|
|
||||||
* properly unwound. This exception is not meant to be caught.
|
|
||||||
*/
|
|
||||||
state& state::check(integer& i, int narg) {
|
|
||||||
i = luaL_checkinteger(L, narg);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef lua_Integer_long
|
|
||||||
/** Check an argument of the current function.
|
|
||||||
* @param l the long to hold the returned value
|
|
||||||
* @param narg the argument number to check
|
|
||||||
*
|
|
||||||
* This function checks if the given argument number is a long.
|
|
||||||
*
|
|
||||||
* @note This function is meant to be called from with in a
|
|
||||||
* lua::cfunction. The error throw is internal to the lua intrepeter.
|
|
||||||
* When compiled as C++, a C++ exception is thrown, so the stack is
|
|
||||||
* properly unwound. This exception is not meant to be caught.
|
|
||||||
*/
|
|
||||||
state& state::check(long& l, int narg) {
|
|
||||||
l = luaL_checklong(L, narg);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Check an argument of the current function.
|
|
||||||
* @param s the string to hold the returned value
|
|
||||||
* @param narg the argument number to check
|
|
||||||
*
|
|
||||||
* This function checks if the given argument number is a string.
|
|
||||||
*
|
|
||||||
* @note This function is meant to be called from with in a
|
|
||||||
* lua::cfunction. The error throw is internal to the lua intrepeter.
|
|
||||||
* When compiled as C++, a C++ exception is thrown, so the stack is
|
|
||||||
* properly unwound. This exception is not meant to be caught.
|
|
||||||
*/
|
|
||||||
state& state::check(std::string& s, int narg) {
|
|
||||||
const char* c;
|
|
||||||
size_t l;
|
|
||||||
c = luaL_checklstring(L, narg, &l);
|
|
||||||
|
|
||||||
s.assign(c, l);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check an argument of the current function.
|
|
||||||
* @param n the lua::number (lua_Number) to hold the returned value
|
|
||||||
* @param narg the argument number to check
|
|
||||||
*
|
|
||||||
* This function checks if the given argument number is a lua::number
|
|
||||||
* (lua_Number, a double by default).
|
|
||||||
*
|
|
||||||
* @note This function is meant to be called from with in a lua::cfunction.
|
|
||||||
* The error throw is internal to the lua interpreter. When compiled as
|
|
||||||
* C++, a C++ exception is thrown, so the stack is properly unwound. This
|
|
||||||
* exception is not meant to be caught.
|
|
||||||
*/
|
|
||||||
state& state::check(number& n, int narg) {
|
|
||||||
n = luaL_checknumber(L, narg);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/** [specialization] Generate a Lua error (T = std::string).
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
void state::error(const std::string& message) {
|
|
||||||
push(message);
|
|
||||||
lua_error(L);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Call a lua function.
|
|
||||||
* @param nargs the number of args to pass to the function
|
|
||||||
* @param nresults the number of values to return from the function
|
|
||||||
* @param on_error A stack index where the error handling function is
|
|
||||||
* stored.
|
|
||||||
* @note The error handling function must be pushed in the stack
|
|
||||||
* before the function to be called and its arguments.
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::pcall(int nargs, int nresults, int on_error) {
|
|
||||||
throw_error(lua_pcall(L, nargs, nresults, on_error));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Call a lua function in unprotected mode.
|
|
||||||
* @param nargs the number of args to pass to the function
|
|
||||||
* @param nresults the number of values to return from the function
|
|
||||||
* stored.
|
|
||||||
* @note If there is an error in the call the program will terminate.
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::call(int nargs, int nresults) {
|
|
||||||
lua_call(L, nargs, nresults);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Ensure the stack is at least the given size.
|
|
||||||
* @param size the size to use
|
|
||||||
*
|
|
||||||
* If the stack is smaller than the given size, it will grow to the
|
|
||||||
* specified size.
|
|
||||||
*
|
|
||||||
* @exception lua::exception Thrown if the operation fails.
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::checkstack(int size) {
|
|
||||||
if (!lua_checkstack(L, size))
|
|
||||||
throw lua::exception("Error growing the stack");
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set a new index as the top of the stack.
|
|
||||||
* @param index the index to use as the new top
|
|
||||||
* @note If the previous top was higher than the new one, top values
|
|
||||||
* are discarded. Otherwise this function pushs nils on to the stack
|
|
||||||
* to get the proper size.
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::settop(int index) {
|
|
||||||
lua_settop(L, index);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the number of elements in the stack.
|
|
||||||
* @note This value is also the index of the top element.
|
|
||||||
* @returns the number of elements in the stack
|
|
||||||
*/
|
|
||||||
int state::gettop() {
|
|
||||||
return lua_gettop(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the number of elements in the stack.
|
|
||||||
* @note This value is also the index of the top element.
|
|
||||||
* @returns the number of elements in the stack
|
|
||||||
*/
|
|
||||||
int state::size() {
|
|
||||||
return lua_gettop(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if the stack is empty.
|
|
||||||
* @returns true if the stack is empty, false otherwise
|
|
||||||
*/
|
|
||||||
bool state::empty() {
|
|
||||||
return !lua_gettop(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Move the top element to the given index.
|
|
||||||
* @param index the index to insert at
|
|
||||||
* @note All elements on top of the given index are shifted up to open
|
|
||||||
* space for this element.
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::insert(int index) {
|
|
||||||
lua_insert(L, index);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Replace the given index with the top element.
|
|
||||||
* @param index the index to replae
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::replace(int index) {
|
|
||||||
lua_replace(L, index);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove the given index from the stack.
|
|
||||||
* @param index the index to remove
|
|
||||||
* @note Elements are shifted down to fill in the empty spot.
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::remove(int index) {
|
|
||||||
lua_remove(L, index);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove the given number of elemens from the stack.
|
|
||||||
* @param elements the number of elements to remove
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::pop(int elements) {
|
|
||||||
lua_pop(L, elements);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Push a copy of the element at the given index to the top of the
|
|
||||||
* stack.
|
|
||||||
* @param index the index of the element to copy
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::pushvalue(int index) {
|
|
||||||
lua_pushvalue(L, index);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a new table on the stack.
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::newtable() {
|
|
||||||
lua_newtable(L);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a new metatable and add it to the registry.
|
|
||||||
* @param tname the name to use for the new metatable in the registry
|
|
||||||
*
|
|
||||||
* This function creates a new metatable and adds it to the registry
|
|
||||||
* with the given key. This function also pushes the new metatable
|
|
||||||
* onto the stack.
|
|
||||||
*
|
|
||||||
* @note Regardless of the return value, the new metatable is always pushed
|
|
||||||
* on to the stack.
|
|
||||||
*
|
|
||||||
* @return true if a new metatable was created, false if the registry
|
|
||||||
* alread has a key with the given name.
|
|
||||||
*/
|
|
||||||
bool state::newmetatable(const std::string& tname) {
|
|
||||||
return luaL_newmetatable(L, tname.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a new userdatum on the stack.
|
|
||||||
* @param nbytes the size of the new userdatum
|
|
||||||
* @return a pointer to the new userdatum
|
|
||||||
*/
|
|
||||||
void* state::newuserdata(size_t nbytes) {
|
|
||||||
return lua_newuserdata(L, nbytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a value from a table on the stack.
|
|
||||||
* @param index the index the table is stored at
|
|
||||||
*
|
|
||||||
* This function gets a value from the table at the given index and
|
|
||||||
* pushes it onto the stack.
|
|
||||||
*
|
|
||||||
* @note You should have already pushed the key used to reference this
|
|
||||||
* value onto the stack before calling this function.
|
|
||||||
*
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::gettable(int index) {
|
|
||||||
lua_gettable(L, index);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a value from a table on the stack.
|
|
||||||
* @param k the key
|
|
||||||
* @param index the index the table is stored at
|
|
||||||
*
|
|
||||||
* This function gets a value from the table at the given index and
|
|
||||||
* pushes it onto the stack.
|
|
||||||
*
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::getfield(const std::string& k, int index) {
|
|
||||||
lua_getfield(L, index, k.c_str());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set a value in a table.
|
|
||||||
* @param index the index the table is stored at
|
|
||||||
*
|
|
||||||
* This function sets a value in a table stored at the given index.
|
|
||||||
*
|
|
||||||
* @note The key and value to be used should have already been pushed
|
|
||||||
* on the stack in that order.
|
|
||||||
*
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::settable(int index) {
|
|
||||||
lua_settable(L, index);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set a field in a table.
|
|
||||||
* @param k the key
|
|
||||||
* @param index the index the table is stored at
|
|
||||||
*
|
|
||||||
* This function sets a value in a table stored at the given index.
|
|
||||||
*
|
|
||||||
* @note The value to be used should be on the top of the stack.
|
|
||||||
*
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::setfield(const std::string& k, int index) {
|
|
||||||
lua_setfield(L, index, k.c_str());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the metatable associated with the given registry entry.
|
|
||||||
* @param tname the name in the registry
|
|
||||||
*
|
|
||||||
* This function gets the metatable associated with the given key in
|
|
||||||
* the registry. The resulting metatable is pushed onto the stack.
|
|
||||||
*
|
|
||||||
* @note This function uses luaL_getmetatable() internally.
|
|
||||||
*
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::getmetatable(const std::string& tname) {
|
|
||||||
luaL_getmetatable(L, tname.c_str());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the metatable of the value at the given index.
|
|
||||||
* @param index the index the value is stored at
|
|
||||||
*
|
|
||||||
* This function pushes on to the stack the metatabe of the value at
|
|
||||||
* the given index.
|
|
||||||
*
|
|
||||||
* @note This function uses lua_getmetatable() internally.
|
|
||||||
*
|
|
||||||
* @returns false if the value at the given index does not have a
|
|
||||||
* metatable or if the index is not valid
|
|
||||||
*/
|
|
||||||
bool state::getmetatable(int index) {
|
|
||||||
return lua_getmetatable(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the next key value pair from a table on the stack.
|
|
||||||
* @param index the stack index the table is at
|
|
||||||
*
|
|
||||||
* This function pops a key from the stack and pushes the next key
|
|
||||||
* value pair to the stack. The key will be stored at index -2 and
|
|
||||||
* the value will be at index -1. The key is expected to be on the
|
|
||||||
* top of the stack.
|
|
||||||
*
|
|
||||||
* @note While traversing a table, do not call
|
|
||||||
* lua::state::to(std::string()) directly on a key, unless you know
|
|
||||||
* that the key is actually a string. lua::state::to(std::string())
|
|
||||||
* changes the value at the given index; this confuses the next call
|
|
||||||
* to lua::state::next().
|
|
||||||
*
|
|
||||||
* <strong>While Loop Example:</strong>
|
|
||||||
* @code
|
|
||||||
* while(L.next() != 0) {
|
|
||||||
* // do stuff
|
|
||||||
* L.pop();
|
|
||||||
* }
|
|
||||||
* @endcode
|
|
||||||
*
|
|
||||||
* <strong>For Loop Example:</strong>
|
|
||||||
* @code
|
|
||||||
* for(L.push(lua::nil()); L.next(); L.pop()) {
|
|
||||||
* // do stuff
|
|
||||||
* }
|
|
||||||
* @endcode
|
|
||||||
*
|
|
||||||
* @returns true as long as there are remaining items in the table
|
|
||||||
*/
|
|
||||||
bool state::next(int index) {
|
|
||||||
return lua_next(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Load a global symbol onto the stack.
|
|
||||||
* @param name the name of the global to load
|
|
||||||
*
|
|
||||||
* This function loads a global symbol onto the stack from the lua
|
|
||||||
* state.
|
|
||||||
*
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::getglobal(const std::string& name) {
|
|
||||||
lua_getglobal(L, name.c_str());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set a global symbol.
|
|
||||||
* @param name the name of the global to set
|
|
||||||
*
|
|
||||||
* This function sets/creates a global symbol from the value above it
|
|
||||||
* on the stack.
|
|
||||||
*
|
|
||||||
* @note You should have pushed the value of the symbol onto the stack
|
|
||||||
* before calling this function.
|
|
||||||
*
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::setglobal(const std::string& name) {
|
|
||||||
lua_setglobal(L, name.c_str());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Load a file as a Lua chunk.
|
|
||||||
* @param filename the name of the file to load
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::loadfile(const std::string& filename) {
|
|
||||||
throw_error(luaL_loadfile(L, filename.c_str()));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Load a string as a Lua chunk.
|
|
||||||
* @param s the string to load
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
state& state::loadstring(const std::string& s) {
|
|
||||||
throw_error(luaL_loadstring(L, s.c_str()));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the length of a value on the stack.
|
|
||||||
* @param index the index the value is stored at
|
|
||||||
* @returns the length of the indicated value
|
|
||||||
*/
|
|
||||||
size_t state::objlen(int index) {
|
|
||||||
return lua_rawlen(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the value at index as a bool.
|
|
||||||
* @param boolean where to store the value
|
|
||||||
* @param index the index to get
|
|
||||||
* @note This function does \em not pop the value from the stack.
|
|
||||||
* @todo Instead of throwing an exception here, we may just return an
|
|
||||||
* error code.
|
|
||||||
* @throws lua::bad_conversion if the value on the stack could not be
|
|
||||||
* converted to the indicated type
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
state& state::to(bool& boolean, int index) {
|
|
||||||
if (lua_isboolean(L, index))
|
|
||||||
boolean = lua_toboolean(L, index);
|
|
||||||
else
|
|
||||||
throw bad_conversion("Cannot convert non 'boolean' value to bool");
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the value at index as a string.
|
|
||||||
* @param string where to store the value
|
|
||||||
* @param index the index to get
|
|
||||||
* @note This function does \em not pop the value from the stack.
|
|
||||||
* @todo Instead of throwing an exception here, we may just return an
|
|
||||||
* error code.
|
|
||||||
*
|
|
||||||
* @note lua::state::to(std::string()) will convert the value at the
|
|
||||||
* indicated index to a string <em>on the stack</em>. This can
|
|
||||||
* confuse lua::state::next();
|
|
||||||
*
|
|
||||||
* @throws lua::bad_conversion if the value on the stack could not be
|
|
||||||
* converted to the indicated type
|
|
||||||
* @returns a reference to this lua::state
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
state& state::to(std::string& string, int index) {
|
|
||||||
if (lua_isstring(L, index))
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
const char *str = lua_tolstring(L, index, &len);
|
|
||||||
string.replace(0, std::string::npos, str, len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw bad_conversion("Cannot convert value to string");
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the value at index as a bool.
|
|
||||||
* @param default_value this value is returned if the conversion fails
|
|
||||||
* @param index the index to get
|
|
||||||
* @note This function does \em not pop the value from the stack.
|
|
||||||
* @returns the indicated value from the stack or the default value if the
|
|
||||||
* conversion fails
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
bool state::as(bool default_value, int index) {
|
|
||||||
if (lua_isboolean(L, index))
|
|
||||||
return lua_toboolean(L, index);
|
|
||||||
else
|
|
||||||
return default_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [specialization] Get the value at index as a bool (T = bool).
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
bool state::as(int index) {
|
|
||||||
if (lua_isboolean(L, index))
|
|
||||||
return lua_toboolean(L, index);
|
|
||||||
else
|
|
||||||
throw bad_conversion("Cannot convert non 'boolean' value to bool");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [specialization] Get the value at index as a string (T = std::string).
|
|
||||||
* @note lua::state::as(std::string()) will convert the value at the
|
|
||||||
* indicated index to a string <em>on the stack</em>. This can confuse
|
|
||||||
* lua::state::next();
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
std::string state::as(int index) {
|
|
||||||
if (lua_isstring(L, index))
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
const char *str = lua_tolstring(L, index, &len);
|
|
||||||
return std::string(str, len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw bad_conversion("Cannot convert value to string");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [specialization] Check if the given index is a nil (T = lua::nil).
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
bool state::is<nil>(int index) {
|
|
||||||
return lua_isnil(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [specialization] Check if the given index is a boolean (T = bool).
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
bool state::is<bool>(int index) {
|
|
||||||
return lua_isboolean(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [specialization] Check if the given index is a string (T = std::string).
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
bool state::is<std::string>(int index) {
|
|
||||||
return lua_isstring(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [specialization] Check if the given index is a table (T = lua::table).
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
bool state::is<table>(int index) {
|
|
||||||
return lua_istable(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [specialization] Check if the given index is a C function (T =
|
|
||||||
* lua::cfunction).
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
bool state::is<cfunction>(int index) {
|
|
||||||
return lua_iscfunction(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [specialization] Check if the given index is a function (T =
|
|
||||||
* lua::function).
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
bool state::is<function>(int index) {
|
|
||||||
return lua_isfunction(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [specialization] Check if the given index is userdata (T =
|
|
||||||
* lua::userdata).
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
bool state::is<userdata>(int index) {
|
|
||||||
return lua_isuserdata(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** [specialization] Check if the given index is light userdata (T =
|
|
||||||
* lua::lightuserdata).
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
bool state::is<lightuserdata>(int index) {
|
|
||||||
return lua_islightuserdata(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
#include "lune.h"
|
|
||||||
lua::object *lua::local_object::mytbl=0;
|
|
@ -1,153 +0,0 @@
|
|||||||
#include "Core.h"
|
|
||||||
#include "Console.h"
|
|
||||||
#include "Export.h"
|
|
||||||
#include "PluginManager.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include "modules/Vermin.h"
|
|
||||||
#include "modules/Materials.h"
|
|
||||||
|
|
||||||
using std::vector;
|
|
||||||
using std::string;
|
|
||||||
using namespace DFHack;
|
|
||||||
|
|
||||||
command_result colonies (color_ostream &out, vector <string> & parameters);
|
|
||||||
|
|
||||||
DFHACK_PLUGIN("colonies");
|
|
||||||
REQUIRE_GLOBAL(world); // used by Materials
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
|
|
||||||
{
|
|
||||||
commands.push_back(PluginCommand(
|
|
||||||
"colonies", "List or change wild colonies (ants hills and such)",
|
|
||||||
colonies, false,
|
|
||||||
" Without any options, this command lists all the vermin colonies present.\n"
|
|
||||||
"Options:\n"
|
|
||||||
//" kill - destroy colonies\n" // unlisted because it's likely broken anyway
|
|
||||||
" bees - turn colonies into honey bee hives\n"
|
|
||||||
));
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
|
|
||||||
{
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroyColonies();
|
|
||||||
void convertColonies(Materials *Materials);
|
|
||||||
void showColonies(color_ostream &out, Materials *Materials);
|
|
||||||
|
|
||||||
command_result colonies (color_ostream &out, vector <string> & parameters)
|
|
||||||
{
|
|
||||||
bool destroy = false;
|
|
||||||
bool convert = false;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < parameters.size();i++)
|
|
||||||
{
|
|
||||||
if(parameters[i] == "kill")
|
|
||||||
destroy = true;
|
|
||||||
else if(parameters[i] == "bees")
|
|
||||||
convert = true;
|
|
||||||
else
|
|
||||||
return CR_WRONG_USAGE;
|
|
||||||
}
|
|
||||||
if (destroy && convert)
|
|
||||||
{
|
|
||||||
out.printerr("Kill or make bees? DECIDE!\n");
|
|
||||||
return CR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
CoreSuspender suspend;
|
|
||||||
|
|
||||||
Materials * materials = Core::getInstance().getMaterials();
|
|
||||||
|
|
||||||
materials->ReadCreatureTypesEx();
|
|
||||||
|
|
||||||
if (destroy)
|
|
||||||
destroyColonies();
|
|
||||||
else if (convert)
|
|
||||||
convertColonies(materials);
|
|
||||||
else
|
|
||||||
showColonies(out, materials);
|
|
||||||
|
|
||||||
materials->Finish();
|
|
||||||
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
//FIXME: this is probably bullshit
|
|
||||||
void destroyColonies()
|
|
||||||
{
|
|
||||||
uint32_t numSpawnPoints = Vermin::getNumVermin();
|
|
||||||
for (uint32_t i = 0; i < numSpawnPoints; i++)
|
|
||||||
{
|
|
||||||
Vermin::t_vermin sp;
|
|
||||||
Vermin::Read(i, sp);
|
|
||||||
|
|
||||||
if (sp.visible && sp.is_colony)
|
|
||||||
{
|
|
||||||
sp.visible = false;
|
|
||||||
Vermin::Write(i, sp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert all colonies to honey bees.
|
|
||||||
void convertColonies(Materials *Materials)
|
|
||||||
{
|
|
||||||
int bee_idx = -1;
|
|
||||||
for (size_t i = 0; i < Materials->raceEx.size(); i++)
|
|
||||||
{
|
|
||||||
if (Materials->raceEx[i].id == "HONEY_BEE")
|
|
||||||
{
|
|
||||||
bee_idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bee_idx == -1)
|
|
||||||
{
|
|
||||||
std::cerr << "Honey bees not present in game." << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t numSpawnPoints = Vermin::getNumVermin();
|
|
||||||
for (uint32_t i = 0; i < numSpawnPoints; i++)
|
|
||||||
{
|
|
||||||
Vermin::t_vermin sp;
|
|
||||||
Vermin::Read(i, sp);
|
|
||||||
|
|
||||||
if (sp.visible && sp.is_colony)
|
|
||||||
{
|
|
||||||
sp.race = bee_idx;
|
|
||||||
Vermin::Write(i, sp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void showColonies(color_ostream &out, Materials *Materials)
|
|
||||||
{
|
|
||||||
uint32_t numSpawnPoints = Vermin::getNumVermin();
|
|
||||||
int numColonies = 0;
|
|
||||||
for (uint32_t i = 0; i < numSpawnPoints; i++)
|
|
||||||
{
|
|
||||||
Vermin::t_vermin sp;
|
|
||||||
|
|
||||||
Vermin::Read(i, sp);
|
|
||||||
|
|
||||||
if (sp.visible && sp.is_colony)
|
|
||||||
{
|
|
||||||
numColonies++;
|
|
||||||
string race="(no race)";
|
|
||||||
if(sp.race != -1)
|
|
||||||
race = Materials->raceEx[sp.race].id;
|
|
||||||
|
|
||||||
out.print("Colony %u: %s at %d:%d:%d\n", i,
|
|
||||||
race.c_str(), sp.x, sp.y, sp.z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numColonies == 0)
|
|
||||||
out << "No colonies present." << std::endl;
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit 5b167d2ba89b877d80e0609feae8771aeaef356d
|
|
@ -1,31 +0,0 @@
|
|||||||
PROJECT (export)
|
|
||||||
# A list of source files
|
|
||||||
SET(PROJECT_SRCS
|
|
||||||
dwarfexport.cpp
|
|
||||||
)
|
|
||||||
# A list of headers
|
|
||||||
SET(PROJECT_HDRS
|
|
||||||
dwarfexport.h
|
|
||||||
)
|
|
||||||
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE)
|
|
||||||
|
|
||||||
# mash them together (headers are marked as headers and nothing will try to compile them)
|
|
||||||
LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS})
|
|
||||||
|
|
||||||
#linux
|
|
||||||
IF(UNIX)
|
|
||||||
add_definitions(-DLINUX_BUILD)
|
|
||||||
SET(PROJECT_LIBS
|
|
||||||
# add any extra linux libs here
|
|
||||||
${PROJECT_LIBS}
|
|
||||||
)
|
|
||||||
# windows
|
|
||||||
ELSE(UNIX)
|
|
||||||
SET(PROJECT_LIBS
|
|
||||||
# add any extra linux libs here
|
|
||||||
${PROJECT_LIBS}
|
|
||||||
$(NOINHERIT)
|
|
||||||
)
|
|
||||||
ENDIF(UNIX)
|
|
||||||
# this makes sure all the stuff is put in proper places and linked to dfhack
|
|
||||||
DFHACK_PLUGIN(dwarfexport ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS})
|
|
@ -1,244 +0,0 @@
|
|||||||
// some headers required for a plugin. Nothing special, just the basics.
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
#define DFHACK_WANT_MISCUTILS
|
|
||||||
#include <Core.h>
|
|
||||||
#include <VersionInfo.h>
|
|
||||||
#include <Console.h>
|
|
||||||
#include <Export.h>
|
|
||||||
#include <PluginManager.h>
|
|
||||||
#include <modules/Units.h>
|
|
||||||
#include <modules/Translation.h>
|
|
||||||
|
|
||||||
#include <df/ui.h>
|
|
||||||
#include <df/world.h>
|
|
||||||
#include <df/unit.h>
|
|
||||||
#include <df/unit_soul.h>
|
|
||||||
#include <df/unit_labor.h>
|
|
||||||
#include <df/unit_skill.h>
|
|
||||||
/*
|
|
||||||
dwarfexport
|
|
||||||
===========
|
|
||||||
Export dwarves to RuneSmith-compatible XML; also unused by modern tools.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using namespace DFHack;
|
|
||||||
using df::global::ui;
|
|
||||||
using df::global::world;
|
|
||||||
|
|
||||||
// our own, empty header.
|
|
||||||
#include "dwarfexport.h"
|
|
||||||
#include <df/personality_facet_type.h>
|
|
||||||
|
|
||||||
|
|
||||||
// Here go all the command declarations...
|
|
||||||
// mostly to allow having the mandatory stuff on top of the file and commands on the bottom
|
|
||||||
command_result export_dwarves (color_ostream &con, std::vector <std::string> & parameters);
|
|
||||||
|
|
||||||
DFHACK_PLUGIN("dwarfexport");
|
|
||||||
|
|
||||||
// Mandatory init function. If you have some global state, create it here.
|
|
||||||
DFhackCExport command_result plugin_init (color_ostream &con, std::vector <PluginCommand> &commands)
|
|
||||||
{
|
|
||||||
// Fill the command list with your commands.
|
|
||||||
commands.push_back(PluginCommand("dwarfexport",
|
|
||||||
"Export dwarves to RuneSmith-compatible XML.",
|
|
||||||
export_dwarves /*,
|
|
||||||
true or false - true means that the command can't be used from non-interactive user interface'*/));
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is called right before the plugin library is removed from memory.
|
|
||||||
DFhackCExport command_result plugin_shutdown (color_ostream &con)
|
|
||||||
{
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* physicals[] = {
|
|
||||||
"Strength",
|
|
||||||
"Agility",
|
|
||||||
"Toughness",
|
|
||||||
"Endurance",
|
|
||||||
"Recuperation",
|
|
||||||
"DiseaseResistance",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char* mentals[] = {
|
|
||||||
"AnalyticalAbility",
|
|
||||||
"Focus",
|
|
||||||
"Willpower",
|
|
||||||
"Creatvity", //Speeling deliberate
|
|
||||||
"Intuition",
|
|
||||||
"Patience",
|
|
||||||
"Memory",
|
|
||||||
"LinguisticAbility",
|
|
||||||
"SpatialSense",
|
|
||||||
"Musicality",
|
|
||||||
"KinaestheticSense",
|
|
||||||
"Empathy",
|
|
||||||
"SocialAwareness",
|
|
||||||
};
|
|
||||||
|
|
||||||
static void element(const char* name, const char* content, ostream& out, const char* extra_indent="") {
|
|
||||||
out << extra_indent << " <" << name << ">" << content << "</" << name << ">" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void element(const char* name, const uint32_t content, ostream& out, const char* extra_indent="") {
|
|
||||||
out << extra_indent << " <" << name << ">" << content << "</" << name << ">" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printAttributes(color_ostream &con, df::unit* cre, ostream& out) {
|
|
||||||
out << " <Attributes>" << endl;
|
|
||||||
for (int i = 0; i < NUM_CREATURE_PHYSICAL_ATTRIBUTES; i++) {
|
|
||||||
element(physicals[i], cre->body.physical_attrs[i].value, out, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
df::unit_soul * s = cre->status.current_soul;
|
|
||||||
if (s) {
|
|
||||||
for (int i = 0; i < NUM_CREATURE_MENTAL_ATTRIBUTES; i++) {
|
|
||||||
element(mentals[i], s->mental_attrs[i].value, out, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out << " </Attributes>" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printTraits(color_ostream &con, df::unit* cre, ostream& out)
|
|
||||||
{
|
|
||||||
|
|
||||||
out << " <Traits>" << endl;
|
|
||||||
df::unit_soul * s = cre->status.current_soul;
|
|
||||||
if (s)
|
|
||||||
{
|
|
||||||
FOR_ENUM_ITEMS(personality_facet_type,index)
|
|
||||||
{
|
|
||||||
out << " <Trait name='" << ENUM_KEY_STR(personality_facet_type, index) <<
|
|
||||||
"' value='" << s->traits[index] << "'>";
|
|
||||||
//FIXME: needs reimplementing trait string generation
|
|
||||||
/*
|
|
||||||
string trait = con->vinfo->getTrait(i, s->traits[i]);
|
|
||||||
if (!trait.empty()) {
|
|
||||||
out << trait.c_str();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
out << "</Trait>" << endl;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out << " </Traits>" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t getCreatureAge(df::unit* cre)
|
|
||||||
{
|
|
||||||
int32_t yearDifference = *df::global::cur_year - cre->relations.birth_year;
|
|
||||||
|
|
||||||
// If the birthday this year has not yet passed, subtract one year.
|
|
||||||
// ASSUMPTION: birth_time is on the same scale as cur_year_tick
|
|
||||||
if (cre->relations.birth_time >= *df::global::cur_year_tick) {
|
|
||||||
yearDifference--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return yearDifference;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printLabors(color_ostream &con, df::unit* cre, ostream& out)
|
|
||||||
{
|
|
||||||
// Using British spelling here, consistent with Runesmith
|
|
||||||
out << " <Labours>" << endl;
|
|
||||||
FOR_ENUM_ITEMS(unit_labor, iCount)
|
|
||||||
{
|
|
||||||
if (cre->status.labors[iCount]) {
|
|
||||||
// Get the caption for the labor index.
|
|
||||||
element("Labour", ENUM_ATTR_STR(unit_labor, caption, iCount), out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out << " </Labours>" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printSkill(color_ostream &con, df::unit_skill* skill, ostream& out)
|
|
||||||
{
|
|
||||||
out << " <Skill>" << endl;
|
|
||||||
|
|
||||||
element("Name", ENUM_ATTR_STR(job_skill, caption, skill->id), out);
|
|
||||||
element("Level", skill->rating, out);
|
|
||||||
|
|
||||||
out << " </Skill>" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void printSkills(color_ostream &con, df::unit* cre, ostream& out)
|
|
||||||
{
|
|
||||||
|
|
||||||
std::vector<df::unit_skill* > vSkills = cre->status.current_soul->skills;
|
|
||||||
|
|
||||||
out << " <Skills>" << endl;
|
|
||||||
for (int iCount = 0; iCount < vSkills.size(); iCount++)
|
|
||||||
{
|
|
||||||
printSkill(con, vSkills.at(iCount), out);
|
|
||||||
}
|
|
||||||
|
|
||||||
out << " </Skills>" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GDC needs:
|
|
||||||
// Name
|
|
||||||
// Nickname
|
|
||||||
// Sex
|
|
||||||
// Attributes
|
|
||||||
// Traits
|
|
||||||
static void export_dwarf(color_ostream &con, df::unit* cre, ostream& out) {
|
|
||||||
string info = cre->name.first_name;
|
|
||||||
info += " ";
|
|
||||||
info += Translation::TranslateName(&cre->name, false);
|
|
||||||
info[0] = toupper(info[0]);
|
|
||||||
con.print("Exporting %s\n", info.c_str());
|
|
||||||
|
|
||||||
out << " <Creature>" << endl;
|
|
||||||
element("Name", info.c_str(), out);
|
|
||||||
element("Nickname", cre->name.nickname.c_str(), out);
|
|
||||||
element("Sex", cre->sex == 0 ? "Female" : "Male", out);
|
|
||||||
element("Age", getCreatureAge(cre), out); // Added age, active labors, and skills March 9, 2012
|
|
||||||
printAttributes(con, cre, out);
|
|
||||||
printTraits(con, cre, out);
|
|
||||||
printLabors(con, cre, out);
|
|
||||||
printSkills(con, cre, out);
|
|
||||||
|
|
||||||
out << " </Creature>" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
command_result export_dwarves (color_ostream &con, std::vector <std::string> & parameters)
|
|
||||||
{
|
|
||||||
string filename;
|
|
||||||
if (parameters.size() == 1) {
|
|
||||||
filename = parameters[0];
|
|
||||||
} else {
|
|
||||||
con.print("export <filename>\n");
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ofstream outf(filename.c_str());
|
|
||||||
if (!outf) {
|
|
||||||
con.printerr("Failed to open file %s\n", filename.c_str());
|
|
||||||
return CR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
CoreSuspender suspend;
|
|
||||||
|
|
||||||
uint32_t race = ui->race_id;
|
|
||||||
uint32_t civ = ui->civ_id;
|
|
||||||
|
|
||||||
outf << "<?xml version='1.0' encoding='ibm850'?>" << endl << "<Creatures>" << endl;
|
|
||||||
|
|
||||||
for (int i = 0; i < world->units.all.size(); ++i)
|
|
||||||
{
|
|
||||||
df::unit* cre = world->units.all[i];
|
|
||||||
if (cre->race == race && cre->civ_id == civ) {
|
|
||||||
export_dwarf(con, cre, outf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outf << "</Creatures>" << endl;
|
|
||||||
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
#pragma once
|
|
@ -1,241 +0,0 @@
|
|||||||
-- Stuff used by dfusion
|
|
||||||
local _ENV = mkmodule('plugins.dfusion')
|
|
||||||
|
|
||||||
local ms=require("memscan")
|
|
||||||
|
|
||||||
local marker={0xDE,0xAD,0xBE,0xEF}
|
|
||||||
--utility functions
|
|
||||||
function dwordToTable(dword)
|
|
||||||
local b={bit32.extract(dword,0,8),bit32.extract(dword,8,8),bit32.extract(dword,16,8),bit32.extract(dword,24,8)}
|
|
||||||
return b
|
|
||||||
end
|
|
||||||
function concatTables(t1,t2)
|
|
||||||
for k,v in pairs(t2) do
|
|
||||||
table.insert(t1,v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function makeCall(from,to)
|
|
||||||
local ret={0xe8}
|
|
||||||
concatTables(ret,dwordToTable(to-from-5))
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
-- A reversable binary patch
|
|
||||||
patches={}
|
|
||||||
BinaryPatch=defclass(BinaryPatch)
|
|
||||||
BinaryPatch.ATTRS {pre_data=DEFAULT_NIL,data=DEFAULT_NIL,address=DEFAULT_NIL,name=DEFAULT_NIL}
|
|
||||||
function BinaryPatch:init(args)
|
|
||||||
self.is_applied=false
|
|
||||||
if args.pre_data==nil or args.data==nil or args.address==nil or args.name==nil then
|
|
||||||
error("Invalid parameters to binary patch")
|
|
||||||
end
|
|
||||||
if patches[self.name]~=nil then
|
|
||||||
error("Patch already exist")
|
|
||||||
end
|
|
||||||
|
|
||||||
for k,v in ipairs(args.data) do
|
|
||||||
if args.pre_data[k]==nil then
|
|
||||||
error("can't edit without revert data")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function BinaryPatch:postinit(args)
|
|
||||||
patches[args.name]=self
|
|
||||||
end
|
|
||||||
function BinaryPatch:test()
|
|
||||||
local arr=ms.CheckedArray.new('uint8_t',self.address,self.address+#self.pre_data)
|
|
||||||
for k,v in ipairs(self.pre_data) do
|
|
||||||
if arr[k-1]~=v then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
function BinaryPatch:apply()
|
|
||||||
if not self:test() then
|
|
||||||
error(string.format("pre-data for binary patch does not match expected"))
|
|
||||||
end
|
|
||||||
|
|
||||||
local post_buf=df.new('uint8_t',#self.pre_data)
|
|
||||||
for k,v in ipairs(self.pre_data) do
|
|
||||||
if self.data[k]==nil then
|
|
||||||
post_buf[k-1]=v
|
|
||||||
else
|
|
||||||
post_buf[k-1]=self.data[k]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local ret=dfhack.with_finalize(function() post_buf:delete() end,dfhack.internal.patchMemory,self.address,post_buf,#self.pre_data)
|
|
||||||
if not ret then
|
|
||||||
error("Patch application failed!")
|
|
||||||
end
|
|
||||||
self.is_applied=true
|
|
||||||
end
|
|
||||||
function BinaryPatch:repatch(newdata)
|
|
||||||
if newdata==nil then newdata=self.data end
|
|
||||||
self:remove()
|
|
||||||
self.data=newdata
|
|
||||||
self:apply()
|
|
||||||
end
|
|
||||||
function BinaryPatch:remove(delete)
|
|
||||||
if delete==nil then
|
|
||||||
delete=true
|
|
||||||
end
|
|
||||||
if not self.is_applied then
|
|
||||||
error("can't remove BinaryPatch, not applied.")
|
|
||||||
end
|
|
||||||
local arr=ms.CheckedArray.new('uint8_t',self.address,self.address+#self.pre_data)
|
|
||||||
|
|
||||||
local post_buf=df.new('uint8_t',#self.pre_data)
|
|
||||||
for k,v in pairs(self.pre_data) do
|
|
||||||
post_buf[k-1]=v
|
|
||||||
end
|
|
||||||
local ret=dfhack.with_finalize(function() post_buf:delete() end,dfhack.internal.patchMemory,self.address,post_buf,#self.pre_data)
|
|
||||||
if not ret then
|
|
||||||
error("Patch remove failed!")
|
|
||||||
end
|
|
||||||
self.is_applied=false
|
|
||||||
if delete then
|
|
||||||
patches[self.name]=nil
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function BinaryPatch:__gc()
|
|
||||||
if self.is_applied then
|
|
||||||
self:remove()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- A binary hack (obj file) loader/manager
|
|
||||||
-- has to have: a way to get offsets for marked areas (for post load modification) or some way to do that pre-load
|
|
||||||
-- page managing (including excecute/write flags for DEP and the like)
|
|
||||||
-- TODO plugin state enum, a way to modify post install (could include repatching code...)
|
|
||||||
plugins=plugins or {}
|
|
||||||
BinaryPlugin=defclass(BinaryPlugin)
|
|
||||||
BinaryPlugin.ATTRS {filename=DEFAULT_NIL,reloc_table={},name=DEFAULT_NIL}
|
|
||||||
function BinaryPlugin:init(args)
|
|
||||||
|
|
||||||
end
|
|
||||||
function BinaryPlugin:postinit(args)
|
|
||||||
if self.name==nil then error("Not a valid plugin name!") end
|
|
||||||
if plugins[args.name]==nil then
|
|
||||||
plugins[self.name]=self
|
|
||||||
else
|
|
||||||
error("Trying to create a same plugin")
|
|
||||||
end
|
|
||||||
self.allocated_object={}
|
|
||||||
self:load()
|
|
||||||
end
|
|
||||||
function BinaryPlugin:get_or_alloc(name,typename,arrsize)
|
|
||||||
if self.allocated_object[name]~=nil then
|
|
||||||
return self.allocated_object[name]
|
|
||||||
else
|
|
||||||
return self:allocate(name,typename,arrsize)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function BinaryPlugin:allocate(name,typename,arrsize)
|
|
||||||
local trg
|
|
||||||
if df[typename]==nil then
|
|
||||||
trg=df.new(typename,arrsize)
|
|
||||||
self.allocated_object[name]=trg
|
|
||||||
else
|
|
||||||
trg=df[typename]:new(arrsize)
|
|
||||||
self.allocated_object[name]=trg
|
|
||||||
end
|
|
||||||
return trg
|
|
||||||
end
|
|
||||||
function BinaryPlugin:load()
|
|
||||||
local obj=loadObjectFile(self.filename)
|
|
||||||
self.data=df.reinterpret_cast("uint8_t",obj.data)
|
|
||||||
self.size=obj.data_size
|
|
||||||
for _,v in pairs(obj.symbols) do
|
|
||||||
if string.sub(v.name,1,5)=="mark_" then
|
|
||||||
local new_pos=self:find_marker(v.pos)
|
|
||||||
self.reloc_table[string.sub(v.name,6)]=new_pos
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function BinaryPlugin:find_marker(start_pos)
|
|
||||||
local matched=0
|
|
||||||
for i=start_pos,self.size do
|
|
||||||
if self.data[i]==marker[4-matched] then
|
|
||||||
matched=matched+1
|
|
||||||
if matched == 4 then
|
|
||||||
return i-4
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function BinaryPlugin:set_marker_dword(marker,dword) -- i hope Toady does not make a 64bit version...
|
|
||||||
if self.reloc_table[marker]==nil then
|
|
||||||
error("marker ".. marker.. " not found")
|
|
||||||
end
|
|
||||||
local b=dwordToTable(dword)
|
|
||||||
local off=self.reloc_table[marker]
|
|
||||||
for k,v in ipairs(b) do
|
|
||||||
self.data[off+k]=b[k]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function BinaryPlugin:move_to_df()
|
|
||||||
local _,addr=df.sizeof(self.data)
|
|
||||||
markAsExecutable(addr)
|
|
||||||
return addr
|
|
||||||
end
|
|
||||||
function BinaryPlugin:print_data()
|
|
||||||
local out=""
|
|
||||||
for i=0,self.size do
|
|
||||||
out=out..string.format(" %02x",self.data[i])
|
|
||||||
if math.modf(i,16)==15 then
|
|
||||||
print(out)
|
|
||||||
out=""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print(out)
|
|
||||||
end
|
|
||||||
function BinaryPlugin:status()
|
|
||||||
return "invalid, base class only!"
|
|
||||||
end
|
|
||||||
function BinaryPlugin:__gc()
|
|
||||||
for k,v in pairs(self.allocated_object) do
|
|
||||||
df.delete(v)
|
|
||||||
end
|
|
||||||
if self.unload then
|
|
||||||
self:unload()
|
|
||||||
end
|
|
||||||
self.data:delete()
|
|
||||||
end
|
|
||||||
-- a Menu for some stuff. Maybe add a posibility of it working as a gui, or a gui adaptor?
|
|
||||||
-- Todo add hints, and parse them to make a "smart" choice of parameters to pass
|
|
||||||
SimpleMenu=defclass(SimpleMenu)
|
|
||||||
SimpleMenu.ATTRS{title=DEFAULT_NIL}
|
|
||||||
function SimpleMenu:init(args)
|
|
||||||
self.items={}
|
|
||||||
end
|
|
||||||
function SimpleMenu:add(name,entry,hints)
|
|
||||||
table.insert(self.items,{entry,name,hints})
|
|
||||||
end
|
|
||||||
function SimpleMenu:display()
|
|
||||||
print("Select choice (q exits):")
|
|
||||||
for p,c in pairs(self.items) do
|
|
||||||
print(string.format("%3d).%s",p,c[2]))
|
|
||||||
end
|
|
||||||
local ans
|
|
||||||
repeat
|
|
||||||
local r
|
|
||||||
r=dfhack.lineedit()
|
|
||||||
if r==nil then return end
|
|
||||||
if r=='q' then return end
|
|
||||||
ans=tonumber(r)
|
|
||||||
|
|
||||||
if ans==nil or not(ans<=#self.items and ans>0) then
|
|
||||||
print("Invalid choice.")
|
|
||||||
end
|
|
||||||
|
|
||||||
until ans~=nil and (ans<=#self.items and ans>0)
|
|
||||||
if type(self.items[ans][1])=="function" then
|
|
||||||
self.items[ans][1]()
|
|
||||||
else
|
|
||||||
self.items[ans][1]:display()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return _ENV
|
|
@ -1,172 +0,0 @@
|
|||||||
local _ENV = mkmodule('plugins.dfusion.adv_tools')
|
|
||||||
local dfu=require("plugins.dfusion")
|
|
||||||
local tools=require("plugins.dfusion.tools")
|
|
||||||
menu=dfu.SimpleMenu()
|
|
||||||
function Reincarnate(trg_unit,swap_soul) --only for adventurer i guess
|
|
||||||
if swap_soul==nil then
|
|
||||||
swap_soul=true
|
|
||||||
end
|
|
||||||
local adv=trg_unit or df.global.world.units.active[0]
|
|
||||||
if adv.flags1.dead==false then
|
|
||||||
qerror("You are not dead (yet)!")
|
|
||||||
end
|
|
||||||
local hist_fig=dfhack.units.getNemesis(adv).figure
|
|
||||||
if hist_fig==nil then
|
|
||||||
qerror("No historical figure for adventurer...")
|
|
||||||
end
|
|
||||||
local events=df.global.world.history.events
|
|
||||||
local trg_hist_fig
|
|
||||||
for i=#events-1,0,-1 do -- reverse search because almost always it will be last entry
|
|
||||||
if df.history_event_hist_figure_diedst:is_instance(events[i]) then
|
|
||||||
--print("is instance:"..i)
|
|
||||||
if events[i].victim_hf==hist_fig.id then
|
|
||||||
--print("Is same id:"..i)
|
|
||||||
trg_hist_fig=events[i].slayer_hf
|
|
||||||
if trg_hist_fig then
|
|
||||||
trg_hist_fig=df.historical_figure.find(trg_hist_fig)
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if trg_hist_fig ==nil then
|
|
||||||
qerror("Slayer not found")
|
|
||||||
end
|
|
||||||
|
|
||||||
local trg_unit=trg_hist_fig.unit_id
|
|
||||||
if trg_unit==nil then
|
|
||||||
qerror("Unit id not found!")
|
|
||||||
end
|
|
||||||
local trg_unit_final=df.unit.find(trg_unit)
|
|
||||||
|
|
||||||
change_adv(trg_unit_final)
|
|
||||||
if swap_soul then --actually add a soul...
|
|
||||||
t_soul=adv.status.current_soul
|
|
||||||
adv.status.current_soul=df.NULL
|
|
||||||
adv.status.souls:resize(0)
|
|
||||||
trg_unit_final.status.current_soul=t_soul
|
|
||||||
trg_unit_final.status.souls:insert(#trg_unit_final.status.souls,t_soul)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
menu:add("Reincarnate",Reincarnate,{{df.unit,"optional"}})-- bool, optional
|
|
||||||
function change_adv(unit,nemesis)
|
|
||||||
if nemesis==nil then
|
|
||||||
nemesis=true --default value is nemesis switch too.
|
|
||||||
end
|
|
||||||
if unit==nil then
|
|
||||||
unit=dfhack.gui.getSelectedUnit()--getCreatureAtPointer()
|
|
||||||
end
|
|
||||||
if unit==nil then
|
|
||||||
error("Invalid unit!")
|
|
||||||
end
|
|
||||||
local other=df.global.world.units.active
|
|
||||||
local unit_indx
|
|
||||||
for k,v in pairs(other) do
|
|
||||||
if v==unit then
|
|
||||||
unit_indx=k
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if unit_indx==nil then
|
|
||||||
error("Unit not found in array?!") --should not happen
|
|
||||||
end
|
|
||||||
other[unit_indx]=other[0]
|
|
||||||
other[0]=unit
|
|
||||||
if nemesis then --basicly copied from advtools plugin...
|
|
||||||
local nem=dfhack.units.getNemesis(unit)
|
|
||||||
local other_nem=dfhack.units.getNemesis(other[unit_indx])
|
|
||||||
if other_nem then
|
|
||||||
other_nem.flags[0]=false
|
|
||||||
other_nem.flags[1]=true
|
|
||||||
end
|
|
||||||
if nem then
|
|
||||||
nem.flags[0]=true
|
|
||||||
nem.flags[2]=true
|
|
||||||
for k,v in pairs(df.global.world.nemesis.all) do
|
|
||||||
if v.id==nem.id then
|
|
||||||
df.global.ui_advmode.player_id=k
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
qerror("Current unit does not have nemesis record, further working not guaranteed")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
menu:add("Change adventurer",change_adv)
|
|
||||||
function log_pos()
|
|
||||||
local adv=df.global.world.units.active[0]
|
|
||||||
|
|
||||||
local wmap=df.global.world.map
|
|
||||||
local sub_pos={x=adv.pos.x,y=adv.pos.y,z=adv.pos.z}
|
|
||||||
local region_pos={x=wmap.region_x,y=wmap.region_y,z=wmap.region_z}
|
|
||||||
local pos={x=sub_pos.x+region_pos.x*48,y=sub_pos.y+region_pos.y*48,z=sub_pos.z+region_pos.z}
|
|
||||||
local state
|
|
||||||
if adv.flags1.dead then
|
|
||||||
state="dead"
|
|
||||||
else
|
|
||||||
state="live n kicking"
|
|
||||||
end
|
|
||||||
local message=string.format("%s %s at pos={%d,%d,%d} region={%d,%d,%d}",dfhack.TranslateName(adv.name),state,pos.x,pos.y,pos.z,region_pos.x,region_pos.y,region_pos.z)
|
|
||||||
print(message)
|
|
||||||
local path="deaths_"..df.global.world.cur_savegame.save_dir..".txt"
|
|
||||||
local f=io.open(path,"a")
|
|
||||||
f:write(message)
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
menu:add("Log adventurers position",log_pos)
|
|
||||||
function addSite(x,y,rgn_max_x,rgn_min_x,rgn_max_y,rgn_min_y,civ_id,name,sitetype)
|
|
||||||
if x==nil or y==nil then
|
|
||||||
x=(df.global.world.map.region_x+1)/16
|
|
||||||
y=(df.global.world.map.region_y+1)/16
|
|
||||||
end
|
|
||||||
if name==nil then
|
|
||||||
name=dfhack.lineedit("Site name:")or "Hacked site"
|
|
||||||
end
|
|
||||||
if sitetype==nil then
|
|
||||||
sitetype=tonumber(dfhack.lineedit("Site type (numeric):")) or 7
|
|
||||||
end
|
|
||||||
rgn_max_x=rgn_max_x or (df.global.world.map.region_x+1)%16
|
|
||||||
rgn_max_y=rgn_max_y or (df.global.world.map.region_y+1)%16
|
|
||||||
rgn_min_y=rgn_min_y or rgn_max_y
|
|
||||||
rgn_min_x=rgn_min_x or rgn_max_x
|
|
||||||
print("Region:",rgn_max_x,rgn_min_x,rgn_max_y,rgn_min_y)
|
|
||||||
--[=[
|
|
||||||
<angavrilov> global = pos*16 + rgn
|
|
||||||
<angavrilov> BUT
|
|
||||||
<angavrilov> for cities global is usually 17x17, i.e. max size
|
|
||||||
<angavrilov> while rgn designates a small bit in the middle
|
|
||||||
<angavrilov> for stuff like forts that formula holds exactly
|
|
||||||
]=]--
|
|
||||||
local wd=df.global.world.world_data
|
|
||||||
local nsite=df.world_site:new()
|
|
||||||
nsite.name.first_name=name
|
|
||||||
nsite.name.has_name=true
|
|
||||||
nsite.pos:assign{x=x,y=y}
|
|
||||||
nsite.rgn_max_x=rgn_max_x
|
|
||||||
nsite.rgn_min_x=rgn_min_x
|
|
||||||
nsite.rgn_min_y=rgn_min_y
|
|
||||||
nsite.rgn_max_y=rgn_max_y
|
|
||||||
nsite.global_max_x=nsite.pos.x*16+nsite.rgn_max_x
|
|
||||||
nsite.global_min_x=nsite.pos.x*16+nsite.rgn_min_x
|
|
||||||
nsite.global_max_y=nsite.pos.y*16+nsite.rgn_max_y
|
|
||||||
nsite.global_min_y=nsite.pos.y*16+nsite.rgn_min_y
|
|
||||||
nsite.id=wd.next_site_id
|
|
||||||
nsite.civ_id=civ_id or -1
|
|
||||||
nsite.cur_owner_id=civ_id or -1
|
|
||||||
nsite.type=sitetype --lair = 7
|
|
||||||
nsite.flags:resize(23)
|
|
||||||
--nsite.flags[4]=true
|
|
||||||
--nsite.flags[5]=true
|
|
||||||
--nsite.flags[6]=true
|
|
||||||
nsite.index=#wd.sites+1
|
|
||||||
wd.sites:insert("#",nsite)
|
|
||||||
wd.next_site_id=wd.next_site_id+1
|
|
||||||
--might not be needed...
|
|
||||||
--[[local unk130=df.world_site_unk130:new()
|
|
||||||
unk130.index=#wd.site_unk130+1
|
|
||||||
wd.site_unk130:insert("#",unk130)
|
|
||||||
--wd.next_site_unk136_id=wd.next_site_unk136_id+1--]]
|
|
||||||
return nsite
|
|
||||||
end
|
|
||||||
menu:add("Create site at current location",addSite)
|
|
||||||
return _ENV
|
|
@ -1,124 +0,0 @@
|
|||||||
local _ENV = mkmodule('plugins.dfusion.embark')
|
|
||||||
local dfu=require("plugins.dfusion")
|
|
||||||
local ms=require("memscan")
|
|
||||||
local MAX_RACES=100
|
|
||||||
CustomEmbark=defclass(CustomEmbark,dfu.BinaryPlugin)
|
|
||||||
local myos=dfhack.getOSType()
|
|
||||||
if myos=="windows" then
|
|
||||||
CustomEmbark.ATTRS{filename="hack/lua/plugins/dfusion/embark.o",name="CustomEmbark",race_caste_data=DEFAULT_NIL}
|
|
||||||
function CustomEmbark:parseRaces(races)
|
|
||||||
if #races<7 then
|
|
||||||
error("caste and race count must be bigger than 6")
|
|
||||||
end
|
|
||||||
if #races>MAX_RACES then
|
|
||||||
error("caste and race count must be less then "..MAX_RACES)
|
|
||||||
end
|
|
||||||
local n_to_id=require("plugins.dfusion.tools").build_race_names()
|
|
||||||
|
|
||||||
local ids={}
|
|
||||||
for k,v in pairs(races) do
|
|
||||||
local race=v[1] or v
|
|
||||||
ids[k]={}
|
|
||||||
ids[k][1]=n_to_id[race]
|
|
||||||
if ids[k][1]==nil then qerror(race.." not found!") end
|
|
||||||
ids[k][2]=v[2] or -1
|
|
||||||
end
|
|
||||||
self.race_caste_data=ids
|
|
||||||
end
|
|
||||||
function CustomEmbark:install(race_caste_data)
|
|
||||||
local stoff=dfhack.internal.getAddress('start_dwarf_count')
|
|
||||||
if race_caste_data~=nil then
|
|
||||||
self:parseRaces(race_caste_data)
|
|
||||||
end
|
|
||||||
|
|
||||||
if stoff==nil then
|
|
||||||
error("address for start_dwarf_count not found!")
|
|
||||||
end
|
|
||||||
local _,race_id_offset=df.sizeof(df.global.ui:_field("race_id"))
|
|
||||||
print(string.format("start=%08x",stoff))
|
|
||||||
local needle={0x0f,0xb7,0x0d} --movzx eax,dword ptr [race_id]
|
|
||||||
local tmp_table=dfu.dwordToTable(race_id_offset)
|
|
||||||
for k,v in ipairs(tmp_table) do
|
|
||||||
table.insert(needle,v)
|
|
||||||
end
|
|
||||||
|
|
||||||
local mem=ms.get_code_segment()
|
|
||||||
print(mem.uint8_t:addr2idx(stoff))
|
|
||||||
print(mem.uint8_t:find(needle,mem.uint8_t:addr2idx(stoff)))
|
|
||||||
local _,trg_offset=mem.uint8_t:find(needle,mem.uint8_t:addr2idx(stoff),nil)--maybe endoff=stoff+bignumber
|
|
||||||
if trg_offset==nil then
|
|
||||||
error("address for race_load not found")
|
|
||||||
end
|
|
||||||
local call_data={0x90,0x90}
|
|
||||||
local _,data_offset=df.sizeof(self.data)
|
|
||||||
dfu.concatTables(call_data,dfu.makeCall(trg_offset+2,data_offset))
|
|
||||||
self.call_patch=self.call_patch or dfu.BinaryPatch{pre_data=needle,data=call_data,address=trg_offset,name="custom_embark_call_patch"}
|
|
||||||
needle={0x83,0xc8,0xff} -- or eax, 0xFF
|
|
||||||
local _,caste_offset=mem.uint8_t:find(needle,mem.uint8_t:addr2idx(trg_offset),nil)
|
|
||||||
if caste_offset==nil or caste_offset-stoff>1000 then
|
|
||||||
error("Caste change code not found or found too far!")
|
|
||||||
end
|
|
||||||
|
|
||||||
self.disable_castes=self.disable_castes or dfu.BinaryPatch{pre_data={0x83,0xc8,0xff},data={0x90,0x90,0x90},address=caste_offset,name="custom_embark_caste_disable"}
|
|
||||||
self.disable_castes:apply()
|
|
||||||
|
|
||||||
|
|
||||||
self:setEmbarkParty(self.race_caste_data)
|
|
||||||
local caste_array=self:get_or_alloc("caste_array","uint16_t",MAX_RACES)
|
|
||||||
local race_array=self:get_or_alloc("race_array","uint16_t",MAX_RACES)
|
|
||||||
|
|
||||||
local race_array_off,caste_array_off
|
|
||||||
local _
|
|
||||||
_,race_array_off=df.sizeof(race_array)
|
|
||||||
_,caste_array_off=df.sizeof(caste_array)
|
|
||||||
self:set_marker_dword("race",caste_array_off) --hehe... mixed them up i guess...
|
|
||||||
self:set_marker_dword("caste",race_array_off)
|
|
||||||
|
|
||||||
self:move_to_df()
|
|
||||||
self.call_patch:apply()
|
|
||||||
self.installed=true
|
|
||||||
end
|
|
||||||
|
|
||||||
function CustomEmbark:setEmbarkParty(racesAndCastes)
|
|
||||||
local stoff=dfhack.internal.getAddress('start_dwarf_count')
|
|
||||||
|
|
||||||
|
|
||||||
if self.dwarfcount== nil then
|
|
||||||
self.dwarfcount=dfu.BinaryPatch{pre_data=dfu.dwordToTable(7),data=dfu.dwordToTable(#self.race_caste_data),address=stoff,name="custom_embark_embarkcount"}
|
|
||||||
self.dwarfcount:apply()
|
|
||||||
else
|
|
||||||
self.dwarfcount:repatch(dfu.dwordToTable(#self.race_caste_data))
|
|
||||||
end
|
|
||||||
local caste_array=self:get_or_alloc("caste_array","uint16_t",MAX_RACES)
|
|
||||||
local race_array=self:get_or_alloc("race_array","uint16_t",MAX_RACES)
|
|
||||||
|
|
||||||
for k,v in ipairs(self.race_caste_data) do
|
|
||||||
caste_array[k-1]=v[2] or -1
|
|
||||||
race_array[k-1]=v[1]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function CustomEmbark:status()
|
|
||||||
if self.installed then
|
|
||||||
return "valid, installed"
|
|
||||||
else
|
|
||||||
return "valid, not installed"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function CustomEmbark:uninstall()
|
|
||||||
if self.installed then
|
|
||||||
self.call_patch:remove()
|
|
||||||
self.disable_castes:remove()
|
|
||||||
self.dwarfcount:remove()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function CustomEmbark:unload()
|
|
||||||
self:uninstall()
|
|
||||||
if Embark~=nil then
|
|
||||||
Embark=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Embark=Embark or CustomEmbark()
|
|
||||||
else
|
|
||||||
CustomEmbark.status=function() return"invalid, os not supported" end
|
|
||||||
end
|
|
||||||
return _ENV
|
|
Binary file not shown.
@ -1,121 +0,0 @@
|
|||||||
local _ENV = mkmodule('plugins.dfusion.friendship')
|
|
||||||
local dfu=require("plugins.dfusion")
|
|
||||||
local ms=require("memscan")
|
|
||||||
|
|
||||||
local MAX_RACES=100
|
|
||||||
local MAX_CODE_DIST=250
|
|
||||||
FriendshipRainbow=defclass(FriendshipRainbow,dfu.BinaryPlugin)
|
|
||||||
FriendshipRainbow.name="FriendshipRainbow"
|
|
||||||
-- os independant... I think...
|
|
||||||
FriendshipRainbow.ATTRS{filename="hack/lua/plugins/dfusion/friendship.o",name="FriendshipRainbow",race_data=DEFAULT_NIL}
|
|
||||||
FriendshipRainbow.class_status="valid, not installed"
|
|
||||||
function FriendshipRainbow:findall_needles(codesg,needle) -- todo move to memscan.lua
|
|
||||||
local cidx,caddr=codesg.uint8_t:find(needle)
|
|
||||||
local ret={}
|
|
||||||
while cidx~=nil do
|
|
||||||
table.insert(ret,{cidx,caddr})
|
|
||||||
cidx,caddr=codesg.uint8_t:find(needle,cidx+1)
|
|
||||||
end
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
function FriendshipRainbow:find_one(codesg,needle,crace)
|
|
||||||
dfu.concatTables(needle,dfu.dwordToTable(crace))
|
|
||||||
return self:findall_needles(codesg,needle)
|
|
||||||
end
|
|
||||||
function FriendshipRainbow:find_all()
|
|
||||||
local code=ms.get_code_segment()
|
|
||||||
local locations={}
|
|
||||||
local _,crace=df.sizeof(df.global.ui:_field("race_id"))
|
|
||||||
|
|
||||||
dfu.concatTables(locations,self:find_one(code,{0x66,0xa1},crace)) --mov ax,[ptr]
|
|
||||||
dfu.concatTables(locations,self:find_one(code,{0xa1},crace)) --mov ax,[ptr]
|
|
||||||
local registers=
|
|
||||||
{0x05, -- (e)ax
|
|
||||||
0x1d, --ebx
|
|
||||||
0x0d, --ecx
|
|
||||||
0x15, --edx
|
|
||||||
0x35, --esi
|
|
||||||
0x3d, --edi
|
|
||||||
--0x25, --esp not used?
|
|
||||||
--0x2d, --ebp not used?
|
|
||||||
}
|
|
||||||
for k,reg in ipairs(registers) do
|
|
||||||
|
|
||||||
dfu.concatTables(locations,self:find_one(code,{0x0f,0xbf,reg},crace)) --movsx reg,[ptr]
|
|
||||||
dfu.concatTables(locations,self:find_one(code,{0x66,0x8b,reg},crace)) --mov reg,[ptr]
|
|
||||||
end
|
|
||||||
|
|
||||||
return self:filter_locations(code,locations)
|
|
||||||
end
|
|
||||||
function FriendshipRainbow:filter_locations(codesg,locations)
|
|
||||||
local ret={}
|
|
||||||
local registers={0x80,0x83,0x81,0x82,0x86,0x87,
|
|
||||||
0x98,0x9b,0x99,0x9a,0x9e,0x9f,
|
|
||||||
0x88,0x8b,0x89,0x8a,0x8e,0x8f,
|
|
||||||
0x90,0x93,0x91,0x92,0x96,0x97,
|
|
||||||
0xb0,0xb3,0xb1,0xb2,0xb6,0xb7,
|
|
||||||
0xb8,0xbb,0xb9,0xba,0xbe,0xbf}
|
|
||||||
for _,entry in ipairs(locations) do
|
|
||||||
for _,r in ipairs(registers) do
|
|
||||||
|
|
||||||
local idx,addr=codesg.uint8_t:find({0x39,r,0x8c,0x00,0x00,0x00},
|
|
||||||
codesg.uint8_t:addr2idx(entry[2]),codesg.uint8_t:addr2idx(entry[2])+MAX_CODE_DIST)
|
|
||||||
if addr then
|
|
||||||
table.insert(ret,{addr,r})
|
|
||||||
break
|
|
||||||
end
|
|
||||||
idx,addr=codesg.uint8_t:find({0x3b,r,0x8c,0x00,0x00,0x00},
|
|
||||||
codesg.uint8_t:addr2idx(entry[2]),codesg.uint8_t:addr2idx(entry[2])+MAX_CODE_DIST)
|
|
||||||
if addr then
|
|
||||||
table.insert(ret,{addr,r})
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
function FriendshipRainbow:patchCalls(target)
|
|
||||||
local addrs=self:find_all()
|
|
||||||
local swaps={}
|
|
||||||
for k,adr in ipairs(addrs) do
|
|
||||||
local newval=dfu.makeCall(adr[1],target)
|
|
||||||
table.insert(newval,adr[2])
|
|
||||||
for t,val in ipairs(newval) do
|
|
||||||
swaps[adr[1]+t-1]=val
|
|
||||||
end
|
|
||||||
end
|
|
||||||
dfhack.internal.patchBytes(swaps)
|
|
||||||
end
|
|
||||||
function FriendshipRainbow:set_races(arr)
|
|
||||||
local n_to_id=require("plugins.dfusion.tools").build_race_names()
|
|
||||||
local ids={}
|
|
||||||
for k,v in ipairs(self.race_data) do -- to check if all races are valid.
|
|
||||||
ids[k]=n_to_id[v]
|
|
||||||
end
|
|
||||||
for k,v in ipairs(ids) do
|
|
||||||
arr[k-1]=ids[k]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function FriendshipRainbow:install(races)
|
|
||||||
self.race_data=races or self.race_data
|
|
||||||
if #self.race_data<1 then
|
|
||||||
error("race count must be bigger than 0")
|
|
||||||
end
|
|
||||||
if #self.race_data>MAX_RACES then
|
|
||||||
error("race count must be less then "..MAX_RACES)
|
|
||||||
end
|
|
||||||
local rarr=self:allocate("race_array",'uint16_t',MAX_RACES)
|
|
||||||
local _,rarr_offset=df.sizeof(rarr)
|
|
||||||
self:set_marker_dword("racepointer",rarr_offset)
|
|
||||||
self:set_races(rarr)
|
|
||||||
self:set_marker_dword("racecount",#self.race_data)
|
|
||||||
local safe_loc=self:allocate("safe_loc",'uint32_t',1)
|
|
||||||
local _1,safe_loc_offset=df.sizeof(safe_loc)
|
|
||||||
self:set_marker_dword("safeloc1",safe_loc_offset)
|
|
||||||
self:set_marker_dword("safeloc2",safe_loc_offset)
|
|
||||||
local addr=self:move_to_df()
|
|
||||||
self:patchCalls(addr)
|
|
||||||
self.installed=true
|
|
||||||
end
|
|
||||||
Friendship=Friendship or FriendshipRainbow()
|
|
||||||
return _ENV
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
as -anl --32 -o friendship.o friendship.asm
|
|
@ -1,7 +0,0 @@
|
|||||||
.intel_syntax
|
|
||||||
mov eax , [esp+0x1C] # loop counter
|
|
||||||
mark_caste:
|
|
||||||
movsx ecx, word ptr[eax*2+0xdeadbeef]
|
|
||||||
mark_race:
|
|
||||||
movzx eax,word ptr [eax*2+0xDEADBEEF]
|
|
||||||
ret
|
|
@ -1,106 +0,0 @@
|
|||||||
.intel_syntax
|
|
||||||
push eax
|
|
||||||
mov eax,[esp+0x04]
|
|
||||||
push ebx
|
|
||||||
pushfd
|
|
||||||
mov eax,[eax] # get a byte after the call this procedure to analyze what register holds cr ptr
|
|
||||||
jmptbl:
|
|
||||||
cmp al,0x81
|
|
||||||
jz regC
|
|
||||||
cmp al,0x82
|
|
||||||
jz regD
|
|
||||||
cmp al,0x83
|
|
||||||
jz regB
|
|
||||||
cmp al,0x85
|
|
||||||
jz regBP
|
|
||||||
cmp al,0x86
|
|
||||||
jz regESI
|
|
||||||
cmp al,0x87
|
|
||||||
jz regEDI
|
|
||||||
cmp al,0x88
|
|
||||||
jz regA
|
|
||||||
cmp al,0x8A
|
|
||||||
jz regD
|
|
||||||
cmp al,0x8B
|
|
||||||
jz regB
|
|
||||||
cmp al,0x8D
|
|
||||||
jz regBP
|
|
||||||
cmp al,0x8E
|
|
||||||
jz regESI
|
|
||||||
cmp al,0x8F
|
|
||||||
jz regEDI
|
|
||||||
cmp al,0x90
|
|
||||||
jz regA
|
|
||||||
cmp al,0x91
|
|
||||||
jz regC
|
|
||||||
cmp al,0x93
|
|
||||||
jz regB
|
|
||||||
cmp al,0x95
|
|
||||||
jz regBP
|
|
||||||
cmp al,0x96
|
|
||||||
jz regESI
|
|
||||||
cmp al,0x97
|
|
||||||
jz regEDI
|
|
||||||
jmp fail
|
|
||||||
regA:
|
|
||||||
mov eax, [esp+0x8]
|
|
||||||
mov eax, [eax+0x8c]
|
|
||||||
jmp compare
|
|
||||||
regC:
|
|
||||||
mov eax, [ecx+0x8c]
|
|
||||||
jmp compare
|
|
||||||
regB:
|
|
||||||
mov eax, [ebx+0x8c]
|
|
||||||
jmp compare
|
|
||||||
regD:
|
|
||||||
mov eax, [edx+0x8c]
|
|
||||||
jmp compare
|
|
||||||
regBP:
|
|
||||||
mov eax, [ebp+0x8c]
|
|
||||||
jmp compare
|
|
||||||
regESI:
|
|
||||||
mov eax, [esi+0x8c]
|
|
||||||
jmp compare
|
|
||||||
regEDI:
|
|
||||||
mov eax, [edi+0x8c]
|
|
||||||
#jmp compare
|
|
||||||
compare:
|
|
||||||
push ecx
|
|
||||||
mark_racepointer:
|
|
||||||
mov ebx,0xDEADBEEF #write a pointer to the list of allowed races
|
|
||||||
mark_racecount:
|
|
||||||
mov ecx,0xDEADBEEF #write a number of allowed races
|
|
||||||
loop1:
|
|
||||||
cmp word[ebx+ecx*2],ax
|
|
||||||
jz endok
|
|
||||||
dec ecx
|
|
||||||
cmp ecx ,-1
|
|
||||||
jnz loop1
|
|
||||||
pop ecx
|
|
||||||
popfd
|
|
||||||
jmp fail
|
|
||||||
endok:
|
|
||||||
pop ecx
|
|
||||||
popfd
|
|
||||||
cmp eax,eax
|
|
||||||
jmp endfinal
|
|
||||||
fail:
|
|
||||||
|
|
||||||
xor ebx,ebx
|
|
||||||
xor eax,eax
|
|
||||||
inc eax
|
|
||||||
cmp eax,ebx
|
|
||||||
endfinal:
|
|
||||||
|
|
||||||
pop ebx
|
|
||||||
pop eax
|
|
||||||
mark_safeloc1:
|
|
||||||
mov [0xDEADBEEF],eax #write a pointer to safe location (usually after this)
|
|
||||||
pop eax
|
|
||||||
pushfd
|
|
||||||
inc eax #skip one instruction
|
|
||||||
popfd
|
|
||||||
push eax
|
|
||||||
mark_safeloc2:
|
|
||||||
mov eax,[0xDEADBEEF] #write a pointer to safe location (same as above)
|
|
||||||
ret
|
|
@ -1,243 +0,0 @@
|
|||||||
local _ENV = mkmodule('plugins.dfusion.tools')
|
|
||||||
local dfu=require("plugins.dfusion")
|
|
||||||
local ms=require "memscan"
|
|
||||||
menu=dfu.SimpleMenu()
|
|
||||||
RaceNames={}
|
|
||||||
function build_race_names()
|
|
||||||
if #RaceNames~=0 then
|
|
||||||
return RaceNames
|
|
||||||
else
|
|
||||||
for k,v in pairs(df.global.world.raws.creatures.all) do
|
|
||||||
RaceNames[v.creature_id]=k
|
|
||||||
end
|
|
||||||
dfhack.onStateChange.invalidate_races=function(change_id) --todo does this work?
|
|
||||||
if change_id==SC_WORLD_UNLOADED then
|
|
||||||
dfhack.onStateChange.invalidate_races=nil
|
|
||||||
RaceNames={}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return RaceNames
|
|
||||||
end
|
|
||||||
end
|
|
||||||
function setrace(name)
|
|
||||||
local RaceTable=build_race_names()
|
|
||||||
print("Your current race is:"..df.global.world.raws.creatures.all[df.global.ui.race_id].creature_id)
|
|
||||||
local id
|
|
||||||
if name == nil then
|
|
||||||
print("Type new race's token name in full caps (q to quit):")
|
|
||||||
repeat
|
|
||||||
local entry=dfhack.lineedit()
|
|
||||||
if entry=="q" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
id=RaceTable[entry]
|
|
||||||
until id~=nil
|
|
||||||
else
|
|
||||||
id=RaceTable[name]
|
|
||||||
if id==nil then
|
|
||||||
error("Name not found!")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
df.global.ui.race_id=id
|
|
||||||
end
|
|
||||||
menu:add("Set current race",setrace)
|
|
||||||
function GiveSentience(names)
|
|
||||||
local RaceTable=build_race_names() --slow.If loaded don't load again
|
|
||||||
local id,ids
|
|
||||||
if names ==nil then
|
|
||||||
ids={}
|
|
||||||
print("Type race's token name in full caps to give sentience to:")
|
|
||||||
repeat
|
|
||||||
id=dfhack.lineedit()
|
|
||||||
id=RaceTable[entry]
|
|
||||||
if id~=nil then
|
|
||||||
table.insert(ids,id)
|
|
||||||
end
|
|
||||||
until id==nil
|
|
||||||
|
|
||||||
else
|
|
||||||
ids={}
|
|
||||||
for _,name in pairs(names) do
|
|
||||||
id=RaceTable[name]
|
|
||||||
table.insert(ids,id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for _,id in pairs(ids) do
|
|
||||||
local races=df.global.world.raws.creatures.all
|
|
||||||
|
|
||||||
local castes=races[id].caste
|
|
||||||
print(string.format("Caste count:%i",#castes))
|
|
||||||
for i =0,#castes-1 do
|
|
||||||
|
|
||||||
print("Caste name:"..castes[i].caste_id.."...")
|
|
||||||
|
|
||||||
local flags=castes[i].flags
|
|
||||||
--print(string.format("%x",flagoffset))
|
|
||||||
if flags.CAN_SPEAK then
|
|
||||||
print("\tis sentient.")
|
|
||||||
else
|
|
||||||
print("\tnon sentient. Allocating IQ...")
|
|
||||||
flags.CAN_SPEAK=true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
menu:add("Give Sentience",GiveSentience)
|
|
||||||
function MakeFollow(unit,trgunit)
|
|
||||||
if unit == nil then
|
|
||||||
unit=dfhack.gui.getSelectedUnit()
|
|
||||||
end
|
|
||||||
if unit== nil then
|
|
||||||
error("Invalid creature")
|
|
||||||
end
|
|
||||||
if trgunit==nil then
|
|
||||||
trgunit=df.global.world.units.active[0]
|
|
||||||
end
|
|
||||||
unit.relations.group_leader_id=trgunit.id
|
|
||||||
local u_nem=dfhack.units.getNemesis(unit)
|
|
||||||
local t_nem=dfhack.units.getNemesis(trgunit)
|
|
||||||
if u_nem then
|
|
||||||
u_nem.group_leader_id=t_nem.id
|
|
||||||
end
|
|
||||||
if t_nem and u_nem then
|
|
||||||
t_nem.companions:insert(#t_nem.companions,u_nem.id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
menu:add("Make creature follow",MakeFollow)
|
|
||||||
function project(unit,trg) --TODO add to menu?
|
|
||||||
if unit==nil then
|
|
||||||
unit=getCreatureAtPointer()
|
|
||||||
end
|
|
||||||
|
|
||||||
if unit==nil then
|
|
||||||
error("Failed to project unit. Unit not selected/valid")
|
|
||||||
end
|
|
||||||
-- todo: add projectile to world, point to unit, add flag to unit, add gen-ref to projectile.
|
|
||||||
local p=df.proj_unitst:new()
|
|
||||||
local startpos={x=unit.pos.x,y=unit.pos.y,z=unit.pos.z}
|
|
||||||
p.origin_pos=startpos
|
|
||||||
p.target_pos=trg
|
|
||||||
p.cur_pos=startpos
|
|
||||||
p.prev_pos=startpos
|
|
||||||
p.unit=unit
|
|
||||||
--- wtf stuff
|
|
||||||
p.unk14=100
|
|
||||||
p.unk16=-1
|
|
||||||
p.unk23=-1
|
|
||||||
p.fall_delay=5
|
|
||||||
p.fall_counter=5
|
|
||||||
p.collided=true
|
|
||||||
-- end wtf
|
|
||||||
local citem=df.global.world.proj_list
|
|
||||||
local maxid=1
|
|
||||||
local newlink=df.proj_list_link:new()
|
|
||||||
newlink.item=p
|
|
||||||
while citem.item~= nil do
|
|
||||||
if citem.item.id>maxid then maxid=citem.item.id end
|
|
||||||
if citem.next ~= nil then
|
|
||||||
citem=citem.next
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
p.id=maxid+1
|
|
||||||
newlink.prev=citem
|
|
||||||
citem.next=newlink
|
|
||||||
local proj_ref=df.general_ref_projectile:new()
|
|
||||||
proj_ref.projectile_id=p.id
|
|
||||||
unit.general_refs:insert(#unit.general_refs,proj_ref)
|
|
||||||
unit.flags1.projectile=true
|
|
||||||
end
|
|
||||||
function empregnate(unit)
|
|
||||||
if unit==nil then
|
|
||||||
unit=dfhack.gui.getSelectedUnit()
|
|
||||||
end
|
|
||||||
if unit==nil then
|
|
||||||
error("Failed to empregnate. Unit not selected/valid")
|
|
||||||
end
|
|
||||||
if unit.curse then
|
|
||||||
unit.curse.add_tags2.STERILE=false
|
|
||||||
end
|
|
||||||
local genes = unit.appearance.genes
|
|
||||||
if unit.relations.pregnancy_genes == nil then
|
|
||||||
print("creating preg ptr.")
|
|
||||||
if false then
|
|
||||||
print(string.format("%x %x",df.sizeof(unit.relations:_field("pregnancy_genes"))))
|
|
||||||
return
|
|
||||||
end
|
|
||||||
unit.relations.pregnancy_genes = { new = true, assign = genes }
|
|
||||||
end
|
|
||||||
local ngenes = unit.relations.pregnancy_genes
|
|
||||||
if #ngenes.appearance ~= #genes.appearance or #ngenes.colors ~= #genes.colors then
|
|
||||||
print("Array sizes incorrect, fixing.")
|
|
||||||
ngenes:assign(genes);
|
|
||||||
end
|
|
||||||
print("Setting preg timer.")
|
|
||||||
unit.relations.pregnancy_timer=10
|
|
||||||
unit.relations.pregnancy_caste=1
|
|
||||||
end
|
|
||||||
menu:add("Empregnate",empregnate)
|
|
||||||
function healunit(unit)
|
|
||||||
if unit==nil then
|
|
||||||
unit=dfhack.gui.getSelectedUnit()
|
|
||||||
end
|
|
||||||
|
|
||||||
if unit==nil then
|
|
||||||
error("Failed to Heal unit. Unit not selected/valid")
|
|
||||||
end
|
|
||||||
|
|
||||||
unit.body.wounds:resize(0) -- memory leak here :/
|
|
||||||
unit.body.blood_count=unit.body.blood_max
|
|
||||||
--set flags for standing and grasping...
|
|
||||||
unit.status2.limbs_stand_max=4
|
|
||||||
unit.status2.limbs_stand_count=4
|
|
||||||
unit.status2.limbs_grasp_max=4
|
|
||||||
unit.status2.limbs_grasp_count=4
|
|
||||||
--should also set temperatures, and flags for breath etc...
|
|
||||||
unit.flags1.dead=false
|
|
||||||
unit.flags2.calculated_bodyparts=false
|
|
||||||
unit.flags2.calculated_nerves=false
|
|
||||||
unit.flags2.circulatory_spray=false
|
|
||||||
unit.flags2.vision_good=true
|
|
||||||
unit.flags2.vision_damaged=false
|
|
||||||
unit.flags2.vision_missing=false
|
|
||||||
unit.counters.winded=0
|
|
||||||
unit.counters.unconscious=0
|
|
||||||
for k,v in pairs(unit.body.components) do
|
|
||||||
for kk,vv in pairs(v) do
|
|
||||||
if k == 'body_part_status' then v[kk].whole = 0 else v[kk] = 0 end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
menu:add("Heal unit",healunit)
|
|
||||||
function powerup(unit,labor_rating,military_rating,skills)
|
|
||||||
if unit==nil then
|
|
||||||
unit=dfhack.gui.getSelectedUnit()
|
|
||||||
end
|
|
||||||
if unit==nil then
|
|
||||||
error("Failed to power up unit. Unit not selected/valid")
|
|
||||||
end
|
|
||||||
|
|
||||||
if unit.status.current_soul== nil then
|
|
||||||
error("Failed to power up unit. Unit has no soul")
|
|
||||||
end
|
|
||||||
local utils = require 'utils'
|
|
||||||
labor_rating = labor_rating or 15
|
|
||||||
military_rating = military_rating or 70
|
|
||||||
|
|
||||||
skill =skill or { 0,2,3,4,5,6,7,8,9,10,11,12,13,14,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,41,42,43,44,45,46,47,48,49,54,55,57,58,59,60,61,62,63,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,95,96,97,98,99,100,101,102,103,104,105,109,110,111,112,113,114,115 }
|
|
||||||
local military = { 38,39,41,42,43,44,45,46,54,99,100,101,102,103,104,105 }
|
|
||||||
|
|
||||||
for sk,sv in ipairs(skill) do
|
|
||||||
local new_rating = labor_rating
|
|
||||||
for _,v in ipairs(military) do
|
|
||||||
if v == sv then
|
|
||||||
local new_rating = military_rating
|
|
||||||
end
|
|
||||||
end
|
|
||||||
utils.insert_or_update(unit.status.current_soul.skills, { new = true, id = sv, rating = new_rating, experience = (new_rating * 500) + (new_rating * (new_rating - 1)) * 50}, 'id')
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
menu:add("Power up",powerup)
|
|
||||||
return _ENV
|
|
@ -1 +0,0 @@
|
|||||||
proto/*.pb.*
|
|
@ -1,43 +0,0 @@
|
|||||||
PROJECT(mapexport)
|
|
||||||
|
|
||||||
# add *our* headers here.
|
|
||||||
SET(PROJECT_HDRS
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(PROJECT_SRCS
|
|
||||||
mapexport.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
SET(PROJECT_PROTOS
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/proto/Tile.proto
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/proto/Plant.proto
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/proto/Block.proto
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/proto/Material.proto
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/proto/Map.proto
|
|
||||||
)
|
|
||||||
|
|
||||||
#Create new lists of what sources and headers protoc will output after we invoke it
|
|
||||||
STRING(REPLACE ".proto" ".pb.cc;" PROJECT_PROTO_SRCS ${PROJECT_PROTOS})
|
|
||||||
STRING(REPLACE ".proto" ".pb.h;" PROJECT_PROTO_HDRS ${PROJECT_PROTOS})
|
|
||||||
|
|
||||||
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_PROTO_HDRS} PROPERTIES GENERATED TRUE)
|
|
||||||
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_PROTO_SRCS} PROPERTIES GENERATED TRUE)
|
|
||||||
|
|
||||||
LIST(APPEND PROJECT_HDRS ${PROJECT_PROTO_HDRS})
|
|
||||||
LIST(APPEND PROJECT_SRCS ${PROJECT_PROTO_SRCS})
|
|
||||||
|
|
||||||
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE)
|
|
||||||
LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS})
|
|
||||||
|
|
||||||
#Generate sources from our proto files and store them in the source tree
|
|
||||||
ADD_CUSTOM_COMMAND(
|
|
||||||
OUTPUT ${PROJECT_PROTO_SRCS} ${PROJECT_PROTO_HDRS}
|
|
||||||
COMMAND protoc-bin -I=${CMAKE_CURRENT_SOURCE_DIR}/proto/ --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/proto/ ${PROJECT_PROTOS}
|
|
||||||
DEPENDS protoc-bin ${PROJECT_PROTOS}
|
|
||||||
)
|
|
||||||
|
|
||||||
IF(WIN32)
|
|
||||||
DFHACK_PLUGIN(mapexport ${PROJECT_SRCS} ${PROJECT_HDRS} LINK_LIBRARIES protobuf-lite)
|
|
||||||
ELSE()
|
|
||||||
DFHACK_PLUGIN(mapexport ${PROJECT_SRCS} ${PROJECT_HDRS} LINK_LIBRARIES protobuf-lite)
|
|
||||||
ENDIF()
|
|
@ -1,325 +0,0 @@
|
|||||||
#include "Core.h"
|
|
||||||
#include "Console.h"
|
|
||||||
#include "Export.h"
|
|
||||||
#include "PluginManager.h"
|
|
||||||
#include "modules/MapCache.h"
|
|
||||||
using namespace DFHack;
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <google/protobuf/io/coded_stream.h>
|
|
||||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
|
||||||
#include <google/protobuf/io/gzip_stream.h>
|
|
||||||
using namespace google::protobuf::io;
|
|
||||||
|
|
||||||
#include "DataDefs.h"
|
|
||||||
#include "df/world.h"
|
|
||||||
#include "df/plant.h"
|
|
||||||
#include "modules/Constructions.h"
|
|
||||||
|
|
||||||
#include "proto/Map.pb.h"
|
|
||||||
#include "proto/Block.pb.h"
|
|
||||||
|
|
||||||
using namespace DFHack;
|
|
||||||
using df::global::world;
|
|
||||||
/*
|
|
||||||
mapexport
|
|
||||||
=========
|
|
||||||
Export the current loaded map as a file. This was used by visualizers for
|
|
||||||
DF 0.34.11, but is now basically obsolete.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef std::vector<df::plant *> PlantList;
|
|
||||||
|
|
||||||
command_result mapexport (color_ostream &out, std::vector <std::string> & parameters);
|
|
||||||
|
|
||||||
DFHACK_PLUGIN("mapexport");
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
|
|
||||||
{
|
|
||||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
|
||||||
commands.push_back(PluginCommand("mapexport", "Exports the current map to a file.", mapexport, true));
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
|
|
||||||
{
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static dfproto::Tile::TileMaterialType toProto(df::tiletype_material mat)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* This is surely ugly, but casting enums without officially
|
|
||||||
* defined numerical values to protobuf enums is against the
|
|
||||||
* way protobufs are supposed to be used, because it defeats
|
|
||||||
* the backward compatible nature of the protocols.
|
|
||||||
*/
|
|
||||||
switch (mat)
|
|
||||||
{
|
|
||||||
#define CONVERT(name) case tiletype_material::name: return dfproto::Tile::name;
|
|
||||||
case tiletype_material::NONE:
|
|
||||||
CONVERT(AIR)
|
|
||||||
case tiletype_material::PLANT:
|
|
||||||
CONVERT(SOIL)
|
|
||||||
CONVERT(STONE)
|
|
||||||
CONVERT(FEATURE)
|
|
||||||
CONVERT(LAVA_STONE)
|
|
||||||
CONVERT(MINERAL)
|
|
||||||
CONVERT(FROZEN_LIQUID)
|
|
||||||
CONVERT(CONSTRUCTION)
|
|
||||||
CONVERT(GRASS_LIGHT)
|
|
||||||
CONVERT(GRASS_DARK)
|
|
||||||
CONVERT(GRASS_DRY)
|
|
||||||
CONVERT(GRASS_DEAD)
|
|
||||||
CONVERT(HFS)
|
|
||||||
CONVERT(CAMPFIRE)
|
|
||||||
CONVERT(FIRE)
|
|
||||||
CONVERT(ASHES)
|
|
||||||
case tiletype_material::MAGMA:
|
|
||||||
return dfproto::Tile::MAGMA_TYPE;
|
|
||||||
CONVERT(DRIFTWOOD)
|
|
||||||
CONVERT(POOL)
|
|
||||||
CONVERT(BROOK)
|
|
||||||
CONVERT(RIVER)
|
|
||||||
#undef CONVERT
|
|
||||||
}
|
|
||||||
return dfproto::Tile::AIR;
|
|
||||||
}
|
|
||||||
|
|
||||||
command_result mapexport (color_ostream &out, std::vector <std::string> & parameters)
|
|
||||||
{
|
|
||||||
bool showHidden = false;
|
|
||||||
|
|
||||||
int filenameParameter = 1;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < parameters.size();i++)
|
|
||||||
{
|
|
||||||
if(parameters[i] == "help" || parameters[i] == "?")
|
|
||||||
{
|
|
||||||
out.print("Exports the currently visible map to a file.\n"
|
|
||||||
"Usage: mapexport [options] <filename>\n"
|
|
||||||
"Example: mapexport all embark.dfmap\n"
|
|
||||||
"Options:\n"
|
|
||||||
" all - Export the entire map, not just what's revealed.\n"
|
|
||||||
);
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
if (parameters[i] == "all")
|
|
||||||
{
|
|
||||||
showHidden = true;
|
|
||||||
filenameParameter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CoreSuspender suspend;
|
|
||||||
|
|
||||||
uint32_t x_max=0, y_max=0, z_max=0;
|
|
||||||
|
|
||||||
if (!Maps::IsValid())
|
|
||||||
{
|
|
||||||
out.printerr("Map is not available!\n");
|
|
||||||
return CR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parameters.size() < filenameParameter)
|
|
||||||
{
|
|
||||||
out.printerr("Please supply a filename.\n");
|
|
||||||
return CR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string filename = parameters[filenameParameter-1];
|
|
||||||
if (filename.rfind(".dfmap") == std::string::npos) filename += ".dfmap";
|
|
||||||
out << "Writing to " << filename << "..." << std::endl;
|
|
||||||
|
|
||||||
std::ofstream output_file(filename.c_str(), std::ios::out | std::ios::trunc | std::ios::binary);
|
|
||||||
if (!output_file.is_open())
|
|
||||||
{
|
|
||||||
out.printerr("Couldn't open the output file.\n");
|
|
||||||
return CR_FAILURE;
|
|
||||||
}
|
|
||||||
ZeroCopyOutputStream *raw_output = new OstreamOutputStream(&output_file);
|
|
||||||
GzipOutputStream *zip_output = new GzipOutputStream(raw_output);
|
|
||||||
CodedOutputStream *coded_output = new CodedOutputStream(zip_output);
|
|
||||||
|
|
||||||
coded_output->WriteLittleEndian32(0x50414DDF); //Write our file header
|
|
||||||
|
|
||||||
Maps::getSize(x_max, y_max, z_max);
|
|
||||||
MapExtras::MapCache map;
|
|
||||||
DFHack::Materials *mats = Core::getInstance().getMaterials();
|
|
||||||
|
|
||||||
out << "Writing map info..." << std::endl;
|
|
||||||
|
|
||||||
dfproto::Map protomap;
|
|
||||||
protomap.set_x_size(x_max);
|
|
||||||
protomap.set_y_size(y_max);
|
|
||||||
protomap.set_z_size(z_max);
|
|
||||||
|
|
||||||
out << "Writing material dictionary..." << std::endl;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < world->raws.inorganics.size(); i++)
|
|
||||||
{
|
|
||||||
dfproto::Material *protomaterial = protomap.add_inorganic_material();
|
|
||||||
protomaterial->set_index(i);
|
|
||||||
protomaterial->set_name(world->raws.inorganics[i]->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < world->raws.plants.all.size(); i++)
|
|
||||||
{
|
|
||||||
dfproto::Material *protomaterial = protomap.add_organic_material();
|
|
||||||
protomaterial->set_index(i);
|
|
||||||
protomaterial->set_name(world->raws.plants.all[i]->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<df::coord,std::pair<uint32_t,uint16_t> > constructionMaterials;
|
|
||||||
if (Constructions::isValid())
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < Constructions::getCount(); i++)
|
|
||||||
{
|
|
||||||
df::construction *construction = Constructions::getConstruction(i);
|
|
||||||
constructionMaterials[construction->pos] = std::make_pair(construction->mat_index, construction->mat_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
coded_output->WriteVarint32(protomap.ByteSize());
|
|
||||||
protomap.SerializeToCodedStream(coded_output);
|
|
||||||
|
|
||||||
DFHack::t_feature blockFeatureGlobal;
|
|
||||||
DFHack::t_feature blockFeatureLocal;
|
|
||||||
|
|
||||||
out.print("Writing map block information");
|
|
||||||
|
|
||||||
for(uint32_t z = 0; z < z_max; z++)
|
|
||||||
{
|
|
||||||
for(uint32_t b_y = 0; b_y < y_max; b_y++)
|
|
||||||
{
|
|
||||||
for(uint32_t b_x = 0; b_x < x_max; b_x++)
|
|
||||||
{
|
|
||||||
if (b_x == 0 && b_y == 0 && z % 10 == 0) out.print(".");
|
|
||||||
// Get the map block
|
|
||||||
df::coord2d blockCoord(b_x, b_y);
|
|
||||||
MapExtras::Block *b = map.BlockAt(DFHack::DFCoord(b_x, b_y, z));
|
|
||||||
if (!b || !b->is_valid())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
dfproto::Block protoblock;
|
|
||||||
protoblock.set_x(b_x);
|
|
||||||
protoblock.set_y(b_y);
|
|
||||||
protoblock.set_z(z);
|
|
||||||
|
|
||||||
// Find features
|
|
||||||
b->GetGlobalFeature(&blockFeatureGlobal);
|
|
||||||
b->GetLocalFeature(&blockFeatureLocal);
|
|
||||||
|
|
||||||
int global_z = df::global::world->map.region_z + z;
|
|
||||||
|
|
||||||
// Iterate over all the tiles in the block
|
|
||||||
for(uint32_t y = 0; y < 16; y++)
|
|
||||||
{
|
|
||||||
for(uint32_t x = 0; x < 16; x++)
|
|
||||||
{
|
|
||||||
df::coord2d coord(x, y);
|
|
||||||
df::tile_designation des = b->DesignationAt(coord);
|
|
||||||
df::tile_occupancy occ = b->OccupancyAt(coord);
|
|
||||||
|
|
||||||
// Skip hidden tiles
|
|
||||||
if (!showHidden && des.bits.hidden)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
dfproto::Tile *prototile = protoblock.add_tile();
|
|
||||||
prototile->set_x(x);
|
|
||||||
prototile->set_y(y);
|
|
||||||
|
|
||||||
// Check for liquid
|
|
||||||
if (des.bits.flow_size)
|
|
||||||
{
|
|
||||||
prototile->set_liquid_type((dfproto::Tile::LiquidType)des.bits.liquid_type);
|
|
||||||
prototile->set_flow_size(des.bits.flow_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
df::tiletype type = b->tiletypeAt(coord);
|
|
||||||
prototile->set_type((dfproto::Tile::TileType)tileShape(type));
|
|
||||||
prototile->set_tile_material(toProto(tileMaterial(type)));
|
|
||||||
|
|
||||||
df::coord map_pos = df::coord(b_x*16+x,b_y*16+y,z);
|
|
||||||
|
|
||||||
switch (tileMaterial(type))
|
|
||||||
{
|
|
||||||
case tiletype_material::SOIL:
|
|
||||||
case tiletype_material::STONE:
|
|
||||||
prototile->set_material_type(0);
|
|
||||||
prototile->set_material_index(b->layerMaterialAt(coord));
|
|
||||||
break;
|
|
||||||
case tiletype_material::MINERAL:
|
|
||||||
prototile->set_material_type(0);
|
|
||||||
prototile->set_material_index(b->veinMaterialAt(coord));
|
|
||||||
break;
|
|
||||||
case tiletype_material::FEATURE:
|
|
||||||
if (blockFeatureLocal.type != -1 && des.bits.feature_local)
|
|
||||||
{
|
|
||||||
if (blockFeatureLocal.type == feature_type::deep_special_tube
|
|
||||||
&& blockFeatureLocal.main_material == 0) // stone
|
|
||||||
{
|
|
||||||
prototile->set_material_type(0);
|
|
||||||
prototile->set_material_index(blockFeatureLocal.sub_material);
|
|
||||||
}
|
|
||||||
if (blockFeatureGlobal.type != -1 && des.bits.feature_global
|
|
||||||
&& blockFeatureGlobal.type == feature_type::feature_underworld_from_layer
|
|
||||||
&& blockFeatureGlobal.main_material == 0) // stone
|
|
||||||
{
|
|
||||||
prototile->set_material_type(0);
|
|
||||||
prototile->set_material_index(blockFeatureGlobal.sub_material);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case tiletype_material::CONSTRUCTION:
|
|
||||||
if (constructionMaterials.find(map_pos) != constructionMaterials.end())
|
|
||||||
{
|
|
||||||
prototile->set_material_index(constructionMaterials[map_pos].first);
|
|
||||||
prototile->set_material_type(constructionMaterials[map_pos].second);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b->getRaw())
|
|
||||||
{
|
|
||||||
PlantList *plants = &b->getRaw()->plants;
|
|
||||||
for (PlantList::const_iterator it = plants->begin(); it != plants->end(); it++)
|
|
||||||
{
|
|
||||||
const df::plant & plant = *(*it);
|
|
||||||
df::coord2d loc(plant.pos.x, plant.pos.y);
|
|
||||||
loc = loc % 16;
|
|
||||||
if (showHidden || !b->DesignationAt(loc).bits.hidden)
|
|
||||||
{
|
|
||||||
dfproto::Plant *protoplant = protoblock.add_plant();
|
|
||||||
protoplant->set_x(loc.x);
|
|
||||||
protoplant->set_y(loc.y);
|
|
||||||
protoplant->set_is_shrub(plant.flags.bits.is_shrub);
|
|
||||||
protoplant->set_material(plant.material);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
coded_output->WriteVarint32(protoblock.ByteSize());
|
|
||||||
protoblock.SerializeToCodedStream(coded_output);
|
|
||||||
} // block x
|
|
||||||
// Clean uneeded memory
|
|
||||||
map.trash();
|
|
||||||
} // block y
|
|
||||||
} // z
|
|
||||||
|
|
||||||
delete coded_output;
|
|
||||||
delete zip_output;
|
|
||||||
delete raw_output;
|
|
||||||
|
|
||||||
mats->Finish();
|
|
||||||
out.print("\nMap succesfully exported!\n");
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package dfproto;
|
|
||||||
option optimize_for = LITE_RUNTIME;
|
|
||||||
|
|
||||||
import "Tile.proto";
|
|
||||||
import "Plant.proto";
|
|
||||||
|
|
||||||
message Block
|
|
||||||
{
|
|
||||||
required uint32 x = 1;
|
|
||||||
required uint32 y = 2;
|
|
||||||
required uint32 z = 3;
|
|
||||||
repeated Tile tile = 4;
|
|
||||||
repeated Plant plant = 5;
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
package dfproto;
|
|
||||||
option optimize_for = LITE_RUNTIME;
|
|
||||||
|
|
||||||
import "Material.proto";
|
|
||||||
|
|
||||||
message Map
|
|
||||||
{
|
|
||||||
required uint32 x_size = 1;
|
|
||||||
required uint32 y_size = 2;
|
|
||||||
required uint32 z_size = 3;
|
|
||||||
repeated Material inorganic_material = 4;
|
|
||||||
repeated Material organic_material = 5;
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package dfproto;
|
|
||||||
option optimize_for = LITE_RUNTIME;
|
|
||||||
|
|
||||||
message Material
|
|
||||||
{
|
|
||||||
required uint32 index= 1;
|
|
||||||
required string name = 2;
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package dfproto;
|
|
||||||
option optimize_for = LITE_RUNTIME;
|
|
||||||
|
|
||||||
message Plant
|
|
||||||
{
|
|
||||||
required uint32 x = 1;
|
|
||||||
required uint32 y = 2;
|
|
||||||
required bool is_shrub = 3;
|
|
||||||
optional uint32 material = 4;
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
package dfproto;
|
|
||||||
option optimize_for = LITE_RUNTIME;
|
|
||||||
|
|
||||||
message Tile
|
|
||||||
{
|
|
||||||
enum TileType
|
|
||||||
{
|
|
||||||
EMPTY = 0;
|
|
||||||
FLOOR = 1;
|
|
||||||
BOULDER = 2;
|
|
||||||
PEBBLES = 3;
|
|
||||||
WALL = 4;
|
|
||||||
FORTIFICATION = 5;
|
|
||||||
STAIR_UP = 6;
|
|
||||||
STAIR_DOWN = 7;
|
|
||||||
STAIR_UPDOWN = 8;
|
|
||||||
RAMP = 9;
|
|
||||||
RAMP_TOP = 10;
|
|
||||||
BROOK_BED = 11;
|
|
||||||
BROOK_TOP = 12;
|
|
||||||
TREE = 13;
|
|
||||||
SAPLING = 14;
|
|
||||||
SHRUB = 15;
|
|
||||||
ENDLESS_PIT = 16;
|
|
||||||
}
|
|
||||||
enum LiquidType
|
|
||||||
{
|
|
||||||
WATER = 0;
|
|
||||||
MAGMA = 1;
|
|
||||||
}
|
|
||||||
enum TileMaterialType
|
|
||||||
{
|
|
||||||
AIR = 0;
|
|
||||||
SOIL = 1;
|
|
||||||
STONE = 2;
|
|
||||||
FEATURE = 3;
|
|
||||||
LAVA_STONE = 4;
|
|
||||||
MINERAL = 5;
|
|
||||||
FROZEN_LIQUID = 6;
|
|
||||||
CONSTRUCTION = 7;
|
|
||||||
GRASS_LIGHT = 8;
|
|
||||||
GRASS_DARK = 9;
|
|
||||||
GRASS_DRY = 10;
|
|
||||||
GRASS_DEAD = 11;
|
|
||||||
HFS = 12;
|
|
||||||
CAMPFIRE = 13;
|
|
||||||
FIRE = 14;
|
|
||||||
ASHES = 15;
|
|
||||||
MAGMA_TYPE = 16;
|
|
||||||
DRIFTWOOD = 17;
|
|
||||||
POOL = 18;
|
|
||||||
BROOK = 19;
|
|
||||||
RIVER = 20;
|
|
||||||
}
|
|
||||||
required uint32 x = 1;
|
|
||||||
required uint32 y = 2;
|
|
||||||
required TileType type = 3;
|
|
||||||
optional TileMaterialType tile_material = 4;
|
|
||||||
optional uint32 material_index = 5;
|
|
||||||
optional uint32 material_type = 6;
|
|
||||||
optional LiquidType liquid_type = 7;
|
|
||||||
optional uint32 flow_size = 8;
|
|
||||||
}
|
|
@ -0,0 +1,82 @@
|
|||||||
|
-- List, create, or change wild colonies (eg honey bees)
|
||||||
|
-- By PeridexisErrant and Warmist
|
||||||
|
|
||||||
|
local help = [[=begin
|
||||||
|
|
||||||
|
colonies
|
||||||
|
========
|
||||||
|
List vermin colonies, place honey bees, or convert all vermin
|
||||||
|
to honey bees. Usage:
|
||||||
|
|
||||||
|
:colonies: List all vermin colonies on the map.
|
||||||
|
:colonies place: Place a honey bee colony under the cursor.
|
||||||
|
:colonies convert: Convert all existing colonies to honey bees.
|
||||||
|
|
||||||
|
The ``place`` and ``convert`` subcommands by default create or
|
||||||
|
convert to honey bees, as this is the most commonly useful.
|
||||||
|
However both accept an optional flag to use a different vermin
|
||||||
|
type, for example ``colonies place ANT`` creates an ant colony
|
||||||
|
and ``colonies convert TERMITE`` ends your beekeeping industry.
|
||||||
|
|
||||||
|
=end]]
|
||||||
|
|
||||||
|
function findVermin(target_verm)
|
||||||
|
for k,v in pairs(df.global.world.raws.creatures.all) do
|
||||||
|
if v.creature_id == target_verm then
|
||||||
|
return k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
qerror("No vermin found with name: "..target_verm)
|
||||||
|
end
|
||||||
|
|
||||||
|
function list_colonies()
|
||||||
|
for idx, col in pairs(df.global.world.vermin.colonies) do
|
||||||
|
race = df.global.world.raws.creatures.all[col.race].creature_id
|
||||||
|
print(race..' at '..col.pos.x..', '..col.pos.y..', '..col.pos.z)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function convert_vermin_to(target_verm)
|
||||||
|
local vermin_id = findVermin(target_verm)
|
||||||
|
local changed = 0
|
||||||
|
for _, verm in pairs(df.global.world.vermin.colonies) do
|
||||||
|
verm.race = vermin_id
|
||||||
|
verm.caste = -1 -- check for queen bee?
|
||||||
|
verm.amount = 18826
|
||||||
|
verm.visible = true
|
||||||
|
changed = changed + 1
|
||||||
|
end
|
||||||
|
print('Converted '..changed..' colonies to '..target_verm)
|
||||||
|
end
|
||||||
|
|
||||||
|
function place_vermin(target_verm)
|
||||||
|
local pos = copyall(df.global.cursor)
|
||||||
|
if pos.x == -30000 then
|
||||||
|
qerror("Cursor must be pointing somewhere")
|
||||||
|
end
|
||||||
|
local verm = df.vermin:new()
|
||||||
|
verm.race = findVermin(target_verm)
|
||||||
|
verm.flags.is_colony = true
|
||||||
|
verm.caste = -1 -- check for queen bee?
|
||||||
|
verm.amount = 18826
|
||||||
|
verm.visible = true
|
||||||
|
verm.pos:assign(pos)
|
||||||
|
df.global.world.vermin.colonies:insert("#", verm)
|
||||||
|
df.global.world.vermin.all:insert("#", verm)
|
||||||
|
end
|
||||||
|
|
||||||
|
local args = {...}
|
||||||
|
local target_verm = args[2] or "HONEY_BEE"
|
||||||
|
|
||||||
|
if args[1] == 'help' or args[1] == '?' then
|
||||||
|
print(help)
|
||||||
|
elseif args[1] == 'convert' then
|
||||||
|
convert_vermin_to(target_verm)
|
||||||
|
elseif args[1] == 'place' then
|
||||||
|
place_vermin(target_verm)
|
||||||
|
else
|
||||||
|
if #df.global.world.vermin.colonies < 1 then
|
||||||
|
dfhack.printerr('There are no colonies on the map.')
|
||||||
|
end
|
||||||
|
list_colonies()
|
||||||
|
end
|
@ -1,22 +0,0 @@
|
|||||||
-- a collection of misc lua scripts
|
|
||||||
--[[=begin
|
|
||||||
|
|
||||||
dfusion
|
|
||||||
=======
|
|
||||||
Interface to a lecacy script system.
|
|
||||||
|
|
||||||
=end]]
|
|
||||||
|
|
||||||
local dfu=require("plugins.dfusion")
|
|
||||||
local myos=dfhack.getOSType()
|
|
||||||
args={...}
|
|
||||||
mainmenu=dfu.SimpleMenu()
|
|
||||||
function runsave()
|
|
||||||
local path=string.format("data/save/%s/dfhack.lua",df.global.world.cur_savegame.save_dir)
|
|
||||||
print("doing file:"..path)
|
|
||||||
loadfile(path)()
|
|
||||||
end
|
|
||||||
mainmenu:add("Run save script",runsave)
|
|
||||||
mainmenu:add("Adventurer tools",require("plugins.dfusion.adv_tools").menu)
|
|
||||||
mainmenu:add("Misc tools",require("plugins.dfusion.tools").menu)
|
|
||||||
mainmenu:display()
|
|
@ -1,50 +0,0 @@
|
|||||||
-- On map load writes information about the loaded region to gamelog.txt
|
|
||||||
-- By Kurik Amudnil and Warmist (http://www.bay12forums.com/smf/index.php?topic=91166.msg4467072#msg4467072)
|
|
||||||
--[[=begin
|
|
||||||
|
|
||||||
log-region
|
|
||||||
==========
|
|
||||||
When enabled in :file:`dfhack.init`, each time a fort is loaded identifying information
|
|
||||||
will be written to the gamelog. Assists in parsing the file if you switch
|
|
||||||
between forts, and adds information for story-building.
|
|
||||||
|
|
||||||
=end]]
|
|
||||||
|
|
||||||
local function write_gamelog(msg)
|
|
||||||
local log = io.open('gamelog.txt', 'a')
|
|
||||||
log:write(msg.."\n")
|
|
||||||
log:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function fullname(item)
|
|
||||||
return dfhack.TranslateName(item.name)..' ('..dfhack.TranslateName(item.name ,true)..')'
|
|
||||||
end
|
|
||||||
|
|
||||||
local args = {...}
|
|
||||||
if args[1] == 'disable' then
|
|
||||||
dfhack.onStateChange[_ENV] = nil
|
|
||||||
else
|
|
||||||
dfhack.onStateChange[_ENV] = function(op)
|
|
||||||
if op == SC_WORLD_LOADED then
|
|
||||||
if df.world_site.find(df.global.ui.site_id) ~= nil then -- added this check, now only attempts write in fort mode
|
|
||||||
local site = df.world_site.find(df.global.ui.site_id)
|
|
||||||
local fort_ent = df.global.ui.main.fortress_entity
|
|
||||||
local civ_ent = df.historical_entity.find(df.global.ui.civ_id)
|
|
||||||
local world = df.global.world
|
|
||||||
-- site positions
|
|
||||||
-- site .pos.x .pos.y
|
|
||||||
-- site .rgn_min_x .rgn_min_y .rgn_max_x .rgn_max.y
|
|
||||||
-- site .global_min_x .global_min_y .global_max_x .global_max_y
|
|
||||||
--site.name
|
|
||||||
--fort_ent.name
|
|
||||||
--civ_ent.name
|
|
||||||
|
|
||||||
write_gamelog('Loaded '..world.cur_savegame.save_dir..', '..fullname(world.world_data)..
|
|
||||||
' at coordinates ('..site.pos.x..','..site.pos.y..')'..NEWLINE..
|
|
||||||
'Loaded the fortress '..fullname(site)..
|
|
||||||
(fort_ent and ', colonized by the group '..fullname(fort_ent) or '')..
|
|
||||||
(civ_ent and ' of the civilization '..fullname(civ_ent) or '')..'.'..NEWLINE)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -0,0 +1,192 @@
|
|||||||
|
-- Regularly writes extra info to gamelog.txt
|
||||||
|
local help = [[=begin
|
||||||
|
|
||||||
|
modtools/extra-gamelog
|
||||||
|
======================
|
||||||
|
This script writes extra information to the gamelog.
|
||||||
|
This is useful for tools like :forums:`Soundsense <106497>`.
|
||||||
|
|
||||||
|
=end]]
|
||||||
|
|
||||||
|
msg = dfhack.gui.writeToGamelog
|
||||||
|
|
||||||
|
function log_on_load(op)
|
||||||
|
if op ~= SC_WORLD_LOADED then return end
|
||||||
|
|
||||||
|
-- Seasons fix for Soundsense
|
||||||
|
local seasons = {
|
||||||
|
[-1] = 'Nothing', -- worldgen
|
||||||
|
'Spring',
|
||||||
|
'Summer',
|
||||||
|
'Autumn',
|
||||||
|
'Winter'}
|
||||||
|
msg(seasons[df.global.cur_season]..' has arrived on the calendar.')
|
||||||
|
|
||||||
|
-- Weather fix for Soundsense
|
||||||
|
local raining = false
|
||||||
|
local snowing = false
|
||||||
|
for _, row in ipairs(df.global.current_weather) do
|
||||||
|
for _, weather in ipairs(row) do
|
||||||
|
raining = raining or weather == 1
|
||||||
|
snowing = snowing or weather == 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if (not snowing and not raining) then msg("The weather has cleared.")
|
||||||
|
elseif raining then msg("It has started raining.")
|
||||||
|
elseif snowing then msg("A snow storm has come.")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Log site information for forts
|
||||||
|
if df.world_site.find(df.global.ui.site_id) == nil then return end
|
||||||
|
local site = df.world_site.find(df.global.ui.site_id)
|
||||||
|
local fort_ent = df.global.ui.main.fortress_entity
|
||||||
|
local civ_ent = df.historical_entity.find(df.global.ui.civ_id)
|
||||||
|
local function fullname(item)
|
||||||
|
return dfhack.TranslateName(item.name)..' ('..dfhack.TranslateName(item.name ,true)..')'
|
||||||
|
end
|
||||||
|
msg('Loaded '..df.global.world.cur_savegame.save_dir..', '..fullname(df.global.world.world_data)..
|
||||||
|
' at coordinates ('..site.pos.x..','..site.pos.y..')')
|
||||||
|
msg('Loaded the fortress '..fullname(site)..
|
||||||
|
(fort_ent and ', colonized by the group '..fullname(fort_ent) or '')..
|
||||||
|
(civ_ent and ' of the civilization '..fullname(civ_ent)..'.' or '.'))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
old_expedition_leader = nil
|
||||||
|
old_mayor = nil
|
||||||
|
function log_nobles()
|
||||||
|
local expedition_leader = nil
|
||||||
|
local mayor = nil
|
||||||
|
local function check(unit)
|
||||||
|
if not dfhack.units.isCitizen(unit) then return end
|
||||||
|
for _, pos in ipairs(dfhack.units.getNoblePositions(unit) or {}) do
|
||||||
|
if pos.position.name[0] == "expedition leader" then
|
||||||
|
expedition_leader = unit
|
||||||
|
elseif pos.position.name[0] == "mayor" then
|
||||||
|
mayor = unit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for _, unit in ipairs(df.global.world.units.active) do
|
||||||
|
check(unit)
|
||||||
|
end
|
||||||
|
|
||||||
|
if old_mayor == nil and expedition_leader == nil and mayor ~= nil and old_expedition_leader ~= nil then
|
||||||
|
msg("Expedition leader was replaced by mayor.")
|
||||||
|
end
|
||||||
|
|
||||||
|
if expedition_leader ~= old_expedition_leader then
|
||||||
|
if expedition_leader == nil then
|
||||||
|
msg("Expedition leader position is now vacant.")
|
||||||
|
else
|
||||||
|
msg(dfhack.TranslateName(dfhack.units.getVisibleName(expedition_leader)).." became expedition leader.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if mayor ~= old_mayor then
|
||||||
|
if mayor == nil then
|
||||||
|
msg("Mayor position is now vacant.")
|
||||||
|
else
|
||||||
|
msg(dfhack.TranslateName(dfhack.units.getVisibleName(mayor)).." became mayor.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
old_mayor = mayor
|
||||||
|
old_expedition_leader = expedition_leader
|
||||||
|
end
|
||||||
|
|
||||||
|
siege = false
|
||||||
|
function log_siege()
|
||||||
|
local function cur_siege()
|
||||||
|
for _, unit in ipairs(df.global.world.units.active) do
|
||||||
|
if unit.flags1.active_invader then return true end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local old_siege = siege
|
||||||
|
siege = cur_siege()
|
||||||
|
if siege ~= old_siege and siege then
|
||||||
|
msg("A vile force of darkness has arrived!")
|
||||||
|
elseif siege ~= old_siege and not siege then
|
||||||
|
msg("Siege was broken.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local workshopTypes = {
|
||||||
|
[0]="Carpenters Workshop",
|
||||||
|
"Farmers Workshop",
|
||||||
|
"Masons Workshop",
|
||||||
|
"Craftsdwarfs Workshop",
|
||||||
|
"Jewelers Workshop",
|
||||||
|
"Metalsmiths Forge",
|
||||||
|
"Magma Forge",
|
||||||
|
"Bowyers Workshop",
|
||||||
|
"Mechanics Workshop",
|
||||||
|
"Siege Workshop",
|
||||||
|
"Butchers Workshop",
|
||||||
|
"Leatherworks Workshop",
|
||||||
|
"Tanners Workshop",
|
||||||
|
"Clothiers Workshop",
|
||||||
|
"Fishery",
|
||||||
|
"Still",
|
||||||
|
"Loom",
|
||||||
|
"Quern",
|
||||||
|
"Kennels",
|
||||||
|
"Kitchen",
|
||||||
|
"Ashery",
|
||||||
|
"Dyers Workshop",
|
||||||
|
"Millstone",
|
||||||
|
"Custom",
|
||||||
|
"Tool",
|
||||||
|
}
|
||||||
|
|
||||||
|
local furnaceTypes = {
|
||||||
|
[0]="Wood Furnace",
|
||||||
|
"Smelter",
|
||||||
|
"Glass Furnace",
|
||||||
|
"Kiln",
|
||||||
|
"Magma Smelter",
|
||||||
|
"Magma Glass Furnace",
|
||||||
|
"Magma Kiln",
|
||||||
|
"Custom Furnace",
|
||||||
|
}
|
||||||
|
|
||||||
|
buildStates = {}
|
||||||
|
|
||||||
|
function log_buildings()
|
||||||
|
for _, building in ipairs(df.global.world.buildings.all) do
|
||||||
|
if getmetatable(building) == "building_workshopst" or getmetatable(building) == "building_furnacest" then
|
||||||
|
buildStates[building.id] = buildStates[building.id] or building.flags.exists
|
||||||
|
if buildStates[building.id] ~= building.flags.exists then
|
||||||
|
buildStates[building.id] = building.flags.exists
|
||||||
|
if building.flags.exists then
|
||||||
|
if getmetatable(building) == "building_workshopst" then
|
||||||
|
msg(workshopTypes[building.type].." was built.")
|
||||||
|
elseif getmetatable(building) == "building_furnacest" then
|
||||||
|
msg(furnaceTypes[building.type].." was built.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function event_loop()
|
||||||
|
log_nobles()
|
||||||
|
log_siege()
|
||||||
|
log_buildings()
|
||||||
|
if extra_gamelog_enabled then dfhack.timeout(50, 'ticks', event_loop) end
|
||||||
|
end
|
||||||
|
|
||||||
|
extra_gamelog_enabled = false
|
||||||
|
local args = {...}
|
||||||
|
if args[1] == 'disable' then
|
||||||
|
dfhack.onStateChange[_ENV] = nil
|
||||||
|
extra_gamelog_enabled = false
|
||||||
|
elseif args[1] == 'enable' then
|
||||||
|
dfhack.onStateChange[_ENV] = log_on_load
|
||||||
|
extra_gamelog_enabled = true
|
||||||
|
event_loop()
|
||||||
|
else
|
||||||
|
print(help)
|
||||||
|
end
|
@ -1,34 +0,0 @@
|
|||||||
-- On map load writes the current season to gamelog.txt
|
|
||||||
--[[=begin
|
|
||||||
|
|
||||||
soundsense-season
|
|
||||||
=================
|
|
||||||
It is a well known issue that Soundsense cannot detect the correct
|
|
||||||
current season when a savegame is loaded and has to play random
|
|
||||||
season music until a season switch occurs.
|
|
||||||
|
|
||||||
This script registers a hook that prints the appropriate string
|
|
||||||
to :file:`gamelog.txt` on every map load to fix this. For best results
|
|
||||||
call the script from :file:`dfhack.init`.
|
|
||||||
|
|
||||||
=end]]
|
|
||||||
|
|
||||||
local seasons = {
|
|
||||||
[-1] = 'Nothing', -- worldgen
|
|
||||||
[0] = 'Spring',
|
|
||||||
[1] = 'Summer',
|
|
||||||
[2] = 'Autumn',
|
|
||||||
[3] = 'Winter',
|
|
||||||
}
|
|
||||||
|
|
||||||
local args = {...}
|
|
||||||
|
|
||||||
if args[1] == 'disable' then
|
|
||||||
dfhack.onStateChange[_ENV] = nil
|
|
||||||
else
|
|
||||||
dfhack.onStateChange[_ENV] = function(op)
|
|
||||||
if op == SC_WORLD_LOADED then
|
|
||||||
dfhack.gui.writeToGamelog(seasons[df.global.cur_season]..' has arrived on the calendar.')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in New Issue