diff --git a/TrueCraft.Client/Content/default-pack.png b/TrueCraft.Client/Content/default-pack.png new file mode 100644 index 0000000..cf893db Binary files /dev/null and b/TrueCraft.Client/Content/default-pack.png differ diff --git a/TrueCraft.Client/Content/default-pack.txt b/TrueCraft.Client/Content/default-pack.txt new file mode 100644 index 0000000..b90cfbc --- /dev/null +++ b/TrueCraft.Client/Content/default-pack.txt @@ -0,0 +1 @@ +No description available. \ No newline at end of file diff --git a/TrueCraft.Client/Rendering/Mesh.cs b/TrueCraft.Client/Rendering/Mesh.cs index 91a8109..43d8cd8 100644 --- a/TrueCraft.Client/Rendering/Mesh.cs +++ b/TrueCraft.Client/Rendering/Mesh.cs @@ -38,7 +38,7 @@ namespace TrueCraft.Client.Rendering lock (_syncLock) { _vertices = new VertexBuffer(_graphicsDevice, VertexPositionNormalTexture.VertexDeclaration, - value.Length, BufferUsage.WriteOnly); + (value.Length + 1), BufferUsage.WriteOnly); _vertices.SetData(value); } @@ -119,7 +119,7 @@ namespace TrueCraft.Client.Rendering _indices[index].Dispose(); _indices[index] = new IndexBuffer(_graphicsDevice, typeof(int), - indices.Length, BufferUsage.WriteOnly); + (indices.Length + 1), BufferUsage.WriteOnly); _indices[index].SetData(indices); } } diff --git a/TrueCraft.Client/Rendering/TextureMapper.cs b/TrueCraft.Client/Rendering/TextureMapper.cs index aac19de..4f2e162 100644 --- a/TrueCraft.Client/Rendering/TextureMapper.cs +++ b/TrueCraft.Client/Rendering/TextureMapper.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using TrueCraft.Core; +using Ionic.Zip; namespace TrueCraft.Client.Rendering { @@ -34,7 +35,7 @@ namespace TrueCraft.Client.Rendering /// /// /// - public TexturePack TexturePack { get; private set; } + private GraphicsDevice Device { get; set; } /// /// @@ -50,38 +51,54 @@ namespace TrueCraft.Client.Rendering /// /// /// - /// - public TextureMapper(GraphicsDevice graphicsDevice, TexturePack texturePack = null) + public TextureMapper(GraphicsDevice graphicsDevice) { if (graphicsDevice == null) throw new ArgumentException(); - TexturePack = texturePack; + Device = graphicsDevice; Customs = new Dictionary(); IsDisposed = false; - - if (TexturePack != null) - LoadTextures(graphicsDevice); } /// /// /// - /// - private void LoadTextures(GraphicsDevice graphicsDevice) + /// + /// + public void AddTexture(string key, Texture2D texture) { - foreach (var entry in TexturePack.Archive.Entries) + if (string.IsNullOrEmpty(key) || (texture == null)) + throw new ArgumentException(); + + if (Customs.ContainsKey(key)) + Customs[key] = texture; + else + Customs.Add(key, texture); + } + + /// + /// + /// + /// + public void AddTexturePack(TexturePack texturePack) + { + if (texturePack == null) + return; + + // Make sure to 'silence' errors loading custom texture packs; + // they're unimportant as we can just use default textures. + try { - // Make sure to 'silence' errors loading custom texture packs; - // they're unimportant as we can just use default textures. - try + var archive = new ZipFile(Path.Combine(TexturePack.TexturePackPath, texturePack.Name)); + foreach (var entry in archive.Entries) { var key = entry.FileName; using (var stream = entry.OpenReader()) - Customs.Add(key, Texture2D.FromStream(graphicsDevice, stream)); + AddTexture(key, Texture2D.FromStream(Device, stream)); } - catch { } } + catch { return; } } /// @@ -93,6 +110,9 @@ namespace TrueCraft.Client.Rendering { Texture2D result = null; TryGetTexture(key, out result); + if (result == null) + throw new InvalidOperationException(); + return result; } @@ -104,23 +124,19 @@ namespace TrueCraft.Client.Rendering /// public bool TryGetTexture(string key, out Texture2D texture) { - // -> Try to load from external texture pack - // -> Try to load from default texture pack - // -> Fail gracefully - if (string.IsNullOrEmpty(key)) throw new ArgumentException(); bool hasTexture = false; texture = null; - if (TexturePack != null) - { - Texture2D customTexture = null; - var inCustom = Customs.TryGetValue(key, out customTexture); - texture = (inCustom) ? customTexture : null; - hasTexture = inCustom; - } + // -> Try to load from custom textures + Texture2D customTexture = null; + var inCustom = Customs.TryGetValue(key, out customTexture); + texture = (inCustom) ? customTexture : null; + hasTexture = inCustom; + + // -> Try to load from default textures if (!hasTexture) { Texture2D defaultTexture = null; @@ -129,6 +145,7 @@ namespace TrueCraft.Client.Rendering hasTexture = inDefault; } + // -> Fail gracefully return hasTexture; } @@ -145,7 +162,7 @@ namespace TrueCraft.Client.Rendering Customs.Clear(); Customs = null; - TexturePack = null; + Device = null; IsDisposed = true; } } diff --git a/TrueCraft.Client/Rendering/TexturePackExtensions.cs b/TrueCraft.Client/Rendering/TexturePackExtensions.cs deleted file mode 100644 index 7fa81ea..0000000 --- a/TrueCraft.Client/Rendering/TexturePackExtensions.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.Xna.Framework.Graphics; -using System; -using TrueCraft.Core; -using Ionic.Zip; - -namespace TrueCraft.Client.Rendering -{ - public static class TexturePackExtensions - { - /// - /// - /// - /// - /// - /// - public static Texture2D GetTexture(this TexturePack instance, GraphicsDevice graphicsDevice, string entryName) - { - ZipEntry entry = null; - foreach (var item in instance.Archive.Entries) - { - if (item.FileName == entryName) - { - entry = item; - break; - } - } - - if (entry == null) - return null; - - Texture2D texture = null; - using (var reader = entry.OpenReader()) - texture = Texture2D.FromStream(graphicsDevice, reader); - return texture; - } - } -} diff --git a/TrueCraft.Client/TrueCraft.Client.csproj b/TrueCraft.Client/TrueCraft.Client.csproj index 1c043c6..b37fc48 100644 --- a/TrueCraft.Client/TrueCraft.Client.csproj +++ b/TrueCraft.Client/TrueCraft.Client.csproj @@ -68,8 +68,6 @@ ..\lib\Ionic.Zip.Reduced.dll - - @@ -89,7 +87,6 @@ - @@ -147,6 +144,12 @@ + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/TrueCraft.Client/TrueCraftGame.cs b/TrueCraft.Client/TrueCraftGame.cs index ad60449..b747325 100644 --- a/TrueCraft.Client/TrueCraftGame.cs +++ b/TrueCraft.Client/TrueCraftGame.cs @@ -42,7 +42,6 @@ namespace TrueCraft.Client private MouseComponent MouseComponent { get; set; } private GameTime GameTime { get; set; } private Microsoft.Xna.Framework.Vector3 Delta { get; set; } - private TexturePack TexturePack { get; set; } private TextureMapper TextureMapper { get; set; } private BasicEffect OpaqueEffect, TransparentEffect; @@ -52,9 +51,9 @@ namespace TrueCraft.Client Window.Title = "TrueCraft"; Content.RootDirectory = "Content"; Graphics = new GraphicsDeviceManager(this); - Graphics.IsFullScreen = false; - Graphics.PreferredBackBufferWidth = 1280; - Graphics.PreferredBackBufferHeight = 720; + Graphics.IsFullScreen = UserSettings.Local.IsFullscreen; + Graphics.PreferredBackBufferWidth = UserSettings.Local.WindowResolution.Width; + Graphics.PreferredBackBufferHeight = UserSettings.Local.WindowResolution.Height; Client = client; EndPoint = endPoint; NextPhysicsUpdate = DateTime.MinValue; @@ -131,9 +130,9 @@ namespace TrueCraft.Client TextureMapper.LoadDefaults(GraphicsDevice); // Load any custom textures if needed. - TexturePack = (UserSettings.Local.SelectedTexturePack != TexturePack.DefaultID) ? - new TexturePack(UserSettings.Local.SelectedTexturePack) : null; - TextureMapper = new TextureMapper(GraphicsDevice, TexturePack); + TextureMapper = new TextureMapper(GraphicsDevice); + if (UserSettings.Local.SelectedTexturePack != TexturePack.Default.Name) + TextureMapper.AddTexturePack(TexturePack.FromArchive(Path.Combine(TexturePack.TexturePackPath, UserSettings.Local.SelectedTexturePack))); DejaVu = new FontRenderer( new Font(Content, "Fonts/DejaVu", FontStyle.Regular), diff --git a/TrueCraft.Core/TexturePack.cs b/TrueCraft.Core/TexturePack.cs index 614fbf3..e9c735a 100644 --- a/TrueCraft.Core/TexturePack.cs +++ b/TrueCraft.Core/TexturePack.cs @@ -12,7 +12,18 @@ namespace TrueCraft.Core /// /// /// - public const string DefaultID = "#Default"; + public static readonly TexturePack Unknown = new TexturePack( + "?", + File.OpenRead(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content/default-pack.png")), + File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content/default-pack.txt"))); + + /// + /// + /// + public static readonly TexturePack Default = new TexturePack( + "Default", + File.OpenRead(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content/pack.png")), + File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content/pack.txt"))); /// /// @@ -21,7 +32,7 @@ namespace TrueCraft.Core { get { - return System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".truecraft/texturepacks/"); } } @@ -29,7 +40,47 @@ namespace TrueCraft.Core /// /// /// - public string Path { get; private set; } + /// + public static TexturePack FromArchive(string path) + { + if (string.IsNullOrEmpty(path)) + throw new ArgumentException(); + + string description = Unknown.Description; + Stream image = Unknown.Image; + try + { + var archive = new ZipFile(path); + foreach (var entry in archive.Entries) + { + if (entry.FileName == "pack.txt") + { + using (var stream = entry.OpenReader()) + { + using (var reader = new StreamReader(stream)) + description = reader.ReadToEnd().TrimEnd('\n', '\r', ' '); + } + } + else if (entry.FileName == "pack.png") + { + using (var stream = entry.OpenReader()) + { + var buffer = new byte[entry.UncompressedSize]; + stream.Read(buffer, 0, buffer.Length); + image = new MemoryStream((int)entry.UncompressedSize); + image.Write(buffer, 0, buffer.Length); + + // Fixes 'GLib.GException: Unrecognized image file format' on Linux. + image.Seek(0, SeekOrigin.Begin); + } + } + } + } + catch { return null; } + + string name = new FileInfo(path).Name; + return new TexturePack(name, image, description); + } /// /// @@ -39,7 +90,7 @@ namespace TrueCraft.Core /// /// /// - public ZipFile Archive { get; private set; } + public Stream Image { get; private set; } /// /// @@ -49,88 +100,14 @@ namespace TrueCraft.Core /// /// /// - public MemoryStream Image { get; private set; } - - /// - /// - /// - public bool IsCorrupt { get; private set; } - - /// - /// - /// - public TexturePack() + /// + /// + /// + public TexturePack(string name, Stream image, string description) { - Path = TexturePack.DefaultID; - Archive = new ZipFile(); - Name = "Default"; - } - - /// - /// - /// - /// - public TexturePack(string path) - { - if (string.IsNullOrEmpty(path) || !File.Exists(path)) - MakeDefault(); - - Path = path; - var fileInfo = new FileInfo(path); // A bit weird, but it works. - Name = fileInfo.Name; - try { Archive = new ZipFile(path); } - catch { IsCorrupt = true; } - - GetPackInfo(); - } - - /// - /// - /// - private void MakeDefault() - { - Path = TexturePack.DefaultID; - Archive = new ZipFile(); - Name = "Default"; - Image = null; - Description = null; - } - - /// - /// - /// - /// - private void GetPackInfo() - { - try - { - foreach (var entry in Archive.Entries) - { - if (entry.FileName == "pack.txt") - { - using (var stream = entry.OpenReader()) - { - using (var reader = new StreamReader(stream)) - Description = reader.ReadToEnd(); - } - } - else if (entry.FileName == "pack.png") - { - using (var stream = entry.OpenReader()) - { - // Better way to do this? - var buffer = new byte[entry.UncompressedSize]; - stream.Read(buffer, 0, buffer.Length); - Image = new MemoryStream((int)entry.UncompressedSize); - Image.Write(buffer, 0, buffer.Length); - - // Fixes 'GLib.GException: Unrecognized image file format' on Linux. - Image.Seek(0, SeekOrigin.Begin); - } - } - } - } - catch { IsCorrupt = true; } + Name = name; + Image = image; + Description = description; } } } diff --git a/TrueCraft.Core/UserSettings.cs b/TrueCraft.Core/UserSettings.cs index 86a9543..8ead5d9 100644 --- a/TrueCraft.Core/UserSettings.cs +++ b/TrueCraft.Core/UserSettings.cs @@ -23,6 +23,8 @@ namespace TrueCraft.Core public string LastIP { get; set; } public string SelectedTexturePack { get; set; } public FavoriteServer[] FavoriteServers { get; set; } + public bool IsFullscreen { get; set; } + public WindowResolution WindowResolution { get; set; } public UserSettings() { @@ -30,8 +32,14 @@ namespace TrueCraft.Core Username = ""; Password = ""; LastIP = ""; - SelectedTexturePack = TexturePack.DefaultID; + SelectedTexturePack = TexturePack.Default.Name; FavoriteServers = new FavoriteServer[0]; + IsFullscreen = false; + WindowResolution = new WindowResolution() + { + Width = 1280, + Height = 720 + }; } public void Load() @@ -52,4 +60,40 @@ namespace TrueCraft.Core public string Name { get; set; } public string Address { get; set; } } + + public class WindowResolution + { + public static readonly WindowResolution[] Defaults = + new WindowResolution[] + { + // (from Wikipedia/other) + WindowResolution.FromString("800 x 600"), // SVGA + WindowResolution.FromString("960 x 640"), // DVGA + WindowResolution.FromString("1024 x 600"), // WSVGA + WindowResolution.FromString("1024 x 768"), // XGA + WindowResolution.FromString("1280 x 1024"), // SXGA + WindowResolution.FromString("1600 x 1200"), // UXGA + WindowResolution.FromString("1920 x 1080"), // big + WindowResolution.FromString("1920 x 1200"), // really big + WindowResolution.FromString("4096 x 2160"), // huge + }; + + public static WindowResolution FromString(string str) + { + var tmp = str.Split('x'); + return new WindowResolution() + { + Width = int.Parse(tmp[0].Trim()), + Height = int.Parse(tmp[1].Trim()) + }; + } + + public int Width { get; set; } + public int Height { get; set; } + + public override string ToString() + { + return string.Format("{0} x {1}", Width, Height); + } + } } \ No newline at end of file diff --git a/TrueCraft.Launcher/Views/OptionView.cs b/TrueCraft.Launcher/Views/OptionView.cs index 5442775..92d13b0 100644 --- a/TrueCraft.Launcher/Views/OptionView.cs +++ b/TrueCraft.Launcher/Views/OptionView.cs @@ -11,16 +11,14 @@ namespace TrueCraft.Launcher.Views public class OptionView : VBox { public LauncherWindow Window { get; set; } - public Image DefaultImage { get; set; } - public string DefaultDescription { get; set; } - public Image UnknownImage { get; set; } - public string UnknownDescription { get; set; } public Label OptionLabel { get; set; } + public Label ResolutionLabel { get; set; } + public ComboBox ResolutionComboBox { get; set; } + public CheckBox FullscreenCheckBox { get; set; } public Label TexturePackLabel { get; set; } public DataField TexturePackImageField { get; set; } - public DataField TexturePackNameField { get; set; } - public DataField TexturePackDescField { get; set; } + public DataField TexturePackTextField { get; set; } public ListStore TexturePackStore { get; set; } public ListView TexturePackListView { get; set; } public Button OpenFolderButton { get; set; } @@ -31,15 +29,6 @@ namespace TrueCraft.Launcher.Views public OptionView(LauncherWindow window) { - DefaultImage = Image.FromFile( - Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content/pack.png")); - DefaultDescription = File.ReadAllText( - Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content/pack.txt")); - UnknownImage = Image.FromFile( - Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content/default-pack.png")); - UnknownDescription = File.ReadAllText( - Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content/default-pack.txt")); - _texturePacks = new List(); _lastTexturePack = null; @@ -51,11 +40,40 @@ namespace TrueCraft.Launcher.Views Font = Font.WithSize(16), TextAlignment = Alignment.Center }; + + ResolutionLabel = new Label("Select a resolution..."); + ResolutionComboBox = new ComboBox(); + + int resolutionIndex = -1; + for (int i = 0; i < WindowResolution.Defaults.Length; i++) + { + ResolutionComboBox.Items.Add(WindowResolution.Defaults[i].ToString()); + + if (resolutionIndex == -1) + { + resolutionIndex = + ((WindowResolution.Defaults[i].Width == UserSettings.Local.WindowResolution.Width) && + (WindowResolution.Defaults[i].Height == UserSettings.Local.WindowResolution.Height)) ? i : -1; + } + } + + if (resolutionIndex == -1) + { + ResolutionComboBox.Items.Add(UserSettings.Local.WindowResolution.ToString()); + resolutionIndex = ResolutionComboBox.Items.Count - 1; + } + + ResolutionComboBox.SelectedIndex = resolutionIndex; + FullscreenCheckBox = new CheckBox() + { + Label = "Fullscreen mode", + State = (UserSettings.Local.IsFullscreen) ? CheckBoxState.On : CheckBoxState.Off + }; + TexturePackLabel = new Label("Select a texture pack..."); TexturePackImageField = new DataField(); - TexturePackNameField = new DataField(); - TexturePackDescField = new DataField(); - TexturePackStore = new ListStore(TexturePackImageField, TexturePackNameField, TexturePackDescField); + TexturePackTextField = new DataField(); + TexturePackStore = new ListStore(TexturePackImageField, TexturePackTextField); TexturePackListView = new ListView { MinHeight = 200, @@ -67,14 +85,27 @@ namespace TrueCraft.Launcher.Views BackButton = new Button("Back"); TexturePackListView.Columns.Add("Image", TexturePackImageField); - TexturePackListView.Columns.Add("Text", TexturePackNameField, TexturePackDescField); + TexturePackListView.Columns.Add("Text", TexturePackTextField); + + ResolutionComboBox.SelectionChanged += (sender, e) => + { + UserSettings.Local.WindowResolution = + WindowResolution.FromString(ResolutionComboBox.SelectedText); + UserSettings.Local.Save(); + }; + + FullscreenCheckBox.Clicked += (sender, e) => + { + UserSettings.Local.IsFullscreen = !UserSettings.Local.IsFullscreen; + UserSettings.Local.Save(); + }; TexturePackListView.SelectionChanged += (sender, e) => { var texturePack = _texturePacks[TexturePackListView.SelectedRow]; if (_lastTexturePack != texturePack) { - UserSettings.Local.SelectedTexturePack = texturePack.Path; + UserSettings.Local.SelectedTexturePack = texturePack.Name; UserSettings.Local.Save(); } }; @@ -94,6 +125,9 @@ namespace TrueCraft.Launcher.Views LoadTexturePacks(); this.PackStart(OptionLabel); + this.PackStart(ResolutionLabel); + this.PackStart(ResolutionComboBox); + this.PackStart(FullscreenCheckBox); this.PackStart(TexturePackLabel); this.PackStart(TexturePackListView); this.PackStart(OpenFolderButton); @@ -103,9 +137,8 @@ namespace TrueCraft.Launcher.Views private void LoadTexturePacks() { // We load the default texture pack specially. - var defaultPack = new TexturePack(); - _texturePacks.Add(defaultPack); - AddTexturePackRow(defaultPack); + _texturePacks.Add(TexturePack.Default); + AddTexturePackRow(TexturePack.Default); // Make sure to create the texture pack directory if there is none. if (!Directory.Exists(TexturePack.TexturePackPath)) @@ -117,8 +150,8 @@ namespace TrueCraft.Launcher.Views if (!zip.EndsWith(".zip")) continue; - var texturePack = new TexturePack(zip); - if (!texturePack.IsCorrupt) + var texturePack = TexturePack.FromArchive(zip); + if (texturePack != null) { _texturePacks.Add(texturePack); AddTexturePackRow(texturePack); @@ -129,19 +162,9 @@ namespace TrueCraft.Launcher.Views private void AddTexturePackRow(TexturePack pack) { var row = TexturePackStore.AddRow(); - var isDefault = (pack.Path == TexturePack.DefaultID); - if (isDefault) - { - TexturePackStore.SetValue(row, TexturePackImageField, DefaultImage.WithSize(IconSize.Medium)); - TexturePackStore.SetValue(row, TexturePackNameField, pack.Name); - TexturePackStore.SetValue(row, TexturePackDescField, DefaultDescription); - } - else - { - TexturePackStore.SetValue(row, TexturePackImageField, (pack.Image == null) ? UnknownImage.WithSize(IconSize.Medium) : Image.FromStream(pack.Image).WithSize(IconSize.Medium)); - TexturePackStore.SetValue(row, TexturePackNameField, pack.Name); - TexturePackStore.SetValue(row, TexturePackDescField, pack.Description ?? UnknownDescription); - } + + TexturePackStore.SetValue(row, TexturePackImageField, Image.FromStream(pack.Image).WithSize(IconSize.Medium)); + TexturePackStore.SetValue(row, TexturePackTextField, pack.Name + "\r\n" + pack.Description); } } }