From e41ddc4e779ca601211fce514af242cd83e24685 Mon Sep 17 00:00:00 2001 From: Matei Date: Mon, 16 May 2005 07:30:39 +0000 Subject: [PATCH] Added random number functions using Boost as well as a "library.js" file in which the high-level API can be implemented in JS. This was SVN commit r2313. --- source/tools/rmgen/api.cpp | 197 ++++++++++++++++++++++++++++++++ source/tools/rmgen/api.h | 23 ++++ source/tools/rmgen/library.js | 12 ++ source/tools/rmgen/map.cpp | 8 +- source/tools/rmgen/output.cpp | 11 +- source/tools/rmgen/random.cpp | 20 ++++ source/tools/rmgen/random.h | 3 + source/tools/rmgen/rmgen.cpp | 189 ++++++------------------------ source/tools/rmgen/rmgen.h | 10 +- source/tools/rmgen/rmgen.vcproj | 20 +++- source/tools/rmgen/stdafx.h | 3 + source/tools/rmgen/test.js | 17 +-- 12 files changed, 337 insertions(+), 176 deletions(-) create mode 100644 source/tools/rmgen/api.cpp create mode 100644 source/tools/rmgen/api.h create mode 100644 source/tools/rmgen/library.js create mode 100644 source/tools/rmgen/random.cpp create mode 100644 source/tools/rmgen/random.h diff --git a/source/tools/rmgen/api.cpp b/source/tools/rmgen/api.cpp new file mode 100644 index 0000000000..9daeba8127 --- /dev/null +++ b/source/tools/rmgen/api.cpp @@ -0,0 +1,197 @@ +#include "stdafx.h" +#include "api.h" +#include "rmgen.h" +#include "map.h" +#include "random.h" + +using namespace std; + +// Function specs + +JSFunctionSpec globalFunctions[] = { +// {name, native, args} + {"init", init, 3}, + {"print", print, 1}, + {"error", error, 1}, + {"getTerrain", getTerrain, 2}, + {"setTerrain", setTerrain, 3}, + {"getHeight", getHeight, 2}, + {"setHeight", setHeight, 3}, + {"randInt", randInt, 1}, + {"randFloat", randFloat, 0}, + {0} +}; + +// JS API implementation + +JSBool print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if(argc != 1) { + JS_ReportError(cx, "print: expected 1 argument but got %d", argc); + } + + cout << JS_GetStringBytes(JS_ValueToString(cx, argv[0])); + return JS_TRUE; +} + +JSBool error(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if(argc != 1) { + // wow, you made an error calling the error() function! + JS_ReportError(cx, "error: expected 1 argument but got %d", argc); + } + + JS_ReportError(cx, JS_GetStringBytes(JS_ValueToString(cx, argv[0]))); + return JS_TRUE; +} + +JSBool init(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if(argc != 3) { + JS_ReportError(cx, "init: expected 3 arguments but got %d", argc); + } + if(!JSVAL_IS_INT(argv[0])) { + JS_ReportError(cx, "init: first argument must be an integer"); + } + if(!JSVAL_IS_STRING(argv[1])) { + JS_ReportError(cx, "init: second argument must be a string"); + } + if(!JSVAL_IS_NUMBER(argv[2])) { + JS_ReportError(cx, "init: third argument must be a number"); + } + if(theMap != 0) { + JS_ReportError(cx, "init: cannot be called twice"); + } + + int size = JSVAL_TO_INT(argv[0]); + char* baseTerrain = JS_GetStringBytes(JSVAL_TO_STRING(argv[1])); + jsdouble baseHeight; + JS_ValueToNumber(cx, argv[2], &baseHeight); + + theMap = new Map(size, baseTerrain, (float) baseHeight); + return JS_TRUE; +} + +JSBool getTerrain(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if(argc != 2) { + JS_ReportError(cx, "getTerrain: expected 2 arguments but got %d", argc); + } + if(theMap == 0) { + JS_ReportError(cx, "getTerrain: cannot be called before init()"); + } + if(!JSVAL_IS_INT(argv[0])) { + JS_ReportError(cx, "getTerrain: first argument must be an integer"); + } + if(!JSVAL_IS_INT(argv[1])) { + JS_ReportError(cx, "getTerrain: second argument must be an integer"); + } + + int x = JSVAL_TO_INT(argv[0]); + int y = JSVAL_TO_INT(argv[1]); + string terrain = theMap->getTerrain(x, y); + *rval = NewJSString(terrain); + return JS_TRUE; +} + +JSBool setTerrain(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if(argc != 3) { + JS_ReportError(cx, "setTerrain: expected 3 arguments but got %d", argc); + } + if(theMap == 0) { + JS_ReportError(cx, "setTerrain: cannot be called before init()"); + } + if(!JSVAL_IS_INT(argv[0])) { + JS_ReportError(cx, "setTerrain: first argument must be an integer"); + } + if(!JSVAL_IS_INT(argv[1])) { + JS_ReportError(cx, "setTerrain: second argument must be an integer"); + } + if(!JSVAL_IS_STRING(argv[2])) { + JS_ReportError(cx, "setTerrain: third argument must be a string"); + } + + int x = JSVAL_TO_INT(argv[0]); + int y = JSVAL_TO_INT(argv[1]); + char* terrain = JS_GetStringBytes(JSVAL_TO_STRING(argv[2])); + theMap->setTerrain(x, y, terrain); + return JS_TRUE; +} + +JSBool getHeight(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if(argc != 2) { + JS_ReportError(cx, "getHeight: expected 2 arguments but got %d", argc); + } + if(theMap == 0) { + JS_ReportError(cx, "getHeight: cannot be called before init()"); + } + if(!JSVAL_IS_INT(argv[0])) { + JS_ReportError(cx, "getHeight: first argument must be an integer"); + } + if(!JSVAL_IS_INT(argv[1])) { + JS_ReportError(cx, "getHeight: second argument must be an integer"); + } + + int x = JSVAL_TO_INT(argv[0]); + int y = JSVAL_TO_INT(argv[1]); + jsdouble height = theMap->getHeight(x, y); + JS_NewDoubleValue(cx, height, rval); + return JS_TRUE; +} + +JSBool setHeight(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if(argc != 3) { + JS_ReportError(cx, "setHeight: expected 3 arguments but got %d", argc); + } + if(theMap == 0) { + JS_ReportError(cx, "setHeight: cannot be called before init()"); + } + if(!JSVAL_IS_INT(argv[0])) { + JS_ReportError(cx, "setHeight: first argument must be an integer"); + } + if(!JSVAL_IS_INT(argv[1])) { + JS_ReportError(cx, "setHeight: second argument must be an integer"); + } + if(!JSVAL_IS_NUMBER(argv[2])) { + JS_ReportError(cx, "setHeight: third argument must be a number"); + } + + int x = JSVAL_TO_INT(argv[0]); + int y = JSVAL_TO_INT(argv[1]); + jsdouble height; + JS_ValueToNumber(cx, argv[2], &height); + theMap->setHeight(x, y, (float) height); + return JS_TRUE; +} + +JSBool randInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if(argc != 1) { + JS_ReportError(cx, "randInt: expected 1 argument but got %d", argc); + } + if(!JSVAL_IS_INT(argv[0])) { + JS_ReportError(cx, "randInt: first argument must be an integer"); + } + + int x = JSVAL_TO_INT(argv[0]); + if(x<=0) { + JS_ReportError(cx, "randInt: argument must be positive"); + } + int r = RandInt(x); + *rval = INT_TO_JSVAL(r); + return JS_TRUE; +} + +JSBool randFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + if(argc != 0) { + JS_ReportError(cx, "randFloat: expected 0 arguments but got %d", argc); + } + + jsdouble r = RandFloat(); + JS_NewDoubleValue(cx, r, rval); + return JS_TRUE; +} \ No newline at end of file diff --git a/source/tools/rmgen/api.h b/source/tools/rmgen/api.h new file mode 100644 index 0000000000..372c9fe36f --- /dev/null +++ b/source/tools/rmgen/api.h @@ -0,0 +1,23 @@ +#ifndef __API_H__ +#define __API_H__ + +// Function specs +extern JSFunctionSpec globalFunctions[]; + +// JS API implementation + +JSBool init(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +JSBool error(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +JSBool print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +JSBool getTerrain(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +JSBool setTerrain(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +JSBool getHeight(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +JSBool setHeight(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +JSBool randInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +JSBool randFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); + +#endif \ No newline at end of file diff --git a/source/tools/rmgen/library.js b/source/tools/rmgen/library.js new file mode 100644 index 0000000000..456eba6a7d --- /dev/null +++ b/source/tools/rmgen/library.js @@ -0,0 +1,12 @@ +function println(x) { + print(x); + print("\n"); +} + +function chooseRand() { + if(arguments.length==0) { + error("chooseRand: requires at least 1 argument"); + } + var ar = (arguments.length==1 ? arguments[0] : arguments); + return ar[randInt(ar.length)]; +} \ No newline at end of file diff --git a/source/tools/rmgen/map.cpp b/source/tools/rmgen/map.cpp index 0a17436c86..0dea925730 100644 --- a/source/tools/rmgen/map.cpp +++ b/source/tools/rmgen/map.cpp @@ -67,20 +67,20 @@ bool Map::validH(int x, int y) { string Map::getTerrain(int x, int y) { if(!validT(x,y)) JS_ReportError(cx, "getTerrain: invalid tile position"); - else return idToName[terrain[x][y]]; + return idToName[terrain[x][y]]; } void Map::setTerrain(int x, int y, const string& t) { if(!validT(x,y)) JS_ReportError(cx, "setTerrain: invalid tile position"); - else terrain[x][y] = getId(t); + terrain[x][y] = getId(t); } float Map::getHeight(int x, int y) { if(!validH(x,y)) JS_ReportError(cx, "getHeight: invalid point position"); - else return height[x][y]; + return height[x][y]; } void Map::setHeight(int x, int y, float h) { if(!validH(x,y)) JS_ReportError(cx, "setHeight: invalid point position"); - else height[x][y] = h; + height[x][y] = h; } \ No newline at end of file diff --git a/source/tools/rmgen/output.cpp b/source/tools/rmgen/output.cpp index ba5886bfc0..3006fb321b 100644 --- a/source/tools/rmgen/output.cpp +++ b/source/tools/rmgen/output.cpp @@ -8,7 +8,6 @@ using namespace std; typedef unsigned short u16; typedef unsigned int u32; - void OutputXml(Map* m, FILE* f) { const char* xml = "\ \n\ @@ -24,6 +23,16 @@ void OutputXml(Map* m, FILE* f) { \n\ \n\ \n"; + + /* + + + 0 + + + + */ + fprintf(f, "%s", xml); } diff --git a/source/tools/rmgen/random.cpp b/source/tools/rmgen/random.cpp new file mode 100644 index 0000000000..681380ce5f --- /dev/null +++ b/source/tools/rmgen/random.cpp @@ -0,0 +1,20 @@ +#include "stdafx.h" +#include "random.h" + +using namespace boost; + +mt19937 rng; + +void SeedRand(unsigned long s) { + rng.seed(s); +} + +int RandInt(int maxVal) { + return rng()%maxVal; +} + +float RandFloat() { + return float(rng()) * (1.0f/4294967296.0f); +} + + diff --git a/source/tools/rmgen/random.h b/source/tools/rmgen/random.h new file mode 100644 index 0000000000..17cbb20bbd --- /dev/null +++ b/source/tools/rmgen/random.h @@ -0,0 +1,3 @@ +void SeedRand(unsigned long seed); +int RandInt(int maxVal); +float RandFloat(); // in range [0,1) diff --git a/source/tools/rmgen/rmgen.cpp b/source/tools/rmgen/rmgen.cpp index 601cf0ff54..7e574b1c45 100644 --- a/source/tools/rmgen/rmgen.cpp +++ b/source/tools/rmgen/rmgen.cpp @@ -2,9 +2,13 @@ #include "rmgen.h" #include "map.h" #include "output.h" +#include "api.h" +#include "random.h" using namespace std; +const char* LIBRARY_FILE = "library.js"; + JSRuntime *rt = 0; JSContext *cx = 0; JSObject *global = 0; @@ -19,17 +23,6 @@ void ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) { Shutdown(1); } -JSFunctionSpec globalFunctions[] = { -// {name, native, args} - {"init", init, 3}, - {"print", print, 1}, - {"getTerrain", getTerrain, 2}, - {"setTerrain", setTerrain, 3}, - {"getHeight", getHeight, 2}, - {"setHeight", setHeight, 3}, - {0} -}; - void InitJS() { rt = JS_NewRuntime(8L * 1024L * 1024L); cx = JS_NewContext(rt, 8192); @@ -65,165 +58,59 @@ jsval NewJSString(const string& str) { return STRING_TO_JSVAL(JS_NewString(cx, buf, str.length())); } -// JS API implementation - -JSBool print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - if(argc != 1) { - JS_ReportError(cx, "print: expected 1 argument but got %d", argc); +void ExecuteFile(const char* fileName) { + FILE* f = fopen(fileName, "r"); + if(!f) { + cerr << "Cannot open " << fileName << endl; + Shutdown(1); } - cout << JS_GetStringBytes(JS_ValueToString(cx, argv[0])); - return JS_TRUE; + string code; + char buf[1025]; + while(fgets(buf, 1024, f)) { + code += buf; + } + + jsval rval; + JSBool ok = JS_EvaluateScript(cx, global, code.c_str(), code.length(), fileName, 1, &rval); + if(!ok) Shutdown(1); } -JSBool init(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - if(argc != 3) { - JS_ReportError(cx, "init: expected 3 arguments but got %d", argc); - } - if(!JSVAL_IS_INT(argv[0])) { - JS_ReportError(cx, "init: first argument must be an integer"); - } - if(!JSVAL_IS_STRING(argv[1])) { - JS_ReportError(cx, "init: second argument must be a string"); - } - if(!JSVAL_IS_NUMBER(argv[2])) { - JS_ReportError(cx, "init: third argument must be a number"); - } - if(theMap != 0) { - JS_ReportError(cx, "init: cannot be called twice"); - } - - int size = JSVAL_TO_INT(argv[0]); - char* baseTerrain = JS_GetStringBytes(JSVAL_TO_STRING(argv[1])); - jsdouble baseHeight; - JS_ValueToNumber(cx, argv[2], &baseHeight); - - theMap = new Map(size, baseTerrain, (float) baseHeight); - return JS_TRUE; -} - -JSBool getTerrain(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - if(argc != 2) { - JS_ReportError(cx, "getTerrain: expected 2 arguments but got %d", argc); - } - if(theMap == 0) { - JS_ReportError(cx, "getTerrain: cannot be called before init()"); - } - if(!JSVAL_IS_INT(argv[0])) { - JS_ReportError(cx, "getTerrain: first argument must be an integer"); - } - if(!JSVAL_IS_INT(argv[1])) { - JS_ReportError(cx, "getTerrain: second argument must be an integer"); - } - - int x = JSVAL_TO_INT(argv[0]); - int y = JSVAL_TO_INT(argv[1]); - string terrain = theMap->getTerrain(x, y); - *rval = NewJSString(terrain); - return JS_TRUE; -} - -JSBool setTerrain(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - if(argc != 3) { - JS_ReportError(cx, "setTerrain: expected 3 arguments but got %d", argc); - } - if(theMap == 0) { - JS_ReportError(cx, "setTerrain: cannot be called before init()"); - } - if(!JSVAL_IS_INT(argv[0])) { - JS_ReportError(cx, "setTerrain: first argument must be an integer"); - } - if(!JSVAL_IS_INT(argv[1])) { - JS_ReportError(cx, "setTerrain: second argument must be an integer"); - } - if(!JSVAL_IS_STRING(argv[2])) { - JS_ReportError(cx, "setTerrain: third argument must be a string"); - } - - int x = JSVAL_TO_INT(argv[0]); - int y = JSVAL_TO_INT(argv[1]); - char* terrain = JS_GetStringBytes(JSVAL_TO_STRING(argv[2])); - theMap->setTerrain(x, y, terrain); - return JS_TRUE; -} - -JSBool getHeight(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - if(argc != 2) { - JS_ReportError(cx, "getHeight: expected 2 arguments but got %d", argc); - } - if(theMap == 0) { - JS_ReportError(cx, "getHeight: cannot be called before init()"); - } - if(!JSVAL_IS_INT(argv[0])) { - JS_ReportError(cx, "getHeight: first argument must be an integer"); - } - if(!JSVAL_IS_INT(argv[1])) { - JS_ReportError(cx, "getHeight: second argument must be an integer"); - } - - int x = JSVAL_TO_INT(argv[0]); - int y = JSVAL_TO_INT(argv[1]); - jsdouble height = theMap->getHeight(x, y); - JS_NewDoubleValue(cx, height, rval); - return JS_TRUE; -} - -JSBool setHeight(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - if(argc != 3) { - JS_ReportError(cx, "setHeight: expected 3 arguments but got %d", argc); - } - if(theMap == 0) { - JS_ReportError(cx, "setHeight: cannot be called before init()"); - } - if(!JSVAL_IS_INT(argv[0])) { - JS_ReportError(cx, "setHeight: first argument must be an integer"); - } - if(!JSVAL_IS_INT(argv[1])) { - JS_ReportError(cx, "setHeight: second argument must be an integer"); - } - if(!JSVAL_IS_NUMBER(argv[2])) { - JS_ReportError(cx, "setHeight: third argument must be a number"); - } - - int x = JSVAL_TO_INT(argv[0]); - int y = JSVAL_TO_INT(argv[1]); - jsdouble height; - JS_ValueToNumber(cx, argv[2], &height); - theMap->setHeight(x, y, (float) height); - return JS_TRUE; -} // Program entry point int main(int argc, char* argv[]) { InitJS(); - if(argc!=3) { - cerr << "Usage: rmgen