develop
Petr Mrázek 2011-04-02 07:18:26 +02:00
commit 091cc88655
8 changed files with 629 additions and 4 deletions

@ -447,6 +447,8 @@ class BodyPart(Structure):
("single", _dfhack_string),
("plural", _dfhack_string)]
_bodypart_ptr = POINTER(BodyPart)
class ColorModifier(Structure):
_fields_ = [("part", _dfhack_string),
("colorlist", POINTER(c_uint)),
@ -466,7 +468,7 @@ class CreatureCaste(Structure):
("adjective", _dfhack_string),
("color_modifier", _colormodifier_ptr),
("color_modifier_length", c_uint),
("bodypart", POINTER(BodyPart)),
("bodypart", _bodypart_ptr),
("bodypart_length", c_uint),
("strength", Attribute),
("agility", Attribute),
@ -588,10 +590,48 @@ class Hotkey(Structure):
("y", c_int),
("z", c_int)]
_hotkey_ptr = POINTER(Hotkey)
def _alloc_hotkey_buffer_callback(ptr, count):
print "hotkey alloc: %d" % count
return util._allocate_array(ptr, Hotkey, count)
_hotkey_functype = CFUNCTYPE(c_int, POINTER(POINTER(Hotkey)), c_uint)
_hotkey_functype = CFUNCTYPE(c_int, POINTER(_hotkey_ptr), c_uint)
_hotkey_func = _hotkey_functype(_alloc_hotkey_buffer_callback)
_register_callback("alloc_hotkey_buffer_callback", _hotkey_func)
_register_callback("alloc_hotkey_buffer_callback", _hotkey_func)
class MemRange(Structure):
_fields_ = [("start", c_ulong),
("end", c_ulong),
("name", (c_char * 1024)),
("read", c_uint, 1),
("write", c_uint, 1),
("execute", c_uint, 1),
("shared", c_uint, 1),
("valid", c_ubyte),
("buffer", POINTER(c_ubyte))]
_memrange_ptr = POINTER(MemRange)
def _alloc_memrange_buffer(ptr, descriptors, count):
arr_list = []
m_arr = (MemRange * count)()
for i, v in enumerate(m_arr):
buf_arr = (c_ubyte * int(descriptors[i]))()
buf_ptr = cast(buf_arr, POINTER(c_ubyte))
v.buffer = buf_ptr
arr_list.extend((buf_arr, buf_ptr))
p = cast(m_arr, _memrange_ptr)
ptr[0] = p
pointer_dict[addressof(m_arr)] = (ptr, m_arr, p, arr_list)
return 1
_alloc_memrange_buffer_functype = CFUNCTYPE(c_int, POINTER(_memrange_ptr), POINTER(c_uint), c_uint)
_alloc_memrange_buffer_func = _alloc_memrange_buffer_functype(_alloc_memrange_buffer)
_register_callback("alloc_memrange_buffer_callback", _alloc_memrange_buffer_func)

@ -0,0 +1,135 @@
from ctypes import *
from dftypes import libdfhack
from util import check_pointer_cache
libdfhack.Process_readQuad.argtypes = [ c_void_p, c_uint, POINTER(c_ulong) ]
libdfhack.Process_writeQuad.argtypes = [ c_void_p, c_uint, c_ulong ]
libdfhack.Process_readDWord.argtypes = [ c_void_p, c_uint, POINTER(c_uint) ]
libdfhack.Process_writeDWord.argtypes = [ c_void_p, c_uint, c_uint ]
libdfhack.Process_readWord.argtypes = [ c_void_p, c_uint, POINTER(c_ushort) ]
libdfhack.Process_writeWord.argtypes = [ c_void_p, c_uint, c_ushort ]
libdfhack.Process_readByte.argtypes = [ c_void_p, c_uint, POINTER(c_ubyte) ]
libdfhack.Process_writeByte.argtypes = [ c_void_p, c_uint, c_ubyte ]
libdfhack.Process_readFloat.argtypes = [ c_void_p, c_uint, POINTER(c_float) ]
libdfhack.Process_read.argtypes = [ c_void_p, c_uint, c_uint ]
libdfhack.Process_read.restype = c_void_p
libdfhack.Process_write.argtypes = [ c_void_p, c_uint, c_uint, POINTER(c_ubyte) ]
libdfhack.Process_getThreadIDs.restype = c_void_p
class Process(object):
def __init__(self, ptr):
self._p_ptr = ptr
def attach(self):
return libdfhack.Process_attach(self._p_ptr) > 0
def detach(self):
return libdfhack.Process_detach(self._p_ptr) > 0
def suspend(self):
return libdfhack.Process_suspend(self._p_ptr) > 0
def async_suspend(self):
return libdfhack.Process_asyncSuspend(self._p_ptr) > 0
def resume(self):
return libdfhack.Process_resume(self._p_ptr) > 0
def force_resume(self):
return libdfhack.Process_forceresume(self._p_ptr) > 0
def read_quad(self, address):
q = c_ulong(0)
if libdfhack.Process_readQuad(self._p_ptr, address, byref(q)) > 0:
return long(q.value)
else:
return -1
def write_quad(self, address, value):
return libdfhack.Process_writeQuad(self._p_ptr, address, value) > 0
def read_dword(self, address):
d = c_uint(0)
if libdfhack.Process_readDWord(self._p_ptr, address, byref(d)) > 0:
return int(d.value)
else:
return -1
def write_dword(self, address, value):
return libdfhack.Process_writeDWord(self._p_ptr, address, value) > 0
def read_word(self, address):
s = c_ushort(0)
if libdfhack.Process_readWord(self._p_ptr, address, byref(s)) > 0:
return int(s.value)
else:
return -1
def write_word(self, address, value):
return libdfhack.Process_writeWord(self._p_ptr, address, value) > 0
def read_byte(self, address):
b = c_ubyte(0)
if libdfhack.Process_readByte(self._p_ptr, address, byref(b)) > 0:
return int(b.value)
else:
return -1
def write_byte(self, address, value):
return libdfhack.Process_writeByte(self._p_ptr, address, value) > 0
def read_float(self, address):
f = c_float(0)
if libdfhack.Process_readFloat(self._p_ptr, address, byref(f)) > 0:
return float(f.value)
else:
return -1
def read(self, address, length):
return check_pointer_cache(libdfhack.Process_read(self._p_ptr, address, length))
def write(self, address, length, buffer):
libdfhack.Process_write(self._p_ptr, address, length, byref(buffer))
def get_thread_ids(self):
return check_pointer_cache(libdfhack.Process_getThreadIDs(self._p_ptr))
def set_and_wait(self, state):
return libdfhack.Process_SetAndWait(self._p_ptr, state) > 0
@property
def is_suspended(self):
return libdfhack.Process_isSuspended(self._p_ptr) > 0
@property
def is_attached(self):
return libdfhack.Process_isAttached(self._p_ptr) > 0
@property
def is_identified(self):
return libdfhack.Process_isIdentified(self._p_ptr) > 0
@property
def is_snapshot(self):
return libdfhack.Process_isSnapshot(self._p_ptr) > 0
@property
def pid(self):
p = c_int(0)
if libdfhack.Process_getPID(self._p_ptr, byref(p)) > 0:
return int(p.value)
else:
return -1

@ -54,6 +54,7 @@ include/dfhack/modules/World.h
SET(PROJECT_C_HDRS
include/DFHack_C.h
include/dfhack-c/DFProcess_C.h
include/dfhack-c/DFTypes_C.h
include/dfhack-c/DFContext_C.h
include/dfhack-c/modules/Buildings_C.h
@ -102,6 +103,7 @@ modules/World.cpp
SET(PROJECT_C_SRCS
DFContext_C.cpp
DFProcess_C.cpp
DFTypes_C.cpp
modules/Buildings_C.cpp

@ -0,0 +1,339 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
#include "dfhack/DFIntegers.h"
#include "dfhack-c/DFTypes_C.h"
#include "dfhack-c/DFProcess_C.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PTR_CHECK if(p_Ptr == NULL) return -1;
int C_ProcessID_Compare(c_processID* left, c_processID* right)
{
if(left == NULL || right == NULL)
return PROCESSID_C_NULL;
else
{
if(left->time == right->time && left->pid == right->pid)
return PROCESSID_C_EQ;
else if(left->time < right->time || left->pid < right->pid)
return PROCESSID_C_LT;
else
return PROCESSID_C_GT;
}
}
#define FUNCTION_FORWARD(func_name) \
int Process_##func_name (DFHackObject* p_Ptr) \
{ \
if(p_Ptr == NULL) \
return -1; \
if(((DFHack::Process*)p_Ptr)->func_name()) \
return 1; \
else \
return 0; \
}
FUNCTION_FORWARD(attach)
FUNCTION_FORWARD(detach)
FUNCTION_FORWARD(suspend)
FUNCTION_FORWARD(asyncSuspend)
FUNCTION_FORWARD(resume)
FUNCTION_FORWARD(forceresume)
FUNCTION_FORWARD(isSuspended)
FUNCTION_FORWARD(isAttached)
FUNCTION_FORWARD(isIdentified)
FUNCTION_FORWARD(isSnapshot)
#define MEMREAD_FUNC_FORWARD(func_name, type) \
int Process_##func_name(DFHackObject* p_Ptr, uint32_t address, type* value) \
{ \
PTR_CHECK \
((DFHack::Process*)p_Ptr)->func_name(address, *value); \
return 1; \
}
#define MEMWRITE_FUNC_FORWARD(func_name, type) \
int Process_##func_name(DFHackObject* p_Ptr, uint32_t address, type value) \
{ \
PTR_CHECK \
((DFHack::Process*)p_Ptr)->func_name(address, value); \
return 1; \
}
MEMREAD_FUNC_FORWARD(readQuad, uint64_t)
MEMWRITE_FUNC_FORWARD(writeQuad, uint64_t)
MEMREAD_FUNC_FORWARD(readDWord, uint32_t)
MEMWRITE_FUNC_FORWARD(writeDWord, uint32_t)
MEMREAD_FUNC_FORWARD(readWord, uint16_t)
MEMWRITE_FUNC_FORWARD(writeWord, uint16_t)
MEMREAD_FUNC_FORWARD(readFloat, float)
MEMREAD_FUNC_FORWARD(readByte, uint8_t)
MEMWRITE_FUNC_FORWARD(writeByte, uint8_t)
MEMREAD_FUNC_FORWARD(readSTLVector, t_vecTriplet);
uint8_t* Process_read(DFHackObject* p_Ptr, uint32_t address, uint32_t length)
{
if(p_Ptr == NULL || alloc_ubyte_buffer_callback == NULL)
return NULL;
uint8_t* buf;
((*alloc_ubyte_buffer_callback)(&buf, length));
if(buf == NULL)
return NULL;
((DFHack::Process*)p_Ptr)->read(address, length, buf);
return buf;
}
void Process_write(DFHackObject* p_Ptr, uint32_t address, uint32_t length, uint8_t* buffer)
{
if(p_Ptr == NULL || buffer == NULL)
return;
((DFHack::Process*)p_Ptr)->write(address, length, buffer);
}
char* Process_readString(DFHackObject* p_Ptr, uint32_t offset)
{
if(p_Ptr == NULL || alloc_char_buffer_callback == NULL)
return NULL;
std::string pString = ((DFHack::Process*)p_Ptr)->readSTLString(offset);
if(pString.length() > 0)
{
size_t length = pString.length();
char* buf;
//add 1 for the null terminator
((*alloc_char_buffer_callback)(&buf, length + 1));
if(buf == NULL)
return NULL;
memset(buf, '\n', length + 1);
pString.copy(buf, length);
return buf;
}
else
return "";
}
char* Process_getPath(DFHackObject* p_Ptr)
{
if(p_Ptr == NULL || alloc_char_buffer_callback == NULL)
return NULL;
std::string pString = ((DFHack::Process*)p_Ptr)->getPath();
if(pString.length() > 0)
{
size_t length = pString.length();
char* buf;
//add 1 for the null terminator
((*alloc_char_buffer_callback)(&buf, length + 1));
if(buf == NULL)
return NULL;
memset(buf, '\0', length + 1);
pString.copy(buf, length);
return buf;
}
else
return "";
}
char* Process_readClassName(DFHackObject* p_Ptr, uint32_t vptr)
{
if(p_Ptr == NULL || alloc_char_buffer_callback == NULL)
return NULL;
std::string cString = ((DFHack::Process*)p_Ptr)->readClassName(vptr);
if(cString.length() > 0)
{
size_t length = cString.length();
char* buf;
//add 1 for the null terminator
((*alloc_char_buffer_callback)(&buf, length + 1));
if(buf == NULL)
return NULL;
memset(buf, '\0', length + 1);
cString.copy(buf, length);
return buf;
}
else
return "";
}
uint32_t* Process_getThreadIDs(DFHackObject* p_Ptr)
{
if(p_Ptr == NULL || alloc_uint_buffer_callback == NULL)
return NULL;
std::vector<uint32_t> threads;
if(((DFHack::Process*)p_Ptr)->getThreadIDs(threads))
{
uint32_t* buf;
if(threads.size() > 0)
{
((*alloc_uint_buffer_callback)(&buf, threads.size()));
if(buf == NULL)
return NULL;
copy(threads.begin(), threads.end(), buf);
return buf;
}
}
else
return NULL;
}
t_memrange* Process_getMemRanges(DFHackObject* p_Ptr)
{
if(p_Ptr == NULL || alloc_memrange_buffer_callback == NULL)
return NULL;
std::vector<t_memrange> ranges;
((DFHack::Process*)p_Ptr)->getMemRanges(ranges);
if(ranges.size() > 0)
{
t_memrange* buf;
uint32_t* rangeDescriptorBuf = (uint32_t*)calloc(ranges.size(), sizeof(uint32_t));
for(uint32_t i = 0; i < ranges.size(); i++)
{
t_memrange* r = &ranges[i];
rangeDescriptorBuf[i] = (uint32_t)(r->end - r->start);
}
((*alloc_memrange_buffer_callback)(&buf, rangeDescriptorBuf, ranges.size()));
free(rangeDescriptorBuf);
if(buf == NULL)
return NULL;
for(uint32_t i = 0; i < ranges.size(); i++)
{
t_memrange* r = &ranges[i];
buf[i].start = r->start;
buf[i].end = r->end;
memset(buf[i].name, '\0', 1024);
strncpy(buf[i].name, r->name, 1024);
buf[i].read = r->read;
buf[i].write = r->write;
buf[i].execute = r->execute;
buf[i].shared = r->shared;
buf[i].valid = r->valid;
memcpy(buf[i].buffer, r->buffer, r->end - r->start);
}
return buf;
}
else
return NULL;
}
int Process_getPID(DFHackObject* p_Ptr, int32_t* pid)
{
if(p_Ptr == NULL)
{
*pid = -1;
return -1;
}
else
{
*pid = ((DFHack::Process*)p_Ptr)->getPID();
return 1;
}
}
int Process_getModuleIndex(DFHackObject* p_Ptr, char* name, uint32_t version, uint32_t* output)
{
PTR_CHECK
if(((DFHack::Process*)p_Ptr)->getModuleIndex(name, version, *output))
return 1;
else
return 0;
}
int Process_SetAndWait(DFHackObject* p_Ptr, uint32_t state)
{
PTR_CHECK
if(((DFHack::Process*)p_Ptr)->SetAndWait(state))
return 1;
else
return 0;
}
#ifdef __cplusplus
}
#endif

@ -88,6 +88,8 @@ int (*alloc_screen_buffer_callback)(t_screen**, uint32_t) = NULL;
int (*alloc_tree_buffer_callback)(t_tree**, uint32_t) = NULL;
int (*alloc_memrange_buffer_callback)(t_memrange**, uint32_t*, uint32_t) = NULL;
int (*alloc_customWorkshop_buffer_callback)(t_customWorkshop**, uint32_t) = NULL;
int (*alloc_material_buffer_callback)(t_material**, uint32_t) = NULL;
@ -119,6 +121,11 @@ REG_MACRO(Tree, t_tree**, alloc_tree_buffer_callback)
REG_MACRO(CustomWorkshop, t_customWorkshop**, alloc_customWorkshop_buffer_callback)
REG_MACRO(Material, t_material**, alloc_material_buffer_callback)
void RegisterMemRangeBufferCallback(int (*funcptr)(t_memrange**, uint32_t*, uint32_t))
{
alloc_memrange_buffer_callback = funcptr;
}
UNREG_MACRO(Byte, alloc_byte_buffer_callback)
UNREG_MACRO(Short, alloc_short_buffer_callback)
UNREG_MACRO(Int, alloc_int_buffer_callback)
@ -133,6 +140,7 @@ UNREG_MACRO(Feature, alloc_feature_buffer_callback)
UNREG_MACRO(Hotkey, alloc_hotkey_buffer_callback)
UNREG_MACRO(Screen, alloc_screen_buffer_callback)
UNREG_MACRO(Tree, alloc_tree_buffer_callback)
UNREG_MACRO(MemRange, alloc_memrange_buffer_callback)
UNREG_MACRO(CustomWorkshop, alloc_customWorkshop_buffer_callback)
UNREG_MACRO(Material, alloc_material_buffer_callback)

@ -137,7 +137,6 @@ DFHACK_EXPORT DFHackObject* Context_getProcess(DFHackObject* context);
DFHACK_EXPORT DFHackObject* Context_getCreatures(DFHackObject* context);
DFHACK_EXPORT DFHackObject* Context_getMaps(DFHackObject* context);
DFHACK_EXPORT DFHackObject* Context_getGui(DFHackObject* context);
DFHACK_EXPORT DFHackObject* Context_getPosition(DFHackObject* context);
DFHACK_EXPORT DFHackObject* Context_getMaterials(DFHackObject* context);
DFHACK_EXPORT DFHackObject* Context_getTranslation(DFHackObject* context);
DFHACK_EXPORT DFHackObject* Context_getVegetation(DFHackObject* context);

@ -0,0 +1,96 @@
/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf, doomchild
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#ifndef PROCESS_C_API
#define PROCESS_C_API
#include "DFHack_C.h"
#include "dfhack/DFProcess.h"
#ifdef __cplusplus
extern "C" {
#endif
struct c_processID
{
uint64_t time;
uint64_t pid;
};
#define PROCESSID_C_NULL -2
#define PROCESSID_C_LT -1
#define PROCESSID_C_EQ 0
#define PROCESSID_C_GT 1
DFHACK_EXPORT extern int C_ProcessID_Compare(c_processID* left, c_processID* right);
DFHACK_EXPORT int Process_attach(DFHackObject* p_Ptr);
DFHACK_EXPORT int Process_detach(DFHackObject* p_Ptr);
DFHACK_EXPORT int Process_suspend(DFHackObject* p_Ptr);
DFHACK_EXPORT int Process_asyncSuspend(DFHackObject* p_Ptr);
DFHACK_EXPORT int Process_resume(DFHackObject* p_Ptr);
DFHACK_EXPORT int Process_forceresume(DFHackObject* p_Ptr);
DFHACK_EXPORT int Process_readQuad(DFHackObject* p_Ptr, uint32_t address, uint64_t* value);
DFHACK_EXPORT int Process_writeQuad(DFHackObject* p_Ptr, uint32_t address, uint64_t value);
DFHACK_EXPORT int Process_readDWord(DFHackObject* p_Ptr, uint32_t address, uint32_t* value);
DFHACK_EXPORT int Process_writeDWord(DFHackObject* p_Ptr, uint32_t address, uint32_t value);
DFHACK_EXPORT int Process_readWord(DFHackObject* p_Ptr, uint32_t address, uint16_t* value);
DFHACK_EXPORT int Process_writeWord(DFHackObject* p_Ptr, uint32_t address, uint16_t value);
DFHACK_EXPORT int Process_readFloat(DFHackObject* p_Ptr, uint32_t address, float* value);
DFHACK_EXPORT int Process_readByte(DFHackObject* p_Ptr, uint32_t address, uint8_t* value);
DFHACK_EXPORT int Process_writeByte(DFHackObject* p_Ptr, uint32_t address, uint8_t value);
DFHACK_EXPORT uint8_t* Process_read(DFHackObject* p_Ptr, uint32_t address, uint32_t length);
DFHACK_EXPORT void Process_write(DFHackObject* p_Ptr, uint32_t address, uint32_t length, uint8_t* buffer);
DFHACK_EXPORT int Process_readSTLVector(DFHackObject* p_Ptr, uint32_t address, t_vecTriplet* vector);
DFHACK_EXPORT char* Process_readString(DFHackObject* p_Ptr, uint32_t offset);
DFHACK_EXPORT char* Process_getPath(DFHackObject* p_Ptr);
DFHACK_EXPORT char* Process_readClassName(DFHackObject* p_Ptr, uint32_t vptr);
DFHACK_EXPORT int Process_isSuspended(DFHackObject* p_Ptr);
DFHACK_EXPORT int Process_isAttached(DFHackObject* p_Ptr);
DFHACK_EXPORT int Process_isIdentified(DFHackObject* p_Ptr);
DFHACK_EXPORT int Process_isSnapshot(DFHackObject* p_Ptr);
DFHACK_EXPORT uint32_t* Process_getThreadIDs(DFHackObject* p_Ptr);
DFHACK_EXPORT t_memrange* Process_getMemRanges(DFHackObject* p_Ptr);
DFHACK_EXPORT int Process_getPID(DFHackObject* p_Ptr, int32_t* pid);
DFHACK_EXPORT int Process_getModuleIndex(DFHackObject* p_Ptr, char* name, uint32_t version, uint32_t* output);
DFHACK_EXPORT int Process_SetAndWait(DFHackObject* p_Ptr, uint32_t state);
#ifdef __cplusplus
}
#endif
#endif

@ -26,6 +26,7 @@ distribution.
#define TYPES_C_API
#include "DFHack_C.h"
#include "DFProcess_C.h"
#include "dfhack/DFTypes.h"
#include "dfhack/modules/Maps.h"
#include "dfhack/modules/Materials.h"
@ -61,6 +62,8 @@ DFHACK_EXPORT extern int (*alloc_screen_buffer_callback)(t_screen**, uint32_t);
DFHACK_EXPORT extern int (*alloc_tree_buffer_callback)(t_tree**, uint32_t);
DFHACK_EXPORT extern int (*alloc_memrange_buffer_callback)(t_memrange**, uint32_t*, uint32_t);
DFHACK_EXPORT void RegisterByteBufferCallback(int (*funcptr)(int8_t**, uint32_t));
DFHACK_EXPORT void RegisterShortBufferCallback(int (*funcptr)(int16_t**, uint32_t));
DFHACK_EXPORT void RegisterIntBufferCallback(int (*funcptr)(int32_t**, uint32_t));
@ -81,6 +84,8 @@ DFHACK_EXPORT void RegisterScreenBufferCallback(int (*funcptr)(t_screen**, uint3
DFHACK_EXPORT void RegisterTreeBufferCallback(int (*funcptr)(t_tree**, uint32_t));
DFHACK_EXPORT void RegisterMemRangeBufferCallback(int (*funcptr)(t_memrange**, uint32_t*, uint32_t));
HUNREG_MACRO(Byte)
HUNREG_MACRO(Short)
HUNREG_MACRO(Int)
@ -99,6 +104,7 @@ HUNREG_MACRO(Hotkey)
HUNREG_MACRO(Screen)
HUNREG_MACRO(Tree)
HUNREG_MACRO(MemRange)
struct t_customWorkshop
{