script_controller.cpp

Go to the documentation of this file.
00001 /* $Id: script_controller.cpp 23632 2011-12-19 21:05:25Z truebrain $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "../../stdafx.h"
00013 #include "../../string_func.h"
00014 #include "../../script/squirrel.hpp"
00015 #include "../../rev.h"
00016 
00017 #include "script_controller.hpp"
00018 #include "../script_fatalerror.hpp"
00019 #include "../script_info.hpp"
00020 #include "../script_instance.hpp"
00021 #include "../script_suspend.hpp"
00022 #include "script_log.hpp"
00023 
00024 /* static */ void ScriptController::SetCommandDelay(int ticks)
00025 {
00026   if (ticks <= 0) return;
00027   ScriptObject::SetDoCommandDelay(ticks);
00028 }
00029 
00030 /* static */ void ScriptController::Sleep(int ticks)
00031 {
00032   if (!ScriptObject::CanSuspend()) {
00033     throw Script_FatalError("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.");
00034   }
00035 
00036   if (ticks <= 0) {
00037     ScriptLog::Warning("Sleep() value should be > 0. Assuming value 1.");
00038     ticks = 1;
00039   }
00040 
00041   throw Script_Suspend(ticks, NULL);
00042 }
00043 
00044 /* static */ void ScriptController::Print(bool error_msg, const char *message)
00045 {
00046   ScriptLog::Log(error_msg ? ScriptLog::LOG_SQ_ERROR : ScriptLog::LOG_SQ_INFO, message);
00047 }
00048 
00049 ScriptController::ScriptController(CompanyID company) :
00050   ticks(0),
00051   loaded_library_count(0)
00052 {
00053   ScriptObject::SetCompany(company);
00054 }
00055 
00056 ScriptController::~ScriptController()
00057 {
00058   for (LoadedLibraryList::iterator iter = this->loaded_library.begin(); iter != this->loaded_library.end(); iter++) {
00059     free((*iter).second);
00060     free((*iter).first);
00061   }
00062 
00063   this->loaded_library.clear();
00064 }
00065 
00066 /* static */ uint ScriptController::GetTick()
00067 {
00068   return ScriptObject::GetActiveInstance()->GetController()->ticks;
00069 }
00070 
00071 /* static */ int ScriptController::GetOpsTillSuspend()
00072 {
00073   return ScriptObject::GetActiveInstance()->GetOpsTillSuspend();
00074 }
00075 
00076 /* static */ int ScriptController::GetSetting(const char *name)
00077 {
00078   return ScriptObject::GetActiveInstance()->GetSetting(name);
00079 }
00080 
00081 /* static */ uint ScriptController::GetVersion()
00082 {
00083   return _openttd_newgrf_version;
00084 }
00085 
00086 /* static */ HSQOBJECT ScriptController::Import(const char *library, const char *class_name, int version)
00087 {
00088   ScriptController *controller = ScriptObject::GetActiveInstance()->GetController();
00089   Squirrel *engine = ScriptObject::GetActiveInstance()->engine;
00090   HSQUIRRELVM vm = engine->GetVM();
00091 
00092   /* Internally we store libraries as 'library.version' */
00093   char library_name[1024];
00094   snprintf(library_name, sizeof(library_name), "%s.%d", library, version);
00095   strtolower(library_name);
00096 
00097   ScriptInfo *lib = ScriptObject::GetActiveInstance()->FindLibrary(library, version);
00098   if (lib == NULL) {
00099     char error[1024];
00100     snprintf(error, sizeof(error), "couldn't find library '%s' with version %d", library, version);
00101     throw sq_throwerror(vm, OTTD2SQ(error));
00102   }
00103 
00104   /* Get the current table/class we belong to */
00105   HSQOBJECT parent;
00106   sq_getstackobj(vm, 1, &parent);
00107 
00108   char fake_class[1024];
00109 
00110   LoadedLibraryList::iterator iter = controller->loaded_library.find(library_name);
00111   if (iter != controller->loaded_library.end()) {
00112     ttd_strlcpy(fake_class, (*iter).second, sizeof(fake_class));
00113   } else {
00114     int next_number = ++controller->loaded_library_count;
00115 
00116     /* Create a new fake internal name */
00117     snprintf(fake_class, sizeof(fake_class), "_internalNA%d", next_number);
00118 
00119     /* Load the library in a 'fake' namespace, so we can link it to the name the user requested */
00120     sq_pushroottable(vm);
00121     sq_pushstring(vm, OTTD2SQ(fake_class), -1);
00122     sq_newclass(vm, SQFalse);
00123     /* Load the library */
00124     if (!engine->LoadScript(vm, lib->GetMainScript(), false)) {
00125       char error[1024];
00126       snprintf(error, sizeof(error), "there was a compile error when importing '%s' version %d", library, version);
00127       throw sq_throwerror(vm, OTTD2SQ(error));
00128     }
00129     /* Create the fake class */
00130     sq_newslot(vm, -3, SQFalse);
00131     sq_pop(vm, 1);
00132 
00133     controller->loaded_library[strdup(library_name)] = strdup(fake_class);
00134   }
00135 
00136   /* Find the real class inside the fake class (like 'sets.Vector') */
00137   sq_pushroottable(vm);
00138   sq_pushstring(vm, OTTD2SQ(fake_class), -1);
00139   if (SQ_FAILED(sq_get(vm, -2))) {
00140     throw sq_throwerror(vm, _SC("internal error assigning library class"));
00141   }
00142   sq_pushstring(vm, OTTD2SQ(lib->GetInstanceName()), -1);
00143   if (SQ_FAILED(sq_get(vm, -2))) {
00144     char error[1024];
00145     snprintf(error, sizeof(error), "unable to find class '%s' in the library '%s' version %d", lib->GetInstanceName(), library, version);
00146     throw sq_throwerror(vm, OTTD2SQ(error));
00147   }
00148   HSQOBJECT obj;
00149   sq_getstackobj(vm, -1, &obj);
00150   sq_pop(vm, 3);
00151 
00152   if (StrEmpty(class_name)) return obj;
00153 
00154   /* Now link the name the user wanted to our 'fake' class */
00155   sq_pushobject(vm, parent);
00156   sq_pushstring(vm, OTTD2SQ(class_name), -1);
00157   sq_pushobject(vm, obj);
00158   sq_newclass(vm, SQTrue);
00159   sq_newslot(vm, -3, SQFalse);
00160   sq_pop(vm, 1);
00161 
00162   return obj;
00163 }