mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-11-29 12:03:51 +00:00
Merge branch 'experimental' into tile-optimization
This commit is contained in:
commit
f641764765
12 changed files with 129 additions and 110 deletions
|
@ -3109,6 +3109,10 @@ std::string DSQ::getUserInputString(std::string labelText, std::string t, bool a
|
|||
doAlphabetInputKey(KEY_MINUS, '-', (char*)&map, &text, '_');
|
||||
|
||||
doAlphabetInputKey(KEY_TILDE, '~', (char*)&map, &text, '~');
|
||||
doAlphabetInputKey(KEY_EQUALS, '=', (char*)&map, &text);
|
||||
doAlphabetInputKey(KEY_LBRACKET, '(', (char*)&map, &text);
|
||||
doAlphabetInputKey(KEY_RBRACKET, ')', (char*)&map, &text);
|
||||
doAlphabetInputKey(KEY_SEMICOLON, ';', (char*)&map, &text);
|
||||
}
|
||||
|
||||
if (getKeyState(KEY_BACKSPACE))
|
||||
|
|
|
@ -2447,7 +2447,7 @@ bool Entity::doCollisionAvoidance(float dt, int search, float mod, Vector *vp, f
|
|||
Vector accum;
|
||||
int c = 0;
|
||||
bool isInWaterBubble = false;
|
||||
if (waterBubble && isUnderWater())
|
||||
if (isUnderWater() && waterBubble) // isUnderWater() may set waterBubble
|
||||
{
|
||||
//debugLog("collision avoidance in bubble");
|
||||
isInWaterBubble = true;
|
||||
|
|
|
@ -230,6 +230,7 @@ Game::Game() : StateObject()
|
|||
doScreenTrans = false;
|
||||
noSceneTransitionFadeout = false;
|
||||
fullTilesetReload = false;
|
||||
highestLoadedEntityID = 0;
|
||||
}
|
||||
|
||||
Game::~Game()
|
||||
|
@ -908,7 +909,7 @@ EntitySaveData *Game::getEntitySaveDataForEntity(Entity *e)
|
|||
int Game::findUnusedEntityID(bool temporary) const
|
||||
{
|
||||
const int inc = temporary ? -1 : 1;
|
||||
int id = 0;
|
||||
int id = temporary ? 0 : highestLoadedEntityID + 1; // never touch entity IDs that were in use in the map xml
|
||||
retry:
|
||||
id += inc;
|
||||
FOR_ENTITIES(i)
|
||||
|
@ -1228,7 +1229,7 @@ Path *Game::getWaterbubbleAt(const Vector& pos, float rad) const
|
|||
|
||||
UnderWaterResult Game::isUnderWater(const Vector& pos, float rad) const
|
||||
{
|
||||
UnderWaterResult ret { false, NULL };
|
||||
UnderWaterResult ret = { false, NULL };
|
||||
if (!game->useWaterLevel || game->waterLevel.x == 0
|
||||
|| (useWaterLevel && waterLevel.x > 0 && pos.y-rad > waterLevel.x))
|
||||
{
|
||||
|
@ -1795,9 +1796,11 @@ next_SE:
|
|||
void Game::spawnEntities(const EntitySaveData *sav, size_t n)
|
||||
{
|
||||
std::vector<size_t> conflicting, usable;
|
||||
int highest = 0;
|
||||
for(size_t i = 0; i < n; ++i)
|
||||
{
|
||||
const EntitySaveData& es = sav[i];
|
||||
highest = std::max(es.id, highest);
|
||||
|
||||
// check for ID conflicts
|
||||
int id = es.id;
|
||||
|
@ -1820,6 +1823,8 @@ void Game::spawnEntities(const EntitySaveData *sav, size_t n)
|
|||
conflicting.push_back(i);
|
||||
}
|
||||
|
||||
highestLoadedEntityID = highest;
|
||||
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Game::spawnEntities: Spawning " << usable.size() << " entities";
|
||||
|
@ -1838,7 +1843,7 @@ void Game::spawnEntities(const EntitySaveData *sav, size_t n)
|
|||
}
|
||||
|
||||
// spawn and renumber the rest
|
||||
int lastid = 0;
|
||||
int lastid = highest;
|
||||
for(size_t i = 0; i < conflicting.size(); ++i)
|
||||
{
|
||||
// find an unused ID
|
||||
|
|
|
@ -90,6 +90,8 @@ class ObsRow
|
|||
public:
|
||||
inline ObsRow(unsigned tx, unsigned ty, unsigned len)
|
||||
: tx(tx), ty(ty), len(len) {}
|
||||
inline ObsRow(const ObsRow& o)
|
||||
: tx(o.tx), ty(o.ty), len(o.len) {}
|
||||
const unsigned tx, ty, len;
|
||||
};
|
||||
|
||||
|
@ -412,6 +414,7 @@ public:
|
|||
void onContinuityReset();
|
||||
|
||||
protected:
|
||||
unsigned highestLoadedEntityID;
|
||||
|
||||
void toggleHelpScreen(bool on, const std::string &label="");
|
||||
void onToggleHelpScreen();
|
||||
|
|
|
@ -970,17 +970,18 @@ void Core::resetTimer()
|
|||
|
||||
void Core::setMousePosition(const Vector &p)
|
||||
{
|
||||
float px = p.x + virtualOffX;
|
||||
float py = p.y;
|
||||
int ix, iy;
|
||||
virtualCoordsToPixelPos(ix, iy, p);
|
||||
|
||||
SDL_Event ev = { sdlUserMouseEventID };
|
||||
ev.motion.x = ix;
|
||||
ev.motion.y = iy;
|
||||
ev.motion.xrel = 0;
|
||||
ev.motion.yrel = 0;
|
||||
ev.motion.state = 0;
|
||||
SDL_PushEvent(&ev);
|
||||
|
||||
window->warpMouse(
|
||||
px * (float(width)/float(virtualWidth)),
|
||||
py * (float(height)/float(virtualHeight))
|
||||
);
|
||||
window->warpMouse(ix, iy);
|
||||
|
||||
ev.motion.state = 1;
|
||||
SDL_PushEvent(&ev);
|
||||
|
@ -1247,12 +1248,12 @@ void Core::setMouseConstraintCircle(const Vector& pos, float circle)
|
|||
|
||||
|
||||
|
||||
int Core::getVirtualOffX()
|
||||
int Core::getVirtualOffX() const
|
||||
{
|
||||
return virtualOffX;
|
||||
}
|
||||
|
||||
int Core::getVirtualOffY()
|
||||
int Core::getVirtualOffY() const
|
||||
{
|
||||
return virtualOffY;
|
||||
}
|
||||
|
@ -1279,12 +1280,39 @@ bool Core::doMouseConstraint()
|
|||
return false;
|
||||
}
|
||||
|
||||
Vector Core::pixelPosToVirtualCoords(int x, int y) const
|
||||
{
|
||||
const float mx = float(virtualWidth)/float(getWindowWidth());
|
||||
const float my = float(virtualHeight)/float(getWindowHeight());
|
||||
|
||||
return Vector(
|
||||
(x * mx) - getVirtualOffX(),
|
||||
y * my
|
||||
);
|
||||
}
|
||||
|
||||
void Core::virtualCoordsToPixelPos(int& x, int& y, const Vector& p) const
|
||||
{
|
||||
const float px = p.x + getVirtualOffX();
|
||||
const float py = p.y;
|
||||
x = px * (float(getWindowWidth())/float(virtualWidth));
|
||||
y = py * (float(getWindowHeight())/float(virtualHeight));
|
||||
}
|
||||
|
||||
void Core::onEvent(const SDL_Event& event)
|
||||
{
|
||||
const bool focus = window->hasFocus();
|
||||
if(event.type == sdlUserMouseEventID)
|
||||
{
|
||||
mouse._enableMotionEvents = event.motion.state;
|
||||
mouse._enableMotionEvents = !!event.motion.state;
|
||||
if(event.motion.state) // If 1, the generated mouse move is done and the rest is true mouse events
|
||||
{
|
||||
// We just set the position, so lets make sure that this mouse move isn't picked up
|
||||
// as a relative change, ie. there was no actual user mouse move.
|
||||
// There may be regular mouse move events after this one, which will be picked up normally.
|
||||
mouse.lastPosition = pixelPosToVirtualCoords(event.motion.x, event.motion.y);
|
||||
goto motion; // All the needed data are there, use this like a regular motion event
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1324,16 +1352,15 @@ void Core::onEvent(const SDL_Event& event)
|
|||
}
|
||||
break;
|
||||
|
||||
// This event is also sent when SDL sets the mouse position!
|
||||
// Since there's no way to distinguish the generated event from a true "user moved the mouse" event,
|
||||
// sdlUserMouseEventID (above) is used to guard a generated motion event.
|
||||
case SDL_MOUSEMOTION:
|
||||
{
|
||||
if (focus)
|
||||
if (focus && mouse._enableMotionEvents)
|
||||
{
|
||||
const float mx = float(virtualWidth)/float(getWindowWidth());
|
||||
const float my = float(virtualHeight)/float(getWindowHeight());
|
||||
|
||||
mouse.position.x = ((event.motion.x) * mx) - getVirtualOffX();
|
||||
mouse.position.y = event.motion.y * my;
|
||||
if(mouse._enableMotionEvents)
|
||||
motion:
|
||||
mouse.position = pixelPosToVirtualCoords(event.motion.x, event.motion.y);
|
||||
mouse._wasMoved = true;
|
||||
}
|
||||
}
|
||||
|
@ -1438,10 +1465,7 @@ void Core::pollEvents(float dt)
|
|||
if(mouse._wasMoved)
|
||||
{
|
||||
if(doMouseConstraint())
|
||||
{
|
||||
setMousePosition(mouse.position);
|
||||
window->handleInput();
|
||||
}
|
||||
mouse.change = mouse.position - mouse.lastPosition;
|
||||
}
|
||||
|
||||
|
|
|
@ -233,6 +233,8 @@ public:
|
|||
// state functions
|
||||
|
||||
void setMousePosition(const Vector &p);
|
||||
Vector pixelPosToVirtualCoords(int x, int y) const;
|
||||
void virtualCoordsToPixelPos(int& x, int& y, const Vector& p) const;
|
||||
|
||||
void setFullscreen(bool full);
|
||||
|
||||
|
@ -383,8 +385,8 @@ public:
|
|||
int getDisplayIndex();
|
||||
int getRefreshRate();
|
||||
|
||||
int getVirtualOffX();
|
||||
int getVirtualOffY();
|
||||
int getVirtualOffX() const;
|
||||
int getVirtualOffY() const;
|
||||
|
||||
void centerMouse();
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ void Precacher::doCache(ProgressCallback progress)
|
|||
debugLog(os.str());
|
||||
std::vector<Texture*> tmp(todo.size());
|
||||
core->texmgr.loadBatch(&tmp[0], &todo[0], todo.size(), TextureMgr::KEEP,
|
||||
progress ? texLoadProgressCallback : NULL, progress);
|
||||
progress ? texLoadProgressCallback : NULL, (void*)progress);
|
||||
todo.clear();
|
||||
texkeep.reserve(texkeep.size() + tmp.size());
|
||||
for(size_t i = 0; i < tmp.size(); ++i)
|
||||
|
|
|
@ -137,51 +137,16 @@ void Bone::createStrip(bool vert, int num)
|
|||
}
|
||||
|
||||
|
||||
Quad* Bone::addFrame(const std::string &gfx)
|
||||
void Bone::addFrame(const std::string &gfx)
|
||||
{
|
||||
renderQuad = false;
|
||||
Quad *q = new Quad();
|
||||
q->setTexture(gfx);
|
||||
q->renderBeforeParent = 1;
|
||||
addChild(q, PM_POINTER);
|
||||
return q;
|
||||
framegfx.push_back(gfx);
|
||||
}
|
||||
|
||||
void Bone::showFrame(int idx)
|
||||
{
|
||||
|
||||
int c = 0;
|
||||
for (Children::iterator i = children.begin(); i != children.end(); i++)
|
||||
{
|
||||
RenderObject *r = (*i);
|
||||
if (idx == c)
|
||||
{
|
||||
if (r->alpha == 0)
|
||||
{
|
||||
r->alpha = 1;
|
||||
|
||||
// add option to turn on alpha fading
|
||||
//r->alpha.interpolateTo(1, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
r->alpha = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r->alpha == 1)
|
||||
{
|
||||
r->alpha = 0;
|
||||
//r->alpha.interpolateTo(0, t*2);
|
||||
}
|
||||
else
|
||||
{
|
||||
r->alpha = 0;
|
||||
}
|
||||
}
|
||||
c++;
|
||||
}
|
||||
size_t i = idx;
|
||||
if(i < framegfx.size())
|
||||
setTexture(framegfx[i]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -391,6 +356,11 @@ bool BoneCommand::parse(Bone *b, SimpleIStringStream &is)
|
|||
}
|
||||
else if(type == "AC_RESET_PASS")
|
||||
command = AC_RESET_PASS;
|
||||
else if(type == "AC_SET_FH")
|
||||
{
|
||||
command = AC_SET_FH;
|
||||
is >> slot;
|
||||
}
|
||||
else // fail
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
@ -445,6 +415,19 @@ void BoneCommand::run()
|
|||
case AC_RESET_PASS:
|
||||
b->setRenderPass(b->originalRenderPass);
|
||||
break;
|
||||
case AC_SET_FH:
|
||||
{
|
||||
bool should = false;
|
||||
switch(slot)
|
||||
{
|
||||
case 0: should = b->originalFH; break;
|
||||
case 1: should = !b->originalFH; break;
|
||||
case 2: should = true; break;
|
||||
default: should = false; break;
|
||||
}
|
||||
b->fhTo(should);
|
||||
break;
|
||||
}
|
||||
case AC_SEGS_START:
|
||||
case AC_SEGS_STOP:
|
||||
break;
|
||||
|
@ -605,7 +588,7 @@ void AnimationLayer::createTransitionAnimation(Animation& to, float time)
|
|||
|
||||
void AnimationLayer::stopAnimation()
|
||||
{
|
||||
if(s->loaded && getCurrentAnimation()->resetPassOnEnd)
|
||||
if(s->loaded && getCurrentAnimation()->resetOnEnd)
|
||||
resetPass();
|
||||
animating = false;
|
||||
if (!enqueuedAnimation.empty())
|
||||
|
@ -627,7 +610,7 @@ float AnimationLayer::getAnimationLength()
|
|||
}
|
||||
|
||||
Animation::Animation()
|
||||
: resetPassOnEnd(false)
|
||||
: resetOnEnd(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -980,7 +963,7 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
bone->SetAttribute("gfx", this->bones[i]->gfx.c_str());
|
||||
bone->SetAttribute("pidx", this->bones[i]->pidx);
|
||||
bone->SetAttribute("name", this->bones[i]->name.c_str());
|
||||
bone->SetAttribute("fh", this->bones[i]->isfh());
|
||||
bone->SetAttribute("fh", this->bones[i]->originalFH);
|
||||
bone->SetAttribute("fv", this->bones[i]->isfv());
|
||||
bone->SetAttribute("gc", this->bones[i]->generateCollisionMask);
|
||||
bone->SetAttribute("cr", this->bones[i]->collideRadius);
|
||||
|
@ -1039,22 +1022,12 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
}
|
||||
|
||||
|
||||
for (Children::iterator j = this->bones[i]->children.begin(); j != this->bones[i]->children.end(); j++)
|
||||
{
|
||||
Bone *b = dynamic_cast<Bone*>(*j);
|
||||
Quad *q = dynamic_cast<Quad*>(*j);
|
||||
Particle *p = dynamic_cast<Particle*>(*j);
|
||||
if (q && !b && !p)
|
||||
for(size_t j = 0; j < this->bones[i]->framegfx.size(); ++j)
|
||||
{
|
||||
XMLElement *frame = xml->NewElement("Frame");
|
||||
frame->SetAttribute("gfx", q->texture->name.c_str());
|
||||
if (q->getRenderPass() != 0)
|
||||
{
|
||||
frame->SetAttribute("pass", q->getRenderPass());
|
||||
}
|
||||
frame->SetAttribute("gfx", this->bones[i]->framegfx[j].c_str());
|
||||
bone->InsertEndChild(frame);
|
||||
}
|
||||
}
|
||||
bones->InsertEndChild(bone);
|
||||
}
|
||||
xml->InsertEndChild(bones);
|
||||
|
@ -1065,8 +1038,8 @@ bool SkeletalSprite::saveSkeletal(const std::string &fn)
|
|||
Animation *a = &this->animations[i];
|
||||
XMLElement *animation = xml->NewElement("Animation");
|
||||
animation->SetAttribute("name", a->name.c_str());
|
||||
if(a->resetPassOnEnd)
|
||||
animation->SetAttribute("resetPassOnEnd", a->resetPassOnEnd);
|
||||
if(!a->resetOnEnd)
|
||||
animation->SetAttribute("resetOnEnd", a->resetOnEnd);
|
||||
|
||||
for (size_t j = 0; j < a->interpolators.size(); ++j)
|
||||
{
|
||||
|
@ -1206,6 +1179,7 @@ Bone *SkeletalSprite::initBone(int idx, std::string gfx, int pidx, bool rbp, std
|
|||
b->pidx = pidx;
|
||||
b->collideRadius = cr;
|
||||
b->name = name;
|
||||
b->originalFH = fh;
|
||||
|
||||
if (fh)
|
||||
b->flipHorizontal();
|
||||
|
@ -1492,19 +1466,11 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
int frc=0;
|
||||
while(fr)
|
||||
{
|
||||
Quad *q=0;
|
||||
std::string gfx;
|
||||
if (fr->Attribute("gfx"))
|
||||
{
|
||||
gfx = fr->Attribute("gfx");
|
||||
q = newb->addFrame(gfx);
|
||||
}
|
||||
if (fr->Attribute("pass"))
|
||||
{
|
||||
if (q)
|
||||
{
|
||||
q->setRenderPass(atoi(fr->Attribute("pass")));
|
||||
}
|
||||
newb->addFrame(gfx);
|
||||
}
|
||||
fr = fr->NextSiblingElement("Frame");
|
||||
frc++;
|
||||
|
@ -1698,7 +1664,8 @@ void SkeletalSprite::loadSkeletal(const std::string &fn)
|
|||
{
|
||||
Animation newAnimation;
|
||||
newAnimation.name = animation->Attribute("name");
|
||||
newAnimation.resetPassOnEnd = animation->BoolAttribute("resetPassOnEnd");
|
||||
if(animation->Attribute("resetOnEnd"))
|
||||
newAnimation.resetOnEnd = animation->BoolAttribute("resetOnEnd");
|
||||
stringToLower(newAnimation.name);
|
||||
|
||||
XMLElement *key = animation->FirstChildElement("Key");
|
||||
|
@ -1952,7 +1919,10 @@ void AnimationLayer::resetPass()
|
|||
{
|
||||
Bone *b = s->bones[i];
|
||||
if (contains(b))
|
||||
{
|
||||
b->setRenderPass(b->originalRenderPass);
|
||||
b->fhTo(b->originalFH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@ enum AnimationCommand
|
|||
AC_SND_PLAY ,
|
||||
AC_SEGS_STOP,
|
||||
AC_SET_PASS,
|
||||
AC_RESET_PASS
|
||||
AC_RESET_PASS,
|
||||
AC_SET_FH
|
||||
};
|
||||
|
||||
class ParticleEffect;
|
||||
|
@ -58,7 +59,7 @@ public:
|
|||
ANIM_ALL = ANIM_POS | ANIM_ROT
|
||||
};
|
||||
void createStrip(bool vert, int num);
|
||||
Quad* addFrame(const std::string &gfx);
|
||||
void addFrame(const std::string &gfx);
|
||||
void showFrame(int i);
|
||||
void destroy() OVERRIDE;
|
||||
std::string gfx;
|
||||
|
@ -93,6 +94,7 @@ public:
|
|||
bool fileRenderQuad;
|
||||
bool selectable;
|
||||
int originalRenderPass; // stores the render pass originally set in the XML file. For AC_RESET_PASS.
|
||||
bool originalFH;
|
||||
|
||||
void spawnParticlesFromCollisionMask(const char *p, unsigned intv, int layer, float rotz = 0);
|
||||
Vector getCollisionMaskNormal(Vector pos, float dist) const;
|
||||
|
@ -107,6 +109,8 @@ public:
|
|||
std::vector<Vector> collisionMask;
|
||||
std::vector<Vector> transformedCollisionMask;
|
||||
float collisionMaskRadius;
|
||||
std::vector<std::string> framegfx;
|
||||
|
||||
};
|
||||
|
||||
class BoneCommand
|
||||
|
@ -181,7 +185,7 @@ public:
|
|||
size_t getSkeletalKeyframeIndex(SkeletalKeyframe *skey);
|
||||
size_t getNumKeyframes();
|
||||
void reverse();
|
||||
bool resetPassOnEnd;
|
||||
bool resetOnEnd;
|
||||
|
||||
BoneGridInterpolator *getBoneGridInterpolator(size_t boneIdx);
|
||||
typedef std::vector <BoneGridInterpolator> Interpolators;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6...3.20)
|
||||
PROJECT(Aquaria)
|
||||
SET(CMAKE_CXX_STANDARD 98)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
||||
|
||||
|
@ -56,6 +57,9 @@ OPTION(AQUARIA_USE_GLM "Use GLM for matrix math" TRUE)
|
|||
OPTION(AQUARIA_DEBUG_SHOW_PATHS "Show important paths upon game start to aid in finding path problems" FALSE)
|
||||
mark_as_advanced(AQUARIA_DEBUG_SHOW_PATHS)
|
||||
|
||||
#add_compile_options(-fsanitize=address)
|
||||
#add_link_options(-fsanitize=address)
|
||||
|
||||
################ Look for external libraries
|
||||
|
||||
### Pick one: SDL 1.2 or SDL2
|
||||
|
@ -137,14 +141,17 @@ ELSE(AQUARIA_DEMO_BUILD)
|
|||
ADD_DEFINITIONS(-DAQUARIA_BUILD_SCENEEDITOR=1)
|
||||
ENDIF(AQUARIA_DEMO_BUILD)
|
||||
|
||||
IF(NOT MSVC)
|
||||
# MSVC defines these in release mode by default, gcc/mingw do not
|
||||
IF(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
ADD_DEFINITIONS(-DNDEBUG) # MSVC defines this in release mode by default, gcc/mingw do not
|
||||
ADD_DEFINITIONS(-DNDEBUG)
|
||||
message(STATUS "This is a release build.")
|
||||
ENDIF(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
ADD_DEFINITIONS(-D_DEBUG) # MSVC defines this in debug mode by default, gcc/mingw do not
|
||||
ADD_DEFINITIONS(-D_DEBUG)
|
||||
message(STATUS "This is a debug build.")
|
||||
ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
ENDIF(NOT MSVC)
|
||||
|
||||
# FIXME: These should go
|
||||
IF(UNIX)
|
||||
|
|
|
@ -172,7 +172,7 @@ void DirBase::forEachDir(DirEnumCallback f, void *user /* = NULL */, bool safe /
|
|||
|
||||
DirBase *DirBase::getDirByName(const char *dn, bool /* unused: lazyLoad = true */, bool useSubtrees /* = true */)
|
||||
{
|
||||
if(!dn[0] || (dn[0] == '.' && !dn[1]))
|
||||
if(!dn || !dn[0] || (dn[0] == '.' && !dn[1]))
|
||||
return this;
|
||||
|
||||
Dirs::iterator it = _subdirs.find(dn);
|
||||
|
@ -312,7 +312,7 @@ DirBase *Dir::getDirByName(const char *dn, bool lazyLoad /* = true */, bool useS
|
|||
return NULL;
|
||||
|
||||
// Fix for absolute paths: No dir should have '/' (or any other absolute dirs) as subdir.
|
||||
if(fullnameLen() && dn[0] == '/')
|
||||
if(fullnameLen() && (dn && dn[0] == '/'))
|
||||
return NULL;
|
||||
|
||||
// Lazy-load file if it's not in the tree yet
|
||||
|
|
|
@ -65,7 +65,7 @@ template <typename T> void SkipSelfPath(T *& s)
|
|||
|
||||
inline std::string joinPath(std::string base, const char *sub)
|
||||
{
|
||||
if(!*sub)
|
||||
if(!sub || !*sub)
|
||||
return base;
|
||||
if(*sub != '/' && base.length() && base[base.length()-1] != '/')
|
||||
base += '/';
|
||||
|
|
Loading…
Reference in a new issue