1
1
forked from 0ad/0ad

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.
This commit is contained in:
Matei 2005-05-16 07:30:39 +00:00
parent 9de76bea4c
commit e41ddc4e77
12 changed files with 337 additions and 176 deletions

197
source/tools/rmgen/api.cpp Normal file
View File

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

23
source/tools/rmgen/api.h Normal file
View File

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

View File

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

View File

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

View File

@ -8,7 +8,6 @@ using namespace std;
typedef unsigned short u16;
typedef unsigned int u32;
void OutputXml(Map* m, FILE* f) {
const char* xml = "\
<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n\
@ -24,6 +23,16 @@ void OutputXml(Map* m, FILE* f) {
<Entities />\n\
<Nonentities />\n\
</Scenario>\n";
/*
<Entity>
<Template>hele_hc</Template>
<Player>0</Player>
<Position x="182.122" y="30.0133" z="426.143" />
<Orientation angle="-3.0442" />
</Entity>
*/
fprintf(f, "%s", xml);
}

View File

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

View File

@ -0,0 +1,3 @@
void SeedRand(unsigned long seed);
int RandInt(int maxVal);
float RandFloat(); // in range [0,1)

View File

@ -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 <script> <output name without extension>" << endl;
if(argc!=3 && argc!=4) {
cerr << "Usage: rmgen <script> <output name without extension> [<seed>]" << endl;
Shutdown(1);
}
FILE* scriptFile = fopen(argv[1], "r");
if(!scriptFile) {
cerr << "Cannot open " << scriptFile << endl;
Shutdown(1);
unsigned long seed;
if(argc==4) {
sscanf(argv[3], "%u", &seed);
}
string script;
char buf[1025];
while(fgets(buf, 1024, scriptFile)) {
script += buf;
else {
seed = time(0);
}
SeedRand(seed);
// Load map settings (things like game type and player info)
ostringstream out;
out << "const SEED=" << seed << ";\n";
string setts = out.str();
jsval rval;
JSBool ok = JS_EvaluateScript(cx, global, script.c_str(), script.length(), argv[1], 1, &rval);
JSBool ok = JS_EvaluateScript(cx, global, setts.c_str(), setts.length(),
"settings declaration", 1, &rval);
if(!ok) Shutdown(1);
// Load library
ExecuteFile(LIBRARY_FILE);
// Run the script
ExecuteFile(argv[1]);
if(!theMap) {
cerr << "Error:\n\tScript never called init!" << endl;
Shutdown(1);

View File

@ -5,17 +5,11 @@ extern JSRuntime *rt;
extern JSContext *cx;
extern JSObject *global;
extern class Map* theMap; // ugly
// Utility functions
void Shutdown(int status);
char* ValToString(jsval val);
jsval NewJSString(const std::string& str);
// JS API implementation
JSBool init(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);
#endif

View File

@ -19,7 +19,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../../libraries/spidermonkey/include"
AdditionalIncludeDirectories="&quot;C:\Boost\include\boost-1_32&quot;;../../../libraries/spidermonkey/include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
@ -113,12 +113,18 @@
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\api.cpp">
</File>
<File
RelativePath=".\map.cpp">
</File>
<File
RelativePath=".\output.cpp">
</File>
<File
RelativePath=".\random.cpp">
</File>
<File
RelativePath=".\rmgen.cpp">
</File>
@ -142,12 +148,18 @@
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\api.h">
</File>
<File
RelativePath=".\map.h">
</File>
<File
RelativePath=".\output.h">
</File>
<File
RelativePath=".\random.h">
</File>
<File
RelativePath=".\rmgen.h">
</File>
@ -163,9 +175,15 @@
<File
RelativePath="..\..\..\libraries\spidermonkey\lib\js32d.lib">
</File>
<File
RelativePath=".\library.js">
</File>
<File
RelativePath=".\ReadMe.txt">
</File>
<File
RelativePath=".\test.js">
</File>
</Files>
<Globals>
</Globals>

View File

@ -15,12 +15,15 @@
#include <ctime>
#include <fstream>
#include <iostream>
#include <sstream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>
#include <boost/random.hpp>
#ifdef WIN32
#define XP_WIN
#else

View File

@ -1,14 +1,9 @@
print("Hello world!\n");
const SIZE = 64;
init(32, "grass1_a", 1.5);
init(SIZE, "grass1_a", 1.5);
print(getHeight(0,0) + "\n");
for(x=0; x<3; x++) {
for(y=0; y<20; y++) {
setTerrain(x, y, "dirta");
setHeight(x, y, 4.5);
for(var x=0; x<SIZE; x++) {
for(var y=0; y<SIZE; y++) {
setTerrain(x,y, chooseRand("grass1_a","dirta","snow","road1"));
}
}
print(getHeight(0,0) + "\n");
}