From 533cca344f86321117e69e8f1ff69f7a55cfa5bd Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 14 Apr 2018 15:37:20 +1000 Subject: [PATCH] redesign how file and directory methods work --- .../2D/Screens/Menu/LoadLevelScreen.cs | 18 ++---- .../2D/Screens/Menu/SaveLevelScreen.cs | 57 ++++++++--------- .../2D/Screens/Menu/TexturePackScreen.cs | 11 ++-- ClassicalSharp/Audio/AudioPlayer.cs | 14 ++--- ClassicalSharp/Audio/Soundboard.cs | 2 +- ClassicalSharp/Game/ChatLog.cs | 13 ++-- ClassicalSharp/Game/Game.Init.cs | 7 ++- ClassicalSharp/Game/Game.Properties.cs | 6 +- ClassicalSharp/Game/Game.cs | 9 +-- ClassicalSharp/Game/Plugin.cs | 15 +++-- ClassicalSharp/GraphicsAPI/Direct3D9Api.cs | 20 +++--- ClassicalSharp/GraphicsAPI/OpenGLApi.cs | 6 +- ClassicalSharp/GraphicsAPI/OpenGLESApi.cs | 3 +- ClassicalSharp/Network/IServerConnection.cs | 8 +-- ClassicalSharp/Platform/DesktopWindow.cs | 9 +-- ClassicalSharp/Platform/Platform.cs | 62 +++++++++++++++++++ ClassicalSharp/Program.cs | 39 +++++------- ClassicalSharp/TexturePack/Animations.cs | 2 +- ClassicalSharp/TexturePack/EntryList.cs | 18 +++--- ClassicalSharp/TexturePack/TextureCache.cs | 42 ++++++------- ClassicalSharp/TexturePack/TexturePack.cs | 8 +-- ClassicalSharp/Utils/ErrorHandler.cs | 29 +++++---- ClassicalSharp/Utils/Options.cs | 11 +--- Launcher2/Gui/Screens/ResourcesScreen.cs | 4 +- Launcher2/Gui/Views/UpdatesView.cs | 4 +- Launcher2/LauncherWindow.Background.cs | 27 ++++---- Launcher2/LauncherWindow.cs | 2 + Launcher2/Patcher/ResourceChecker.cs | 40 ++++++------ Launcher2/Patcher/ResourceFetcher.cs | 5 +- Launcher2/Patcher/ResourcePatcher.cs | 23 +++---- Launcher2/Patcher/SoundPatcher.cs | 5 +- Launcher2/Program.cs | 26 +++----- Launcher2/Updater/Applier.cs | 23 +++---- Launcher2/Utils/Client.cs | 14 ++--- src/Client/Chat.c | 2 +- src/Client/ErrorHandler.h | 1 + src/Client/Menus.c | 4 +- src/Client/Options.c | 4 +- src/Client/Platform.h | 3 +- src/Client/Program.c | 8 +-- src/Client/WinErrorHandler.c | 11 ++-- src/Client/WinPlatform.c | 23 ++++--- 42 files changed, 343 insertions(+), 295 deletions(-) diff --git a/ClassicalSharp/2D/Screens/Menu/LoadLevelScreen.cs b/ClassicalSharp/2D/Screens/Menu/LoadLevelScreen.cs index ab73b7a0a..378ecc483 100644 --- a/ClassicalSharp/2D/Screens/Menu/LoadLevelScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/LoadLevelScreen.cs @@ -13,15 +13,13 @@ namespace ClassicalSharp.Gui.Screens { public LoadLevelScreen(Game game) : base(game) { titleText = "Select a level"; - string dir = Path.Combine(Program.AppDirectory, "maps"); - string[] rawFiles = Directory.GetFiles(dir); + string[] rawFiles = Platform.DirectoryFiles("maps"); int count = 0; // Only add map files for (int i = 0; i < rawFiles.Length; i++) { string file = rawFiles[i]; - if (file.EndsWith(".cw") || file.EndsWith(".dat") - || file.EndsWith(".fcm") || file.EndsWith(".lvl")) { + if (file.EndsWith(".cw") || file.EndsWith(".dat") || file.EndsWith(".fcm") || file.EndsWith(".lvl")) { count++; } else { rawFiles[i] = null; @@ -38,13 +36,9 @@ namespace ClassicalSharp.Gui.Screens { } protected override void TextButtonClick(Game game, Widget widget) { - string path = Path.Combine(Program.AppDirectory, "maps"); - path = Path.Combine(path, ((ButtonWidget)widget).Text); - if (File.Exists(path)) - LoadMap(path); - } - - void LoadMap(string path) { + string path = Path.Combine("maps", ((ButtonWidget)widget).Text); + if (!Platform.FileExists(path)) return; + IMapFormatImporter importer = null; if (path.EndsWith(".dat")) { importer = new MapDatImporter(); @@ -57,7 +51,7 @@ namespace ClassicalSharp.Gui.Screens { } try { - using (FileStream fs = File.OpenRead(path)) { + using (Stream fs = Platform.FileOpen(path)) { int width, height, length; game.World.Reset(); game.WorldEvents.RaiseOnNewMap(); diff --git a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs index 8ecbbf1cd..3d89af712 100644 --- a/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/SaveLevelScreen.cs @@ -15,14 +15,30 @@ namespace ClassicalSharp.Gui.Screens { InputWidget input; const int overwriteIndex = 2; static FastColour grey = new FastColour(150, 150, 150); + string textPath; public override void Render(double delta) { base.Render(delta); int cX = game.Width / 2, cY = game.Height / 2; - game.Graphics.Draw2DQuad(cX - 250, cY + 90, 500, 2, grey); - + game.Graphics.Draw2DQuad(cX - 250, cY + 90, 500, 2, grey); if (textPath == null) return; - SaveMap(textPath); + + bool classic = textPath.EndsWith(".cw"); + try { + using (Stream fs = Platform.FileCreate(textPath)) { + IMapFormatExporter exporter = null; + if (classic) exporter = new MapCwExporter(); + else exporter = new MapSchematicExporter(); + exporter.Save(fs, game); + } + } catch (Exception ex) { + ErrorHandler.LogError("saving map", ex); + MakeDescWidget("&cError while trying to save map"); + return; + } + + game.Chat.Add("&eSaved map to: " + textPath); + game.Gui.SetNewScreen(new PauseScreen(game)); textPath = null; } @@ -79,23 +95,23 @@ namespace ClassicalSharp.Gui.Screens { void SaveSchematic(Game game, Widget widget) { DoSave(widget, ".schematic"); } void DoSave(Widget widget, string ext) { - string text = input.Text.ToString(); - if (text.Length == 0) { + string file = input.Text.ToString(); + if (file.Length == 0) { MakeDescWidget("&ePlease enter a filename"); return; } - string file = Path.ChangeExtension(text, ext); - text = Path.Combine(Program.AppDirectory, "maps"); - text = Path.Combine(text, file); + file = Path.ChangeExtension(file, ext); + string path = Path.Combine("maps", file); ButtonWidget btn = (ButtonWidget)widget; - if (File.Exists(text) && btn.OptName == null) { + + if (Platform.FileExists(path) && btn.OptName == null) { btn.SetText("&cOverwrite existing?"); btn.OptName = "O"; } else { // NOTE: We don't immediately save here, because otherwise the 'saving...' // will not be rendered in time because saving is done on the main thread. MakeDescWidget("Saving.."); - textPath = text; + textPath = path; RemoveOverwrites(); } } @@ -113,27 +129,6 @@ namespace ClassicalSharp.Gui.Screens { button.SetText(defaultText); } - string textPath; - void SaveMap(string path) { - bool classic = path.EndsWith(".cw"); - try { - if (File.Exists(path)) - File.Delete(path); - using (FileStream fs = new FileStream(path, FileMode.CreateNew, FileAccess.Write)) { - IMapFormatExporter exporter = null; - if (classic) exporter = new MapCwExporter(); - else exporter = new MapSchematicExporter(); - exporter.Save(fs, game); - } - } catch (Exception ex) { - ErrorHandler.LogError("saving map", ex); - MakeDescWidget("&cError while trying to save map"); - return; - } - game.Chat.Add("&eSaved map to: " + Path.GetFileName(path)); - game.Gui.SetNewScreen(new PauseScreen(game)); - } - void MakeDescWidget(string text) { DisposeDescWidget(); widgets[widgets.Length - 1] = TextWidget.Create(game, text, textFont) diff --git a/ClassicalSharp/2D/Screens/Menu/TexturePackScreen.cs b/ClassicalSharp/2D/Screens/Menu/TexturePackScreen.cs index bf8518ba8..c2e5ba764 100644 --- a/ClassicalSharp/2D/Screens/Menu/TexturePackScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/TexturePackScreen.cs @@ -10,19 +10,18 @@ namespace ClassicalSharp.Gui.Screens { public TexturePackScreen(Game game) : base(game) { titleText = "Select a texture pack zip"; - string dir = Path.Combine(Program.AppDirectory, "texpacks"); - entries = Directory.GetFiles(dir, "*.zip"); + entries = Platform.DirectoryFiles("texpacks", "*.zip"); - for (int i = 0; i < entries.Length; i++) + for (int i = 0; i < entries.Length; i++) { entries[i] = Path.GetFileName(entries[i]); + } Array.Sort(entries); } protected override void TextButtonClick(Game game, Widget widget) { string file = ((ButtonWidget)widget).Text; - string dir = Path.Combine(Program.AppDirectory, "texpacks"); - string path = Path.Combine(dir, file); - if (!File.Exists(path)) return; + string path = Path.Combine("texpacks", file); + if (!Platform.FileExists(path)) return; int curPage = currentIndex; game.DefaultTexturePack = file; diff --git a/ClassicalSharp/Audio/AudioPlayer.cs b/ClassicalSharp/Audio/AudioPlayer.cs index 05404d536..cb2fb2ef4 100644 --- a/ClassicalSharp/Audio/AudioPlayer.cs +++ b/ClassicalSharp/Audio/AudioPlayer.cs @@ -17,11 +17,11 @@ namespace ClassicalSharp.Audio { public void Init(Game game) { this.game = game; - string path = Path.Combine(Program.AppDirectory, "audio"); - if (Directory.Exists(path)) - files = Directory.GetFiles(path); - else + if (Platform.DirectoryExists("audio")) { + files = Platform.DirectoryFiles("audio"); + } else { files = new string[0]; + } game.MusicVolume = GetVolume(OptionsKey.MusicVolume, OptionsKey.UseMusic); SetMusic(game.MusicVolume); @@ -60,7 +60,8 @@ namespace ClassicalSharp.Audio { musicFiles = new string[musicCount]; for (int i = 0, j = 0; i < files.Length; i++) { if (!Utils.CaselessEnds(files[i], ".ogg")) continue; - musicFiles[j] = files[i]; j++; + musicFiles[j] = Path.GetFileName(files[i]); + j++; } disposingMusic = false; @@ -75,10 +76,9 @@ namespace ClassicalSharp.Audio { Random rnd = new Random(); while (!disposingMusic) { string file = musicFiles[rnd.Next(0, musicFiles.Length)]; - string path = Path.Combine(Program.AppDirectory, file); Utils.LogDebug("playing music file: " + file); - using (FileStream fs = File.OpenRead(path)) { + using (Stream fs = Platform.FileOpen(file)) { OggContainer container = new OggContainer(fs); try { musicOut.SetVolume(game.MusicVolume / 100.0f); diff --git a/ClassicalSharp/Audio/Soundboard.cs b/ClassicalSharp/Audio/Soundboard.cs index ffb511c4f..e3a3693b9 100644 --- a/ClassicalSharp/Audio/Soundboard.cs +++ b/ClassicalSharp/Audio/Soundboard.cs @@ -65,7 +65,7 @@ namespace ClassicalSharp.Audio { } Sound ReadWave(string file) { - using (FileStream fs = File.OpenRead(file)) + using (Stream fs = File.OpenRead(file)) using (BinaryReader r = new BinaryReader(fs)) { string fourCC = GetFourCC(r); diff --git a/ClassicalSharp/Game/ChatLog.cs b/ClassicalSharp/Game/ChatLog.cs index 82654918f..ff44e0bca 100644 --- a/ClassicalSharp/Game/ChatLog.cs +++ b/ClassicalSharp/Game/ChatLog.cs @@ -126,20 +126,19 @@ namespace ClassicalSharp { } void OpenChatFile(DateTime now) { - string basePath = Path.Combine(Program.AppDirectory, "logs"); - if (!Directory.Exists(basePath)) - Directory.CreateDirectory(basePath); + if (!Platform.DirectoryExists("logs")) { + Platform.DirectoryCreate("logs"); + } string date = now.ToString("yyyy-MM-dd"); // Ensure multiple instances do not end up overwriting each other's log entries. for (int i = 0; i < 20; i++) { string id = i == 0 ? "" : " _" + i; - string fileName = date + " " + logName + id + ".log"; - string path = Path.Combine(basePath, fileName); + string path = Path.Combine("logs", date + " " + logName + id + ".log"); - FileStream stream = null; + Stream stream = null; try { - stream = File.Open(path, FileMode.Append, FileAccess.Write, FileShare.Read); + stream = Platform.FileAppend(path); } catch (IOException ex) { int hresult = Marshal.GetHRForException(ex); uint errorCode = (uint)hresult & 0xFFFF; diff --git a/ClassicalSharp/Game/Game.Init.cs b/ClassicalSharp/Game/Game.Init.cs index 3af626364..1f4a9bf8a 100644 --- a/ClassicalSharp/Game/Game.Init.cs +++ b/ClassicalSharp/Game/Game.Init.cs @@ -161,9 +161,12 @@ namespace ClassicalSharp { defTexturePack = Options.Get(OptionsKey.DefaultTexturePack) ?? "default.zip"; TexturePack extractor = new TexturePack(); extractor.Extract("default.zip", this); + // in case the user's default texture pack doesn't have all required textures - if (DefaultTexturePack != "default.zip") - extractor.Extract(DefaultTexturePack, this); + string defTexPack = DefaultTexturePack; + if (defTexPack != "default.zip") { + extractor.Extract(defTexPack, this); + } } void LoadOptions() { diff --git a/ClassicalSharp/Game/Game.Properties.cs b/ClassicalSharp/Game/Game.Properties.cs index f87caef68..b5becfc5c 100644 --- a/ClassicalSharp/Game/Game.Properties.cs +++ b/ClassicalSharp/Game/Game.Properties.cs @@ -9,7 +9,6 @@ using ClassicalSharp.Commands; using ClassicalSharp.Entities; using ClassicalSharp.Events; using ClassicalSharp.GraphicsAPI; -using ClassicalSharp.Gui; using ClassicalSharp.Map; using ClassicalSharp.Mode; using ClassicalSharp.Model; @@ -231,9 +230,8 @@ namespace ClassicalSharp { /// this method returns "default.zip". public string DefaultTexturePack { get { - string path = Path.Combine(Program.AppDirectory, "texpacks"); - path = Path.Combine(path, defTexturePack); - return File.Exists(path) && !ClassicMode ? defTexturePack : "default.zip"; + string texPath = Path.Combine("texpacks", defTexturePack); + return Platform.FileExists(texPath) && !ClassicMode ? defTexturePack : "default.zip"; } set { defTexturePack = value; diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index e75d36660..36486b1ab 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -202,13 +202,14 @@ namespace ClassicalSharp { } void TakeScreenshot() { - string path = PathIO.Combine(Program.AppDirectory, "screenshots"); - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); + if (!Platform.DirectoryExists("screenshots")) { + Platform.DirectoryCreate("screenshots"); + } string timestamp = DateTime.Now.ToString("dd-MM-yyyy-HH-mm-ss"); string file = "screenshot_" + timestamp + ".png"; - path = PathIO.Combine(path, file); + string path = PathIO.Combine("screenshots", file); + Graphics.TakeScreenshot(path, Width, Height); Chat.Add("&eTaken screenshot as: " + file); screenshotRequested = false; diff --git a/ClassicalSharp/Game/Plugin.cs b/ClassicalSharp/Game/Plugin.cs index 3cd8278ed..1afaf5ad8 100644 --- a/ClassicalSharp/Game/Plugin.cs +++ b/ClassicalSharp/Game/Plugin.cs @@ -21,20 +21,20 @@ namespace ClassicalSharp { internal static Game game; internal static List LoadAll() { - string dir = Path.Combine(Program.AppDirectory, "plugins"); - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); + if (!Platform.DirectoryExists("plugins")) { + Platform.DirectoryCreate("plugins"); + } Accepted = new EntryList("plugins", "accepted.txt"); Denied = new EntryList("plugins", "denied.txt"); Accepted.Load(); Denied.Load(); - return LoadPlugins(dir); + return LoadPlugins(); } - static List LoadPlugins(string dir) { - string[] dlls = Directory.GetFiles(dir, "*.dll"); + static List LoadPlugins() { + string[] dlls = Platform.DirectoryFiles("plugins", "*.dll"); List nonLoaded = null; for (int i = 0; i < dlls.Length; i++) { @@ -55,8 +55,7 @@ namespace ClassicalSharp { public static void Load(string pluginName, bool needsInit) { try { - string dir = Path.Combine(Program.AppDirectory, "plugins"); - string path = Path.Combine(dir, pluginName + ".dll"); + string path = Path.Combine("plguins", pluginName + ".dll"); Assembly lib = Assembly.LoadFrom(path); Type[] types = lib.GetTypes(); diff --git a/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs b/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs index c586b2482..69ae05bc3 100644 --- a/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs +++ b/ClassicalSharp/GraphicsAPI/Direct3D9Api.cs @@ -3,6 +3,7 @@ using System; using System.Drawing; using System.Drawing.Imaging; +using System.IO; using System.Runtime.InteropServices; using System.Threading; using OpenTK; @@ -172,7 +173,7 @@ namespace ClassicalSharp.GraphicsAPI { if (managedPool) { texture = device.CreateTexture(width, height, levels, Usage.None, Format.A8R8G8B8, Pool.Managed); - texture.SetData(0, LockFlags.None, scan0, width * height * 4); + texture.SetData(0, LockFlags.None, scan0, width * height * 4); if (mipmaps) DoMipmaps(texture, 0, 0, width, height, scan0, false); } else { D3D.Texture sys = device.CreateTexture(width, height, levels, Usage.None, Format.A8R8G8B8, Pool.SystemMemory); @@ -180,19 +181,19 @@ namespace ClassicalSharp.GraphicsAPI { if (mipmaps) DoMipmaps(sys, 0, 0, width, height, scan0, false); texture = device.CreateTexture(width, height, levels, Usage.None, Format.A8R8G8B8, Pool.Default); - device.UpdateTexture(sys, texture); + device.UpdateTexture(sys, texture); sys.Dispose(); } return GetOrExpand(ref textures, texture, texBufferSize); } - - unsafe void DoMipmaps(D3D.Texture texture, int x, int y, int width, + + unsafe void DoMipmaps(D3D.Texture texture, int x, int y, int width, int height, IntPtr scan0, bool partial) { IntPtr prev = scan0; int lvls = MipmapsLevels(width, height); for (int lvl = 1; lvl <= lvls; lvl++) { - x /= 2; y /= 2; + x /= 2; y /= 2; if (width > 1) width /= 2; if (height > 1) height /= 2; int size = width * height * 4; @@ -295,7 +296,7 @@ namespace ClassicalSharp.GraphicsAPI { public override int CreateVb(IntPtr vertices, VertexFormat format, int count) { int size = count * strideSizes[(int)format]; - DataBuffer buffer = device.CreateVertexBuffer(size, Usage.WriteOnly, + DataBuffer buffer = device.CreateVertexBuffer(size, Usage.WriteOnly, formatMapping[(int)format], Pool.Default); buffer.SetData(vertices, size, LockFlags.None); return GetOrExpand(ref vBuffers, buffer, vBufferSize); @@ -553,9 +554,10 @@ namespace ClassicalSharp.GraphicsAPI { device.GetRenderTargetData(backbuffer, tempSurface); LockedRectangle rect = tempSurface.LockRectangle(LockFlags.ReadOnly | LockFlags.NoDirtyUpdate); - using (Bitmap bmp = new Bitmap(width, height, width * sizeof(int), - PixelFormat.Format32bppRgb, rect.DataPointer)) { - bmp.Save(output, ImageFormat.Png); + using (Bitmap bmp = new Bitmap(width, height, width * sizeof(int), PixelFormat.Format32bppRgb, rect.DataPointer)) { + using (Stream fs = Platform.FileCreate(output)) { + Platform.WriteBmp(bmp, fs); + } } tempSurface.UnlockRectangle(); } diff --git a/ClassicalSharp/GraphicsAPI/OpenGLApi.cs b/ClassicalSharp/GraphicsAPI/OpenGLApi.cs index ffd19c3ac..9fa3c71d6 100644 --- a/ClassicalSharp/GraphicsAPI/OpenGLApi.cs +++ b/ClassicalSharp/GraphicsAPI/OpenGLApi.cs @@ -3,6 +3,7 @@ using System; using System.Drawing; using System.Drawing.Imaging; +using System.IO; using System.Runtime.InteropServices; using OpenTK; using OpenTK.Graphics.OpenGL; @@ -551,7 +552,10 @@ namespace ClassicalSharp.GraphicsAPI { using (FastBitmap fastBmp = new FastBitmap(bmp, true, false)) GL.ReadPixels(0, 0, width, height, GlPixelFormat.Bgra, PixelType.UnsignedByte, fastBmp.Scan0); bmp.RotateFlip(RotateFlipType.RotateNoneFlipY); - bmp.Save(output, ImageFormat.Png); + + using (Stream fs = Platform.FileCreate(output)) { + Platform.WriteBmp(bmp, fs); + } } } diff --git a/ClassicalSharp/GraphicsAPI/OpenGLESApi.cs b/ClassicalSharp/GraphicsAPI/OpenGLESApi.cs index 479f0a001..17dbe9106 100644 --- a/ClassicalSharp/GraphicsAPI/OpenGLESApi.cs +++ b/ClassicalSharp/GraphicsAPI/OpenGLESApi.cs @@ -342,8 +342,9 @@ namespace ClassicalSharp.GraphicsAPI { } } } - using (FileStream fs = File.Create(output)) + using (Stream fs = Platform.FileCreate(output)) { Platform.WriteBmp(bmp, fs); + } } } diff --git a/ClassicalSharp/Network/IServerConnection.cs b/ClassicalSharp/Network/IServerConnection.cs index 10d0370f9..aea6c4ba5 100644 --- a/ClassicalSharp/Network/IServerConnection.cs +++ b/ClassicalSharp/Network/IServerConnection.cs @@ -74,12 +74,12 @@ namespace ClassicalSharp { internal void DownloadTexturePack(string url) { if (game.DeniedUrls.Has(url)) return; - string path = TextureCache.MakePath(url), etag = null; + string etag = null; DateTime lastModified = DateTime.MinValue; - if (File.Exists(path)) { - lastModified = TextureCache.GetLastModified(url, path, game.LastModified); - etag = TextureCache.GetETag(url, path, game.ETags); + if (TextureCache.HasUrl(url)) { + lastModified = TextureCache.GetLastModified(url, game.LastModified); + etag = TextureCache.GetETag(url, game.ETags); } TexturePack.ExtractCurrent(game, url); diff --git a/ClassicalSharp/Platform/DesktopWindow.cs b/ClassicalSharp/Platform/DesktopWindow.cs index 349c76218..e492b83c3 100644 --- a/ClassicalSharp/Platform/DesktopWindow.cs +++ b/ClassicalSharp/Platform/DesktopWindow.cs @@ -41,13 +41,14 @@ namespace ClassicalSharp { } public void LoadIcon() { - string launcherPath = Path.Combine(Program.AppDirectory, "Launcher2.exe"); - if (!File.Exists(launcherPath)) { - launcherPath = Path.Combine(Program.AppDirectory, "Launcher.exe"); + string launcherFile = "Launcher2.exe"; + if (!Platform.FileExists(launcherFile)) { + launcherFile = "Launcher.exe"; } - if (!File.Exists(launcherPath)) return; + if (!Platform.FileExists(launcherFile)) return; try { + string launcherPath = Path.Combine(Platform.AppDirectory, launcherFile); Icon = Icon.ExtractAssociatedIcon(launcherPath); } catch (Exception ex) { ErrorHandler.LogError("DesktopWindow.LoadIcon()", ex); diff --git a/ClassicalSharp/Platform/Platform.cs b/ClassicalSharp/Platform/Platform.cs index b0f932b59..8364bfd91 100644 --- a/ClassicalSharp/Platform/Platform.cs +++ b/ClassicalSharp/Platform/Platform.cs @@ -13,6 +13,8 @@ namespace ClassicalSharp { /// Abstracts away platform specific operations. public static class Platform { + public static string AppDirectory; + public static bool ValidBitmap(Bitmap bmp) { // Mono seems to be returning a bitmap with a native pointer of zero in some weird cases. // We can detect this as property access raises an ArgumentException. @@ -70,5 +72,65 @@ namespace ClassicalSharp { return config != null && config == Bitmap.Config.Argb8888; #endif } + + public static FileStream FileOpen(string relPath) { + string path = Path.Combine(AppDirectory, relPath); + return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); + } + + public static FileStream FileCreate(string relPath) { + string path = Path.Combine(AppDirectory, relPath); + return new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read); + } + + public static FileStream FileAppend(string relPath) { + string path = Path.Combine(AppDirectory, relPath); + return new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read); + } + + public static bool FileExists(string relPath) { + string path = Path.Combine(AppDirectory, relPath); + return File.Exists(path); + } + + public static DateTime FileGetWriteTime(string relPath) { + string path = Path.Combine(AppDirectory, relPath); + return File.GetLastWriteTimeUtc(path); + } + + public static void FileSetWriteTime(string relPath, DateTime time) { + string path = Path.Combine(AppDirectory, relPath); + File.SetLastWriteTimeUtc(path, time); + } + + public static bool DirectoryExists(string relPath) { + string path = Path.Combine(AppDirectory, relPath); + return Directory.Exists(path); + } + + public static void DirectoryCreate(string relPath) { + string path = Path.Combine(AppDirectory, relPath); + Directory.CreateDirectory(path); + } + + public static string[] DirectoryFiles(string relPath) { + string path = Path.Combine(AppDirectory, relPath); + return Directory.GetFiles(relPath); + } + + public static string[] DirectoryFiles(string relPath, string filter) { + string path = Path.Combine(AppDirectory, relPath); + return Directory.GetFiles(relPath, filter); + } + + public static void WriteAllText(string relPath, string text) { + string path = Path.Combine(AppDirectory, relPath); + File.WriteAllText(path, text); + } + + public static void WriteAllBytes(string relPath, byte[] data) { + string path = Path.Combine(AppDirectory, relPath); + File.WriteAllBytes(path, data); + } } } diff --git a/ClassicalSharp/Program.cs b/ClassicalSharp/Program.cs index 80e7e08ca..50704c475 100644 --- a/ClassicalSharp/Program.cs +++ b/ClassicalSharp/Program.cs @@ -3,7 +3,6 @@ using System; using System.IO; using System.Net; using System.Windows.Forms; -using ClassicalSharp.Textures; using OpenTK; namespace ClassicalSharp { @@ -12,21 +11,21 @@ namespace ClassicalSharp { public const string AppName = "ClassicalSharp 0.99.9.94"; - public static string AppDirectory; #if !LAUNCHER [STAThread] static void Main(string[] args) { - AppDirectory = AppDomain.CurrentDomain.BaseDirectory; + Platform.AppDirectory = AppDomain.CurrentDomain.BaseDirectory; CleanupMainDirectory(); - string path = Path.Combine(Program.AppDirectory, "texpacks"); - if (!File.Exists(Path.Combine(path, "default.zip"))) { - Message("default.zip not found, try running the launcher first."); return; + string defPath = Path.Combine("texpacks", "default.zip"); + if (!Platform.FileExists(defPath)) { + ErrorHandler.ShowDialog("Missing file", "default.zip not found, try running the launcher first."); + return; } - path = Path.Combine(AppDirectory, "OpenTK.dll"); - if (!File.Exists(path)) { - Message("OpenTK.dll needs to be in the same folder as the game"); return; + if (!Platform.FileExists("OpenTK.dll")) { + ErrorHandler.ShowDialog("Missing file", "OpenTK.dll needs to be in the same folder as the game"); + return; } // NOTE: we purposely put this in another method, as we need to ensure @@ -36,8 +35,7 @@ namespace ClassicalSharp { } static void RunGame(string[] args) { - string logPath = Path.Combine(AppDirectory, "client.log"); - ErrorHandler.InstallHandler(logPath); + ErrorHandler.InstallHandler("client.log"); OpenTK.Configuration.SkipPerfCountersHack(); Utils.LogDebug("Starting " + AppName + ".."); @@ -70,9 +68,6 @@ namespace ClassicalSharp { } } - // put in separate function, because we don't want to load winforms assembly if possible - static void Message(string message) { MessageBox.Show(message, "Missing file"); } - static void RunMultiplayer(string[] args, bool nullContext, int width, int height) { IPAddress ip = null; if (!IPAddress.TryParse(args[2], out ip)) { @@ -97,14 +92,14 @@ namespace ClassicalSharp { } #endif - internal static void CleanupMainDirectory() { - string mapPath = Path.Combine(Program.AppDirectory, "maps"); - if (!Directory.Exists(mapPath)) - Directory.CreateDirectory(mapPath); - - string texPath = Path.Combine(Program.AppDirectory, "texpacks"); - if (!Directory.Exists(texPath)) - Directory.CreateDirectory(texPath); + public static void CleanupMainDirectory() { + if (!Platform.DirectoryExists("maps")) { + Platform.DirectoryCreate("maps"); + } + + if (!Platform.DirectoryExists("texpacks")) { + Platform.DirectoryCreate("texpacks"); + } } } } \ No newline at end of file diff --git a/ClassicalSharp/TexturePack/Animations.cs b/ClassicalSharp/TexturePack/Animations.cs index 097d33b76..6b7d97b85 100644 --- a/ClassicalSharp/TexturePack/Animations.cs +++ b/ClassicalSharp/TexturePack/Animations.cs @@ -43,7 +43,7 @@ namespace ClassicalSharp.Textures { animsBuffer = new FastBitmap(animBmp, true, true); } else if (e.Name == "animations.txt" || e.Name == "animation.txt") { MemoryStream stream = new MemoryStream(e.Data); - StreamReader reader = new StreamReader(stream); + StreamReader reader = new StreamReader(stream, false); ReadAnimationsDescription(reader); } else if (e.Name == "uselavaanim") { useLavaAnim = true; diff --git a/ClassicalSharp/TexturePack/EntryList.cs b/ClassicalSharp/TexturePack/EntryList.cs index 57e06737e..2feb2697f 100644 --- a/ClassicalSharp/TexturePack/EntryList.cs +++ b/ClassicalSharp/TexturePack/EntryList.cs @@ -25,12 +25,11 @@ namespace ClassicalSharp.Textures { } public bool Load() { - string path = Path.Combine(Program.AppDirectory, folder); - path = Path.Combine(path, file); - if (!File.Exists(path)) return true; + string path = Path.Combine(folder, file); + if (!Platform.FileExists(path)) return true; try { - using (Stream fs = File.OpenRead(path)) + using (Stream fs = Platform.FileOpen(path)) using (StreamReader reader = new StreamReader(fs, false)) { string line; @@ -48,12 +47,13 @@ namespace ClassicalSharp.Textures { } public bool Save() { - try { - string path = Path.Combine(Program.AppDirectory, folder); - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); + try { + if (!Platform.DirectoryExists(folder)) { + Platform.DirectoryCreate(folder); + } - using (Stream fs = File.Create(Path.Combine(path, file))) + string path = Path.Combine(folder, file); + using (Stream fs = Platform.FileCreate(path)) using (StreamWriter writer = new StreamWriter(fs)) { for (int i = 0; i < Entries.Count; i++) diff --git a/ClassicalSharp/TexturePack/TextureCache.cs b/ClassicalSharp/TexturePack/TextureCache.cs index fd36ce86f..d894aba4f 100644 --- a/ClassicalSharp/TexturePack/TextureCache.cs +++ b/ClassicalSharp/TexturePack/TextureCache.cs @@ -14,18 +14,16 @@ namespace ClassicalSharp.Textures { public static class TextureCache { /// Gets whether the given url has data associated with it in the cache. - public static bool HasUrl(string url) { - return File.Exists(MakePath(url)); - } + public static bool HasUrl(string url) { return Platform.FileExists(MakePath(url)); } /// Gets the stream of data associated with the url from the cache, returning null if the /// data for the url was not found in the cache. public static FileStream GetStream(string url) { string path = MakePath(url); - if (!File.Exists(path)) return null; + if (!Platform.FileExists(path)) return null; try { - return File.OpenRead(path); + return Platform.FileOpen(path); } catch (IOException ex) { ErrorHandler.LogError("Cache.GetData", ex); return null; @@ -34,17 +32,18 @@ namespace ClassicalSharp.Textures { /// Gets the time the data associated with the url from the cache was last modified, /// returning DateTime.MinValue if data for the url was not found in the cache. - public static DateTime GetLastModified(string url, string path, EntryList tags) { + public static DateTime GetLastModified(string url, EntryList tags) { string entry = GetFromTags(url, tags); long ticks = 0; if (entry != null && long.TryParse(entry, out ticks)) { return new DateTime(ticks, DateTimeKind.Utc); } else { - return File.GetLastWriteTimeUtc(path); + string path = MakePath(url); + return Platform.FileGetWriteTime(path); } } - public static string GetETag(string url, string path, EntryList tags) { + public static string GetETag(string url, EntryList tags) { return GetFromTags(url, tags); } @@ -67,12 +66,13 @@ namespace ClassicalSharp.Textures { public static void Add(string url, Bitmap bmp) { string path = MakePath(url); try { - string basePath = PathIO.Combine(Program.AppDirectory, Folder); - if (!Directory.Exists(basePath)) - Directory.CreateDirectory(basePath); + if (!Platform.DirectoryExists(Folder)) { + Platform.DirectoryCreate(Folder); + } - using (FileStream fs = File.Create(path)) + using (Stream fs = Platform.FileCreate(path)) { Platform.WriteBmp(bmp, fs); + } } catch (IOException ex) { ErrorHandler.LogError("Cache.AddToCache", ex); } @@ -82,10 +82,11 @@ namespace ClassicalSharp.Textures { public static void Add(string url, byte[] data) { string path = MakePath(url); try { - string basePath = PathIO.Combine(Program.AppDirectory, Folder); - if (!Directory.Exists(basePath)) - Directory.CreateDirectory(basePath); - File.WriteAllBytes(path, data); + if (!Platform.DirectoryExists(Folder)) { + Platform.DirectoryCreate(Folder); + } + + Platform.WriteAllBytes(path, data); } catch (IOException ex) { ErrorHandler.LogError("Cache.AddToCache", ex); } @@ -113,13 +114,8 @@ namespace ClassicalSharp.Textures { } - const string Folder = "texturecache"; - - public static string MakePath(string url) { - string crc32 = CRC32(url); - string basePath = PathIO.Combine(Program.AppDirectory, Folder); - return PathIO.Combine(basePath, crc32); - } + const string Folder = "texturecache"; + public static string MakePath(string url) { return PathIO.Combine(Folder, CRC32(url)); } static string CRC32(string url) { byte[] data = Encoding.UTF8.GetBytes(url); diff --git a/ClassicalSharp/TexturePack/TexturePack.cs b/ClassicalSharp/TexturePack/TexturePack.cs index fc2c0ac13..97abb3916 100644 --- a/ClassicalSharp/TexturePack/TexturePack.cs +++ b/ClassicalSharp/TexturePack/TexturePack.cs @@ -17,11 +17,11 @@ namespace ClassicalSharp.Textures { Game game; - public void Extract(string path, Game game) { - path = PathIO.Combine("texpacks", path); - path = PathIO.Combine(Program.AppDirectory, path); - using (Stream fs = File.OpenRead(path)) + public void Extract(string file, Game game) { + string path = PathIO.Combine("texpacks", file); + using (Stream fs = Platform.FileOpen(path)) { Extract(fs, game); + } } public void Extract(Stream stream, Game game) { diff --git a/ClassicalSharp/Utils/ErrorHandler.cs b/ClassicalSharp/Utils/ErrorHandler.cs index f64dcf109..0cf093a40 100644 --- a/ClassicalSharp/Utils/ErrorHandler.cs +++ b/ClassicalSharp/Utils/ErrorHandler.cs @@ -11,14 +11,12 @@ namespace ClassicalSharp { /// and also logs it to a specified log file. public static class ErrorHandler { - static string logFile = "crash.log"; static string fileName = "crash.log"; /// Adds a handler for when a unhandled exception occurs, unless /// a debugger is attached to the process in which case this does nothing. public static void InstallHandler(string logFile) { - ErrorHandler.logFile = logFile; - fileName = Path.GetFileName(logFile); + fileName = logFile; if (!Debugger.IsAttached) AppDomain.CurrentDomain.UnhandledException += UnhandledException; } @@ -40,7 +38,9 @@ namespace ClassicalSharp { Exception ex = (Exception)e.ExceptionObject; bool wroteToCrashLog = true; try { - using (StreamWriter w = new StreamWriter(logFile, true)) { + using (Stream fs = Platform.FileAppend(fileName)) + using (StreamWriter w = new StreamWriter(fs)) + { w.WriteLine("=== crash occurred ==="); w.WriteLine("Time: " + DateTime.Now); @@ -72,12 +72,12 @@ namespace ClassicalSharp { string line1 = "ClassicalSharp crashed."; if (wroteToCrashLog) { - line1 += " The cause has also been logged to \"" + fileName + "\" in " + Program.AppDirectory; + line1 += " The cause has also been logged to \"" + fileName + "\" in " + Platform.AppDirectory; } string line2 = "Please report the crash to github.com/UnknownShadow200/ClassicalSharp/issues so we can fix it."; line2 += Environment.NewLine + Environment.NewLine + Format(ex); - MessageBox.Show(line1 + Environment.NewLine + Environment.NewLine + line2, "We're sorry"); + ShowDialog("We're sorry", line1 + Environment.NewLine + Environment.NewLine + line2); Environment.Exit(1); } @@ -93,16 +93,23 @@ namespace ClassicalSharp { /// Logs an error that occured at the specified location to the log file. public static bool LogError(string location, string text) { try { - using (StreamWriter writer = new StreamWriter(logFile, true)) { - writer.WriteLine("=== handled error ==="); - writer.WriteLine("Occured when: " + location); - writer.WriteLine(text); - writer.WriteLine(); + using (Stream fs = Platform.FileAppend(fileName)) + using (StreamWriter w = new StreamWriter(fs)) + { + w.WriteLine("=== handled error ==="); + w.WriteLine("Occured when: " + location); + w.WriteLine(text); + w.WriteLine(); } } catch (Exception) { return false; } return true; } + + // put in separate function, because we don't want to load winforms assembly if possible + public static void ShowDialog(string title, string msg) { + MessageBox.Show(msg, title); + } } } \ No newline at end of file diff --git a/ClassicalSharp/Utils/Options.cs b/ClassicalSharp/Utils/Options.cs index 20d0e0899..bd7d403e2 100644 --- a/ClassicalSharp/Utils/Options.cs +++ b/ClassicalSharp/Utils/Options.cs @@ -190,14 +190,8 @@ namespace ClassicalSharp { public static bool Load() { - // Both of these are from when running from the launcher - if (Program.AppDirectory == null) - Program.AppDirectory = AppDomain.CurrentDomain.BaseDirectory; - Program.CleanupMainDirectory(); - try { - string path = Path.Combine(Program.AppDirectory, Filename); - using (Stream fs = File.OpenRead(path)) + using (Stream fs = Platform.FileOpen(Filename)) using (StreamReader reader = new StreamReader(fs, false)) { LoadFrom(reader); @@ -239,8 +233,7 @@ namespace ClassicalSharp { public static bool Save() { try { - string path = Path.Combine(Program.AppDirectory, Filename); - using (Stream fs = File.Create(path)) + using (Stream fs = Platform.FileCreate(Filename)) using (StreamWriter writer = new StreamWriter(fs)) { SaveTo(writer); diff --git a/Launcher2/Gui/Screens/ResourcesScreen.cs b/Launcher2/Gui/Screens/ResourcesScreen.cs index d33e5c112..c4d29f72b 100644 --- a/Launcher2/Gui/Screens/ResourcesScreen.cs +++ b/Launcher2/Gui/Screens/ResourcesScreen.cs @@ -1,6 +1,6 @@ // ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT using System; -using System.IO; +using ClassicalSharp; using ClassicalSharp.Network; using Launcher.Gui.Views; using Launcher.Patcher; @@ -90,7 +90,7 @@ namespace Launcher.Gui.Screens { void GotoNextMenu(int x, int y) { game.Downloader.Clear(); - if (File.Exists("options.txt")) { + if (Platform.FileExists("options.txt")) { game.SetScreen(new MainScreen(game)); } else { game.SetScreen(new ChooseModeScreen(game, true)); diff --git a/Launcher2/Gui/Views/UpdatesView.cs b/Launcher2/Gui/Views/UpdatesView.cs index 50076c6ff..cc491f86e 100644 --- a/Launcher2/Gui/Views/UpdatesView.cs +++ b/Launcher2/Gui/Views/UpdatesView.cs @@ -39,11 +39,11 @@ namespace Launcher.Gui.Views { const string dateFormat = "dd-MM-yyyy HH:mm"; protected override void MakeWidgets() { widgetIndex = 0; - string exePath = Path.Combine(Program.AppDirectory, "ClassicalSharp.exe"); + DateTime writeTime = Platform.FileGetWriteTime("ClassicalSharp.exe"); Makers.Label(this, "Your build:", textFont) .SetLocation(Anchor.Centre, Anchor.Centre, -55, -120); - string yourBuild = File.GetLastWriteTime(exePath).ToString(dateFormat); + string yourBuild = writeTime.ToLocalTime().ToString(dateFormat); Makers.Label(this, yourBuild, textFont) .SetLocation(Anchor.Centre, Anchor.Centre, 70, -120); diff --git a/Launcher2/LauncherWindow.Background.cs b/Launcher2/LauncherWindow.Background.cs index 0bfa08719..a8c565d3c 100644 --- a/Launcher2/LauncherWindow.Background.cs +++ b/Launcher2/LauncherWindow.Background.cs @@ -17,28 +17,31 @@ namespace Launcher { fontPng = false; terrainPng = false; Options.Load(); LauncherSkin.LoadFromOptions(); - if (Options.Get("nostalgia-classicbg") != null) + + if (Options.Get("nostalgia-classicbg") != null) { ClassicBackground = Options.GetBool("nostalgia-classicbg", false); - else + } else { ClassicBackground = Options.GetBool("mode-classic", false); + } - string texDir = Path.Combine(Program.AppDirectory, "texpacks"); string texPack = Options.Get(OptionsKey.DefaultTexturePack) ?? "default.zip"; - texPack = Path.Combine(texDir, texPack); + string texPath = Path.Combine("texpacks", texPack); - if (!File.Exists(texPack)) - texPack = Path.Combine(texDir, "default.zip"); - if (!File.Exists(texPack)) return; + if (!Platform.FileExists(texPath)) { + texPath = Path.Combine("texpacks", "default.zip"); + } + if (!Platform.FileExists(texPath)) return; - ExtractTexturePack(texPack); + ExtractTexturePack(texPath); + // user selected texture pack is missing some required .png files if (!fontPng || !terrainPng) { - texPack = Path.Combine(texDir, "default.zip"); - ExtractTexturePack(texPack); + texPath = Path.Combine("texpacks", "default.zip"); + ExtractTexturePack(texPath); } } - void ExtractTexturePack(string texPack) { - using (Stream fs = new FileStream(texPack, FileMode.Open, FileAccess.Read, FileShare.Read)) { + void ExtractTexturePack(string relPath) { + using (Stream fs = Platform.FileOpen(relPath)) { ZipReader reader = new ZipReader(); reader.SelectZipEntry = SelectZipEntry; reader.ProcessZipEntry = ProcessZipEntry; diff --git a/Launcher2/LauncherWindow.cs b/Launcher2/LauncherWindow.cs index 285166a1f..07914a7d5 100644 --- a/Launcher2/LauncherWindow.cs +++ b/Launcher2/LauncherWindow.cs @@ -74,6 +74,8 @@ namespace Launcher { Window.FocusedChanged += FocusedChanged; Window.WindowStateChanged += Resize; Window.Keyboard.KeyDown += KeyDown; + + ClassicalSharp.Program.CleanupMainDirectory(); LoadFont(); logoFont = new Font(FontName, 32, FontStyle.Regular); diff --git a/Launcher2/Patcher/ResourceChecker.cs b/Launcher2/Patcher/ResourceChecker.cs index 10e95b432..0c1f734c7 100644 --- a/Launcher2/Patcher/ResourceChecker.cs +++ b/Launcher2/Patcher/ResourceChecker.cs @@ -1,6 +1,7 @@ // ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT using System; using System.IO; +using ClassicalSharp; using ClassicalSharp.Textures; namespace Launcher.Patcher { @@ -8,21 +9,21 @@ namespace Launcher.Patcher { public sealed class ResourceChecker { public void CheckResourceExistence() { - string audioPath = Path.Combine(Program.AppDirectory, "audio"); - if (!Directory.Exists(audioPath)) - Directory.CreateDirectory(audioPath); + if (!Platform.DirectoryExists("audio")) { + Platform.DirectoryCreate("audio"); + } + DigSoundsExist = CheckDigSoundsExist(); StepSoundsExist = CheckStepSoundsExist(); AllResourcesExist = DigSoundsExist && StepSoundsExist; - string texDir = Path.Combine(Program.AppDirectory, "texpacks"); - string zipPath = Path.Combine(texDir, "default.zip"); - bool defaultZipExists = File.Exists(zipPath); - if (File.Exists(zipPath)) - CheckDefaultZip(zipPath); + string defPath = Path.Combine("texpacks", "default.zip"); + if (Platform.FileExists(defPath)) { + CheckDefaultZip(defPath); + } CheckTexturePack(); - CheckMusic(audioPath); + CheckMusic(); CheckSounds(); } @@ -44,11 +45,11 @@ namespace Launcher.Patcher { } } - void CheckMusic(string audioPath) { + void CheckMusic() { string[] files = ResourceList.MusicFiles; for (int i = 0; i < files.Length; i++) { - string file = Path.Combine(audioPath, files[i]); - musicExists[i] = File.Exists(file); + string path = Path.Combine("audio", files[i]); + musicExists[i] = Platform.FileExists(path); if (musicExists[i]) continue; DownloadSize += musicSizes[i] / 1024f; @@ -73,13 +74,14 @@ namespace Launcher.Patcher { public int ResourcesCount; internal bool[] musicExists = new bool[7]; - void CheckDefaultZip(string path) { + void CheckDefaultZip(string relPath) { ZipReader reader = new ZipReader(); reader.SelectZipEntry = SelectZipEntry; reader.ProcessZipEntry = ProcessZipEntry; - using (Stream src = new FileStream(path, FileMode.Open, FileAccess.Read)) + using (Stream src = Platform.FileOpen(relPath)) { reader.Extract(src); + } } bool SelectZipEntry(string filename) { @@ -98,20 +100,18 @@ namespace Launcher.Patcher { bool CheckDigSoundsExist() { string[] files = ResourceList.DigSounds; - string path = Path.Combine(Program.AppDirectory, "audio"); for (int i = 0; i < files.Length; i++) { - string file = "dig_" + files[i] + ".wav"; - if (!File.Exists(Path.Combine(path, file))) return false; + string path = Path.Combine("audio", "dig_" + files[i] + ".wav"); + if (!Platform.FileExists(path)) return false; } return true; } bool CheckStepSoundsExist() { string[] files = ResourceList.StepSounds; - string path = Path.Combine(Program.AppDirectory, "audio"); for (int i = 0; i < files.Length; i++) { - string file = "step_" + files[i] + ".wav"; - if (!File.Exists(Path.Combine(path, file))) return false; + string path = Path.Combine("audio", "step_" + files[i] + ".wav"); + if (!Platform.FileExists(path)) return false; } return true; } diff --git a/Launcher2/Patcher/ResourceFetcher.cs b/Launcher2/Patcher/ResourceFetcher.cs index 20a1bd41e..c2b8175d8 100644 --- a/Launcher2/Patcher/ResourceFetcher.cs +++ b/Launcher2/Patcher/ResourceFetcher.cs @@ -128,9 +128,8 @@ namespace Launcher.Patcher { return false; if (data == null) continue; - string path = Path.Combine(Program.AppDirectory, "audio"); - path = Path.Combine(path, file); - File.WriteAllBytes(path, data); + string path = Path.Combine("audio", file); + Platform.WriteAllBytes(path, data); } return true; } diff --git a/Launcher2/Patcher/ResourcePatcher.cs b/Launcher2/Patcher/ResourcePatcher.cs index ef41413c3..9ee33c42b 100644 --- a/Launcher2/Patcher/ResourcePatcher.cs +++ b/Launcher2/Patcher/ResourcePatcher.cs @@ -32,11 +32,16 @@ namespace Launcher.Patcher { reader = new ZipReader(); reader.SelectZipEntry = SelectZipEntry_Classic; reader.ProcessZipEntry = ProcessZipEntry_Classic; - string texDir = Path.Combine(Program.AppDirectory, "texpacks"); - string path = Path.Combine(texDir, "default.zip"); - ExtractExisting(path); + string defPath = Path.Combine("texpacks", "default.zip"); - using (Stream dst = new FileStream(path, FileMode.Create, FileAccess.Write)) { + if (Platform.FileExists(defPath)) { + using (Stream src = Platform.FileOpen(defPath)) { + reader.ProcessZipEntry = ExtractExisting; + reader.Extract(src); + } + } + + using (Stream dst = Platform.FileCreate(defPath)) { writer = new ZipWriter(dst); writer.entries = new ZipEntry[100]; for (int i = 0; i < entries.Count; i++) @@ -60,14 +65,6 @@ namespace Launcher.Patcher { List entries = new List(); List datas = new List(); - void ExtractExisting(string path) { - if (!File.Exists(path)) return; - - using (Stream src = new FileStream(path, FileMode.Open, FileAccess.Read)) { - reader.ProcessZipEntry = ExtractExisting; - reader.Extract(src); - } - } void ExtractExisting(string filename, byte[] data, ZipEntry entry) { filename = ResourceList.GetFile(filename); @@ -114,7 +111,7 @@ namespace Launcher.Patcher { CopyTile( 0, 16, 5 * 16, 3 * 16, mask, terrainBmp); CopyTile(16, 16, 6 * 16, 5 * 16, mask, terrainBmp); - CopyTile(32, 16, 11 * 16, 0 * 16, mask, terrainBmp); + CopyTile(32, 16, 11 * 16, 0 * 16, mask, terrainBmp); patchedTerrain = true; } } diff --git a/Launcher2/Patcher/SoundPatcher.cs b/Launcher2/Patcher/SoundPatcher.cs index 6f7e26005..577583f3a 100644 --- a/Launcher2/Patcher/SoundPatcher.cs +++ b/Launcher2/Patcher/SoundPatcher.cs @@ -57,10 +57,9 @@ namespace Launcher.Patcher { } void DecodeSound(string name, byte[] rawData) { - string path = Path.Combine(Program.AppDirectory, "audio"); - path = Path.Combine(path, prefix + name + ".wav"); + string path = Path.Combine("audio", prefix + name + ".wav"); - using (FileStream dst = File.Create(path)) + using (FileStream dst = Platform.FileCreate(path)) using (MemoryStream src = new MemoryStream(rawData)) { dst.SetLength(44); diff --git a/Launcher2/Program.cs b/Launcher2/Program.cs index 55ea9efc0..6056db1d8 100644 --- a/Launcher2/Program.cs +++ b/Launcher2/Program.cs @@ -10,22 +10,20 @@ namespace Launcher { public const string AppName = "ClassicalSharp Launcher 0.99.9.94"; - public static string AppDirectory; - public static bool ShowingErrorDialog = false; [STAThread] static void Main(string[] args) { - AppDirectory = AppDomain.CurrentDomain.BaseDirectory; - - string path = Path.Combine(AppDirectory, "ClassicalSharp.exe"); - if (!File.Exists(path)) { - Message("ClassicalSharp.exe needs to be in the same folder as the launcher."); return; + Platform.AppDirectory = AppDomain.CurrentDomain.BaseDirectory; + + if (!Platform.FileExists("ClassicalSharp.exe")) { + ErrorHandler.ShowDialog("Missing file", "ClassicalSharp.exe needs to be in the same folder as the launcher."); + return; } - - path = Path.Combine(AppDirectory, "OpenTK.dll"); - if (!File.Exists(path)) { - Message("OpenTK.dll needs to be in the same folder as the launcher."); return; + + if (!Platform.FileExists("OpenTK.dll")) { + ErrorHandler.ShowDialog("Missing file", "OpenTK.dll needs to be in the same folder as the launcher."); + return; } // NOTE: we purposely put this in another method, as we need to ensure @@ -34,13 +32,9 @@ namespace Launcher { RunLauncher(); } - // put in separate function, because we don't want to load winforms assembly if possible - static void Message(string message) { MessageBox.Show(message, "Missing file"); } - static void RunLauncher() { - string logPath = Path.Combine(AppDirectory, "launcher.log"); AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler; - ErrorHandler.InstallHandler(logPath); + ErrorHandler.InstallHandler("launcher.log"); OpenTK.Configuration.SkipPerfCountersHack(); LauncherWindow window = new LauncherWindow(); window.Run(); diff --git a/Launcher2/Updater/Applier.cs b/Launcher2/Updater/Applier.cs index c9936de3d..ce190719d 100644 --- a/Launcher2/Updater/Applier.cs +++ b/Launcher2/Updater/Applier.cs @@ -27,16 +27,16 @@ namespace Launcher.Updater { ProcessStartInfo info = new ProcessStartInfo(); info.CreateNoWindow = false; info.UseShellExecute = true; - info.WorkingDirectory = Program.AppDirectory; + info.WorkingDirectory = Platform.AppDirectory; if (OpenTK.Configuration.RunningOnWindows) { - string path = Path.Combine(Program.AppDirectory, "update.bat"); - File.WriteAllText(path, Scripts.BatchFile); + Platform.WriteAllText("update.bat", Scripts.BatchFile); info.FileName = "cmd"; info.Arguments = "/C start cmd /C update.bat"; Process.Start(info); } else { - string path = Path.Combine(Program.AppDirectory, "update.sh"); - File.WriteAllText(path, Scripts.BashFile.Replace("\r\n", "\n")); + string path = Path.Combine(Platform.AppDirectory, "update.sh"); + Platform.WriteAllText("update.sh", Scripts.BashFile.Replace("\r\n", "\n")); + const int flags = 0x7;// read | write | executable int code = chmod(path, (flags << 6) | (flags << 3) | 4); if (code != 0) @@ -55,23 +55,20 @@ namespace Launcher.Updater { internal static extern int chmod(string path, int mode); static void MakeUpdatesFolder(byte[] zipData) { + Platform.DirectoryCreate("CS_Update"); using (MemoryStream stream = new MemoryStream(zipData)) { - ZipReader reader = new ZipReader(); - string path = Path.Combine(Program.AppDirectory, "CS_Update"); - Directory.CreateDirectory(path); - + ZipReader reader = new ZipReader(); reader.ProcessZipEntry = ProcessZipEntry; reader.Extract(stream); } } static void ProcessZipEntry(string filename, byte[] data, ZipEntry entry) { - string path = Path.Combine(Program.AppDirectory, "CS_Update"); - path = Path.Combine(path, Path.GetFileName(filename)); - File.WriteAllBytes(path, data); + string path = Path.Combine("CS_Update", Path.GetFileName(filename)); + Platform.WriteAllBytes(path, data); try { - File.SetLastWriteTimeUtc(path, PatchTime); + Platform.FileSetWriteTime(path, PatchTime); } catch (IOException ex) { ErrorHandler.LogError("I/O exception when trying to set modified time for: " + filename, ex); } catch (UnauthorizedAccessException ex) { diff --git a/Launcher2/Utils/Client.cs b/Launcher2/Utils/Client.cs index dafc1307d..5d2a41daf 100644 --- a/Launcher2/Utils/Client.cs +++ b/Launcher2/Utils/Client.cs @@ -28,15 +28,12 @@ namespace Launcher { return StartImpl(null, true, args, ref shouldExit); } - static bool StartImpl(ClientStartData data, bool classicubeSkins, - string args, ref bool shouldExit) { - string path = Path.Combine(Program.AppDirectory, "ClassicalSharp.exe"); - if (!File.Exists(path)) - return false; + static bool StartImpl(ClientStartData data, bool ccSkins, string args, ref bool shouldExit) { + if (!Platform.FileExists("ClassicalSharp.exe")) return false; - CheckSettings(data, classicubeSkins, out shouldExit); + CheckSettings(data, ccSkins, out shouldExit); try { - StartProcess(path, args); + StartProcess(args); } catch (Win32Exception ex) { if ((uint)ex.ErrorCode != 0x80004005) throw; // HRESULT when user clicks 'cancel' to 'are you sure you want to run ClassicalSharp.exe' @@ -46,7 +43,8 @@ namespace Launcher { return true; } - static void StartProcess(string path, string args) { + static void StartProcess(string args) { + string path = Path.Combine(Platform.AppDirectory, "ClassicalSharp.exe"); if (Configuration.RunningOnMono) { // We also need to handle the case of running Mono through wine if (Configuration.RunningOnWindows) { diff --git a/src/Client/Chat.c b/src/Client/Chat.c index 396979a3e..34a210509 100644 --- a/src/Client/Chat.c +++ b/src/Client/Chat.c @@ -80,7 +80,7 @@ void Chat_OpenLog(DateTime* now) { String_AppendConst(&path, ".log"); void* file; - ReturnCode code = Platform_FileOpen(&file, &path, false); + ReturnCode code = Platform_FileAppend(&file, &path); if (code != 0 && code != ReturnCode_FileShareViolation) { ErrorHandler_FailWithCode(code, "Chat - opening log file"); } diff --git a/src/Client/ErrorHandler.h b/src/Client/ErrorHandler.h index b936e77e1..05ccd1dcb 100644 --- a/src/Client/ErrorHandler.h +++ b/src/Client/ErrorHandler.h @@ -13,4 +13,5 @@ void ErrorHandler_Log(STRING_PURE String* msg); void ErrorHandler_Fail(const UInt8* raw_msg); void ErrorHandler_FailWithCode(ReturnCode returnCode, const UInt8* raw_msg); #define ErrorHandler_CheckOrFail(returnCode, raw_msg) if (returnCode != 0) { ErrorHandler_FailWithCode(returnCode, raw_msg); } +void ErrorHandler_ShowDialog(const UInt8* title, const UInt8* msg); #endif \ No newline at end of file diff --git a/src/Client/Menus.c b/src/Client/Menus.c index b907fb60f..3d74af9fc 100644 --- a/src/Client/Menus.c +++ b/src/Client/Menus.c @@ -1275,7 +1275,7 @@ void LoadLevelScreen_EntryClick(GuiElement* screenElem, GuiElement* w) { if (!Platform_FileExists(&path)) return; void* file; - ReturnCode code = Platform_FileOpen(&file, &path, true); + ReturnCode code = Platform_FileOpen(&file, &path); ErrorHandler_CheckOrFail(code, "Failed to open map file"); Stream stream; Stream_FromFile(&stream, file, &path); @@ -1504,7 +1504,7 @@ void ClassicHacksKeyBindingsScreen_ContextRecreated(void* obj) { KeyBindingsScreen_MakeWidgets(screen, -90, -40, 3, "Hacks controls", 260); } -Screen* ClassicHackKeyBindingsScreen_MakeInstance(void) { +Screen* ClassicHacksKeyBindingsScreen_MakeInstance(void) { static KeyBind binds[6] = { KeyBind_Speed, KeyBind_NoClip, KeyBind_HalfSpeed, KeyBind_Fly, KeyBind_FlyUp, KeyBind_FlyDown }; static const UInt8* descs[6] = { "Speed", "Noclip", "Half speed", "Fly", "Fly up", "Fly down" }; static ButtonWidget buttons[6]; diff --git a/src/Client/Options.c b/src/Client/Options.c index 094bf547e..e01869caa 100644 --- a/src/Client/Options.c +++ b/src/Client/Options.c @@ -141,7 +141,7 @@ void Options_Set(const UInt8* keyRaw, STRING_PURE String* value) { void Options_Load(void) { void* file = NULL; String path = String_FromConst("options.txt"); - ReturnCode result = Platform_FileOpen(&file, &path, true); + ReturnCode result = Platform_FileOpen(&file, &path); if (result == ReturnCode_FileNotFound) return; /* TODO: Should we just log failure to open? */ @@ -182,7 +182,7 @@ void Options_Load(void) { void Options_Save(void) { void* file = NULL; String path = String_FromConst("options.txt"); - ReturnCode result = Platform_FileOpen(&file, &path, true); + ReturnCode result = Platform_FileOpen(&file, &path); /* TODO: Should we just log failure to save? */ ErrorHandler_CheckOrFail(result, "Options - Saving"); diff --git a/src/Client/Platform.h b/src/Client/Platform.h index 9ed71fce4..16a61f1dd 100644 --- a/src/Client/Platform.h +++ b/src/Client/Platform.h @@ -31,7 +31,8 @@ typedef void Platform_EnumFilesCallback(STRING_PURE String* path, void* obj); ReturnCode Platform_EnumFiles(STRING_PURE String* path, void* obj, Platform_EnumFilesCallback callback); ReturnCode Platform_FileCreate(void** file, STRING_PURE String* path); -ReturnCode Platform_FileOpen(void** file, STRING_PURE String* path, bool readOnly); +ReturnCode Platform_FileOpen(void** file, STRING_PURE String* path); +ReturnCode Platform_FileAppend(void** file, STRING_PURE String* path); ReturnCode Platform_FileRead(void* file, UInt8* buffer, UInt32 count, UInt32* bytesRead); ReturnCode Platform_FileWrite(void* file, UInt8* buffer, UInt32 count, UInt32* bytesWritten); ReturnCode Platform_FileClose(void* file); diff --git a/src/Client/Program.c b/src/Client/Program.c index 78494fb42..cfa99d793 100644 --- a/src/Client/Program.c +++ b/src/Client/Program.c @@ -24,7 +24,7 @@ int main(int argc, char* argv[]) { /*void* file; String path = String_FromConstant("H:\\PortableApps\\GitPortable\\App\\Git\\ClassicalSharp\\output\\release\\texpacks\\skybox.png"); - ReturnCode openCode = Platform_FileOpen(&file, &path, true); + ReturnCode openCode = Platform_FileOpen(&file, &path); Stream fileStream; Stream_FromFile(&fileStream, file, &path); Bitmap bmp; @@ -61,7 +61,7 @@ int main(int argc, char* argv[]) { /*void* file; String path = String_FromConstant("H:\\PortableApps\\GitPortable\\App\\Git\\ClassicalSharp\\output\\release\\texpacks\\default.zip"); - ReturnCode openCode = Platform_FileOpen(&file, &path, true); + ReturnCode openCode = Platform_FileOpen(&file, &path); Stream fileStream; Stream_FromFile(&fileStream, file, &path); ZipState state; @@ -71,7 +71,7 @@ int main(int argc, char* argv[]) { void* file; String path = String_FromConst("H:\\PortableApps\\GitPortable\\App\\Git\\ClassicalSharp\\src\\x64\\Release\\canyon.lvl"); - ReturnCode openCode = Platform_FileOpen(&file, &path, true); + ReturnCode openCode = Platform_FileOpen(&file, &path); Stream fileStream; Stream_FromFile(&fileStream, file, &path); Lvl_Load(&fileStream); @@ -79,7 +79,7 @@ int main(int argc, char* argv[]) { /*void* file; String path = String_FromConstant("H:\\PortableApps\\GitPortable\\App\\Git\\\ClassicalSharp\\src\\Debug\\gunzip.c.gz"); - ReturnCode openCode = Platform_FileOpen(&file, &path, true); + ReturnCode openCode = Platform_FileOpen(&file, &path); Stream fileStream; Stream_FromFile(&fileStream, file, &path); diff --git a/src/Client/WinErrorHandler.c b/src/Client/WinErrorHandler.c index 86eece22d..0f2f8fc99 100644 --- a/src/Client/WinErrorHandler.c +++ b/src/Client/WinErrorHandler.c @@ -32,8 +32,7 @@ void ErrorHandler_Fail(const UInt8* raw_msg) { ErrorHandler_WriteLogBody(raw_msg); ErrorHandler_WriteLogEnd(); - HWND win = GetActiveWindow(); - MessageBoxA(win, logMsg.buffer, "We're sorry", 0); + ErrorHandler_ShowDialog("We're sorry", logMsg.buffer); ExitProcess(1); } @@ -45,7 +44,11 @@ void ErrorHandler_FailWithCode(ReturnCode code, const UInt8* raw_msg) { String_AppendConst(&logMsg, "\r\n"); ErrorHandler_WriteLogEnd(); - HWND win = GetActiveWindow(); /* TODO: It's probably wrong to use GetActiveWindow() here */ - MessageBoxA(win, logMsg.buffer, "We're sorry", 0); + ErrorHandler_ShowDialog("We're sorry", logMsg.buffer); ExitProcess(code); +} + +void ErrorHandler_ShowDialog(const UInt8* title, const UInt8* msg) { + HWND win = GetActiveWindow(); /* TODO: It's probably wrong to use GetActiveWindow() here */ + MessageBoxA(win, msg, title, 0); } \ No newline at end of file diff --git a/src/Client/WinPlatform.c b/src/Client/WinPlatform.c index 572c21e14..62fcdb1fc 100644 --- a/src/Client/WinPlatform.c +++ b/src/Client/WinPlatform.c @@ -151,23 +151,28 @@ ReturnCode Platform_EnumFiles(STRING_PURE String* path, void* obj, Platform_Enum } -ReturnCode Platform_FileOpen(void** file, STRING_PURE String* path, bool readOnly) { - UINT32 access = GENERIC_READ; - if (!readOnly) access |= GENERIC_WRITE; - HANDLE handle = CreateFileA(path->buffer, access, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); +ReturnCode Platform_FileOpen(void** file, STRING_PURE String* path) { + HANDLE handle = CreateFileA(path->buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); *file = (void*)handle; return handle != INVALID_HANDLE_VALUE ? 0 : GetLastError(); } ReturnCode Platform_FileCreate(void** file, STRING_PURE String* path) { - UINT32 access = GENERIC_READ | GENERIC_WRITE; - HANDLE handle = CreateFileA(path->buffer, access, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE handle = CreateFileA(path->buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); *file = (void*)handle; return handle != INVALID_HANDLE_VALUE ? 0 : GetLastError(); } +ReturnCode Platform_FileAppend(void** file, STRING_PURE String* path) { + HANDLE handle = CreateFileA(path->buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + *file = (void*)handle; + + if (handle == INVALID_HANDLE_VALUE) return GetLastError(); + return Platform_FileSeek(*file, 0, STREAM_SEEKFROM_END); +} + ReturnCode Platform_FileRead(void* file, UInt8* buffer, UInt32 count, UInt32* bytesRead) { BOOL success = ReadFile((HANDLE)file, buffer, count, bytesRead, NULL); return success ? 0 : GetLastError(); @@ -187,11 +192,11 @@ ReturnCode Platform_FileSeek(void* file, Int32 offset, Int32 seekType) { DWORD pos; switch (seekType) { case STREAM_SEEKFROM_BEGIN: - pos = SetFilePointer(file, offset, NULL, 0); break; + pos = SetFilePointer(file, offset, NULL, FILE_BEGIN); break; case STREAM_SEEKFROM_CURRENT: - pos = SetFilePointer(file, offset, NULL, 1); break; + pos = SetFilePointer(file, offset, NULL, FILE_CURRENT); break; case STREAM_SEEKFROM_END: - pos = SetFilePointer(file, offset, NULL, 2); break; + pos = SetFilePointer(file, offset, NULL, FILE_END); break; default: ErrorHandler_Fail("Invalid SeekType provided when seeking file"); }