Fixes invalid text pasting, Adds API to VM, allow program loading in Lua and assigning to update function
This commit is contained in:
parent
685be24ffa
commit
486b34ebe5
@ -20,6 +20,7 @@
|
||||
#include "dialogues/TextPrompt.h"
|
||||
#include "dialogues/ConfirmPrompt.h"
|
||||
#include "simulation/Simulation.h"
|
||||
#include "virtualmachine/VirtualMachine.h"
|
||||
#include "game/GameModel.h"
|
||||
#include "LuaScriptHelper.h"
|
||||
#include "client/HTTP.h"
|
||||
@ -63,6 +64,7 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
|
||||
initInterfaceAPI();
|
||||
initRendererAPI();
|
||||
initElementsAPI();
|
||||
initVirtualMachineAPI();
|
||||
|
||||
//Old TPT API
|
||||
int i = 0, j;
|
||||
@ -651,6 +653,42 @@ void LuaScriptInterface::initElementsAPI()
|
||||
}
|
||||
}
|
||||
|
||||
vm::VirtualMachine * LuaScriptInterface::updateVirtualMachines[PT_NUM];
|
||||
|
||||
int LuaScriptInterface::updateVM(UPDATE_FUNC_ARGS)
|
||||
{
|
||||
vm::VirtualMachine * vMachine = updateVirtualMachines[parts[i].type];
|
||||
|
||||
vm::word w;
|
||||
int argAddr = 0, argCount = 5;
|
||||
vMachine->sim = sim;
|
||||
|
||||
/* Set up call. */
|
||||
vMachine->OpPUSH(w); //Pointless null in stack
|
||||
w.int4 = (argCount + 2) * sizeof(vm::word);
|
||||
vMachine->OpENTER(w);
|
||||
argAddr = 8;
|
||||
|
||||
//Arguments
|
||||
w.int4 = i; vMachine->Marshal(argAddr, w); argAddr += 4;
|
||||
w.int4 = x; vMachine->Marshal(argAddr, w); argAddr += 4;
|
||||
w.int4 = y; vMachine->Marshal(argAddr, w); argAddr += 4;
|
||||
w.int4 = nt; vMachine->Marshal(argAddr, w); argAddr += 4;
|
||||
w.int4 = surround_space; vMachine->Marshal(argAddr, w); argAddr += 4;
|
||||
|
||||
w.int4 = 0;
|
||||
vMachine->Push(w);
|
||||
|
||||
vMachine->OpCALL(w);
|
||||
vMachine->Run();
|
||||
w.int4 = (argCount + 2) * sizeof(vm::word);
|
||||
vMachine->OpLEAVE(w);
|
||||
vMachine->OpPOP(w); //Pop pointless null
|
||||
vMachine->End();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::elements_loadDefault(lua_State * l)
|
||||
{
|
||||
int args = lua_gettop(l);
|
||||
@ -957,6 +995,11 @@ int LuaScriptInterface::elements_property(lua_State * l)
|
||||
lua_el_func[id] = luaL_ref(l, LUA_REGISTRYINDEX);
|
||||
luacon_sim->elements[id].Update = &luacon_elementReplacement;
|
||||
}
|
||||
else if(lua_type(l, 3) == LUA_TLIGHTUSERDATA)
|
||||
{
|
||||
updateVirtualMachines[id] = (vm::VirtualMachine*)lua_touserdata(l, 3);
|
||||
luacon_sim->elements[id].Update = &updateVM;
|
||||
}
|
||||
else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
|
||||
{
|
||||
lua_el_func[id] = 0;
|
||||
@ -1061,6 +1104,41 @@ int LuaScriptInterface::elements_free(lua_State * l)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LuaScriptInterface::initVirtualMachineAPI()
|
||||
{
|
||||
//Methods
|
||||
struct luaL_reg vmAPIMethods [] = {
|
||||
{"loadProgram", virtualMachine_loadProgram},
|
||||
{NULL, NULL}
|
||||
};
|
||||
luaL_register(l, "virtualMachine", vmAPIMethods);
|
||||
|
||||
//elem shortcut
|
||||
lua_getglobal(l, "virtualMachine");
|
||||
lua_setglobal(l, "vm");
|
||||
|
||||
int vmAPI = lua_gettop(l);
|
||||
}
|
||||
|
||||
int LuaScriptInterface::virtualMachine_loadProgram(lua_State * l)
|
||||
{
|
||||
luaL_checktype(l, 1, LUA_TSTRING);
|
||||
|
||||
vm::VirtualMachine * newVM = new vm::VirtualMachine(1);
|
||||
try
|
||||
{
|
||||
const char * tempString = lua_tostring(l, 1);
|
||||
int tempStringLength = lua_strlen(l, 1);
|
||||
std::vector<char> programData(tempString, tempString+tempStringLength);
|
||||
newVM->LoadProgram(programData);
|
||||
}
|
||||
catch(std::exception & e)
|
||||
{
|
||||
return luaL_error(l, "Unable to load program");
|
||||
}
|
||||
lua_pushlightuserdata(l, newVM);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool LuaScriptInterface::OnBrushChanged(int brushType, int rx, int ry)
|
||||
{
|
||||
|
@ -23,6 +23,12 @@ namespace ui
|
||||
class Window;
|
||||
}
|
||||
|
||||
namespace vm
|
||||
{
|
||||
class VirtualMachine;
|
||||
}
|
||||
|
||||
|
||||
//Because lua only has bindings for C, we're going to have to go outside "outside" the LuaScriptInterface, this means we can only have one instance :(
|
||||
|
||||
#define LOCAL_LUA_DIR "Lua"
|
||||
@ -59,6 +65,9 @@ class LuaScriptInterface: public CommandInterface {
|
||||
static int renderer_colourMode(lua_State * l);
|
||||
|
||||
//Elements
|
||||
static vm::VirtualMachine * updateVirtualMachines[PT_NUM];
|
||||
static int updateVM(UPDATE_FUNC_ARGS);
|
||||
//
|
||||
void initElementsAPI();
|
||||
static int elements_allocate(lua_State * l);
|
||||
static int elements_element(lua_State * l);
|
||||
@ -71,6 +80,10 @@ class LuaScriptInterface: public CommandInterface {
|
||||
static int interface_showWindow(lua_State * l);
|
||||
static int interface_closeWindow(lua_State * l);
|
||||
static int interface_addComponent(lua_State * l);
|
||||
|
||||
//VM
|
||||
void initVirtualMachineAPI();
|
||||
static int virtualMachine_loadProgram(lua_State * l);
|
||||
public:
|
||||
ui::Window * Window;
|
||||
lua_State *l;
|
||||
|
@ -191,6 +191,21 @@ void Textbox::pasteIntoSelection()
|
||||
backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
|
||||
cursor = getLowerSelectionBound();
|
||||
}
|
||||
for(std::string::iterator iter = newText.begin(), end = newText.end(); iter != end; ++iter)
|
||||
{
|
||||
if(!CharacterValid(*iter))
|
||||
{
|
||||
if(inputType == All)
|
||||
{
|
||||
if(*iter == '\n' || *iter == '\r')
|
||||
*iter = ' ';
|
||||
else
|
||||
*iter = '?';
|
||||
}
|
||||
else
|
||||
*iter = '0';
|
||||
}
|
||||
}
|
||||
backingText.insert(cursor, newText);
|
||||
cursor = cursor+newText.length();
|
||||
ClearSelection();
|
||||
|
@ -86,4 +86,15 @@ namespace vm
|
||||
}
|
||||
~OutOfMemoryException() throw() {};
|
||||
};
|
||||
|
||||
class InvalidProgramException: public RuntimeException
|
||||
{
|
||||
public:
|
||||
InvalidProgramException() {}
|
||||
const char * what() const throw()
|
||||
{
|
||||
return "Could not load program";
|
||||
}
|
||||
~InvalidProgramException() throw() {};
|
||||
};
|
||||
}
|
@ -61,9 +61,9 @@ namespace vm
|
||||
|
||||
TRAPDEF(partCreate)
|
||||
{
|
||||
//Push<int4_t>(sim->create_part(ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4));
|
||||
printf("create_part(%d, %d, %d, %d)\n", ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4);
|
||||
printf("%d, %d, %d, %d\n", ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4);
|
||||
Push<int4_t>(0);
|
||||
//Push<int4_t>(sim->create_part(ARG(0).int4, ARG(1).int4, ARG(2).int4, ARG(3).int4));
|
||||
}
|
||||
|
||||
TRAPDEF(partChangeType)
|
||||
|
@ -74,86 +74,87 @@ namespace vm
|
||||
}
|
||||
|
||||
/* Read one octet from file. */
|
||||
int VirtualMachine::readByte(FILE *qvmfile)
|
||||
int VirtualMachine::readByte(std::istream & input)
|
||||
{
|
||||
int o;
|
||||
o = fgetc(qvmfile);
|
||||
o = input.get();
|
||||
if (o < 0) o = 0; /* EOF (hack) */
|
||||
return o;
|
||||
}
|
||||
|
||||
/* Read little-endian 32-bit integer from file. */
|
||||
int VirtualMachine::readInt(FILE *qvmfile)
|
||||
int VirtualMachine::readInt(std::istream & input)
|
||||
{
|
||||
int a, b, c, d, n;
|
||||
|
||||
a = readByte(qvmfile);
|
||||
b = readByte(qvmfile);
|
||||
c = readByte(qvmfile);
|
||||
d = readByte(qvmfile);
|
||||
a = readByte(input);
|
||||
b = readByte(input);
|
||||
c = readByte(input);
|
||||
d = readByte(input);
|
||||
n = (a) | (b << 8) | (c << 16) | (d << 24);
|
||||
return n;
|
||||
}
|
||||
|
||||
int VirtualMachine::LoadProgram(char * filename)
|
||||
int VirtualMachine::readProgram(std::istream & input)
|
||||
{
|
||||
FILE * qvmfile = fopen(filename, "rb");
|
||||
qvm_header_t qvminfo;
|
||||
int i, n;
|
||||
uint1_t x[4];
|
||||
word w;
|
||||
|
||||
DEBUGTRACE("Loading file...\n");
|
||||
qvminfo.magic = readInt(qvmfile); /* magic. */
|
||||
qvminfo.magic = readInt(input); /* magic. */
|
||||
if (qvminfo.magic != QVM_MAGIC)
|
||||
{
|
||||
DEBUGTRACE("Invalid magic");
|
||||
throw InvalidProgramException();
|
||||
//q3vm_error("Does not appear to be a QVM file.");
|
||||
/* XXX: option to force continue. */
|
||||
return 0;
|
||||
}
|
||||
DEBUGTRACE("Magic OK\n");
|
||||
/* variable-length instructions mean instruction count != code length */
|
||||
qvminfo.inscount = readInt(qvmfile);
|
||||
qvminfo.codeoff = readInt(qvmfile);
|
||||
qvminfo.codelen = readInt(qvmfile);
|
||||
qvminfo.dataoff = readInt(qvmfile);
|
||||
qvminfo.datalen = readInt(qvmfile);
|
||||
qvminfo.litlen = readInt(qvmfile);
|
||||
qvminfo.bsslen = readInt(qvmfile);
|
||||
qvminfo.inscount = readInt(input);
|
||||
qvminfo.codeoff = readInt(input);
|
||||
qvminfo.codelen = readInt(input);
|
||||
qvminfo.dataoff = readInt(input);
|
||||
qvminfo.datalen = readInt(input);
|
||||
qvminfo.litlen = readInt(input);
|
||||
qvminfo.bsslen = readInt(input);
|
||||
|
||||
/* Code segment should follow... */
|
||||
/* XXX: use fseek with SEEK_CUR? */
|
||||
DEBUGTRACE("Searching for .code @ %d from %d\n", qvminfo.codeoff, ftell(qvmfile));
|
||||
DEBUGTRACE("Searching for .code @ %d from %d\n", qvminfo.codeoff, input.tellg());
|
||||
|
||||
// rom = (q3vm_rom_t*)(hunk); /* ROM-in-hunk */
|
||||
rom = (Instruction*)calloc(qvminfo.inscount, sizeof(rom[0]));
|
||||
while (ftell(qvmfile) < qvminfo.codeoff)
|
||||
readByte(qvmfile);
|
||||
while (input.tellg() < qvminfo.codeoff)
|
||||
readByte(input);
|
||||
while (romSize < qvminfo.inscount)
|
||||
{
|
||||
n = readByte(qvmfile);
|
||||
n = readByte(input);
|
||||
w.int4 = 0;
|
||||
if ((i = opcodeParameterSize(n)))
|
||||
{
|
||||
x[0] = x[1] = x[2] = x[3] = 0;
|
||||
fread(&x, 1, i, qvmfile);
|
||||
input.readsome((char*)x, 4);
|
||||
w.uint4 = (x[0]) | (x[1] << 8) | (x[2] << 16) | (x[3] << 24);
|
||||
}
|
||||
rom[romSize].Operation = n;
|
||||
rom[romSize].Parameter = w;
|
||||
romSize++;
|
||||
}
|
||||
DEBUGTRACE("After loading code: at %d, should be %d\n", ftell(qvmfile), qvminfo.codeoff + qvminfo.codelen);
|
||||
DEBUGTRACE("After loading code: at %d, should be %d\n", input.tellg(), qvminfo.codeoff + qvminfo.codelen);
|
||||
|
||||
/* Then data segment. */
|
||||
// ram = hunk + ((romlen + 3) & ~3); /* RAM-in-hunk */
|
||||
ram = hunk;
|
||||
DEBUGTRACE("Searching for .data @ %d from %d\n", qvminfo.dataoff, ftell(qvmfile));
|
||||
while (ftell(qvmfile) < qvminfo.dataoff)
|
||||
readByte(qvmfile);
|
||||
DEBUGTRACE("Searching for .data @ %d from %d\n", qvminfo.dataoff, input.tellg());
|
||||
while (input.tellg() < qvminfo.dataoff)
|
||||
readByte(input);
|
||||
for (n = 0; n < (qvminfo.datalen / sizeof(uint1_t)); n++)
|
||||
{
|
||||
i = fread(&x, 1, sizeof(x), qvmfile);
|
||||
i = input.readsome((char*)x, sizeof(x));
|
||||
w.uint4 = (x[0]) | (x[1] << 8) | (x[2] << 16) | (x[3] << 24);
|
||||
*((word*)(ram + ramSize)) = w;
|
||||
ramSize += sizeof(word);
|
||||
@ -164,7 +165,7 @@ namespace vm
|
||||
DEBUGTRACE("Loading .lit\n");
|
||||
for (n = 0; n < (qvminfo.litlen / sizeof(uint1_t)); n++)
|
||||
{
|
||||
i = fread(&x, 1, sizeof(x), qvmfile);
|
||||
i = input.readsome((char*)x, sizeof(x));
|
||||
memcpy(&(w.uint1), &x, sizeof(x)); /* no byte-swapping. */
|
||||
*((word*)(ram + ramSize)) = w;
|
||||
ramSize += sizeof(word);
|
||||
@ -187,8 +188,8 @@ namespace vm
|
||||
{
|
||||
int stacksize = 0x10000;
|
||||
dataStack = ramSize - (stacksize / 2);
|
||||
//returnStack = ramSize;
|
||||
returnStack = dataStack+4;
|
||||
returnStack = ramSize;
|
||||
//returnStack = dataStack+4;
|
||||
RP = returnStack;
|
||||
DP = dataStack;
|
||||
}
|
||||
@ -201,6 +202,122 @@ namespace vm
|
||||
return 1;
|
||||
}
|
||||
|
||||
int VirtualMachine::LoadProgram(std::vector<char> data)
|
||||
{
|
||||
/*class vectorwrapbuf : public std::basic_streambuf<char, std::char_traits<char> >
|
||||
{
|
||||
public:
|
||||
vectorwrapbuf(std::vector<char> &vec) {
|
||||
setg(vec.data(), vec.data(), vec.data() + vec.size());
|
||||
}
|
||||
};
|
||||
vectorwrapbuf databuf(data);
|
||||
std::istream is(&databuf);
|
||||
return readProgram(is);*/
|
||||
std::stringstream ss(std::string(data.begin(), data.end()));
|
||||
return readProgram((std::istream &)ss);
|
||||
}
|
||||
|
||||
int VirtualMachine::LoadProgram(char * filename)
|
||||
{
|
||||
/*FILE * qvmfile = fopen(filename, "rb");
|
||||
qvm_header_t qvminfo;
|
||||
int i, n;
|
||||
uint1_t x[4];
|
||||
word w;
|
||||
|
||||
DEBUGTRACE("Loading file...\n");
|
||||
qvminfo.magic = readInt(qvmfile);
|
||||
if (qvminfo.magic != QVM_MAGIC)
|
||||
{
|
||||
DEBUGTRACE("Invalid magic");
|
||||
return 0;
|
||||
}
|
||||
DEBUGTRACE("Magic OK\n");
|
||||
|
||||
qvminfo.inscount = readInt(qvmfile);
|
||||
qvminfo.codeoff = readInt(qvmfile);
|
||||
qvminfo.codelen = readInt(qvmfile);
|
||||
qvminfo.dataoff = readInt(qvmfile);
|
||||
qvminfo.datalen = readInt(qvmfile);
|
||||
qvminfo.litlen = readInt(qvmfile);
|
||||
qvminfo.bsslen = readInt(qvmfile);
|
||||
|
||||
|
||||
DEBUGTRACE("Searching for .code @ %d from %d\n", qvminfo.codeoff, ftell(qvmfile));
|
||||
|
||||
rom = (Instruction*)calloc(qvminfo.inscount, sizeof(rom[0]));
|
||||
while (ftell(qvmfile) < qvminfo.codeoff)
|
||||
readByte(qvmfile);
|
||||
while (romSize < qvminfo.inscount)
|
||||
{
|
||||
n = readByte(qvmfile);
|
||||
w.int4 = 0;
|
||||
if ((i = opcodeParameterSize(n)))
|
||||
{
|
||||
x[0] = x[1] = x[2] = x[3] = 0;
|
||||
fread(&x, 1, i, qvmfile);
|
||||
w.uint4 = (x[0]) | (x[1] << 8) | (x[2] << 16) | (x[3] << 24);
|
||||
}
|
||||
rom[romSize].Operation = n;
|
||||
rom[romSize].Parameter = w;
|
||||
romSize++;
|
||||
}
|
||||
DEBUGTRACE("After loading code: at %d, should be %d\n", ftell(qvmfile), qvminfo.codeoff + qvminfo.codelen);
|
||||
|
||||
|
||||
ram = hunk;
|
||||
DEBUGTRACE("Searching for .data @ %d from %d\n", qvminfo.dataoff, ftell(qvmfile));
|
||||
while (ftell(qvmfile) < qvminfo.dataoff)
|
||||
readByte(qvmfile);
|
||||
for (n = 0; n < (qvminfo.datalen / sizeof(uint1_t)); n++)
|
||||
{
|
||||
i = fread(&x, 1, sizeof(x), qvmfile);
|
||||
w.uint4 = (x[0]) | (x[1] << 8) | (x[2] << 16) | (x[3] << 24);
|
||||
*((word*)(ram + ramSize)) = w;
|
||||
ramSize += sizeof(word);
|
||||
}
|
||||
|
||||
|
||||
DEBUGTRACE("Loading .lit\n");
|
||||
for (n = 0; n < (qvminfo.litlen / sizeof(uint1_t)); n++)
|
||||
{
|
||||
i = fread(&x, 1, sizeof(x), qvmfile);
|
||||
memcpy(&(w.uint1), &x, sizeof(x));
|
||||
*((word*)(ram + ramSize)) = w;
|
||||
ramSize += sizeof(word);
|
||||
}
|
||||
|
||||
DEBUGTRACE("Allocating .bss %d (%X) bytes\n", qvminfo.bsslen, qvminfo.bsslen);
|
||||
ramSize += qvminfo.bsslen;
|
||||
|
||||
hunkFree = hunkSize - ((ramSize * sizeof(uint1_t)) + 4);
|
||||
|
||||
DEBUGTRACE("VM hunk has %d of %d bytes free (RAM = %d B).\n", hunkFree, hunkSize, ramSize);
|
||||
if (ramSize > hunkSize)
|
||||
{
|
||||
throw OutOfMemoryException();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
int stacksize = 0x10000;
|
||||
dataStack = ramSize - (stacksize / 2);
|
||||
//returnStack = ramSize;
|
||||
returnStack = dataStack+4;
|
||||
RP = returnStack;
|
||||
DP = dataStack;
|
||||
}
|
||||
|
||||
|
||||
PC = romSize + 1;
|
||||
|
||||
ramMask = ramSize;
|
||||
|
||||
return 1;*/
|
||||
}
|
||||
|
||||
void VirtualMachine::End()
|
||||
{
|
||||
PC = romSize+1;
|
||||
|
@ -117,8 +117,9 @@ namespace vm
|
||||
};
|
||||
#undef OPDEF
|
||||
|
||||
int readByte(FILE *qvmfile);
|
||||
int readInt(FILE *qvmfile);
|
||||
int readProgram(std::istream & input);
|
||||
int readByte(std::istream & input);
|
||||
int readInt(std::istream & input);
|
||||
int opcodeParameterSize(int opcode);
|
||||
int syscall(int programCounter);
|
||||
|
||||
@ -153,6 +154,7 @@ public:
|
||||
virtual ~VirtualMachine();
|
||||
|
||||
int LoadProgram(char * filename);
|
||||
int LoadProgram(std::vector<char> fileData);
|
||||
int Run();
|
||||
int CallInterpreted(int address);
|
||||
void End();
|
||||
|
Loading…
Reference in New Issue
Block a user