Fixes invalid text pasting, Adds API to VM, allow program loading in Lua and assigning to update function

This commit is contained in:
Simon Robertshaw 2012-09-14 22:03:14 +01:00
parent 685be24ffa
commit 486b34ebe5
7 changed files with 276 additions and 40 deletions

View File

@ -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)
{

View File

@ -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;

View File

@ -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();

View File

@ -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() {};
};
}

View File

@ -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)

View File

@ -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;

View File

@ -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();