mirror of
https://github.com/minetest/minetest.git
synced 2024-11-23 16:13:46 +01:00
New map directory structure that avoids map size being limited by filesystem
This commit is contained in:
parent
f1bdc6b187
commit
e09fec3373
@ -290,5 +290,24 @@ bool RecursiveDeleteContent(std::string path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CreateAllDirs(std::string path)
|
||||||
|
{
|
||||||
|
|
||||||
|
size_t pos;
|
||||||
|
std::vector<std::string> tocreate;
|
||||||
|
std::string basepath = path;
|
||||||
|
while(!PathExists(basepath))
|
||||||
|
{
|
||||||
|
tocreate.push_back(basepath);
|
||||||
|
pos = basepath.rfind('/');
|
||||||
|
if(pos == std::string::npos)
|
||||||
|
return false;
|
||||||
|
basepath = basepath.substr(0,pos);
|
||||||
|
}
|
||||||
|
for(int i=tocreate.size()-1;i>=0;i--)
|
||||||
|
CreateDir(tocreate[i]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|
||||||
|
@ -38,6 +38,9 @@ std::vector<DirListNode> GetDirListing(std::string path);
|
|||||||
// Returns true if already exists
|
// Returns true if already exists
|
||||||
bool CreateDir(std::string path);
|
bool CreateDir(std::string path);
|
||||||
|
|
||||||
|
// Create all directories on the given path that don't already exist.
|
||||||
|
bool CreateAllDirs(std::string path);
|
||||||
|
|
||||||
bool PathExists(std::string path);
|
bool PathExists(std::string path);
|
||||||
|
|
||||||
// Only pass full paths to this one. True on success.
|
// Only pass full paths to this one. True on success.
|
||||||
|
124
src/map.cpp
124
src/map.cpp
@ -4875,9 +4875,9 @@ plan_b:
|
|||||||
return (s16)level;
|
return (s16)level;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerMap::createDir(std::string path)
|
void ServerMap::createDirs(std::string path)
|
||||||
{
|
{
|
||||||
if(fs::CreateDir(path) == false)
|
if(fs::CreateAllDirs(path) == false)
|
||||||
{
|
{
|
||||||
m_dout<<DTIME<<"ServerMap: Failed to create directory "
|
m_dout<<DTIME<<"ServerMap: Failed to create directory "
|
||||||
<<"\""<<path<<"\""<<std::endl;
|
<<"\""<<path<<"\""<<std::endl;
|
||||||
@ -4885,29 +4885,52 @@ void ServerMap::createDir(std::string path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ServerMap::getSectorSubDir(v2s16 pos)
|
std::string ServerMap::getSectorDir(v2s16 pos, int layout)
|
||||||
{
|
{
|
||||||
char cc[9];
|
char cc[9];
|
||||||
snprintf(cc, 9, "%.4x%.4x",
|
switch(layout)
|
||||||
(unsigned int)pos.X&0xffff,
|
{
|
||||||
(unsigned int)pos.Y&0xffff);
|
case 1:
|
||||||
|
snprintf(cc, 9, "%.4x%.4x",
|
||||||
|
(unsigned int)pos.X&0xffff,
|
||||||
|
(unsigned int)pos.Y&0xffff);
|
||||||
|
|
||||||
return std::string(cc);
|
return m_savedir + "/sectors/" + cc;
|
||||||
}
|
case 2:
|
||||||
|
snprintf(cc, 9, "%.3x/%.3x",
|
||||||
|
(unsigned int)pos.X&0xfff,
|
||||||
|
(unsigned int)pos.Y&0xfff);
|
||||||
|
|
||||||
std::string ServerMap::getSectorDir(v2s16 pos)
|
return m_savedir + "/sectors2/" + cc;
|
||||||
{
|
default:
|
||||||
return m_savedir + "/sectors/" + getSectorSubDir(pos);
|
assert(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v2s16 ServerMap::getSectorPos(std::string dirname)
|
v2s16 ServerMap::getSectorPos(std::string dirname)
|
||||||
{
|
{
|
||||||
if(dirname.size() != 8)
|
|
||||||
throw InvalidFilenameException("Invalid sector directory name");
|
|
||||||
unsigned int x, y;
|
unsigned int x, y;
|
||||||
int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
|
int r;
|
||||||
if(r != 2)
|
size_t spos = dirname.rfind('/') + 1;
|
||||||
throw InvalidFilenameException("Invalid sector directory name");
|
assert(spos != std::string::npos);
|
||||||
|
if(dirname.size() - spos == 8)
|
||||||
|
{
|
||||||
|
// Old layout
|
||||||
|
r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
|
||||||
|
}
|
||||||
|
else if(dirname.size() - spos == 3)
|
||||||
|
{
|
||||||
|
// New layout
|
||||||
|
r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
|
||||||
|
// Sign-extend the 12 bit values up to 16 bits...
|
||||||
|
if(x&0x800) x|=0xF000;
|
||||||
|
if(y&0x800) y|=0xF000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
assert(r == 2);
|
||||||
v2s16 pos((s16)x, (s16)y);
|
v2s16 pos((s16)x, (s16)y);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
@ -5106,7 +5129,7 @@ void ServerMap::saveMapMeta()
|
|||||||
<<"seed="<<m_seed<<", chunksize="<<m_chunksize
|
<<"seed="<<m_seed<<", chunksize="<<m_chunksize
|
||||||
<<std::endl;
|
<<std::endl;
|
||||||
|
|
||||||
createDir(m_savedir);
|
createDirs(m_savedir);
|
||||||
|
|
||||||
std::string fullpath = m_savedir + "/map_meta.txt";
|
std::string fullpath = m_savedir + "/map_meta.txt";
|
||||||
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
|
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
|
||||||
@ -5179,7 +5202,7 @@ void ServerMap::saveChunkMeta()
|
|||||||
dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
|
dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
|
||||||
<<count<<" chunks"<<std::endl;
|
<<count<<" chunks"<<std::endl;
|
||||||
|
|
||||||
createDir(m_savedir);
|
createDirs(m_savedir);
|
||||||
|
|
||||||
std::string fullpath = m_savedir + "/chunk_meta";
|
std::string fullpath = m_savedir + "/chunk_meta";
|
||||||
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
|
std::ofstream os(fullpath.c_str(), std::ios_base::binary);
|
||||||
@ -5267,10 +5290,8 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
|
|||||||
u8 version = SER_FMT_VER_HIGHEST;
|
u8 version = SER_FMT_VER_HIGHEST;
|
||||||
// Get destination
|
// Get destination
|
||||||
v2s16 pos = sector->getPos();
|
v2s16 pos = sector->getPos();
|
||||||
createDir(m_savedir);
|
|
||||||
createDir(m_savedir+"/sectors");
|
|
||||||
std::string dir = getSectorDir(pos);
|
std::string dir = getSectorDir(pos);
|
||||||
createDir(dir);
|
createDirs(dir);
|
||||||
|
|
||||||
std::string fullpath = dir + "/meta";
|
std::string fullpath = dir + "/meta";
|
||||||
std::ofstream o(fullpath.c_str(), std::ios_base::binary);
|
std::ofstream o(fullpath.c_str(), std::ios_base::binary);
|
||||||
@ -5282,22 +5303,21 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
|
|||||||
sector->differs_from_disk = false;
|
sector->differs_from_disk = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapSector* ServerMap::loadSectorMeta(std::string dirname)
|
MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
|
||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
// Get destination
|
// Get destination
|
||||||
v2s16 p2d = getSectorPos(dirname);
|
v2s16 p2d = getSectorPos(sectordir);
|
||||||
std::string dir = m_savedir + "/sectors/" + dirname;
|
|
||||||
|
|
||||||
ServerMapSector *sector = NULL;
|
ServerMapSector *sector = NULL;
|
||||||
|
|
||||||
std::string fullpath = dir + "/meta";
|
std::string fullpath = sectordir + "/meta";
|
||||||
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
|
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
|
||||||
if(is.good() == false)
|
if(is.good() == false)
|
||||||
{
|
{
|
||||||
// If the directory exists anyway, it probably is in some old
|
// If the directory exists anyway, it probably is in some old
|
||||||
// format. Just go ahead and create the sector.
|
// format. Just go ahead and create the sector.
|
||||||
if(fs::PathExists(dir))
|
if(fs::PathExists(sectordir))
|
||||||
{
|
{
|
||||||
dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
|
dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
|
||||||
<<fullpath<<" doesn't exist but directory does."
|
<<fullpath<<" doesn't exist but directory does."
|
||||||
@ -5307,12 +5327,16 @@ MapSector* ServerMap::loadSectorMeta(std::string dirname)
|
|||||||
m_sectors.insert(p2d, sector);
|
m_sectors.insert(p2d, sector);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
throw FileNotGoodException("Cannot open sector metafile");
|
throw FileNotGoodException("Cannot open sector metafile");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sector = ServerMapSector::deSerialize
|
sector = ServerMapSector::deSerialize
|
||||||
(is, this, p2d, m_sectors);
|
(is, this, p2d, m_sectors);
|
||||||
|
if(save_after_load)
|
||||||
|
saveSectorMeta(sector);
|
||||||
}
|
}
|
||||||
|
|
||||||
sector->differs_from_disk = false;
|
sector->differs_from_disk = false;
|
||||||
@ -5323,14 +5347,31 @@ MapSector* ServerMap::loadSectorMeta(std::string dirname)
|
|||||||
bool ServerMap::loadSectorFull(v2s16 p2d)
|
bool ServerMap::loadSectorFull(v2s16 p2d)
|
||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
std::string sectorsubdir = getSectorSubDir(p2d);
|
|
||||||
|
|
||||||
MapSector *sector = NULL;
|
MapSector *sector = NULL;
|
||||||
|
|
||||||
|
// The directory layout we're going to load from.
|
||||||
|
// 1 - original sectors/xxxxzzzz/
|
||||||
|
// 2 - new sectors2/xxx/zzz/
|
||||||
|
// If we load from anything but the latest structure, we will
|
||||||
|
// immediately save to the new one, and remove the old.
|
||||||
|
int loadlayout = 1;
|
||||||
|
std::string sectordir1 = getSectorDir(p2d, 1);
|
||||||
|
std::string sectordir;
|
||||||
|
if(fs::PathExists(sectordir1))
|
||||||
|
{
|
||||||
|
sectordir = sectordir1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loadlayout = 2;
|
||||||
|
sectordir = getSectorDir(p2d, 2);
|
||||||
|
}
|
||||||
|
|
||||||
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
//JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
|
||||||
|
|
||||||
try{
|
try{
|
||||||
sector = loadSectorMeta(sectorsubdir);
|
sector = loadSectorMeta(sectordir, loadlayout != 2);
|
||||||
}
|
}
|
||||||
catch(InvalidFilenameException &e)
|
catch(InvalidFilenameException &e)
|
||||||
{
|
{
|
||||||
@ -5349,7 +5390,7 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
|
|||||||
Load blocks
|
Load blocks
|
||||||
*/
|
*/
|
||||||
std::vector<fs::DirListNode> list2 = fs::GetDirListing
|
std::vector<fs::DirListNode> list2 = fs::GetDirListing
|
||||||
(m_savedir+"/sectors/"+sectorsubdir);
|
(sectordir);
|
||||||
std::vector<fs::DirListNode>::iterator i2;
|
std::vector<fs::DirListNode>::iterator i2;
|
||||||
for(i2=list2.begin(); i2!=list2.end(); i2++)
|
for(i2=list2.begin(); i2!=list2.end(); i2++)
|
||||||
{
|
{
|
||||||
@ -5357,16 +5398,25 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
|
|||||||
if(i2->dir)
|
if(i2->dir)
|
||||||
continue;
|
continue;
|
||||||
try{
|
try{
|
||||||
loadBlock(sectorsubdir, i2->name, sector);
|
loadBlock(sectordir, i2->name, sector, loadlayout != 2);
|
||||||
}
|
}
|
||||||
catch(InvalidFilenameException &e)
|
catch(InvalidFilenameException &e)
|
||||||
{
|
{
|
||||||
// This catches unknown crap in directory
|
// This catches unknown crap in directory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(loadlayout != 2)
|
||||||
|
{
|
||||||
|
dstream<<"Sector converted to new layout - deleting "<<
|
||||||
|
sectordir1<<std::endl;
|
||||||
|
fs::RecursiveDelete(sectordir1);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ServerMap::saveBlock(MapBlock *block)
|
void ServerMap::saveBlock(MapBlock *block)
|
||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
@ -5386,12 +5436,9 @@ void ServerMap::saveBlock(MapBlock *block)
|
|||||||
// Get destination
|
// Get destination
|
||||||
v3s16 p3d = block->getPos();
|
v3s16 p3d = block->getPos();
|
||||||
v2s16 p2d(p3d.X, p3d.Z);
|
v2s16 p2d(p3d.X, p3d.Z);
|
||||||
createDir(m_savedir);
|
|
||||||
createDir(m_savedir+"/sectors");
|
|
||||||
std::string dir = getSectorDir(p2d);
|
std::string dir = getSectorDir(p2d);
|
||||||
createDir(dir);
|
createDirs(dir);
|
||||||
|
|
||||||
// Block file is map/sectors/xxxxxxxx/xxxx
|
|
||||||
char cc[5];
|
char cc[5];
|
||||||
snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
|
snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
|
||||||
std::string fullpath = dir + "/" + cc;
|
std::string fullpath = dir + "/" + cc;
|
||||||
@ -5427,12 +5474,11 @@ void ServerMap::saveBlock(MapBlock *block)
|
|||||||
block->resetChangedFlag();
|
block->resetChangedFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
|
void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
|
||||||
{
|
{
|
||||||
DSTACK(__FUNCTION_NAME);
|
DSTACK(__FUNCTION_NAME);
|
||||||
|
|
||||||
// Block file is map/sectors/xxxxxxxx/xxxx
|
std::string fullpath = sectordir+"/"+blockfile;
|
||||||
std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
|
|
||||||
try{
|
try{
|
||||||
|
|
||||||
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
|
std::ifstream is(fullpath.c_str(), std::ios_base::binary);
|
||||||
@ -5496,7 +5542,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Save old format blocks in new format
|
// Save old format blocks in new format
|
||||||
if(version < SER_FMT_VER_HIGHEST)
|
if(version < SER_FMT_VER_HIGHEST || save_after_load)
|
||||||
{
|
{
|
||||||
saveBlock(block);
|
saveBlock(block);
|
||||||
}
|
}
|
||||||
|
12
src/map.h
12
src/map.h
@ -545,13 +545,9 @@ public:
|
|||||||
Misc. helper functions for fiddling with directory and file
|
Misc. helper functions for fiddling with directory and file
|
||||||
names when saving
|
names when saving
|
||||||
*/
|
*/
|
||||||
void createDir(std::string path);
|
void createDirs(std::string path);
|
||||||
void createSaveDir();
|
|
||||||
// returns something like "xxxxxxxx"
|
|
||||||
std::string getSectorSubDir(v2s16 pos);
|
|
||||||
// returns something like "map/sectors/xxxxxxxx"
|
// returns something like "map/sectors/xxxxxxxx"
|
||||||
std::string getSectorDir(v2s16 pos);
|
std::string getSectorDir(v2s16 pos, int layout = 2);
|
||||||
std::string createSectorDir(v2s16 pos);
|
|
||||||
// dirname: final directory name
|
// dirname: final directory name
|
||||||
v2s16 getSectorPos(std::string dirname);
|
v2s16 getSectorPos(std::string dirname);
|
||||||
v3s16 getBlockPos(std::string sectordir, std::string blockfile);
|
v3s16 getBlockPos(std::string sectordir, std::string blockfile);
|
||||||
@ -572,7 +568,7 @@ public:
|
|||||||
// (no MapBlocks)
|
// (no MapBlocks)
|
||||||
// DEPRECATED? Sectors have no metadata anymore.
|
// DEPRECATED? Sectors have no metadata anymore.
|
||||||
void saveSectorMeta(ServerMapSector *sector);
|
void saveSectorMeta(ServerMapSector *sector);
|
||||||
MapSector* loadSectorMeta(std::string dirname);
|
MapSector* loadSectorMeta(std::string dirname, bool save_after_load);
|
||||||
|
|
||||||
// Full load of a sector including all blocks.
|
// Full load of a sector including all blocks.
|
||||||
// returns true on success, false on failure.
|
// returns true on success, false on failure.
|
||||||
@ -583,7 +579,7 @@ public:
|
|||||||
|
|
||||||
void saveBlock(MapBlock *block);
|
void saveBlock(MapBlock *block);
|
||||||
// This will generate a sector with getSector if not found.
|
// This will generate a sector with getSector if not found.
|
||||||
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector);
|
void loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load=false);
|
||||||
|
|
||||||
// For debug printing
|
// For debug printing
|
||||||
virtual void PrintInfo(std::ostream &out);
|
virtual void PrintInfo(std::ostream &out);
|
||||||
|
Loading…
Reference in New Issue
Block a user