From b98e2532ed9b13b50748f22a4cfb22db7c3761d4 Mon Sep 17 00:00:00 2001 From: fgenesis Date: Fri, 16 May 2014 00:04:56 +0200 Subject: [PATCH 1/3] Fix crash when AnimationLayer is missing --- BBGE/SkeletalSprite.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/BBGE/SkeletalSprite.cpp b/BBGE/SkeletalSprite.cpp index 8fe3263..ae305e3 100644 --- a/BBGE/SkeletalSprite.cpp +++ b/BBGE/SkeletalSprite.cpp @@ -1694,18 +1694,15 @@ void SkeletalSprite::loadSkeletal(const std::string &fn) Animation *SkeletalSprite::getCurrentAnimation(int layer) { - return animLayers[layer].getCurrentAnimation(); + return layer < animLayers.size() ? animLayers[layer].getCurrentAnimation() : NULL; } void SkeletalSprite::setTime(float time, int layer) { - animLayers[layer].timer = time; + if(layer < animLayers.size()) + animLayers[layer].timer = time; } -// hack: -// calculate based on frames -const int lerpAvg = 3; - void AnimationLayer::updateBones() { if (!animating && !(&s->animLayers[0] == this) && fallThru == 0) return; From 3db8c9e13aaf22ea1949fe22c483425fdf655fa2 Mon Sep 17 00:00:00 2001 From: fgenesis Date: Fri, 16 May 2014 00:11:52 +0200 Subject: [PATCH 2/3] Pathfinding & map grid improvements. There were still only 6 of 8 bits of the map grid in use. The last 2 bits are now available as non-colliding user bits, and are ignored unless specially treated. The findPath() function can now be told which bits to respect, which allows to prevent pathfinding to pass through fish tunnels, for example. A function for fast user bit map dilation is added as well. --- Aquaria/Avatar.cpp | 8 +- Aquaria/Entity.cpp | 11 +-- Aquaria/Game.cpp | 159 ++++++++++++++++++++++-------------- Aquaria/Game.h | 56 ++++++++----- Aquaria/GridRender.cpp | 30 +------ Aquaria/PathFinding.cpp | 16 ++-- Aquaria/PathFinding.h | 2 +- Aquaria/ScriptInterface.cpp | 27 +++++- 8 files changed, 185 insertions(+), 124 deletions(-) diff --git a/Aquaria/Avatar.cpp b/Aquaria/Avatar.cpp index ea5856e..43d334c 100644 --- a/Aquaria/Avatar.cpp +++ b/Aquaria/Avatar.cpp @@ -3561,7 +3561,7 @@ void Avatar::lockToWall() while(0); } - if (dsq->game->getGrid(t)==OT_HURT && isDamageTarget(DT_WALLHURT)) + if (dsq->game->isObstructed(t, OT_HURT) && isDamageTarget(DT_WALLHURT)) { good = false; } @@ -3612,16 +3612,16 @@ void Avatar::lockToWall() Vector offdiff = t.worldVector() - position; if (!offdiff.isZero()) { - if (tileType != OT_INVISIBLEIN) + if (tileType & OT_INVISIBLEIN) { Vector adjust = offdiff; - adjust.setLength2D(TILE_SIZE*2); + adjust.setLength2D(TILE_SIZE/2); offdiff -= adjust; } else { Vector adjust = offdiff; - adjust.setLength2D(TILE_SIZE/2); + adjust.setLength2D(TILE_SIZE*2); offdiff -= adjust; } } diff --git a/Aquaria/Entity.cpp b/Aquaria/Entity.cpp index d89a13d..b34b0af 100644 --- a/Aquaria/Entity.cpp +++ b/Aquaria/Entity.cpp @@ -1509,13 +1509,13 @@ bool Entity::isSittingOnInvisibleIn() { for (int y = 0; y < 4; y++) { - if (dsq->game->getGrid(TileVector(t.x+x, t.y+y))==OT_INVISIBLEIN) + if (dsq->game->isObstructed(TileVector(t.x+x, t.y+y), OT_INVISIBLEIN)) return true; - if (dsq->game->getGrid(TileVector(t.x-x, t.y+y))==OT_INVISIBLEIN) + if (dsq->game->isObstructed(TileVector(t.x-x, t.y+y), OT_INVISIBLEIN)) return true; - if (dsq->game->getGrid(TileVector(t.x+x, t.y-y))==OT_INVISIBLEIN) + if (dsq->game->isObstructed(TileVector(t.x+x, t.y-y), OT_INVISIBLEIN)) return true; - if (dsq->game->getGrid(TileVector(t.x-x, t.y-y))==OT_INVISIBLEIN) + if (dsq->game->isObstructed(TileVector(t.x-x, t.y-y), OT_INVISIBLEIN)) return true; } } @@ -3055,6 +3055,7 @@ bool Entity::doCollisionAvoidance(float dt, int search, float mod, Vector *vp, i int minDist=-1; TileVector t(position); TileVector useTile; + const int blockObs = ~ignoreObs; float totalDist = sqrtf(float(sqr((search*2)*TILE_SIZE)+sqr((search*2)*TILE_SIZE))); for (int x = -search; x <= search; x++) @@ -3069,7 +3070,7 @@ bool Entity::doCollisionAvoidance(float dt, int search, float mod, Vector *vp, i } if (waterBlocked || dsq->game->isObstructed(checkT)) { - if (dsq->game->getGrid(checkT) != ignoreObs) + if (dsq->game->isObstructed(checkT, blockObs)) { Vector vtc(t.x+x, t.y+y); Vector vt(t.x, t.y); diff --git a/Aquaria/Game.cpp b/Aquaria/Game.cpp index ddd07e3..8d246b9 100644 --- a/Aquaria/Game.cpp +++ b/Aquaria/Game.cpp @@ -2075,8 +2075,8 @@ void Game::fillGridFromQuad(Quad *q, ObsType obsType, bool trim) //dsq->game->setGrid(TileVector(tpos.x+(w2*TILE_SIZE)+(x/TILE_SIZE), tpos.y+(h2*TILE_SIZE)+(y/TILE_SIZE)), obsType); TileVector tvec(tpos.x+w2+x, tpos.y+h2+y); - if (dsq->game->getGrid(tvec) == OT_EMPTY) - dsq->game->setGrid(tvec, obsType); + if (!dsq->game->isObstructed(tvec)) + dsq->game->addGrid(tvec, obsType); } glPopMatrix(); @@ -2103,7 +2103,7 @@ void Game::clearDynamicGrid(unsigned char maskbyte /* = OT_MASK_BLACK */) // otherwise there is a chance to write a few bytes over the end of the buffer -- FG compile_assert(sizeof(grid) % sizeof(uint32) == 0); - signed char *gridstart = &grid[0][0]; + unsigned char *gridstart = &grid[0][0]; uint32 *gridend = (uint32*)(gridstart + sizeof(grid)); uint32 *gridptr = (uint32*)gridstart; // mask out specific bytes @@ -2165,9 +2165,9 @@ void Game::trimGrid() // from beeing drawn. (The maps were designed with this mind...) for (int x = 0; x < MAX_GRID; x++) { - const signed char *curCol = dsq->game->getGridColumn(x); - const signed char *leftCol = dsq->game->getGridColumn(x-1); - const signed char *rightCol = dsq->game->getGridColumn(x+1); + const unsigned char *curCol = grid[x]; // safe + const unsigned char *leftCol = dsq->game->getGridColumn(x-1); // unsafe + const unsigned char *rightCol = dsq->game->getGridColumn(x+1); // unsafe for (int y = 0; y < MAX_GRID; y++) { if (curCol[y] & OT_MASK_BLACK) @@ -2179,6 +2179,66 @@ void Game::trimGrid() } } +void Game::dilateGrid(unsigned int radius, ObsType test, ObsType set, ObsType allowOverwrite) +{ + if(!radius) + return; + const int lim = MAX_GRID - radius; + const unsigned int denyOverwrite = ~allowOverwrite; + // Box dilation is separable, so we do a two-pass by axis + int dilate = 0; + + // dilate rows + for (int y = 0; y < MAX_GRID; ++y) + { + for (int x = radius; x < lim; ++x) + { + if (grid[x][y] & test) + { + dilate = 2 * radius; + goto doDilate1; + } + if(dilate) + { + --dilate; + doDilate1: + if((grid[x - radius][y] & denyOverwrite) == OT_EMPTY) + grid[x - radius][y] |= set; + } + } + assert(lim + dilate < MAX_GRID); + for(int x = 0; x < dilate; ++x) + if(!(grid[x][y - radius] & test)) + grid[x][y - radius] |= set; + } + + // dilate colums + dilate = 0; + for (int x = 0; x < MAX_GRID; ++x) + { + unsigned char * const curCol = grid[x]; + for (int y = radius; y < lim; ++y) + { + if (curCol[y] & test) + { + dilate = 2 * radius; + goto doDilate2; + } + if(dilate) + { + --dilate; + doDilate2: + if((curCol[y - radius] & denyOverwrite) == OT_EMPTY) + curCol[y - radius] |= set; + } + } + assert(lim + dilate < MAX_GRID); + for(int y = 0; y < dilate; ++y) + if(!(curCol[y - radius] & test)) + curCol[y - radius] |= set; + } +} + float Game::getCoverage(Vector pos, int sampleArea) { TileVector t(pos); @@ -6451,30 +6511,46 @@ void Game::applyState() addRenderObject(songLineRender, LR_HUD); gridRender = new GridRender(OT_INVISIBLE); + gridRender->color = Vector(1, 0, 0); addRenderObject(gridRender, LR_DEBUG_TEXT); gridRender->alpha = 0; gridRender2 = new GridRender(OT_HURT); + gridRender2->color = Vector(1, 1, 0); addRenderObject(gridRender2, LR_DEBUG_TEXT); gridRender2->alpha = 0; gridRender3 = new GridRender(OT_INVISIBLEIN); + gridRender3->color = Vector(1, 0.5f, 0); addRenderObject(gridRender3, LR_DEBUG_TEXT); gridRender3->alpha = 0; edgeRender = new GridRender(OT_BLACKINVIS); + edgeRender->color = Vector(0.3f, 0, 0.6f); addRenderObject(edgeRender, LR_DEBUG_TEXT); edgeRender->alpha = 0; gridRenderEnt = new GridRender(OT_INVISIBLEENT); + gridRenderEnt->color = Vector(0, 1, 0.5); addRenderObject(gridRenderEnt, LR_DEBUG_TEXT); gridRenderEnt->alpha = 0; + gridRenderUser1 = new GridRender(OT_USER1); + addRenderObject(gridRenderUser1, LR_DEBUG_TEXT); + gridRenderUser1->color = Vector(1, 0, 1); + gridRenderUser1->alpha = 0; + + gridRenderUser2 = new GridRender(OT_USER2); + addRenderObject(gridRenderUser2, LR_DEBUG_TEXT); + gridRenderUser2->color = Vector(1, 1, 1); + gridRenderUser2->alpha = 0; + waterSurfaceRender = new WaterSurfaceRender(); //waterSurfaceRender->setRenderPass(-1); addRenderObject(waterSurfaceRender, LR_WATERSURFACE); GridRender *blackRender = new GridRender(OT_BLACK); + blackRender->color = Vector(0, 0, 0); //blackRender->alpha = 0; blackRender->blendEnabled = false; addRenderObject(blackRender, LR_ELEMENTS4); @@ -8515,22 +8591,17 @@ void Game::toggleMiniMapRender(int v) void Game::toggleGridRender() { float t = 0; + float a = 0; if (gridRender->alpha == 0) - { - gridRender->alpha.interpolateTo(0.5, t); - gridRender2->alpha.interpolateTo(0.5, t); - gridRender3->alpha.interpolateTo(0.5, t); - edgeRender->alpha.interpolateTo(0.5, t); - gridRenderEnt->alpha.interpolateTo(0.5, t); - } - else if (gridRender->alpha == 0.5) - { - gridRender->alpha.interpolateTo(0, t); - gridRender2->alpha.interpolateTo(0, t); - gridRender3->alpha.interpolateTo(0, t); - edgeRender->alpha.interpolateTo(0, t); - gridRenderEnt->alpha.interpolateTo(0, t); - } + a = 0.5f; + + gridRender->alpha.interpolateTo(a, t); + gridRender2->alpha.interpolateTo(a, t); + gridRender3->alpha.interpolateTo(a, t); + edgeRender->alpha.interpolateTo(a, t); + gridRenderEnt->alpha.interpolateTo(a, t); + gridRenderUser1->alpha.interpolateTo(a, t); + gridRenderUser2->alpha.interpolateTo(a, t); } Vector Game::getCameraPositionFor(const Vector &pos) @@ -10624,7 +10695,7 @@ void Game::setGrid(ElementTemplate *et, Vector position, float rot360) } TileVector s(t.x+x, t.y+y); //Vector v = Vector(position.x+et->grid[i].x*TILE_SIZE, position.y+et->grid[i].y*TILE_SIZE); - setGrid(s, 1); + setGrid(s, OT_INVISIBLE); } } @@ -10752,6 +10823,12 @@ void Game::removeState() miniMapRender = 0; gridRender = 0; + gridRender2 = 0; + gridRender3 = 0; + edgeRender = 0; + gridRenderEnt = 0; + gridRenderUser1 = 0; + gridRenderUser2 = 0; worldMapRender = 0; //core->sound->stopStreamingOgg(); @@ -10922,44 +10999,6 @@ bool Game::collideCircleWithGrid(const Vector& position, float r) return false; } -bool Game::collideBoxWithGrid(const Vector& position, int hw, int hh) -{ - Vector tile = position; - TileVector t(tile); - tile.x = t.x; - tile.y = t.y; - - float hsz = TILE_SIZE/2; - int xrange=1,yrange=1; - xrange = (hw/TILE_SIZE)+1; - yrange = (hh/TILE_SIZE)+1; - for (int x = tile.x-xrange; x <= tile.x+xrange; x++) - { - for (int y = tile.y-yrange; y <= tile.y+yrange; y++) - { - int v = this->getGrid(TileVector(x, y)); - if (v == 1) - { - if (tile.x == x && tile.y == y) return true; - float rx = (x*TILE_SIZE)+TILE_SIZE/2; - float ry = (y*TILE_SIZE)+TILE_SIZE/2; - - - if (isBoxIn(position, Vector(hw, hh), Vector(rx, ry), Vector(hsz, hsz))) - { - return true; - } - if (isBoxIn(Vector(rx, ry), Vector(hsz, hsz), position, Vector(hw, hh))) - { - return true; - } - } - } - } - return false; -} - - void Game::learnedRecipe(Recipe *r, bool effects) { if (nocasecmp(dsq->getTopStateData()->name,"Game")==0 && !applyingState) diff --git a/Aquaria/Game.h b/Aquaria/Game.h index 5193014..caefa3c 100644 --- a/Aquaria/Game.h +++ b/Aquaria/Game.h @@ -587,6 +587,14 @@ enum ObsType // set by entities OT_INVISIBLEENT = 0x20, + + // mask for all bits that block + OT_BLOCKING = OT_MASK_BLACK | OT_INVISIBLE | OT_INVISIBLEIN | OT_HURT | OT_INVISIBLEENT, + + // free for use, not colliding by default + OT_USER1 = 0x40, + OT_USER2 = 0x80, + OT_USER_MASK = OT_USER1 | OT_USER2, }; struct EntitySaveData @@ -620,12 +628,14 @@ public: std::string getSelectedChoice() { return selectedChoice; } - int getGrid(const TileVector &tile) const; - int getGridRaw(unsigned int x, unsigned int y) const; - const signed char *getGridColumn(int tileX); - void setGrid(const TileVector &tile, int v); - bool isObstructed(const TileVector &tile, int t = -1) const; + ObsType getGrid(const TileVector &tile) const; + ObsType getGridRaw(const TileVector &tile) const; + unsigned char *getGridColumn(int tileX); + void setGrid(const TileVector &tile, ObsType v); + void addGrid(const TileVector &tile, ObsType v); + bool isObstructed(const TileVector &tile, int t = OT_BLOCKING) const; void trimGrid(); + void dilateGrid(unsigned int radius, ObsType test, ObsType set, ObsType allowOverwrite); void clearPointers(); @@ -655,7 +665,6 @@ public: void registerSporeDrop(const Vector &pos, int t); - bool collideBoxWithGrid(const Vector& position, int w, int h); bool collideCircleWithGrid(const Vector& position, float r); bool collideHairVsCircle(Entity *a, int num, const Vector &pos2, float radius, float perc=0, int *colSegment=0); @@ -959,7 +968,7 @@ public: void createGradient(); std::string saveMusic; - GridRender *gridRender, *gridRender2, *gridRender3, *edgeRender, *gridRenderEnt; + GridRender *gridRender, *gridRender2, *gridRender3, *edgeRender, *gridRenderEnt, *gridRenderUser1, *gridRenderUser2; void toggleGridRender(); ElementUpdateList elementUpdateList; ElementUpdateList elementInteractionList; @@ -1174,7 +1183,7 @@ protected: void toggleSceneEditor(); #endif - signed char grid[MAX_GRID][MAX_GRID]; + unsigned char grid[MAX_GRID][MAX_GRID]; Quad *bg, *bg2; @@ -1200,21 +1209,23 @@ extern Game *game; // INLINE FUNCTIONS inline -int Game::getGridRaw(unsigned int x, unsigned int y) const +ObsType Game::getGridRaw(const TileVector &tile) const { - return grid[x][y]; + return (unsigned(tile.x) < unsigned(MAX_GRID) && unsigned(tile.y) < unsigned(MAX_GRID)) + ? ObsType(grid[tile.x][tile.y]) + : OT_INVISIBLE; } inline -int Game::getGrid(const TileVector &tile) const +ObsType Game::getGrid(const TileVector &tile) const { - //if (tile.x < 0 || tile.x >= MAX_GRID || tile.y < 0 || tile.y >= MAX_GRID) return OT_INVISIBLE; - //return grid[tile.x][tile.y]; - return (unsigned(tile.x) < unsigned(MAX_GRID) && unsigned(tile.y) < unsigned(MAX_GRID)) ? grid[tile.x][tile.y] : OT_INVISIBLE; + return (unsigned(tile.x) < unsigned(MAX_GRID) && unsigned(tile.y) < unsigned(MAX_GRID)) + ? ObsType(grid[tile.x][tile.y] & OT_BLOCKING) + : OT_INVISIBLE; } inline -const signed char *Game::getGridColumn(int tileX) +unsigned char *Game::getGridColumn(int tileX) { if (tileX < 0) return grid[0]; @@ -1225,14 +1236,21 @@ const signed char *Game::getGridColumn(int tileX) } inline -void Game::setGrid(const TileVector &tile, int v) +void Game::setGrid(const TileVector &tile, ObsType v) { - if (tile.x < 0 || tile.x >= MAX_GRID || tile.y < 0 || tile.y >= MAX_GRID) return; - grid[tile.x][tile.y] = v; + if (unsigned(tile.x) < unsigned(MAX_GRID) && unsigned(tile.y) < unsigned(MAX_GRID)) + grid[tile.x][tile.y] = v; } inline -bool Game::isObstructed(const TileVector &tile, int t /* = -1 */) const +void Game::addGrid(const TileVector &tile, ObsType v) +{ + if (unsigned(tile.x) < unsigned(MAX_GRID) && unsigned(tile.y) < unsigned(MAX_GRID)) + grid[tile.x][tile.y] |= v; +} + +inline +bool Game::isObstructed(const TileVector &tile, int t /* = OT_BLOCKING */) const { return (getGrid(tile) & t); } diff --git a/Aquaria/GridRender.cpp b/Aquaria/GridRender.cpp index bbfd4a3..fa6c9cd 100644 --- a/Aquaria/GridRender.cpp +++ b/Aquaria/GridRender.cpp @@ -66,30 +66,6 @@ inline static void doRenderGrid(int x, int startCol, int endCol) void GridRender::onRender() { - switch(obsType) - { - case OT_INVISIBLE: - core->setColor(1, 0, 0, alpha.getValue()); - break; - case OT_INVISIBLEIN: - core->setColor(1, 0.5, 0, alpha.getValue()); - break; - case OT_INVISIBLEENT: - core->setColor(0, 1, 0.5, alpha.getValue()); - break; - case OT_BLACK: - core->setColor(0, 0, 0, 1); - break; - case OT_BLACKINVIS: - core->setColor(0.3, 0, 0.6, alpha.getValue()); - break; - case OT_HURT: - core->setColor(1, 1, 0, alpha.getValue()); - break; - default: - break; - } - const signed char obsType = this->obsType; Vector camPos = core->cameraPos; camPos.x -= core->getVirtualOffX() * (core->invGlobalScale); @@ -112,11 +88,11 @@ void GridRender::onRender() return; for (int x = startX; x <= endX; ++x) { - const signed char *gridColumn = dsq->game->getGridColumn(x); + const unsigned char *gridColumn = dsq->game->getGridColumn(x); int startCol = -1, y; // fast-forward to next drawable byte - if(const signed char *next = (const signed char*)memchr(gridColumn + startY, obsType, endY - startY + 1)) // find next byte with correct obs type + if(const unsigned char *next = (const unsigned char*)memchr(gridColumn + startY, obsType, endY - startY + 1)) // find next byte with correct obs type { y = next - gridColumn; // will get incremented right away, which is okay, because we alrady set startCol startCol = y; @@ -131,7 +107,7 @@ void GridRender::onRender() doRenderGrid(x, startCol, y - 1); // fast-forward to next drawable byte - if(const signed char *next = (const signed char*)memchr(gridColumn + y, obsType, endY - y)) // find next byte with correct obs type + if(const unsigned char *next = (const unsigned char*)memchr(gridColumn + y, obsType, endY - y)) // find next byte with correct obs type { y = next - gridColumn; // will get incremented right away, which is okay, because we alrady set startCol startCol = y; diff --git a/Aquaria/PathFinding.cpp b/Aquaria/PathFinding.cpp index f214f88..3a0f69e 100644 --- a/Aquaria/PathFinding.cpp +++ b/Aquaria/PathFinding.cpp @@ -24,16 +24,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "DSQ.h" #include "Game.h" -class SearchGrid +class SearchGridRaw { public: - SearchGrid() : game(dsq->game) {} + SearchGridRaw(ObsType blocking) : game(dsq->game), blockingObsBits(blocking) {} inline bool operator()(unsigned x, unsigned y) const { - return game->getGrid(TileVector(x, y)) == OT_EMPTY; + return (game->getGridRaw(TileVector(x, y)) & blockingObsBits) == OT_EMPTY; } private: + const ObsType blockingObsBits; const Game *game; }; @@ -157,7 +158,7 @@ void PathFinding::generatePath(RenderObject *ro, TileVector start, TileVector go VectorPath& vp = ro->position.data->path; vp.clear(); - SearchGrid grid; + SearchGridRaw grid(OT_BLOCKING); JPS::PathVector path; if(JPS::findPath(path, grid, start.x, start.y, goal.x, goal.y, 1)) { @@ -166,9 +167,12 @@ void PathFinding::generatePath(RenderObject *ro, TileVector start, TileVector go } } -bool PathFinding::generatePathSimple(VectorPath& path, const Vector& start, const Vector& end, unsigned int step /* = 0 */) +bool PathFinding::generatePathSimple(VectorPath& path, const Vector& start, const Vector& end, unsigned int step /* = 0 */, unsigned int obs /* = 0 */) { - SearchGrid grid; + if(obs == OT_EMPTY) + obs = OT_BLOCKING; + + SearchGridRaw grid((ObsType)obs); JPS::PathVector p; TileVector tstart(start); TileVector tend(end); diff --git a/Aquaria/PathFinding.h b/Aquaria/PathFinding.h index c0dc9c2..7920cbb 100644 --- a/Aquaria/PathFinding.h +++ b/Aquaria/PathFinding.h @@ -37,7 +37,7 @@ public: void molestPath(VectorPath &path); void generatePath(RenderObject *go, TileVector g1, TileVector g2, int offx=0, int offy=0); - bool generatePathSimple(VectorPath& path, const Vector& start, const Vector& end, unsigned int step = 0); + bool generatePathSimple(VectorPath& path, const Vector& start, const Vector& end, unsigned int step = 0, unsigned int obs = 0); }; #endif diff --git a/Aquaria/ScriptInterface.cpp b/Aquaria/ScriptInterface.cpp index efe7a40..07e49b8 100644 --- a/Aquaria/ScriptInterface.cpp +++ b/Aquaria/ScriptInterface.cpp @@ -2898,6 +2898,16 @@ luaFunc(reconstructEntityGrid) luaReturnNil(); } +luaFunc(dilateGrid) +{ + unsigned int radius = lua_tointeger(L, 1); + ObsType test = (ObsType)lua_tointeger(L, 2); + ObsType set = (ObsType)lua_tointeger(L, 3); + ObsType allowOverwrite = (ObsType)lua_tointeger(L, 4); + dsq->game->dilateGrid(radius, test, set, allowOverwrite); + luaReturnNil(); +} + luaFunc(entity_setCanLeaveWater) { Entity *e = entity(L); @@ -8347,6 +8357,11 @@ luaFunc(getObstruction) luaReturnInt(dsq->game->getGrid(TileVector(Vector(lua_tonumber(L, 1), lua_tonumber(L, 2))))); } +luaFunc(getGridRaw) +{ + luaReturnInt(dsq->game->getGridRaw(TileVector(Vector(lua_tonumber(L, 1), lua_tonumber(L, 2))))); +} + luaFunc(isObstructedBlock) { float x = lua_tonumber(L, 1); @@ -8568,13 +8583,14 @@ luaFunc(isShuttingDownGameState) luaReturnBool(dsq->game->isShuttingDownGameState()); } -// startx, starty, endx, endy [, step, xtab, ytab] +// startx, starty, endx, endy [, step, xtab, ytab, obsMask] luaFunc(findPath) { VectorPath path; Vector start(lua_tonumber(L, 1), lua_tonumber(L, 2)); Vector end(lua_tonumber(L, 3), lua_tonumber(L, 4)); - if(!dsq->pathFinding.generatePathSimple(path, start, end, lua_tointeger(L, 5))) + ObsType obs = ObsType(lua_tointeger(L, 8)); + if(!dsq->pathFinding.generatePathSimple(path, start, end, lua_tointeger(L, 5), obs)) luaReturnBool(false); const unsigned num = path.getNumPathNodes(); @@ -8964,6 +8980,7 @@ static const struct { luaRegister(reconstructGrid), luaRegister(reconstructEntityGrid), + luaRegister(dilateGrid), luaRegister(ing_hasIET), luaRegister(ing_getIngredientName), @@ -9463,6 +9480,7 @@ static const struct { luaRegister(isObstructed), luaRegister(isObstructedBlock), luaRegister(getObstruction), + luaRegister(getGridRaw), luaRegister(findPath), luaRegister(castLine), luaRegister(getUserInputString), @@ -10597,6 +10615,11 @@ static const struct { luaConstant(OT_INVISIBLEIN), luaConstant(OT_HURT), luaConstant(OT_INVISIBLEENT), + luaConstant(OT_USER1), + luaConstant(OT_USER2), + luaConstant(OT_MASK_BLACK), + luaConstant(OT_BLOCKING), + luaConstant(OT_USER_MASK), luaConstant(SEE_MAP_NEVER), luaConstant(SEE_MAP_DEFAULT), From 86d2fcebda5f90a322848536aa1f4fb2a488fa5e Mon Sep 17 00:00:00 2001 From: fgenesis Date: Fri, 16 May 2014 01:03:54 +0200 Subject: [PATCH 3/3] Fix problematic Lua init and add user setting to keep 'os' and 'io' functions. From the Lua 5.1 manual: "The luaopen_* functions (to open libraries) cannot be called directly, like a regular C function. They must be called through Lua, like a Lua function." All standard tables are now loaded with luaL_openlibs(), which includes os and io. Because these are inherently unsafe, there is a new config setting: This is disabled by default. The title screen will show a warning when the setting is on. --- Aquaria/DSQ.cpp | 12 +++++++++--- Aquaria/ScriptInterface.cpp | 19 ++++++++++++++----- Aquaria/UserSettings.cpp | 12 ++++++++++++ Aquaria/UserSettings.h | 3 ++- files/data/stringbank.txt | 1 + 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/Aquaria/DSQ.cpp b/Aquaria/DSQ.cpp index f090384..61a14b8 100644 --- a/Aquaria/DSQ.cpp +++ b/Aquaria/DSQ.cpp @@ -813,7 +813,10 @@ void loadBitForTexPrecache() void DSQ::setVersionLabelText() { #ifdef AQUARIA_OVERRIDE_VERSION_STRING - versionLabel->setText(AQUARIA_OVERRIDE_VERSION_STRING); + std::string overrideText = AQUARIA_OVERRIDE_VERSION_STRING; + if(user.system.allowDangerousScriptFunctions) + overrideText += continuity.stringBank.get(2050); + versionLabel->setText(overrideText); return; #endif @@ -848,6 +851,9 @@ void DSQ::setVersionLabelText() os << AQUARIA_CUSTOM_BUILD_ID; #endif + if(user.system.allowDangerousScriptFunctions) + os << continuity.stringBank.get(2050); + versionLabel->setText(os.str()); } @@ -907,13 +913,13 @@ This build is not yet final, and as such there are a couple things lacking. They // steam gets inited in here Core::init(); - dsq->continuity.stringBank.load(); + continuity.stringBank.load(); vars = &v; v.load(); // steam callbacks are inited here - dsq->continuity.init(); + continuity.init(); // do copy stuff #ifdef BBGE_BUILD_UNIX diff --git a/Aquaria/ScriptInterface.cpp b/Aquaria/ScriptInterface.cpp index 07e49b8..45cdebc 100644 --- a/Aquaria/ScriptInterface.cpp +++ b/Aquaria/ScriptInterface.cpp @@ -60,6 +60,9 @@ bool complainOnGlobalVar = false; // thread-local variable. bool complainOnUndefLocal = false; +// Set to true to make 'os' and 'io' Lua tables accessible +bool allowUnsafeFunctions = false; + // List of all interface functions called by C++ code, terminated by NULL. static const char * const interfaceFunctions[] = { @@ -10650,6 +10653,8 @@ void ScriptInterface::init() complainOnGlobalVar = devmode; complainOnUndefLocal = devmode; + allowUnsafeFunctions = dsq->user.system.allowDangerousScriptFunctions; + if (!baseState) baseState = createLuaVM(); } @@ -10669,11 +10674,15 @@ void *ScriptInterface::the_alloc(void *ud, void *ptr, size_t osize, size_t nsize lua_State *ScriptInterface::createLuaVM() { lua_State *state = lua_newstate(the_alloc, this); /* opens Lua */ - luaopen_base(state); /* opens the basic library */ - luaopen_table(state); /* opens the table library */ - luaopen_string(state); /* opens the string lib. */ - luaopen_math(state); /* opens the math lib. */ - luaopen_debug(state); + luaL_openlibs(state); + + if(!allowUnsafeFunctions) + { + lua_pushnil(state); + lua_setglobal(state, "os"); + lua_pushnil(state); + lua_setglobal(state, "io"); + } // Set up various tables for state management: diff --git a/Aquaria/UserSettings.cpp b/Aquaria/UserSettings.cpp index d97dc23..771c40f 100644 --- a/Aquaria/UserSettings.cpp +++ b/Aquaria/UserSettings.cpp @@ -60,6 +60,12 @@ void UserSettings::save() xml_devmode.SetAttribute("on", system.devModeOn); } xml_system.InsertEndChild(xml_devmode); + + TiXmlElement xml_unsafe("AllowDangerousScriptFunctions"); + { + xml_unsafe.SetAttribute("on", system.allowDangerousScriptFunctions); + } + xml_system.InsertEndChild(xml_unsafe); } doc.InsertEndChild(xml_system); @@ -382,6 +388,12 @@ void UserSettings::load(bool doApply, const std::string &overrideFile) { xml_devmode->Attribute("on", &system.devModeOn); } + + TiXmlElement *xml_unsafe = xml_system->FirstChildElement("AllowDangerousScriptFunctions"); + if (xml_unsafe) + { + xml_unsafe->Attribute("on", &system.allowDangerousScriptFunctions); + } } TiXmlElement *xml_audio = doc.FirstChildElement("Audio"); diff --git a/Aquaria/UserSettings.h b/Aquaria/UserSettings.h index c6b0c22..cdd19f4 100644 --- a/Aquaria/UserSettings.h +++ b/Aquaria/UserSettings.h @@ -78,10 +78,11 @@ class UserSettings public: struct System { - System() { debugLogOn = 0; devModeOn = 0; } + System() { debugLogOn = 0; devModeOn = 0; allowDangerousScriptFunctions = 0; } int debugLogOn; std::string locale; int devModeOn; + int allowDangerousScriptFunctions; } system; struct Audio diff --git a/files/data/stringbank.txt b/files/data/stringbank.txt index 532bc5a..dc2e690 100644 --- a/files/data/stringbank.txt +++ b/files/data/stringbank.txt @@ -208,6 +208,7 @@ 2032 [Achievements] 2033 Retrieving online mod list... 2034 Open URL in web browser? +2050 -- WARNING: Dangerous script functions are ENABLED! 2100 === for options menu === 2101 Action 2102 Key 1