(svn r9185) [NoAI] -Codechange: split up the squirrel code so we have SquirrelCore
and the rest. The first isn't depending of any AI code. First step in
generalizing squirrel-code.
--- a/projects/openttd.vcproj Wed Mar 14 23:01:30 2007 +0000
+++ b/projects/openttd.vcproj Thu Mar 15 00:01:33 2007 +0000
@@ -960,6 +960,12 @@
RelativePath=".\..\src\ai\squirrel\convert.hpp">
</File>
<File
+ RelativePath=".\..\src\ai\squirrel\core.cpp">
+ </File>
+ <File
+ RelativePath=".\..\src\ai\squirrel\core.hpp">
+ </File>
+ <File
RelativePath=".\..\src\ai\squirrel\squirrel.cpp">
</File>
<File
--- a/projects/openttd_vs80.vcproj Wed Mar 14 23:01:30 2007 +0000
+++ b/projects/openttd_vs80.vcproj Thu Mar 15 00:01:33 2007 +0000
@@ -1500,6 +1500,14 @@
>
</File>
<File
+ RelativePath=".\..\src\ai\squirrel\core.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\ai\squirrel\core.hpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\ai\squirrel\squirrel.cpp"
>
</File>
--- a/source.list Wed Mar 14 23:01:30 2007 +0000
+++ b/source.list Thu Mar 15 00:01:33 2007 +0000
@@ -291,6 +291,8 @@
ai/NoAI/NoAI.hpp
ai/squirrel/convert.cpp
ai/squirrel/convert.hpp
+ai/squirrel/core.cpp
+ai/squirrel/core.hpp
ai/squirrel/squirrel.cpp
ai/squirrel/squirrel.hpp
ai/squirrel/squirrel_class.hpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/squirrel/core.cpp Thu Mar 15 00:01:33 2007 +0000
@@ -0,0 +1,171 @@
+/* $Id$ */
+
+/** @file core.hpp the implementation of the SquirrelCore class. It handles all Squirrel-stuff and gives a nice API back to work with. */
+
+#ifdef _UNICODE
+/* Disable unicode for squirrel to allow compilation with MINGW
+ * and simplify coding for WIN32 (squirrel headers miss a lot of "string" functions)
+ */
+#undef _UNICODE
+#endif
+#include <squirrel.h>
+#include <sqstdio.h>
+#include <stdarg.h>
+#include "../../stdafx.h"
+#include "../../debug.h"
+#include "core.hpp"
+
+void SquirrelCore::CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column)
+{
+#ifdef _SQ64
+ printf("Error %s:%ld/%ld: %s\n", source, line, column, desc);
+#else
+ printf("Error %s:%d/%d: %s\n", source, line, column, desc);
+#endif
+}
+
+void SquirrelCore::RunError(HSQUIRRELVM vm, const char *error)
+{
+ printf("%s\n", error);
+}
+
+SQInteger SquirrelCore::_RunError(HSQUIRRELVM vm)
+{
+ const SQChar *sErr = 0;
+
+ if (sq_gettop(vm) >= 1) {
+ if (SQ_SUCCEEDED(sq_getstring(vm, -1, &sErr))) {
+ SquirrelCore::RunError(vm, sErr);
+ }
+ }
+
+ SquirrelCore::RunError(vm, "Unknown error");
+ return 0;
+}
+
+void SquirrelCore::PrintFunc(HSQUIRRELVM vm, const SQChar *s, ...)
+{
+ va_list arglist;
+ va_start(arglist, s);
+ vprintf(s, arglist);
+ va_end(arglist);
+ printf("\n");
+}
+
+void SquirrelCore::AddMethod(const char *method_name, SQFUNCTION proc, uint nparam, const char *params)
+{
+ sq_pushstring(this->vm, method_name, -1);
+ sq_newclosure(this->vm, proc, 0);
+ sq_setparamscheck(this->vm, nparam, params);
+ sq_setnativeclosurename(this->vm, -1, method_name);
+ sq_createslot(this->vm, -3);
+}
+
+void SquirrelCore::AddMethod(const char *method_name, SQFUNCTION proc)
+{
+ sq_pushstring(this->vm, method_name, -1);
+ sq_newclosure(this->vm, proc, 0);
+ sq_setnativeclosurename(this->vm, -1, method_name);
+ sq_createslot(this->vm, -3);
+}
+
+void SquirrelCore::AddClassBegin(const char *class_name)
+{
+ sq_pushroottable(this->vm);
+ sq_pushstring(this->vm, class_name, -1);
+ sq_newclass(this->vm, SQFalse);
+}
+
+void SquirrelCore::AddClassEnd()
+{
+ sq_createslot(vm, -3);
+}
+
+void SquirrelCore::CallMethod(HSQOBJECT instance, const char *method_name)
+{
+ /* Store the current top */
+ int top = sq_gettop(this->vm);
+ /* Go to the instance-root */
+ sq_pushobject(this->vm, instance);
+ /* Find the function-name inside the script */
+ sq_pushstring(this->vm, method_name, -1);
+ if (SQ_FAILED(sq_get(this->vm, -2))) {
+ DEBUG(misc, 0, "[squirrel] Could not find '%s' in the class", method_name);
+ sq_settop(this->vm, top);
+ return;
+ }
+ /* Call the method */
+ sq_pushobject(this->vm, instance);
+ sq_call(this->vm, 1, 0, 0);
+ /* Reset the top */
+ sq_settop(this->vm, top);
+}
+
+bool SquirrelCore::CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance)
+{
+ int oldtop = sq_gettop(this->vm);
+
+ /* First, find the class */
+ sq_pushroottable(this->vm);
+ sq_pushstring(this->vm, class_name, -1);
+ if (SQ_FAILED(sq_get(this->vm, -2))) {
+ DEBUG(misc, 0, "[squirrel] Failed to find class by the name '%s'", class_name);
+ sq_settop(this->vm, oldtop);
+ return false;
+ }
+
+ /* Create the instance */
+ if (SQ_FAILED(sq_createinstance(this->vm, -1))) {
+ DEBUG(misc, 0, "[squirrel] Failed to create instance for class '%s'", class_name);
+ sq_settop(this->vm, oldtop);
+ return false;
+ }
+
+ if (instance != NULL) {
+ /* Find our instance */
+ sq_getstackobj(this->vm, -1, instance);
+ /* Add a reference to it, so it survives for ever */
+ sq_addref(this->vm, instance);
+ }
+ /* Store it in the class */
+ sq_setinstanceup(this->vm, -1, real_instance);
+
+ /* Reset the top */
+ sq_settop(this->vm, oldtop);
+
+ return true;
+}
+
+SquirrelCore::SquirrelCore()
+{
+ this->vm = sq_open(1024);
+
+ /* Handle compile-errors ourself, so we can display it nicely */
+ sq_setcompilererrorhandler(this->vm, &SquirrelCore::CompileError);
+ sq_notifyallexceptions(this->vm, SQTrue);
+ /* Set a good print-function */
+ sq_setprintfunc(this->vm, &SquirrelCore::PrintFunc);
+ /* Handle runtime-errors ourself, so we can display it nicely */
+ sq_newclosure(this->vm, &SquirrelCore::_RunError, 0);
+ sq_seterrorhandler(this->vm);
+
+ sq_pushroottable(this->vm);
+}
+
+bool SquirrelCore::LoadScript(const char *script)
+{
+ /* Load and run the script */
+ if (SQ_FAILED(sqstd_dofile(this->vm, script, SQFalse, SQTrue))) {
+ DEBUG(misc, 0, "[squirrel] Failed to compile '%s'", script);
+ return false;
+ }
+
+ return true;
+}
+
+SquirrelCore::~SquirrelCore()
+{
+ /* Clean up the stuff */
+ sq_pop(this->vm, 1);
+ sq_close(this->vm);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ai/squirrel/core.hpp Thu Mar 15 00:01:33 2007 +0000
@@ -0,0 +1,81 @@
+/* $Id$ */
+
+/** @file core.hpp defines the SquirrelCore class */
+
+#ifndef SQUIRREL_CORE_HPP
+#define SQUIRREL_CORE_HPP
+
+class SquirrelCore {
+private:
+ HSQUIRRELVM vm; ///< The VirtualMachine instnace for squirrel
+
+ /**
+ * The internal RunError handler. It looks up the real error and calls RunError with it.
+ */
+ static SQInteger _RunError(HSQUIRRELVM vm);
+
+protected:
+ /**
+ * The CompileError handler.
+ */
+ static void CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column);
+
+ /**
+ * The RunError handler.
+ */
+ static void RunError(HSQUIRRELVM vm, const char *error);
+
+ /**
+ * If a user runs 'print' inside a script, this function gets the params.
+ */
+ static void PrintFunc(HSQUIRRELVM vm, const SQChar *s, ...);
+
+public:
+ SquirrelCore();
+ ~SquirrelCore();
+
+ /**
+ * Load a script.
+ * @param script The full script-name to load.
+ * @return False if loading failed.
+ */
+ bool LoadScript(const char *script);
+
+ /**
+ * Adds a function to the stack. Depending on the current state this means
+ * either a method or a global function.
+ */
+ void AddMethod(const char *method_name, SQFUNCTION proc, uint nparam, const char *params);
+ void AddMethod(const char *method_name, SQFUNCTION proc);
+
+ /**
+ * Adds a class to the global scope. Make sure to call AddClassEnd when you
+ * are done adding methods.
+ */
+ void AddClassBegin(const char *class_name);
+
+ /**
+ * Finishes adding a class to the global scope. If this isn't called, no
+ * class is really created.
+ */
+ void AddClassEnd();
+
+ /**
+ * Call a method of an instance.
+ */
+ void CallMethod(HSQOBJECT instance, const char *method_name);
+
+ /**
+ * Creates a class instance.
+ * @param class_name The name of the class of which we create an instance.
+ * @param real_instance The instance to the real class, if it represents a real class.
+ * @param instance Returning value with the pointer to the instance.
+ * @return False if creating failed.
+ */
+ bool CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance);
+
+ HSQUIRRELVM GetVM() { return this->vm; }
+ static bool GetInstance(HSQUIRRELVM vm, SQUserPointer *ptr) { if (SQ_FAILED(sq_getinstanceup(vm, 1, ptr, 0))) return false; return true; }
+};
+
+#endif /* SQUIRREL_CORE_HPP */
--- a/src/ai/squirrel/squirrel.cpp Wed Mar 14 23:01:30 2007 +0000
+++ b/src/ai/squirrel/squirrel.cpp Thu Mar 15 00:01:33 2007 +0000
@@ -5,7 +5,6 @@
#include "squirrel.hpp"
#include <sqstdio.h>
#include <sqstdaux.h>
-#include <stdarg.h>
#include "../../debug.h"
#define SQUIRREL_CLASS
@@ -16,48 +15,6 @@
#include "../core/ai_map.hpp"
#include "../core/ai_town.hpp"
-/**
- * Here we handle errors that come from squirrel.
- */
-static void Squirrel_CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column)
-{
-#ifdef _SQ64
- printf("Error %s:%ld/%ld: %s\n", source, line, column, desc);
-#else
- printf("Error %s:%d/%d: %s\n", source, line, column, desc);
-#endif
-}
-
-/**
- * Here we handle run-time errors that come from squirrel.
- */
-static SQInteger Squirrel_RunError(HSQUIRRELVM vm)
-{
- const SQChar *sErr = 0;
-
- if (sq_gettop(vm) >= 1) {
- if (SQ_SUCCEEDED(sq_getstring(vm, -1, &sErr))) {
- printf("%s\n", sErr);
- } else {
- printf("Unknown error\n");
- }
- }
-
- return 0;
-}
-
-/**
- * Here we handle 'print' command within squirrel script.
- */
-static void Squirrel_PrintFunc(HSQUIRRELVM vm, const SQChar *s, ...)
-{
- va_list arglist;
- va_start(arglist, s);
- vprintf(s, arglist);
- va_end(arglist);
- printf("\n");
-}
-
SQInteger Squirrel::SQDestructor(SQUserPointer p, SQInteger size)
{
return 1;
@@ -71,52 +28,18 @@
SQInteger Squirrel::SQGetTick(HSQUIRRELVM vm)
{
- SQUserPointer ptr;
+ SQUserPointer self;
- /* Find the 'self' pointer */
- if (SQ_FAILED(sq_getinstanceup(vm, 1, &ptr, 0))) {
- DEBUG(ai, 0, "[squirrel] Failed to find the instance-pointer");
+ if (!SquirrelCore::GetInstance(vm, &self)) {
+ DEBUG(ai, 0, "[squirrel] Failed to find instance pointer");
return SQ_ERROR;
}
/* Return the value */
- sq_pushinteger(vm, ((Squirrel *)ptr)->GetTick());
+ sq_pushinteger(vm, ((Squirrel *)self)->GetTick());
return 1;
}
-bool Squirrel::SQCreateClass(const char *classname)
-{
- int oldtop = sq_gettop(this->vm);
-
- /* First, find the class */
- sq_pushroottable(this->vm);
- sq_pushstring(this->vm, classname, -1);
- sq_get(this->vm, -2);
-
- /* Create the instance */
- if (SQ_FAILED(sq_createinstance(this->vm, -1))) {
- DEBUG(ai, 0, "[squirrel] Failed to create instance for class '%s'", classname);
- sq_settop(this->vm, oldtop);
- return false;
- }
-
- /* Find our instance */
- sq_getstackobj(this->vm, -1, &this->SQ_instance);
- /* Add a reference to it, so it survives for ever */
- sq_addref(this->vm, &this->SQ_instance);
- /* Store it in the class */
- sq_setinstanceup(this->vm, -1, this);
- /* Make sure we get called when the AI is destroyed */
- sq_setreleasehook(this->vm, -1, &Squirrel::SQDestructor);
-
- /* Reset the top */
- sq_settop(this->vm, oldtop);
-
- DEBUG(ai, 1, "[squirrel] Created an instance of class '%s' with pointer '%p'", classname, this->SQ_instance._unVal.pUserPointer);
-
- return true;
-}
-
SQInteger Squirrel::SQRegisterAI(HSQUIRRELVM vm)
{
const SQChar *classname = NULL;
@@ -142,111 +65,56 @@
sq_setforeignptr(vm, NULL);
/* Create the new class */
- if (!self->SQCreateClass(classname)) {
+ if (!self->core->CreateClassInstance(classname, self, &self->SQ_instance)) {
return SQ_ERROR;
}
return 0;
}
-inline void Squirrel::SQAddMethod(const char *name, SQFUNCTION proc, uint nparam, const char *params)
-{
- sq_pushstring(this->vm, name, -1);
- sq_newclosure(this->vm, proc, 0);
- sq_setparamscheck(this->vm, nparam, params);
- sq_setnativeclosurename(this->vm, -1, name);
- sq_createslot(this->vm, -3);
-}
-
void Squirrel::RegisterClasses()
{
- SQInteger top = sq_gettop(this->vm);
+ HSQUIRRELVM vm = this->core->GetVM();
+ SQInteger top = sq_gettop(vm);
/* Store 'this' so we can find it back later on */
- sq_setforeignptr(this->vm, this);
+ sq_setforeignptr(vm, this);
- /* Create AIController class (the 'main' of it all) */
- sq_pushroottable(this->vm);
- sq_pushstring(this->vm, "AIController", -1);
- sq_newclass(this->vm, SQFalse);
+ this->core->AddClassBegin("AIController");
/* Create a constructor, so we can assign the right 'this' */
- this->SQAddMethod("constructor", &Squirrel::SQConstructor, 1, "x");
+ this->core->AddMethod("constructor", &Squirrel::SQConstructor, 1, "x");
/* Assign other functions as AIController won't be done via the normal way */
- this->SQAddMethod("GetTick", &Squirrel::SQGetTick, 1, "x");
+ this->core->AddMethod("GetTick", &Squirrel::SQGetTick, 1, "x");
- /* Finally really create the class */
- sq_createslot(this->vm, -3);
+ this->core->AddClassEnd();
/* Register the 'RegisterAI()' function */
- sq_pushroottable(this->vm);
- this->SQAddMethod("RegisterAI", &Squirrel::SQRegisterAI, 2, "ts");
+ sq_pushroottable(vm);
+ this->core->AddMethod("RegisterAI", &Squirrel::SQRegisterAI, 2, "ts");
- SQAIBaseRegister(this->vm);
- SQAICompanyRegister(this->vm);
- SQAIMapRegister(this->vm);
- SQAITownRegister(this->vm);
+ SQAIBaseRegister(vm);
+ SQAICompanyRegister(vm);
+ SQAIMapRegister(vm);
+ SQAITownRegister(vm);
/* Reset top */
- sq_settop(this->vm, top);
+ sq_settop(vm, top);
}
-Squirrel::Squirrel(const char *script_dir)
+Squirrel::Squirrel(const char *script)
{
- char filename[1024];
-
- this->vm = sq_open(1024);
-
- /* Handle compile-errors ourself, so we can display it nicely */
- sq_setcompilererrorhandler(this->vm, Squirrel_CompileError);
- sq_notifyallexceptions(this->vm, SQTrue);
- /* Set a good print-function */
- sq_setprintfunc(this->vm, Squirrel_PrintFunc);
- /* Handle runtime-errors ourself, so we can display it nicely */
- sq_newclosure(this->vm, &Squirrel_RunError, 0);
- sq_seterrorhandler(this->vm);
-
- /* TODO -- This is ugly! */
- strcpy(filename, "ai/");
- strcat(filename, script_dir);
- strcat(filename, PATHSEP);
- strcat(filename, "main.nut");
-
- DEBUG(ai, 1, "[squirrel] Starting AI with script in '%s'", filename);
-
- sq_pushroottable(this->vm);
+ this->core = new SquirrelCore();
this->RegisterClasses();
-
- /* Load and run the script */
- if (SQ_FAILED(sqstd_dofile(this->vm, filename, SQFalse, SQTrue))) {
- DEBUG(ai, 0, "[squirrel] Failed to compile '%s'", filename);
- return;
- }
+ this->core->LoadScript(script);
}
Squirrel::~Squirrel()
{
- /* Clean up the stuff */
- sq_pop(this->vm, 1);
- sq_close(this->vm);
+ delete this->core;
}
/* virtual */ void Squirrel::GameLoop()
{
- /* Store the current top */
- int top = sq_gettop(this->vm);
- /* Go to the instance-root */
- sq_pushobject(this->vm, this->SQ_instance);
- /* Find the function-name inside the script */
- sq_pushstring(this->vm, "GameLoop", -1);
- if (SQ_FAILED(sq_get(this->vm, -2))) {
- DEBUG(ai, 0, "[squirrel] Could not find 'GameLoop' in the AIController class");
- sq_settop(this->vm, top);
- return;
- }
- /* Call the method */
- sq_pushobject(this->vm, this->SQ_instance);
- sq_call(this->vm, 1, 0, 0);
- /* Reset the top */
- sq_settop(this->vm, top);
+ this->core->CallMethod(this->SQ_instance, "GameLoop");
}
--- a/src/ai/squirrel/squirrel.hpp Wed Mar 14 23:01:30 2007 +0000
+++ b/src/ai/squirrel/squirrel.hpp Thu Mar 15 00:01:33 2007 +0000
@@ -13,16 +13,12 @@
#undef _UNICODE
#endif
#include <squirrel.h>
+#include "core.hpp"
class Squirrel: public AIController {
private:
- HSQUIRRELVM vm; ///< The Virtual Machine for squirrel
HSQOBJECT SQ_instance; ///< The internal instance of squirrel
-
- /**
- * Add a single method to a class (in creation) in Squirrel.
- */
- void SQAddMethod(const char *name, SQFUNCTION proc, uint nparam, const char *params);
+ SquirrelCore *core; ///< The SquirrelCore (engine)
/**
* Registers all our classes, so it can be used from Squirrel.