diff --git a/scripts/make_release.py b/scripts/make_release.py index 7bc74b159..1a1359041 100644 --- a/scripts/make_release.py +++ b/scripts/make_release.py @@ -61,6 +61,7 @@ os.mkdir(package_dir) print "adding files" shutil.copy("readme.txt", package_dir) shutil.copy("license.txt", package_dir) +shutil.copy("storage.cfg", package_dir) if include_data and not use_bundle: os.mkdir(os.path.join(package_dir, "data")) @@ -133,6 +134,7 @@ if use_bundle: os.mkdir(serverbundle_resource_dir) os.mkdir(os.path.join(serverbundle_resource_dir, "data")) os.mkdir(os.path.join(serverbundle_resource_dir, "data/maps")) + os.mkdir(os.path.join(serverbundle_resource_dir, "data/mapres")) copydir("data/maps", serverbundle_resource_dir) shutil.copy("other/icons/Teeworlds_srv.icns", serverbundle_resource_dir) shutil.copy(name+"_srv"+exe_ext, serverbundle_bin_dir) diff --git a/src/engine/client.h b/src/engine/client.h index fe8e91f26..11ba73851 100644 --- a/src/engine/client.h +++ b/src/engine/client.h @@ -73,7 +73,7 @@ public: virtual void Connect(const char *pAddress) = 0; virtual void Disconnect() = 0; virtual void Quit() = 0; - virtual const char *DemoPlayer_Play(const char *pFilename) = 0; + virtual const char *DemoPlayer_Play(const char *pFilename, int StorageType) = 0; virtual void DemoRecorder_Start(const char *pFilename) = 0; // networking @@ -121,9 +121,6 @@ public: return SendMsg(&Packer, Flags); } - // - virtual const char *UserDirectory() = 0; - // virtual const char *ErrorString() = 0; virtual const char *LatestVersion() = 0; diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 4952446f2..7c0c632e3 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -585,7 +585,7 @@ void CClient::ServerInfoRequest() int CClient::LoadData() { - m_DebugFont = Graphics()->LoadTexture("debug_font.png", CImageInfo::FORMAT_AUTO, IGraphics::TEXLOAD_NORESAMPLE); + m_DebugFont = Graphics()->LoadTexture("debug_font.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, IGraphics::TEXLOAD_NORESAMPLE); return 1; } @@ -990,7 +990,7 @@ void CClient::ProcessPacket(CNetChunk *pPacket) m_MapdownloadChunk = 0; str_copy(m_aMapdownloadName, pMap, sizeof(m_aMapdownloadName)); - m_MapdownloadFile = Storage()->OpenFile(m_aMapdownloadFilename, IOFLAG_WRITE); + m_MapdownloadFile = Storage()->OpenFile(m_aMapdownloadFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); m_MapdownloadCrc = MapCrc; m_MapdownloadTotalsize = -1; m_MapdownloadAmount = 0; @@ -1537,13 +1537,6 @@ void CClient::Update() m_ServerBrowser.Update(); } -const char *CClient::UserDirectory() -{ - static char saPath[1024] = {0}; - fs_storage_path("Teeworlds", saPath, sizeof(saPath)); - return saPath; -} - void CClient::VersionUpdate() { if(m_VersionInfo.m_State == 0) @@ -1871,7 +1864,7 @@ void CClient::Con_AddFavorite(IConsole::IResult *pResult, void *pUserData) pSelf->m_ServerBrowser.AddFavorite(Addr); } -const char *CClient::DemoPlayer_Play(const char *pFilename) +const char *CClient::DemoPlayer_Play(const char *pFilename, int StorageType) { int Crc; const char *pError; @@ -1881,7 +1874,7 @@ const char *CClient::DemoPlayer_Play(const char *pFilename) // try to start playback m_DemoPlayer.SetListner(this); - if(m_DemoPlayer.Load(Storage(), m_pConsole, pFilename)) + if(m_DemoPlayer.Load(Storage(), m_pConsole, pFilename, StorageType)) return "error loading demo"; // load map @@ -1926,7 +1919,7 @@ const char *CClient::DemoPlayer_Play(const char *pFilename) void CClient::Con_Play(IConsole::IResult *pResult, void *pUserData) { CClient *pSelf = (CClient *)pUserData; - pSelf->DemoPlayer_Play(pResult->GetString(0)); + pSelf->DemoPlayer_Play(pResult->GetString(0), IStorage::TYPE_ALL); } void CClient::DemoRecorder_Start(const char *pFilename) diff --git a/src/engine/client/client.h b/src/engine/client/client.h index aa381467a..d9199b94c 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -259,8 +259,6 @@ public: void Update(); - virtual const char *UserDirectory(); - void InitEngine(const char *pAppname); void RegisterInterfaces(); void InitInterfaces(); @@ -283,7 +281,7 @@ public: void RegisterCommands(); - const char *DemoPlayer_Play(const char *pFilename); + const char *DemoPlayer_Play(const char *pFilename, int StorageType); void DemoRecorder_Start(const char *pFilename); virtual class CEngine *Engine() { return &m_Engine; } diff --git a/src/engine/client/graphics.cpp b/src/engine/client/graphics.cpp index 14a88394b..665f9ce71 100644 --- a/src/engine/client/graphics.cpp +++ b/src/engine/client/graphics.cpp @@ -354,7 +354,7 @@ int CGraphics_OpenGL::LoadTextureRaw(int Width, int Height, int Format, const vo } // simple uncompressed RGBA loaders -int CGraphics_OpenGL::LoadTexture(const char *pFilename, int StoreFormat, int Flags) +int CGraphics_OpenGL::LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags) { int l = str_length(pFilename); int Id; @@ -362,7 +362,7 @@ int CGraphics_OpenGL::LoadTexture(const char *pFilename, int StoreFormat, int Fl if(l < 3) return -1; - if(LoadPNG(&Img, pFilename)) + if(LoadPNG(&Img, pFilename, StorageType)) { if (StoreFormat == CImageInfo::FORMAT_AUTO) StoreFormat = Img.m_Format; @@ -375,7 +375,7 @@ int CGraphics_OpenGL::LoadTexture(const char *pFilename, int StoreFormat, int Fl return m_InvalidTexture; } -int CGraphics_OpenGL::LoadPNG(CImageInfo *pImg, const char *pFilename) +int CGraphics_OpenGL::LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) { char aCompleteFilename[512]; unsigned char *pBuffer; @@ -384,7 +384,7 @@ int CGraphics_OpenGL::LoadPNG(CImageInfo *pImg, const char *pFilename) // open file for reading png_init(0,0); // ignore_convention - IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, aCompleteFilename, sizeof(aCompleteFilename)); + IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, StorageType, aCompleteFilename, sizeof(aCompleteFilename)); if(File) io_close(File); else @@ -450,7 +450,7 @@ void CGraphics_OpenGL::ScreenshotDirect(const char *pFilename) char aWholePath[1024]; png_t Png; // ignore_convention - IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_WRITE, aWholePath, sizeof(aWholePath)); + IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE, aWholePath, sizeof(aWholePath)); if(File) io_close(File); @@ -898,7 +898,7 @@ void CGraphics_SDL::Swap() { IOHANDLE io; str_format(aFilename, sizeof(aFilename), "screenshots/screenshot%s-%05d.png", aDate, Index); - io = m_pStorage->OpenFile(aFilename, IOFLAG_READ); + io = m_pStorage->OpenFile(aFilename, IOFLAG_READ, IStorage::TYPE_SAVE); if(io) io_close(io); else diff --git a/src/engine/client/graphics.h b/src/engine/client/graphics.h index fa360a22a..ef6360e8a 100644 --- a/src/engine/client/graphics.h +++ b/src/engine/client/graphics.h @@ -87,8 +87,8 @@ public: virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags); // simple uncompressed RGBA loaders - virtual int LoadTexture(const char *pFilename, int StoreFormat, int Flags); - virtual int LoadPNG(CImageInfo *pImg, const char *pFilename); + virtual int LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags); + virtual int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType); void ScreenshotDirect(const char *pFilename); diff --git a/src/engine/client/sound.cpp b/src/engine/client/sound.cpp index b829686c8..69fd74625 100644 --- a/src/engine/client/sound.cpp +++ b/src/engine/client/sound.cpp @@ -325,7 +325,7 @@ int CSound::LoadWV(const char *pFilename) if(!m_pStorage) return -1; - ms_File = m_pStorage->OpenFile(pFilename, IOFLAG_READ); // TODO: use system.h stuff for this + ms_File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_ALL); if(!ms_File) { dbg_msg("sound/wv", "failed to open %s", pFilename); diff --git a/src/engine/client/text.cpp b/src/engine/client/text.cpp index bdf71dbb4..0fb6b043f 100644 --- a/src/engine/client/text.cpp +++ b/src/engine/client/text.cpp @@ -70,7 +70,7 @@ struct CFontSizeData class CFont { public: - char m_aFilename[128]; + char m_aFilename[512]; FT_Face m_FtFace; CFontSizeData m_aSizes[NUM_FONT_SIZES]; }; diff --git a/src/engine/graphics.h b/src/engine/graphics.h index 4d3c0bc02..cbd7bbff5 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -74,10 +74,10 @@ public: virtual void BlendAdditive() = 0; virtual int MemoryUsage() const = 0; - virtual int LoadPNG(CImageInfo *pImg, const char *pFilename) =0; + virtual int LoadPNG(CImageInfo *pImg, const char *pFilename, int StorageType) =0; virtual int UnloadTexture(int Index) = 0; virtual int LoadTextureRaw(int Width, int Height, int Format, const void *pData, int StoreFormat, int Flags) = 0; - virtual int LoadTexture(const char *pFilename, int StoreFormat, int Flags) = 0; + virtual int LoadTexture(const char *pFilename, int StorageType, int StoreFormat, int Flags) = 0; virtual void TextureSet(int TextureID) = 0; struct CLineItem diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 37d5770a9..c7b728d46 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1043,7 +1043,7 @@ int CServer::LoadMap(const char *pMapName) // load compelate map into memory for download { - IOHANDLE File = Storage()->OpenFile(aBuf, IOFLAG_READ); + IOHANDLE File = Storage()->OpenFile(aBuf, IOFLAG_READ, IStorage::TYPE_ALL); m_CurrentMapSize = (int)io_length(File); if(m_pCurrentMapData) mem_free(m_pCurrentMapData); diff --git a/src/engine/shared/config.cpp b/src/engine/shared/config.cpp index 4ff026896..85c6b5ec8 100644 --- a/src/engine/shared/config.cpp +++ b/src/engine/shared/config.cpp @@ -74,7 +74,7 @@ public: { if(!m_pStorage) return; - m_ConfigFile = m_pStorage->OpenFile("settings.cfg", IOFLAG_WRITE); + m_ConfigFile = m_pStorage->OpenFile("settings.cfg", IOFLAG_WRITE, IStorage::TYPE_SAVE); if(!m_ConfigFile) return; diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 808b64edc..e32a0f81d 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -300,7 +300,7 @@ void CConsole::ExecuteFile(const char *pFilename) m_pFirstExec = &ThisFile; // exec the file - IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_READ); + IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_ALL); char aBuf[256]; if(File) diff --git a/src/engine/shared/datafile.cpp b/src/engine/shared/datafile.cpp index 4ef278cd7..81d0e2cfb 100644 --- a/src/engine/shared/datafile.cpp +++ b/src/engine/shared/datafile.cpp @@ -65,11 +65,11 @@ struct CDatafile char *m_pData; }; -bool CDataFileReader::Open(class IStorage *pStorage, const char *pFilename) +bool CDataFileReader::Open(class IStorage *pStorage, const char *pFilename, int StorageType) { dbg_msg("datafile", "loading. filename='%s'", pFilename); - IOHANDLE File = pStorage->OpenFile(pFilename, IOFLAG_READ); + IOHANDLE File = pStorage->OpenFile(pFilename, IOFLAG_READ, StorageType); if(!File) { dbg_msg("datafile", "could not open '%s'", pFilename); @@ -394,7 +394,7 @@ unsigned CDataFileReader::Crc() bool CDataFileWriter::Open(class IStorage *pStorage, const char *pFilename) { dbg_assert(!m_File, "a file already exists"); - m_File = pStorage->OpenFile(pFilename, IOFLAG_WRITE); + m_File = pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(!m_File) return false; diff --git a/src/engine/shared/datafile.h b/src/engine/shared/datafile.h index e0f08b7cc..0392e493f 100644 --- a/src/engine/shared/datafile.h +++ b/src/engine/shared/datafile.h @@ -12,7 +12,7 @@ public: bool IsOpen() const { return m_pDataFile != 0; } - bool Open(class IStorage *pStorage, const char *pFilename); + bool Open(class IStorage *pStorage, const char *pFilename, int StorageType); bool Close(); void *GetData(int Index); diff --git a/src/engine/shared/demo.cpp b/src/engine/shared/demo.cpp index 5ae7a340f..4ae4a4c55 100644 --- a/src/engine/shared/demo.cpp +++ b/src/engine/shared/demo.cpp @@ -40,12 +40,12 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con char aMapFilename[128]; // try the normal maps folder str_format(aMapFilename, sizeof(aMapFilename), "maps/%s.map", pMap); - IOHANDLE MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ); + IOHANDLE MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL); if(!MapFile) { // try the downloaded maps str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%08x.map", pMap, Crc); - MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ); + MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL); } if(!MapFile) { @@ -55,7 +55,7 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con return -1; } - m_File = pStorage->OpenFile(pFilename, IOFLAG_WRITE); + m_File = pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(!m_File) { io_close(MapFile); @@ -513,10 +513,10 @@ void CDemoPlayer::Unpause() } } -int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename) +int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, int StorageType) { m_pConsole = pConsole; - m_File = pStorage->OpenFile(pFilename, IOFLAG_READ); + m_File = pStorage->OpenFile(pFilename, IOFLAG_READ, StorageType); if(!m_File) { char aBuf[256]; @@ -566,7 +566,7 @@ int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const int Crc = (m_Info.m_Header.m_aCrc[0]<<24) | (m_Info.m_Header.m_aCrc[1]<<16) | (m_Info.m_Header.m_aCrc[2]<<8) | (m_Info.m_Header.m_aCrc[3]); char aMapFilename[128]; str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%08x.map", m_Info.m_Header.m_aMap, Crc); - IOHANDLE MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ); + IOHANDLE MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL); if(MapFile) { @@ -580,7 +580,7 @@ int CDemoPlayer::Load(class IStorage *pStorage, class IConsole *pConsole, const io_read(m_File, pMapData, MapSize); // save map - MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_WRITE); + MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); io_write(MapFile, pMapData, MapSize); io_close(MapFile); diff --git a/src/engine/shared/demo.h b/src/engine/shared/demo.h index eeaa1f992..9d5105427 100644 --- a/src/engine/shared/demo.h +++ b/src/engine/shared/demo.h @@ -103,7 +103,7 @@ public: void SetListner(IListner *pListner); - int Load(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename); + int Load(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, int StorageType); int Play(); void Pause(); void Unpause(); diff --git a/src/engine/shared/map.cpp b/src/engine/shared/map.cpp index 505d18e95..827930aa2 100644 --- a/src/engine/shared/map.cpp +++ b/src/engine/shared/map.cpp @@ -28,7 +28,7 @@ public: IStorage *pStorage = Kernel()->RequestInterface(); if(!pStorage) return false; - return m_DataFile.Open(pStorage, pMapName); + return m_DataFile.Open(pStorage, pMapName, IStorage::TYPE_ALL); } virtual bool IsLoaded() diff --git a/src/engine/shared/masterserver.cpp b/src/engine/shared/masterserver.cpp index f10469bda..9ecf3f71b 100644 --- a/src/engine/shared/masterserver.cpp +++ b/src/engine/shared/masterserver.cpp @@ -119,7 +119,7 @@ public: return -1; // try to open file - File = pStorage->OpenFile("masters.cfg", IOFLAG_READ); + File = pStorage->OpenFile("masters.cfg", IOFLAG_READ, IStorage::TYPE_SAVE); if(!File) return -1; @@ -165,7 +165,7 @@ public: return -1; // try to open file - File = pStorage->OpenFile("masters.cfg", IOFLAG_WRITE); + File = pStorage->OpenFile("masters.cfg", IOFLAG_WRITE, IStorage::TYPE_SAVE); if(!File) return -1; diff --git a/src/engine/shared/storage.cpp b/src/engine/shared/storage.cpp index 8785a5bf8..cfe64e4ba 100644 --- a/src/engine/shared/storage.cpp +++ b/src/engine/shared/storage.cpp @@ -3,6 +3,7 @@ #include #include #include "engine.h" +#include "linereader.h" // compiled-in data-dir path #define DATA_DIR "data" @@ -10,36 +11,29 @@ class CStorage : public IStorage { public: - char m_aApplicationSavePath[512]; - char m_aDatadir[512]; + enum + { + MAX_PATHS = 16, + MAX_PATH_LENGTH = 512 + }; + + char m_aaStoragePaths[MAX_PATHS][MAX_PATH_LENGTH]; + int m_NumPaths; + char m_aDatadir[MAX_PATH_LENGTH]; + char m_aUserdir[MAX_PATH_LENGTH]; CStorage() { - m_aApplicationSavePath[0] = 0; + mem_zero(m_aaStoragePaths, sizeof(m_aaStoragePaths)); + m_NumPaths = 0; m_aDatadir[0] = 0; + m_aUserdir[0] = 0; } int Init(const char *pApplicationName, int NumArgs, const char **ppArguments) { - char aPath[1024] = {0}; - fs_storage_path(pApplicationName, m_aApplicationSavePath, sizeof(m_aApplicationSavePath)); - if(fs_makedir(m_aApplicationSavePath) == 0) - { - str_format(aPath, sizeof(aPath), "%s/screenshots", m_aApplicationSavePath); - fs_makedir(aPath); - - str_format(aPath, sizeof(aPath), "%s/maps", m_aApplicationSavePath); - fs_makedir(aPath); - - str_format(aPath, sizeof(aPath), "%s/dumps", m_aApplicationSavePath); - fs_makedir(aPath); - - str_format(aPath, sizeof(aPath), "%s/downloadedmaps", m_aApplicationSavePath); - fs_makedir(aPath); - - str_format(aPath, sizeof(aPath), "%s/demos", m_aApplicationSavePath); - fs_makedir(aPath); - } + // get userdir + fs_storage_path(pApplicationName, m_aUserdir, sizeof(m_aUserdir)); // check for datadir override for(int i = 1; i < NumArgs; i++) @@ -50,54 +44,160 @@ public: break; } } - - return FindDatadir(ppArguments[0]); + // get datadir + FindDatadir(ppArguments[0]); + + // load paths from storage.cfg + LoadPaths(ppArguments[0]); + + if(!m_NumPaths) + { + dbg_msg("storage", "using standard paths"); + AddDefaultPaths(); + } + + // add save directories + if(m_NumPaths && (!m_aaStoragePaths[TYPE_SAVE][0] || !fs_makedir(m_aaStoragePaths[TYPE_SAVE]))) + { + char aPath[MAX_PATH_LENGTH]; + fs_makedir(GetPath(TYPE_SAVE, "screenshots", aPath, sizeof(aPath))); + fs_makedir(GetPath(TYPE_SAVE, "maps", aPath, sizeof(aPath))); + fs_makedir(GetPath(TYPE_SAVE, "dumps", aPath, sizeof(aPath))); + fs_makedir(GetPath(TYPE_SAVE, "downloadedmaps", aPath, sizeof(aPath))); + fs_makedir(GetPath(TYPE_SAVE, "demos", aPath, sizeof(aPath))); + } + + return m_NumPaths ? 0 : 1; + } + + void LoadPaths(const char *pArgv0) + { + // check current directory + IOHANDLE File = io_open("storage.cfg", IOFLAG_READ); + if(!File) + { + // check usable path in argv[0] + unsigned int Pos = ~0U; + for(unsigned i = 0; pArgv0[i]; i++) + if(pArgv0[i] == '/' || pArgv0[i] == '\\') + Pos = i; + if(Pos < MAX_PATH_LENGTH) + { + char aBuffer[MAX_PATH_LENGTH]; + str_copy(aBuffer, pArgv0, Pos+1); + str_append(aBuffer, "/storage.cfg", sizeof(aBuffer)); + File = io_open(aBuffer, IOFLAG_READ); + } + + if(Pos >= MAX_PATH_LENGTH || !File) + { + dbg_msg("storage", "couldn't open storage.cfg"); + return; + } + } + + char *pLine; + CLineReader LineReader; + LineReader.Init(File); + + while((pLine = LineReader.Get())) + { + if(str_length(pLine) > 9 && !str_comp_num(pLine, "add_path ", 9)) + AddPath(pLine+9); + } + + io_close(File); + + if(!m_NumPaths) + dbg_msg("storage", "no paths found in storage.cfg"); + } + + void AddDefaultPaths() + { + AddPath("$USERDIR"); + AddPath("$DATADIR"); + AddPath("$CURRENTDIR"); + } + + void AddPath(const char *pPath) + { + if(m_NumPaths >= MAX_PATHS || !pPath[0]) + return; + + int OldNum = m_NumPaths; + + if(!str_comp(pPath, "$USERDIR")) + { + if(m_aUserdir[0]) + str_copy(m_aaStoragePaths[m_NumPaths++], m_aUserdir, MAX_PATH_LENGTH); + } + else if(!str_comp(pPath, "$DATADIR")) + { + if(m_aDatadir[0]) + str_copy(m_aaStoragePaths[m_NumPaths++], m_aDatadir, MAX_PATH_LENGTH); + } + else if(!str_comp(pPath, "$CURRENTDIR")) + { + m_aaStoragePaths[m_NumPaths++][0] = 0; + } + else + { + if(fs_is_dir(pPath)) + str_copy(m_aaStoragePaths[m_NumPaths++], pPath, MAX_PATH_LENGTH); + } + + if(OldNum != m_NumPaths) + dbg_msg("storage", "added path '%s'", pPath); } - int FindDatadir(const char *pArgv0) + void FindDatadir(const char *pArgv0) { // 1) use provided data-dir override if(m_aDatadir[0]) { - if(fs_is_dir(m_aDatadir)) - return 0; - else + char aBuffer[MAX_PATH_LENGTH]; + str_format(aBuffer, sizeof(aBuffer), "%s/mapres", m_aDatadir); + if(!fs_is_dir(aBuffer)) { - dbg_msg("engine/datadir", "specified data-dir '%s' does not exist", m_aDatadir); - return -1; + dbg_msg("storage", "specified data directory '%s' does not exist", m_aDatadir); + m_aDatadir[0] = 0; } + else + return; } // 2) use data-dir in PWD if present if(fs_is_dir("data/mapres")) { str_copy(m_aDatadir, "data", sizeof(m_aDatadir)); - return 0; + return; } // 3) use compiled-in data-dir if present - if (fs_is_dir(DATA_DIR "/mapres")) + if(fs_is_dir(DATA_DIR "/mapres")) { str_copy(m_aDatadir, DATA_DIR, sizeof(m_aDatadir)); - return 0; + return; } // 4) check for usable path in argv[0] { unsigned int Pos = ~0U; for(unsigned i = 0; pArgv0[i]; i++) - if(pArgv0[i] == '/') + if(pArgv0[i] == '/' || pArgv0[i] == '\\') Pos = i; - if (Pos < sizeof(m_aDatadir)) + if(Pos < MAX_PATH_LENGTH) { - char aBaseDir[sizeof(m_aDatadir)]; - str_copy(aBaseDir, pArgv0, Pos); - aBaseDir[Pos] = '\0'; + char aBaseDir[MAX_PATH_LENGTH]; + str_copy(aBaseDir, pArgv0, Pos+1); str_format(m_aDatadir, sizeof(m_aDatadir), "%s/data", aBaseDir); + str_append(aBaseDir, "/data/mapres", sizeof(aBaseDir)); - if (fs_is_dir(m_aDatadir)) - return 0; + if(fs_is_dir(aBaseDir)) + return; + else + m_aDatadir[0] = 0; } } @@ -105,11 +205,11 @@ public: // 5) check for all default locations { const char *aDirs[] = { - "/usr/share/teeworlds/data", - "/usr/share/games/teeworlds/data", - "/usr/local/share/teeworlds/data", - "/usr/local/share/games/teeworlds/data", - "/opt/teeworlds/data" + "/usr/share/teeworlds/data/mapres", + "/usr/share/games/teeworlds/data/mapres", + "/usr/local/share/teeworlds/data/mapres", + "/usr/local/share/games/teeworlds/data/mapres", + "/opt/teeworlds/data/mapres" }; const int DirsCount = sizeof(aDirs) / sizeof(aDirs[0]); @@ -119,55 +219,41 @@ public: if (fs_is_dir(aDirs[i])) { str_copy(m_aDatadir, aDirs[i], sizeof(m_aDatadir)); - return 0; + return; } } } #endif // no data-dir found - dbg_msg("engine/datadir", "warning no data directory found"); - return -1; + dbg_msg("storage", "warning no data directory found"); } - virtual void ListDirectory(int Types, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) + virtual void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) { - char aBuffer[1024]; - - // list current directory - if(Types&TYPE_CURRENT) + char aBuffer[MAX_PATH_LENGTH]; + if(Type == TYPE_ALL) { - fs_listdir(pPath, pfnCallback, TYPE_CURRENT, pUser); + // list all available directories + for(int i = 0; i < m_NumPaths; ++i) + fs_listdir(GetPath(i, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, i, pUser); } - - // list users directory - if(Types&TYPE_SAVE) + else if(Type >= 0 && Type < m_NumPaths) { - str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aApplicationSavePath, pPath); - fs_listdir(aBuffer, pfnCallback, TYPE_SAVE, pUser); + // list wanted directory + fs_listdir(GetPath(Type, pPath, aBuffer, sizeof(aBuffer)), pfnCallback, Type, pUser); } - - // list datadir directory - if(Types&TYPE_DATA) - { - str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aDatadir, pPath); - fs_listdir(aBuffer, pfnCallback, TYPE_DATA, pUser); - } } - virtual const char *GetDirectory(int Type) const + const char *GetPath(int Type, const char *pDir, char *pBuffer, unsigned BufferSize) { - switch(Type) - { - case TYPE_SAVE: return m_aApplicationSavePath; - case TYPE_DATA: return m_aDatadir; - default: return ""; - } + str_format(pBuffer, BufferSize, "%s%s%s", m_aaStoragePaths[Type], !m_aaStoragePaths[Type][0] ? "" : "/", pDir); + return pBuffer; } - virtual IOHANDLE OpenFile(const char *pFilename, int Flags, char *pBuffer = 0, int BufferSize = 0) + virtual IOHANDLE OpenFile(const char *pFilename, int Flags, int Type, char *pBuffer = 0, int BufferSize = 0) { - char aBuffer[1024]; + char aBuffer[MAX_PATH_LENGTH]; if(!pBuffer) { pBuffer = aBuffer; @@ -176,45 +262,42 @@ public: if(Flags&IOFLAG_WRITE) { - str_format(pBuffer, BufferSize, "%s/%s", m_aApplicationSavePath, pFilename); - return io_open(pBuffer, Flags); + return io_open(GetPath(TYPE_SAVE, pFilename, pBuffer, BufferSize), Flags); } else { IOHANDLE Handle = 0; - - // check current directory - Handle = io_open(pFilename, Flags); - if(Handle) - return Handle; - - // check user directory - str_format(pBuffer, BufferSize, "%s/%s", m_aApplicationSavePath, pFilename); - Handle = io_open(pBuffer, Flags); - if(Handle) - return Handle; - - // check normal data directory - str_format(pBuffer, BufferSize, "%s/%s", m_aDatadir, pFilename); - Handle = io_open(pBuffer, Flags); - if(Handle) - return Handle; + + if(Type == TYPE_ALL) + { + // check all available directories + for(int i = 0; i < m_NumPaths; ++i) + { + Handle = io_open(GetPath(i, pFilename, pBuffer, BufferSize), Flags); + if(Handle) + return Handle; + } + } + else if(Type >= 0 && Type < m_NumPaths) + { + // check wanted directory + Handle = io_open(GetPath(Type, pFilename, pBuffer, BufferSize), Flags); + if(Handle) + return Handle; + } } pBuffer[0] = 0; return 0; } - virtual bool RemoveFile(const char *pFilename) + virtual bool RemoveFile(const char *pFilename, int Type) { - char aBuffer[1024]; - str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aApplicationSavePath, pFilename); - bool Fail = remove(aBuffer); - - if(Fail) - Fail = remove(pFilename); - - return !Fail; + if(Type < 0 || Type >= m_NumPaths) + return false; + + char aBuffer[MAX_PATH_LENGTH]; + return remove(GetPath(Type, pFilename, aBuffer, sizeof(aBuffer))); } static IStorage *Create(const char *pApplicationName, int NumArgs, const char **ppArguments) @@ -222,6 +305,7 @@ public: CStorage *p = new CStorage(); if(p && p->Init(pApplicationName, NumArgs, ppArguments)) { + dbg_msg("storage", "initialisation failed"); delete p; p = 0; } diff --git a/src/engine/storage.h b/src/engine/storage.h index b9b022396..c483c52d3 100644 --- a/src/engine/storage.h +++ b/src/engine/storage.h @@ -9,16 +9,13 @@ class IStorage : public IInterface public: enum { - TYPE_SAVE = 1, - TYPE_CURRENT = 2, - TYPE_DATA = 4, - TYPE_ALL = ~0 + TYPE_SAVE = 0, + TYPE_ALL = -1 }; - virtual void ListDirectory(int Types, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) = 0; - virtual const char *GetDirectory(int Type) const = 0; - virtual IOHANDLE OpenFile(const char *pFilename, int Flags, char *pBuffer = 0, int BufferSize = 0) = 0; - virtual bool RemoveFile(const char *pFilename) = 0; + virtual void ListDirectory(int Type, const char *pPath, FS_LISTDIR_CALLBACK pfnCallback, void *pUser) = 0; + virtual IOHANDLE OpenFile(const char *pFilename, int Flags, int Type, char *pBuffer = 0, int BufferSize = 0) = 0; + virtual bool RemoveFile(const char *pFilename, int Type) = 0; }; extern IStorage *CreateStorage(const char *pApplicationName, int NumArgs, const char **ppArguments); diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp index cdf4239ab..5fa328dd9 100644 --- a/src/game/client/components/console.cpp +++ b/src/game/client/components/console.cpp @@ -588,7 +588,7 @@ void CGameConsole::Dump(int Type) { IOHANDLE io; str_format(aFilename, sizeof(aFilename), "dumps/%s_dump%s-%05d.txt", Type==1?"remote_console":"local_console", aDate, i); - io = Storage()->OpenFile(aFilename, IOFLAG_WRITE); + io = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(io) { #if defined(CONF_FAMILY_WINDOWS) diff --git a/src/game/client/components/mapimages.cpp b/src/game/client/components/mapimages.cpp index 9be450d13..8870c5c6a 100644 --- a/src/game/client/components/mapimages.cpp +++ b/src/game/client/components/mapimages.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -36,7 +37,7 @@ void CMapImages::OnMapLoad() char Buf[256]; char *pName = (char *)pMap->GetData(pImg->m_ImageName); str_format(Buf, sizeof(Buf), "mapres/%s.png", pName); - m_aTextures[i] = Graphics()->LoadTexture(Buf, CImageInfo::FORMAT_AUTO, 0); + m_aTextures[i] = Graphics()->LoadTexture(Buf, IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); } else { diff --git a/src/game/client/components/maplayers.cpp b/src/game/client/components/maplayers.cpp index 9c93c771e..d3a819c03 100644 --- a/src/game/client/components/maplayers.cpp +++ b/src/game/client/components/maplayers.cpp @@ -135,7 +135,7 @@ void CMapLayers::OnRender() Client()->GetServerInfo(&CurrentServerInfo); char aFilename[256]; str_format(aFilename, sizeof(aFilename), "dumps/tilelayer_dump_%s-%d-%d-%dx%d.txt", CurrentServerInfo.m_aMap, g, l, pTMap->m_Width, pTMap->m_Height); - IOHANDLE File = Storage()->OpenFile(aFilename, IOFLAG_WRITE); + IOHANDLE File = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(File) { #if defined(CONF_FAMILY_WINDOWS) diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 4a53d29ba..caad5a80b 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -1259,7 +1260,7 @@ void CMenus::RenderBackground() //Graphics()->Clear(1,1,1); //render_sunrays(0,0); if(gs_TextureBlob == -1) - gs_TextureBlob = Graphics()->LoadTexture("blob.png", CImageInfo::FORMAT_AUTO, 0); + gs_TextureBlob = Graphics()->LoadTexture("blob.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); float sw = 300*Graphics()->ScreenAspect(); diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index a1e75f61a..ea8be21fe 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -159,7 +159,7 @@ class CMenus : public CComponent char m_aFilename[128]; char m_aName[128]; bool m_IsDir; - int m_DirType; + int m_StorageType; bool operator<(const CDemoItem &Other) { return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false : m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false : @@ -174,7 +174,7 @@ class CMenus : public CComponent void DemolistOnUpdate(bool Reset); void DemolistPopulate(); - static void DemolistFetchCallback(const char *pName, int IsDir, int DirType, void *pUser); + static void DemolistFetchCallback(const char *pName, int IsDir, int StorageType, void *pUser); // found in menus.cpp int Render(); diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index e08114ad8..e960769af 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -417,7 +417,7 @@ int CMenus::UiDoListboxEnd(float *pScrollValue, bool *pItemActivated) return gs_ListBoxNewSelected; } -void CMenus::DemolistFetchCallback(const char *pName, int IsDir, int DirType, void *pUser) +void CMenus::DemolistFetchCallback(const char *pName, int IsDir, int StorageType, void *pUser) { CMenus *pSelf = (CMenus *)pUser; int Length = str_length(pName); @@ -433,14 +433,14 @@ void CMenus::DemolistFetchCallback(const char *pName, int IsDir, int DirType, vo else str_format(Item.m_aName, min(static_cast(sizeof(Item.m_aName)), Length), " %s", pName); Item.m_IsDir = IsDir != 0; - Item.m_DirType = DirType; + Item.m_StorageType = StorageType; pSelf->m_lDemos.add(Item); } void CMenus::DemolistPopulate() { m_lDemos.clear(); - Storage()->ListDirectory(IStorage::TYPE_SAVE|IStorage::TYPE_CURRENT, m_aCurrentDemoFolder, DemolistFetchCallback, this); + Storage()->ListDirectory(IStorage::TYPE_ALL, m_aCurrentDemoFolder, DemolistFetchCallback, this); } void CMenus::DemolistOnUpdate(bool Reset) @@ -466,10 +466,8 @@ void CMenus::RenderDemoList(CUIRect MainView) if(m_DemolistSelectedIndex >= 0 && !m_DemolistSelectedIsDir) { char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "%s%s%s/%s", Storage()->GetDirectory(m_lDemos[m_DemolistSelectedIndex].m_DirType), - Storage()->GetDirectory(m_lDemos[m_DemolistSelectedIndex].m_DirType)[0] ? "/" : "", - m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); - Storage()->RemoveFile(aBuf); + str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); + Storage()->RemoveFile(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType); DemolistPopulate(); DemolistOnUpdate(false); } @@ -529,10 +527,8 @@ void CMenus::RenderDemoList(CUIRect MainView) else // file { char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "%s%s%s/%s", Storage()->GetDirectory(m_lDemos[m_DemolistSelectedIndex].m_DirType), - Storage()->GetDirectory(m_lDemos[m_DemolistSelectedIndex].m_DirType)[0] ? "/" : "", - m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); - const char *pError = Client()->DemoPlayer_Play(aBuf); + str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); + const char *pError = Client()->DemoPlayer_Play(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType); if(pError) PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("error loading demo"), Localize("Ok")); else diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index c8040bfa2..f3c4afe70 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -650,7 +650,7 @@ public: void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array *pLanguages) { - IOHANDLE File = pStorage->OpenFile("data/languages/index.txt", IOFLAG_READ); + IOHANDLE File = pStorage->OpenFile("languages/index.txt", IOFLAG_READ, IStorage::TYPE_ALL); if(!File) { pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", "couldn't open index file"); @@ -681,7 +681,7 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, sorted_array< } char aFileName[128]; - str_format(aFileName, sizeof(aFileName), "data/languages/%s.txt", pLine); + str_format(aFileName, sizeof(aFileName), "languages/%s.txt", pLine); pLanguages->add(CLanguage(pReplacement+3, aFileName)); } io_close(File); @@ -724,7 +724,7 @@ void CMenus::RenderSettingsGeneral(CUIRect MainView) if(OldSelected != s_SelectedLanguage) { str_copy(g_Config.m_ClLanguagefile, s_Languages[s_SelectedLanguage].m_FileName, sizeof(g_Config.m_ClLanguagefile)); - g_Localization.Load(s_Languages[s_SelectedLanguage].m_FileName, Console()); + g_Localization.Load(s_Languages[s_SelectedLanguage].m_FileName, Storage(), Console()); } } diff --git a/src/game/client/components/skins.cpp b/src/game/client/components/skins.cpp index 098111ee0..52c792208 100644 --- a/src/game/client/components/skins.cpp +++ b/src/game/client/components/skins.cpp @@ -20,7 +20,7 @@ void CSkins::SkinScan(const char *pName, int IsDir, int DirType, void *pUser) char aBuf[512]; str_format(aBuf, sizeof(aBuf), "skins/%s", pName); CImageInfo Info; - if(!pSelf->Graphics()->LoadPNG(&Info, aBuf)) + if(!pSelf->Graphics()->LoadPNG(&Info, aBuf, DirType)) { str_format(aBuf, sizeof(aBuf), "failed to load skin from %s", pName); pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "game", aBuf); diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 11841e5bb..2805800da 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -224,7 +224,7 @@ void CGameClient::OnInit() //m_pServerBrowser = Kernel()->RequestInterface(); // set the language - g_Localization.Load(g_Config.m_ClLanguagefile, Console()); + g_Localization.Load(g_Config.m_ClLanguagefile, Storage(), Console()); // init all components for(int i = 0; i < m_All.m_Num; i++) @@ -239,7 +239,12 @@ void CGameClient::OnInit() // load default font static CFont *pDefaultFont; //default_font = gfx_font_load("data/fonts/sazanami-gothic.ttf"); - pDefaultFont = TextRender()->LoadFont("data/fonts/vera.ttf"); + + char aFilename[512]; + IOHANDLE File = Storage()->OpenFile("fonts/vera.ttf", IOFLAG_READ, IStorage::TYPE_ALL, aFilename, sizeof(aFilename)); + if(File) + io_close(File); + pDefaultFont = TextRender()->LoadFont(aFilename); TextRender()->SetDefaultFont(pDefaultFont); g_Config.m_ClThreadsoundloading = 0; @@ -254,7 +259,7 @@ void CGameClient::OnInit() for(int i = 0; i < g_pData->m_NumImages; i++) { g_GameClient.m_pMenus->RenderLoading(gs_LoadCurrent/(float)gs_LoadTotal); - g_pData->m_aImages[i].m_Id = Graphics()->LoadTexture(g_pData->m_aImages[i].m_pFilename, CImageInfo::FORMAT_AUTO, 0); + g_pData->m_aImages[i].m_Id = Graphics()->LoadTexture(g_pData->m_aImages[i].m_pFilename, IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); gs_LoadCurrent++; } diff --git a/src/game/editor/ed_editor.cpp b/src/game/editor/ed_editor.cpp index b1dce3f9a..ea83fb737 100644 --- a/src/game/editor/ed_editor.cpp +++ b/src/game/editor/ed_editor.cpp @@ -559,6 +559,7 @@ CQuad *CEditor::GetSelectedQuad() return 0; } +// TODO: fix/rework the whole file dialog stuff static void CallbackOpenDir(const char *pFileName, void *pUser) { CEditor *pEditor = (CEditor*)pUser; @@ -586,7 +587,7 @@ static void CallbackOpenMap(const char *pFileName, void *pUser) return; } char aCompleteFilename[512]; - str_format(aCompleteFilename, sizeof(aCompleteFilename), "%s/%s", pEditor->Client()->UserDirectory(), pFileName); + //str_format(aCompleteFilename, sizeof(aCompleteFilename), "%s/%s", pEditor->Client()->UserDirectory(), pFileName); if(fs_is_dir(aCompleteFilename)) { CallbackOpenDir(pFileName, pUser); @@ -609,7 +610,7 @@ static void CallbackAppendMap(const char *pFileName, void *pUser) return; } char aCompleteFilename[512]; - str_format(aCompleteFilename, sizeof(aCompleteFilename), "%s/%s", pEditor->Client()->UserDirectory(), pFileName); + //str_format(aCompleteFilename, sizeof(aCompleteFilename), "%s/%s", pEditor->Client()->UserDirectory(), pFileName); if(fs_is_dir(aCompleteFilename)) { CallbackOpenDir(pFileName, pUser); @@ -632,7 +633,7 @@ static void CallbackSaveMap(const char *pFileName, void *pUser) return; } char aCompleteFilename[512]; - str_format(aCompleteFilename, sizeof(aCompleteFilename), "%s/%s", pEditor->Client()->UserDirectory(), pFileName); + //str_format(aCompleteFilename, sizeof(aCompleteFilename), "%s/%s", pEditor->Client()->UserDirectory(), pFileName); if(fs_is_dir(aCompleteFilename)) { CallbackOpenDir(pFileName, pUser); @@ -1899,7 +1900,7 @@ void CEditor::ReplaceImage(const char *pFileName, void *pUser) { CEditor *pEditor = (CEditor *)pUser; CEditorImage ImgInfo(pEditor); - if(!pEditor->Graphics()->LoadPNG(&ImgInfo, pFileName)) + if(!pEditor->Graphics()->LoadPNG(&ImgInfo, pFileName, IStorage::TYPE_ALL)) return; CEditorImage *pImg = pEditor->m_Map.m_lImages[pEditor->m_SelectedImage]; @@ -1914,7 +1915,7 @@ void CEditor::AddImage(const char *pFileName, void *pUser) { CEditor *pEditor = (CEditor *)pUser; CEditorImage ImgInfo(pEditor); - if(!pEditor->Graphics()->LoadPNG(&ImgInfo, pFileName)) + if(!pEditor->Graphics()->LoadPNG(&ImgInfo, pFileName, IStorage::TYPE_ALL)) return; CEditorImage *pImg = new CEditorImage(pEditor); @@ -2146,17 +2147,26 @@ void CEditor::RenderImages(CUIRect ToolBox, CUIRect ToolBar, CUIRect View) } -static void EditorListdirCallback(const char *pName, int IsDir, int DirType, void *pUser) +static void EditorListdirCallback(const char *pName, int IsDir, int StorageType, void *pUser) { CEditor *pEditor = (CEditor*)pUser; + int Length = str_length(pName); if(pName[0] == '.' && (pName[1] == 0 || (pName[1] == '.' && pName[2] == 0 && (!str_comp(pEditor->m_aFileDialogPath, "maps") || !str_comp(pEditor->m_aFileDialogPath, "mapres"))))) return; - pEditor->m_FileList.add(string(pName)); + CEditor::CFilelistItem Item; + str_copy(Item.m_aFilename, pName, sizeof(Item.m_aFilename)); + if(IsDir) + str_format(Item.m_aName, sizeof(Item.m_aName), "%s/", pName); + else + str_format(Item.m_aName, static_cast(sizeof(Item.m_aName)), " %s", pName); + Item.m_IsDir = IsDir != 0; + Item.m_StorageType = StorageType; + pEditor->m_FileList.add(Item); } -void CEditor::AddFileDialogEntry(const char *pName, CUIRect *pView) +void CEditor::AddFileDialogEntry(const CFilelistItem *pItem, CUIRect *pView) { if(m_FilesCur > m_FilesNum) m_FilesNum = m_FilesCur; @@ -2169,9 +2179,9 @@ void CEditor::AddFileDialogEntry(const char *pName, CUIRect *pView) pView->HSplitTop(15.0f, &Button, pView); pView->HSplitTop(2.0f, 0, pView); - if(DoButton_File((void*)(10+(int)Button.y), pName, 0, &Button, 0, 0)) + if(DoButton_File((void*)(10+(int)Button.y), pItem->m_aName, 0, &Button, 0, 0)) { - str_copy(m_aFileDialogFileName, pName, sizeof(m_aFileDialogFileName)); + str_copy(m_aFileDialogFileName, pItem->m_aFilename, sizeof(m_aFileDialogFileName)); str_format(m_aFileDialogCompleteFilename, sizeof(m_aFileDialogCompleteFilename), "%s/%s", m_aFileDialogPath, m_aFileDialogFileName); @@ -2248,7 +2258,7 @@ void CEditor::RenderFileDialog() UI()->ClipEnable(&View); for(int i = 0; i < m_FileList.size(); i++) - AddFileDialogEntry(m_FileList[i].cstr(), &View); + AddFileDialogEntry(&m_FileList[i], &View); // disable clipping again UI()->ClipDisable(); @@ -2274,14 +2284,14 @@ void CEditor::RenderFileDialog() void CEditor::FilelistPopulate() { m_FileList.clear(); - Storage()->ListDirectory(m_FileDialogDirTypes, m_aFileDialogPath, EditorListdirCallback, this); + Storage()->ListDirectory(m_FileDialogStorageType, m_aFileDialogPath, EditorListdirCallback, this); } -void CEditor::InvokeFileDialog(int ListDirTypes, const char *pTitle, const char *pButtonText, +void CEditor::InvokeFileDialog(int StorageType, const char *pTitle, const char *pButtonText, const char *pBasePath, const char *pDefaultName, void (*pfnFunc)(const char *pFileName, void *pUser), void *pUser) { - m_FileDialogDirTypes = ListDirTypes; + m_FileDialogStorageType = StorageType; m_pFileDialogTitle = pTitle; m_pFileDialogButtonText = pButtonText; m_pfnFileDialogFunc = pfnFunc; @@ -3072,10 +3082,10 @@ void CEditor::Init() m_UI.SetGraphics(m_pGraphics, m_pTextRender); m_Map.m_pEditor = this; - ms_CheckerTexture = Graphics()->LoadTexture("editor/checker.png", CImageInfo::FORMAT_AUTO, 0); - ms_BackgroundTexture = Graphics()->LoadTexture("editor/background.png", CImageInfo::FORMAT_AUTO, 0); - ms_CursorTexture = Graphics()->LoadTexture("editor/cursor.png", CImageInfo::FORMAT_AUTO, 0); - ms_EntitiesTexture = Graphics()->LoadTexture("editor/entities.png", CImageInfo::FORMAT_AUTO, 0); + ms_CheckerTexture = Graphics()->LoadTexture("editor/checker.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); + ms_BackgroundTexture = Graphics()->LoadTexture("editor/background.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); + ms_CursorTexture = Graphics()->LoadTexture("editor/cursor.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); + ms_EntitiesTexture = Graphics()->LoadTexture("editor/entities.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0); m_TilesetPicker.m_pEditor = this; m_TilesetPicker.MakePalette(); diff --git a/src/game/editor/ed_editor.h b/src/game/editor/ed_editor.h index 30ec72033..225ff4aba 100644 --- a/src/game/editor/ed_editor.h +++ b/src/game/editor/ed_editor.h @@ -459,7 +459,7 @@ public: m_aFileName[0] = 0; - m_FileDialogDirTypes = 0; + m_FileDialogStorageType = 0; m_pFileDialogTitle = 0; m_pFileDialogButtonText = 0; m_pFileDialogUser = 0; @@ -508,7 +508,7 @@ public: virtual void UpdateAndRender(); void FilelistPopulate(); - void InvokeFileDialog(int ListdirType, const char *pTitle, const char *pButtonText, + void InvokeFileDialog(int StorageType, const char *pTitle, const char *pButtonText, const char *pBasepath, const char *pDefaultName, void (*pfnFunc)(const char *pFilename, void *pUser), void *pUser); @@ -531,7 +531,7 @@ public: char m_aFileName[512]; - int m_FileDialogDirTypes; + int m_FileDialogStorageType; const char *m_pFileDialogTitle; const char *m_pFileDialogButtonText; void (*m_pfnFileDialogFunc)(const char *pFileName, void *pUser); @@ -540,7 +540,19 @@ public: char m_aFileDialogPath[512]; char m_aFileDialogCompleteFilename[512]; int m_FilesNum; - sorted_array m_FileList; + + struct CFilelistItem + { + char m_aFilename[128]; + char m_aName[128]; + bool m_IsDir; + int m_StorageType; + + bool operator<(const CFilelistItem &Other) { return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false : + m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false : + str_comp_filenames(m_aFilename, Other.m_aFilename) < 0; } + }; + sorted_array m_FileList; int m_FilesStartAt; int m_FilesCur; int m_FilesStopAt; @@ -643,7 +655,7 @@ public: void RenderMenubar(CUIRect Menubar); void RenderFileDialog(); - void AddFileDialogEntry(const char *pName, CUIRect *pView); + void AddFileDialogEntry(const CFilelistItem *pItem, CUIRect *pView); void SortImages(); }; diff --git a/src/game/editor/ed_io.cpp b/src/game/editor/ed_io.cpp index 6eae9fb5c..62e3cf658 100644 --- a/src/game/editor/ed_io.cpp +++ b/src/game/editor/ed_io.cpp @@ -372,7 +372,7 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName) { CDataFileReader DataFile; //DATAFILE *df = datafile_load(filename); - if(!DataFile.Open(pStorage, pFileName)) + if(!DataFile.Open(pStorage, pFileName, IStorage::TYPE_ALL)) return 0; Clean(); @@ -411,7 +411,7 @@ int CEditorMap::Load(class IStorage *pStorage, const char *pFileName) // load external CEditorImage ImgInfo(m_pEditor); - if(m_pEditor->Graphics()->LoadPNG(&ImgInfo, aBuf)) + if(m_pEditor->Graphics()->LoadPNG(&ImgInfo, aBuf, IStorage::TYPE_ALL)) { *pImg = ImgInfo; pImg->m_TexId = m_pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, 0); diff --git a/src/game/localization.cpp b/src/game/localization.cpp index fc9ac3df4..82de858f5 100644 --- a/src/game/localization.cpp +++ b/src/game/localization.cpp @@ -4,6 +4,7 @@ #include #include +#include const char *Localize(const char *pStr) { @@ -40,7 +41,7 @@ void CLocalizationDatabase::AddString(const char *pOrgStr, const char *pNewStr) m_Strings.add(s); } -bool CLocalizationDatabase::Load(const char *pFilename, IConsole *pConsole) +bool CLocalizationDatabase::Load(const char *pFilename, IStorage *pStorage, IConsole *pConsole) { // empty string means unload if(pFilename[0] == 0) @@ -50,7 +51,7 @@ bool CLocalizationDatabase::Load(const char *pFilename, IConsole *pConsole) return true; } - IOHANDLE IoHandle = io_open(pFilename, IOFLAG_READ); + IOHANDLE IoHandle = pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_ALL); if(!IoHandle) return false; diff --git a/src/game/localization.h b/src/game/localization.h index e117c4ffe..9a2016c8b 100644 --- a/src/game/localization.h +++ b/src/game/localization.h @@ -24,7 +24,7 @@ class CLocalizationDatabase public: CLocalizationDatabase(); - bool Load(const char *pFilename, class IConsole *pConsole); + bool Load(const char *pFilename, class IStorage *pStorage, class IConsole *pConsole); int Version() { return m_CurrentVersion; } diff --git a/src/tools/map_resave.cpp b/src/tools/map_resave.cpp index ce17e336e..fd2fecfa8 100644 --- a/src/tools/map_resave.cpp +++ b/src/tools/map_resave.cpp @@ -17,7 +17,7 @@ int main(int argc, const char **argv) str_format(aFileName, sizeof(aFileName), "maps/%s", argv[2]); - if(!DataFile.Open(pStorage, argv[1])) + if(!DataFile.Open(pStorage, argv[1], IStorage::TYPE_ALL)) return -1; if(!df.Open(pStorage, aFileName)) return -1; diff --git a/storage.cfg b/storage.cfg new file mode 100644 index 000000000..15f4ab18d --- /dev/null +++ b/storage.cfg @@ -0,0 +1,31 @@ +#### +# This specifies where and in which order Teeworlds looks +# for its data (sounds, skins, ...). The search goes top +# down which means the first path has the highest priority. +# Furthermore the top entry also defines the save path where +# all data (settings.cfg, screenshots, ...) are stored. +# There are 3 special paths available: +# $USERDIR +# - ~/.appname on UNIX based systems +# - ~/Library/Applications Support/appname on Mac OS X +# - %APPDATA%/Appname on Windows based systems +# $DATADIR +# - the 'data' directory which is part of an official +# release +# $CURRENTDIR +# - current working directory +# +# +# The default file has the following entries: +# add_path $USERDIR +# add_path $DATADIR +# add_path $CURRENTDIR +# +# A customised one could look like this: +# add_path user +# add_path mods/mymod +#### + +add_path $USERDIR +add_path $DATADIR +add_path $CURRENTDIR