From 4320b8296ba1b65feb8181e24ef2fbdf8867ba78 Mon Sep 17 00:00:00 2001 From: fgenesis Date: Tue, 3 Jan 2012 04:38:28 +0100 Subject: [PATCH] Add a safe pointer model to ScriptInterface, additional bug/crash fixes. This commit introduces pointer checks to various functions; so that entity_* will no longer crash or produce weird results if passed a Node pointer, etc. The checks are disabled by default, but can be enabled in ScriptInterface.cpp. Fixed possible crashes in a few more functions due to missing NULL-checks. There was a "feature" in the single Lua state that it would keep globals intact until the game was quit. That made any globals from mods "leak" into the game or other mods. Now it resets the Lua state when a mod is loaded or closed. --- Aquaria/Beam.cpp | 1 + Aquaria/CollideEntity.cpp | 1 + Aquaria/Entity.cpp | 1 + Aquaria/Entity.h | 3 +- Aquaria/Ingredient.cpp | 1 + Aquaria/Mod.cpp | 4 +- Aquaria/Path.cpp | 1 + Aquaria/Path.h | 3 +- Aquaria/ScriptInterface.cpp | 230 +++++++++++++++++++++--------------- Aquaria/ScriptInterface.h | 2 + Aquaria/ScriptedEntity.cpp | 3 +- Aquaria/Shot.cpp | 1 + Aquaria/Shot.h | 5 +- Aquaria/Web.cpp | 1 + Aquaria/Web.h | 2 +- BBGE/Quad.cpp | 1 + BBGE/Quad.h | 3 +- BBGE/ScriptObject.cpp | 60 ++++++++++ BBGE/ScriptObject.h | 74 ++++++++++++ BBGE/SkeletalSprite.cpp | 1 + BBGE/SkeletalSprite.h | 2 +- CMakeLists.txt | 1 + 22 files changed, 298 insertions(+), 103 deletions(-) create mode 100644 BBGE/ScriptObject.cpp create mode 100644 BBGE/ScriptObject.h diff --git a/Aquaria/Beam.cpp b/Aquaria/Beam.cpp index 20cfde2..de0db20 100644 --- a/Aquaria/Beam.cpp +++ b/Aquaria/Beam.cpp @@ -28,6 +28,7 @@ Beam::Beams Beam::beams; Beam::Beam(Vector pos, float angle) : Quad() { + addType(SCO_BEAM); cull = false; trace(); //rotation.z = angle; diff --git a/Aquaria/CollideEntity.cpp b/Aquaria/CollideEntity.cpp index c35aba6..313239b 100644 --- a/Aquaria/CollideEntity.cpp +++ b/Aquaria/CollideEntity.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. CollideEntity::CollideEntity() : Entity() { + addType(SCO_COLLIDE_ENTITY); this->canBeTargetedByAvatar = true; weight = 0; bounceAmount = 0.5f; diff --git a/Aquaria/Entity.cpp b/Aquaria/Entity.cpp index 7195779..21d3bc2 100644 --- a/Aquaria/Entity.cpp +++ b/Aquaria/Entity.cpp @@ -167,6 +167,7 @@ bool Entity::canSetBoneLock() Entity::Entity() : StateMachine(), DFSprite() { + addType(SCO_ENTITY); poison = 0.0f; calledEntityDied = false; wasUnderWater = true; diff --git a/Aquaria/Entity.h b/Aquaria/Entity.h index 6dd955d..f59f00e 100644 --- a/Aquaria/Entity.h +++ b/Aquaria/Entity.h @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../BBGE/StateMachine.h" #include "../ExternalLibs/tinyxml.h" #include "../BBGE/SkeletalSprite.h" +#include "../BBGE/ScriptObject.h" #include "DSQ.h" #include "Path.h" @@ -193,7 +194,7 @@ enum BounceType BOUNCE_REAL = 1 }; -class Entity : public StateMachine, public DFSprite +class Entity : public ScriptObject, public DFSprite, public StateMachine { public: Entity(); diff --git a/Aquaria/Ingredient.cpp b/Aquaria/Ingredient.cpp index 93ac9fe..8647b9e 100644 --- a/Aquaria/Ingredient.cpp +++ b/Aquaria/Ingredient.cpp @@ -40,6 +40,7 @@ bool IngredientData::hasIET(IngredientEffectType iet) Ingredient::Ingredient(const Vector &pos, IngredientData *data, int amount) : Entity(), data(data), amount(amount), gone(false), used(false) { + addType(SCO_INGREDIENT); entityType = ET_INGREDIENT; position = pos; lifeSpan = 30; diff --git a/Aquaria/Mod.cpp b/Aquaria/Mod.cpp index 2ec40bc..6daf2f8 100644 --- a/Aquaria/Mod.cpp +++ b/Aquaria/Mod.cpp @@ -196,7 +196,8 @@ void Mod::applyStart() core->clearGarbage(); recache(); dsq->continuity.reset(); - + dsq->scriptInterface.reset(); + // load the mod-init.lua file // which is in the root of the mod's folder // e.g. _mods/recachetest/ @@ -265,6 +266,7 @@ void Mod::stop() core->settings.runInBackground = false; debugMenu = false; shuttingDown = false; + dsq->scriptInterface.reset(); } void Mod::update(float dt) diff --git a/Aquaria/Path.cpp b/Aquaria/Path.cpp index 710d9af..c0e4cf4 100644 --- a/Aquaria/Path.cpp +++ b/Aquaria/Path.cpp @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Path::Path() { + addType(SCO_PATH); localWarpType = LOCALWARP_NONE; effectOn = true; time = 0; diff --git a/Aquaria/Path.h b/Aquaria/Path.h index 2e9b94d..d863d89 100644 --- a/Aquaria/Path.h +++ b/Aquaria/Path.h @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../BBGE/Base.h" #include "../BBGE/Particles.h" +#include "../BBGE/ScriptObject.h" #include "ScriptInterface.h" #undef PATH_MAX // May be set by a system header. @@ -67,7 +68,7 @@ enum PathShape PATHSHAPE_CIRCLE = 1 }; -class Path +class Path : public ScriptObject { public: Path(); diff --git a/Aquaria/ScriptInterface.cpp b/Aquaria/ScriptInterface.cpp index fff56be..6cd8116 100644 --- a/Aquaria/ScriptInterface.cpp +++ b/Aquaria/ScriptInterface.cpp @@ -19,6 +19,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ScriptInterface.h" +#include "../BBGE/ScriptObject.h" extern "C" { #include "lua.h" @@ -37,14 +38,22 @@ extern "C" #include "../BBGE/MathFunctions.h" +// Define this to 1 to check types of pointers passed to functions, +// and warn if a type mismatch is detected. In this case, +// the pointer is treated as NULL, to avoid crashing or undefined behavior. +//#define CHECK_POINTER_TYPES 1 + // If true, send all sort of script errors to errorLog instead of debugLog. -// On win32, this pops up message boxes which help to locate errors easily, +// On win32/OSX, this pops up message boxes which help to locate errors easily, // but can be annoying for regular gameplay. const bool loudScriptErrors = false; +// This setting causes NULL/0 pointers passed to a function to issue +// a Lua error instead of silently ignoring it. +// Some functions expect this behavior - do not enable!. const bool throwLuaErrors = false; -// Set this to true to complain (via errorLog()) whenever a script tries to +// Set this to true to complain whenever a script tries to // get or set a global variable. const bool complainOnGlobalVar = false; @@ -312,10 +321,75 @@ static inline void luaPushPointer(lua_State *L, void *ptr) lua_pushnumber(L, 0); } +static std::string luaFormatStackInfo(lua_State *L) +{ + lua_Debug ar; + if (lua_getstack(L, 1, &ar)) + lua_getinfo(L, "Sl", &ar); + else + { + snprintf(ar.short_src, sizeof(ar.short_src), "???"); + ar.currentline = 0; + } + std::ostringstream os; + os << ar.short_src << ":" << ar.currentline; + return os.str(); +} + + +#if CHECK_POINTER_TYPES +// Not intended to be called. +// Because wild typecasting expects X::_objtype to reside at the same relative +// memory location, be sure this is the case before running into undefined behavior later. +// - The C++ standard allows offsetof() only on POD-types. Oh well, it probably works anyways. +// If it does not compile for some reason, comment it out, hope for the best, and go ahead. +void compile_time_assertions() +{ +#define oo(cls) offsetof(cls, _objtype) +#define compile_assert(pred) switch(0){case 0:case (pred):;} + compile_assert(oo(Path) == oo(Entity)); + compile_assert(oo(Path) == oo(Ingredient)); + compile_assert(oo(Path) == oo(CollideEntity)); + compile_assert(oo(Path) == oo(ScriptedEntity)); + compile_assert(oo(Path) == oo(Beam)); + compile_assert(oo(Path) == oo(Shot)); + compile_assert(oo(Path) == oo(Web)); + compile_assert(oo(Path) == oo(Bone)); + compile_assert(oo(Path) == oo(PauseQuad)); + compile_assert(oo(Path) == oo(Avatar)); +#undef oo +#undef compile_assert +} + +template +static void ensureType(lua_State *L, T *& ptr, ScriptObjectType ty) +{ + if (ptr) + { + ScriptObject *so = (ScriptObject*)(ptr); + if (!so->isType(ty)) + { + std::ostringstream os; + os << "WARNING: " << luaFormatStackInfo(L) + << ": script passed wrong pointer to function (expected type: " + << ScriptObject::getTypeString(ty) << "; got: " + << so->getTypeString() << ')'; + scriptError(os.str()); + + ptr = NULL; // note that the pointer is passed by reference + } + } +} +# define ENSURE_TYPE(ptr, ty) ensureType(L, (ptr), (ty)) +#else +# define ENSURE_TYPE(ptr, ty) +#endif + static inline ScriptedEntity *scriptedEntity(lua_State *L, int slot = 1) { ScriptedEntity *se = (ScriptedEntity*)lua_touserdata(L, slot); + ENSURE_TYPE(se, SCO_SCRIPTED_ENTITY); if (!se) debugLog("ScriptedEntity invalid pointer."); return se; @@ -325,25 +399,17 @@ static inline CollideEntity *collideEntity(lua_State *L, int slot = 1) { CollideEntity *ce = (CollideEntity*)lua_touserdata(L, slot); + ENSURE_TYPE(ce, SCO_COLLIDE_ENTITY); if (!ce) debugLog("CollideEntity invalid pointer."); return ce ; } -static inline -RenderObject *object(lua_State *L, int slot = 1) -{ - //RenderObject *obj = dynamic_cast((RenderObject*)(int(lua_tonumber(L, slot)))); - RenderObject *obj = static_cast(lua_touserdata(L, slot)); - if (!obj) - debugLog("RenderObject invalid pointer"); - return obj; -} - static inline Beam *beam(lua_State *L, int slot = 1) { Beam *b = (Beam*)lua_touserdata(L, slot); + ENSURE_TYPE(b, SCO_BEAM); if (!b) debugLog("Beam invalid pointer."); return b; @@ -364,6 +430,7 @@ static inline Shot *getShot(lua_State *L, int slot = 1) { Shot *shot = (Shot*)lua_touserdata(L, slot); + ENSURE_TYPE(shot, SCO_SHOT); return shot; } @@ -371,13 +438,16 @@ static inline Web *getWeb(lua_State *L, int slot = 1) { Web *web = (Web*)lua_touserdata(L, slot); + ENSURE_TYPE(web, SCO_WEB); return web; } static inline Ingredient *getIng(lua_State *L, int slot = 1) { - return (Ingredient*)lua_touserdata(L, slot); + Ingredient *ing = (Ingredient*)lua_touserdata(L, slot); + ENSURE_TYPE(ing, SCO_INGREDIENT); + return ing; } static inline @@ -402,6 +472,7 @@ static inline Entity *entity(lua_State *L, int slot = 1) { Entity *ent = (Entity*)lua_touserdata(L, slot); + ENSURE_TYPE(ent, SCO_ENTITY); if (!ent) { luaErrorMsg(L, "Entity Invalid Pointer"); @@ -421,6 +492,7 @@ static inline Bone *bone(lua_State *L, int slot = 1) { Bone *b = (Bone*)lua_touserdata(L, slot); + ENSURE_TYPE(b, SCO_BONE); if (!b) { luaErrorMsg(L, "Bone Invalid Pointer"); @@ -445,6 +517,7 @@ static inline Path *path(lua_State *L, int slot = 1) { Path *p = (Path*)lua_touserdata(L, slot); + ENSURE_TYPE(p, SCO_PATH); return p; } @@ -463,28 +536,15 @@ static RenderObject *boneToRenderObject(lua_State *L, int slot = 1) static PauseQuad *getPauseQuad(lua_State *L, int slot = 1) { PauseQuad *q = (PauseQuad*)lua_touserdata(L, slot); - if (q) - return q; - else + ENSURE_TYPE(q, SCO_PAUSEQUAD); + if (!q) errorLog("Invalid PauseQuad/Particle"); - return 0; + return q; } static SkeletalSprite *getSkeletalSprite(Entity *e) { - Avatar *a; - ScriptedEntity *se; - SkeletalSprite *skel = 0; - if ((a = dynamic_cast(e)) != 0) - { - //a->skeletalSprite.transitionAnimate(lua_tostring(L, 2), 0.15, lua_tointeger(L, 3)); - skel = &a->skeletalSprite; - } - else if ((se = dynamic_cast(e)) != 0) - { - skel = &se->skeletalSprite; - } - return skel; + return e ? &e->skeletalSprite : NULL; } static bool looksLikeGlobal(const char *s) @@ -537,20 +597,8 @@ luaFunc(indexWarnGlobal) if (doWarn) { - lua_Debug ar; - if (lua_getstack(L, 1, &ar)) - { - lua_getinfo(L, "Sl", &ar); - } - else - { - snprintf(ar.short_src, sizeof(ar.short_src), "???"); - ar.currentline = 0; - } - - lua_getinfo(L, "Sl", &ar); std::ostringstream os; - os << "WARNING: " << ar.short_src << ":" << ar.currentline + os << "WARNING: " << luaFormatStackInfo(L) << ": script tried to get/call undefined global variable " << varname; scriptError(os.str()); @@ -577,22 +625,11 @@ luaFunc(newindexWarnGlobal) if (doWarn) { - lua_Debug ar; - if (lua_getstack(L, 1, &ar)) - { - lua_getinfo(L, "Sl", &ar); - } - else - { - snprintf(ar.short_src, sizeof(ar.short_src), "???"); - ar.currentline = 0; - } - std::ostringstream os; - os << "WARNING: " << ar.short_src << ":" << ar.currentline + os << "WARNING: " << luaFormatStackInfo(L) << ": script set global " << (lua_type(L, -2) == LUA_TFUNCTION ? "function" : "variable") - << " " << lua_tostring(L, -1); + << " " << varname; scriptError(os.str()); } @@ -611,18 +648,8 @@ luaFunc(indexWarnInstance) lua_remove(L, -3); if (lua_isnil(L, -1)) { - lua_Debug ar; - if (lua_getstack(L, 1, &ar)) - { - lua_getinfo(L, "Sl", &ar); - } - else - { - snprintf(ar.short_src, sizeof(ar.short_src), "???"); - ar.currentline = 0; - } std::ostringstream os; - os << "WARNING: " << ar.short_src << ":" << ar.currentline + os << "WARNING: " << luaFormatStackInfo(L) << ": script tried to get/call undefined instance variable " << lua_tostring(L, -2); errorLog(os.str()); @@ -1819,14 +1846,6 @@ luaFunc(loadMap) luaFunc(entity_followPath) { - /* - std::ostringstream os2; - os2 << lua_tointeger(L, 1); - errorLog(os2.str()); - std::ostringstream os; - os << "Entity: " << scriptedEntity(L)->name << " moving on Path: " << lua_tostring(L, 2); - debugLog(os.str()); - */ Entity *e = entity(L); if (e) { @@ -2627,16 +2646,16 @@ luaFunc(entity_setAnimLayerTimeMult) luaFunc(entity_animate) { SkeletalSprite *skel = getSkeletalSprite(entity(L)); - - // 0.15 - // 0.2 - float transition = lua_tonumber(L, 5); - if (transition == -1) - transition = 0; - else if (transition == 0) - transition = 0.2; - float ret = skel->transitionAnimate(lua_tostring(L, 2), transition, lua_tointeger(L, 3), lua_tointeger(L, 4)); - + float ret = 0; + if (skel) + { + float transition = lua_tonumber(L, 5); + if (transition == -1) + transition = 0; + else if (transition == 0) + transition = 0.2; + ret = skel->transitionAnimate(lua_tostring(L, 2), transition, lua_tointeger(L, 3), lua_tointeger(L, 4)); + } luaReturnNum(ret); } @@ -3642,13 +3661,17 @@ luaFunc(entity_rotateToVec) luaFunc(entity_update) { - entity(L)->update(lua_tonumber(L, 2)); + Entity *e = entity(L); + if (e) + e->update(lua_tonumber(L, 2)); luaReturnNum(0); } luaFunc(entity_updateSkeletal) { - entity(L)->skeletalSprite.update(lua_tonumber(L, 2)); + Entity *e = entity(L); + if (e) + e->skeletalSprite.update(lua_tonumber(L, 2)); luaReturnNum(0); } @@ -3667,17 +3690,21 @@ luaFunc(entity_msg) luaFunc(entity_updateCurrents) { - luaReturnBool(entity(L)->updateCurrents(lua_tonumber(L, 2))); + Entity *e = entity(L); + luaReturnBool(e ? e->updateCurrents(lua_tonumber(L, 2)) : false); } luaFunc(entity_updateLocalWarpAreas) { - luaReturnBool(entity(L)->updateLocalWarpAreas(getBool(L, 2))); + Entity *e = entity(L); + luaReturnBool(e ? e->updateLocalWarpAreas(getBool(L, 2)) : false); } luaFunc(entity_updateMovement) { - scriptedEntity(L)->updateMovement(lua_tonumber(L, 2)); + ScriptedEntity *e = scriptedEntity(L); + if (e) + e->updateMovement(lua_tonumber(L, 2)); luaReturnNum(0); } @@ -6586,12 +6613,14 @@ luaFunc(entity_getTarget) luaFunc(entity_getTargetPositionX) { - luaReturnInt(int(entity(L)->getTargetEntity()->position.x)); + Entity *e = entity(L); + luaReturnInt(e ? e->getTargetEntity()->position.x : 0); } luaFunc(entity_getTargetPositionY) { - luaReturnInt(int(entity(L)->getTargetEntity()->position.y)); + Entity *e = entity(L); + luaReturnNum(e ? e->getTargetEntity()->position.y : 0); } luaFunc(entity_isNearObstruction) @@ -7095,7 +7124,6 @@ luaFunc(entity_setFlag) luaFunc(entity_getFlag) { Entity *e = entity(L); - int v = lua_tonumber(L, 2); int ret = 0; if (e) { @@ -8821,9 +8849,21 @@ static const struct { // F U N C T I O N S //============================================================================================ +ScriptInterface::ScriptInterface() +: baseState(NULL) +{ +} + void ScriptInterface::init() { - baseState = createLuaVM(); + if (!baseState) + baseState = createLuaVM(); +} + +void ScriptInterface::reset() +{ + shutdown(); + init(); } lua_State *ScriptInterface::createLuaVM() @@ -8987,6 +9027,8 @@ void ScriptInterface::collectGarbage() void ScriptInterface::shutdown() { + destroyLuaVM(baseState); + baseState = NULL; } Script *ScriptInterface::openScript(const std::string &file, bool ignoremissing /* = false */) diff --git a/Aquaria/ScriptInterface.h b/Aquaria/ScriptInterface.h index 52702f8..4bc2c1f 100644 --- a/Aquaria/ScriptInterface.h +++ b/Aquaria/ScriptInterface.h @@ -77,7 +77,9 @@ protected: class ScriptInterface { public: + ScriptInterface(); void init(); + void reset(); void collectGarbage(); void shutdown(); diff --git a/Aquaria/ScriptedEntity.cpp b/Aquaria/ScriptedEntity.cpp index 1dbecac..a7b41ec 100644 --- a/Aquaria/ScriptedEntity.cpp +++ b/Aquaria/ScriptedEntity.cpp @@ -27,7 +27,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. bool ScriptedEntity::runningActivation = false; ScriptedEntity::ScriptedEntity(const std::string &scriptName, Vector position, EntityType et) : CollideEntity(), Segmented(2, 26) -{ +{ + addType(SCO_SCRIPTED_ENTITY); crushDelay = 0; autoSkeletalSpriteUpdate = true; script = 0; diff --git a/Aquaria/Shot.cpp b/Aquaria/Shot.cpp index 64e10dc..1c355b6 100644 --- a/Aquaria/Shot.cpp +++ b/Aquaria/Shot.cpp @@ -323,6 +323,7 @@ Shot::Shot(DamageType damageType, Entity *firer, Vector pos, Entity *target, std Shot::Shot() : Quad(), Segmented(0,0) { + addType(SCO_SHOT); extraDamage= 0; waveTimer = rand()%314; emitter = 0; diff --git a/Aquaria/Shot.h b/Aquaria/Shot.h index 8a56e05..f4f273b 100644 --- a/Aquaria/Shot.h +++ b/Aquaria/Shot.h @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "CollideEntity.h" #include "Segmented.h" #include "../BBGE/Particles.h" +#include "../BBGE/ScriptObject.h" struct ShotData { @@ -69,7 +70,7 @@ struct ShotData }; -class Shot : public Quad, public Segmented +class Shot : public ScriptObject, public Quad, public Segmented { public: //Shot(DamageType damageType, Entity *firer, Vector pos, Entity *target, std::string tex="", float homingness=1000, int maxSpeed=400, int segments=10, float segMin=0.1, float segMax=5, float damage = 1, float lifeTime = 0); @@ -136,7 +137,7 @@ protected: void onUpdate(float dt); }; -class Beam : public Quad +class Beam : public ScriptObject, public Quad { public: Beam(Vector pos, float angle); diff --git a/Aquaria/Web.cpp b/Aquaria/Web.cpp index 2f3aa67..262df92 100644 --- a/Aquaria/Web.cpp +++ b/Aquaria/Web.cpp @@ -27,6 +27,7 @@ Web::Webs Web::webs; Web::Web() : RenderObject() { + addType(SCO_WEB); webs.push_back(this); cull = false; parentEntity = 0; diff --git a/Aquaria/Web.h b/Aquaria/Web.h index 7f4e9bc..4a0789c 100644 --- a/Aquaria/Web.h +++ b/Aquaria/Web.h @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../BBGE/Quad.h" #include "Entity.h" -class Web : public RenderObject +class Web : public ScriptObject, public RenderObject { public: Web(); diff --git a/BBGE/Quad.cpp b/BBGE/Quad.cpp index d708963..db22d44 100644 --- a/BBGE/Quad.cpp +++ b/BBGE/Quad.cpp @@ -918,6 +918,7 @@ void Quad::onSetTexture() PauseQuad::PauseQuad() : Quad(), pauseLevel(0) { + addType(SCO_PAUSEQUAD); } void PauseQuad::onUpdate(float dt) diff --git a/BBGE/Quad.h b/BBGE/Quad.h index 01cae47..571a106 100644 --- a/BBGE/Quad.h +++ b/BBGE/Quad.h @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define __quad__ #include "RenderObject.h" +#include "ScriptObject.h" class QuadLight { @@ -149,7 +150,7 @@ private: void initQuad(); }; -class PauseQuad : public Quad +class PauseQuad : public ScriptObject, public Quad { public: PauseQuad(); diff --git a/BBGE/ScriptObject.cpp b/BBGE/ScriptObject.cpp new file mode 100644 index 0000000..4a6862b --- /dev/null +++ b/BBGE/ScriptObject.cpp @@ -0,0 +1,60 @@ +/* +Copyright (C) 2007, 2012 - Bit-Blot + +This file is part of Aquaria. + +Aquaria 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; either version 2 +of the License, or (at your option) any later version. + +This program 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. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include + +#include "ScriptObject.h" + +static const char *scriptObjTypeNames[] = +{ + /* (1 << 0) */ "Entity", + /* (1 << 1) */ "Ingredient", + /* (1 << 2) */ "CollideEntity", + /* (1 << 3) */ "ScriptedEntity", + /* (1 << 4) */ "Beam", + /* (1 << 5) */ "Shot", + /* (1 << 6) */ "Web", + /* (1 << 7) */ "Bone", + /* (1 << 8) */ "Path/Node", + /* (1 << 9) */ "PauseQuad", + NULL +}; + +std::string ScriptObject::getTypeString(unsigned int ty) +{ + if (ty == SCO_NONE) + return "NO TYPE"; + + bool more = false; + std::ostringstream os; + for (int i = 0; scriptObjTypeNames[i]; ++i) + { + if (ty & (1 << i)) + { + if (more) + os << ", "; + os << scriptObjTypeNames[i]; + more = true; + } + } + return os.str(); +} + diff --git a/BBGE/ScriptObject.h b/BBGE/ScriptObject.h new file mode 100644 index 0000000..37a869a --- /dev/null +++ b/BBGE/ScriptObject.h @@ -0,0 +1,74 @@ +/* +Copyright (C) 2007, 2012 - Bit-Blot + +This file is part of Aquaria. + +Aquaria 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; either version 2 +of the License, or (at your option) any later version. + +This program 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. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#pragma once + +enum ScriptObjectType +{ + SCO_NONE = 0x0000, + + // If you change this enum, do not forget to adjust the string array in the cpp, + // and to add additional compile time assertions to ScriptInterface.cpp as necessary! + SCO_ENTITY = 0x0001, + SCO_INGREDIENT = 0x0002, + SCO_COLLIDE_ENTITY = 0x0004, + SCO_SCRIPTED_ENTITY = 0x0008, + SCO_BEAM = 0x0010, + SCO_SHOT = 0x0020, + SCO_WEB = 0x0040, + SCO_BONE = 0x0080, + SCO_PATH = 0x0100, + SCO_PAUSEQUAD = 0x0200, + + SCO_FORCE_32BIT = 0xFFFFFFFF +}; + + +class ScriptObject +{ +public: + + ScriptObject() + : _objtype(SCO_NONE) + { + } + + virtual ~ScriptObject() {} + + inline void addType(ScriptObjectType ty) + { + _objtype = ScriptObjectType(int(ty) | int(_objtype)); // prevent the compiler from crying + } + + inline bool isType(ScriptObjectType bt) const + { + return (_objtype & bt) != 0; + } + + inline std::string getTypeString() const + { + return getTypeString(_objtype); + } + + static std::string getTypeString(unsigned int ty); + + // public to allow the static compile check in ScriptInterface.cpp to work + ScriptObjectType _objtype; +}; diff --git a/BBGE/SkeletalSprite.cpp b/BBGE/SkeletalSprite.cpp index 7e65838..5a70a39 100644 --- a/BBGE/SkeletalSprite.cpp +++ b/BBGE/SkeletalSprite.cpp @@ -42,6 +42,7 @@ void SkeletalKeyframe::copyAllButTime(SkeletalKeyframe *copy) Bone::Bone() : Quad() { + addType(SCO_BONE); fileRenderQuad = true; skeleton = 0; generateCollisionMask = true; diff --git a/BBGE/SkeletalSprite.h b/BBGE/SkeletalSprite.h index 7a833fd..5b49354 100644 --- a/BBGE/SkeletalSprite.h +++ b/BBGE/SkeletalSprite.h @@ -37,7 +37,7 @@ enum AnimationCommand class ParticleEffect; class SkeletalSprite; -class Bone : public Quad +class Bone : public ScriptObject, public Quad { public: Bone(); diff --git a/CMakeLists.txt b/CMakeLists.txt index 9969e93..1f3fcee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -362,6 +362,7 @@ SET(BBGE_SRCS ${BBGEDIR}/Resource.cpp ${BBGEDIR}/RoundedRect.cpp ${BBGEDIR}/ScreenTransition.cpp + ${BBGEDIR}/ScriptObject.cpp ${BBGEDIR}/Shader.cpp ${BBGEDIR}/SkeletalSprite.cpp ${BBGEDIR}/Slider.cpp