diff --git a/PCK-Studio/Extensions/ColorExtensions.cs b/PCK-Studio/Extensions/ColorExtensions.cs index 3ff94a3d..958c6611 100644 --- a/PCK-Studio/Extensions/ColorExtensions.cs +++ b/PCK-Studio/Extensions/ColorExtensions.cs @@ -15,6 +15,11 @@ internal static Vector4 Normalize(this Color color) return new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f); } + internal static int ToBGR(this Color color) + { + return color.B << 16 | color.G << 8 | color.R; + } + internal static byte BlendValues(byte source, byte overlay, BlendMode blendType) { return (byte)MathExtensions.Clamp(BlendValues(source / 255f, overlay / 255f, blendType) * 255, 0, 255); diff --git a/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs b/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs index 78ef3d85..5ffd1b2f 100644 --- a/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs +++ b/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs @@ -17,6 +17,7 @@ **/ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; @@ -39,28 +40,21 @@ namespace PckStudio.Forms.Editor { internal partial class TextureAtlasEditor : MetroForm { - private Image _workingTexture; - public Image FinalTexture - { - get - { - if (DialogResult != DialogResult.OK) - return null; - return _workingTexture; - } - } + private Image _atlasTexture; + public Image FinalTexture => DialogResult == DialogResult.OK ? _atlasTexture : null; private readonly PckFile _pckFile; private ColorContainer _colourTable; - private readonly Size _areaSize; + private readonly Size _tileAreaSize; private readonly int _rowCount; private readonly int _columnCount; - private readonly ResourceLocation _atlasType; + private readonly ResourceLocation _resourceLocation; private readonly List _tiles; private AtlasTile _selectedTile; // the "parent" tile for tiles that share name; i.e. parts of water_flow private AtlasTile dataTile; + private sealed class AtlasTile { internal readonly int Index; @@ -82,11 +76,11 @@ private int SelectedIndex set { if (value < 0) { - value = _tiles.Count + value; + value += _tiles.Count; } else if (value >= _tiles.Count) { - value = value - _tiles.Count; + value -= _tiles.Count; } SetImageDisplayed(value); } @@ -94,19 +88,28 @@ private int SelectedIndex private const ImageLayoutDirection _imageLayout = ImageLayoutDirection.Horizontal; + private readonly GraphicsConfig _graphicsConfig = new GraphicsConfig() + { + InterpolationMode = InterpolationMode.NearestNeighbor, + PixelOffsetMode = PixelOffsetMode.HighQuality + }; + public TextureAtlasEditor(PckFile pckFile, ResourceLocation resourceLocation, Image atlas) { InitializeComponent(); - AcquireColorTable(pckFile); - - _workingTexture = atlas; + if (!AcquireColorTable(pckFile)) + { + MessageBox.Show("Failed to acquire color information", "Acquire failure", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1); + return; + } - _areaSize = resourceLocation.GetTileArea(atlas.Size); + _atlasTexture = atlas; + _tileAreaSize = resourceLocation.GetTileArea(atlas.Size); _pckFile = pckFile; - _rowCount = atlas.Width / _areaSize.Width; - _columnCount = atlas.Height / _areaSize.Height; - _atlasType = resourceLocation; + _rowCount = atlas.Width / _tileAreaSize.Width; + _columnCount = atlas.Height / _tileAreaSize.Height; + _resourceLocation = resourceLocation; var tileInfos = resourceLocation.Category switch { ResourceCategory.BlockAtlas => Tiles.BlockTileInfos, @@ -122,50 +125,45 @@ public TextureAtlasEditor(PckFile pckFile, ResourceLocation resourceLocation, Im _ => null, }; - originalPictureBox.Image = atlas.GetArea(new Rectangle(0, 0, atlas.Width, atlas.Height)); - - var images = atlas.Split(_areaSize, _imageLayout); - - var tiles = images.enumerate().Select( - p => new AtlasTile( - p.index, - - GetAtlasArea( - p.index, - tileInfos.IndexInRange(p.index) - ? tileInfos[p.index].Width : 1, - tileInfos.IndexInRange(p.index) - ? tileInfos[p.index].Height : 1, - _rowCount, - _columnCount, - _areaSize, - _imageLayout), - - tileInfos.IndexInRange(p.index) - ? tileInfos[p.index] : null, - - // get texture for tiles that are not 1x1 tiles - tileInfos.IndexInRange(p.index) - ? atlas.GetArea( - new Rectangle( - GetSelectedPoint(p.index, _rowCount, _columnCount, _imageLayout).X * _areaSize.Width, - GetSelectedPoint(p.index, _rowCount, _columnCount, _imageLayout).Y * _areaSize.Height, - tileInfos[p.index].Width * _areaSize.Width, - tileInfos[p.index].Height * _areaSize.Height)) - : p.value) - ); - _tiles = new List(tiles); + originalPictureBox.Image = new Bitmap(atlas); + + var images = atlas.Split(_tileAreaSize, _imageLayout); + + AtlasTile MakeTile((int index, Image value) p) + { + int i = p.index; + JsonTileInfo tileInfo = tileInfos.IndexInRange(i) ? tileInfos[i] : null; + + Rectangle atlasArea = GetAtlasArea(i, tileInfo?.TileWidth ?? 1, tileInfo?.TileHeight ?? 1, _rowCount, _columnCount, _tileAreaSize, _imageLayout); + + // get texture for tiles that are not 1x1 tiles + Point selectedPoint = GetSelectedPoint(i, _rowCount, _columnCount, _imageLayout); + + var textureLocation = new Point(selectedPoint.X * _tileAreaSize.Width, selectedPoint.Y * _tileAreaSize.Height); + var textureSize = new Size(tileInfos[i].TileWidth * _tileAreaSize.Width, tileInfos[i].TileHeight * _tileAreaSize.Height); + var textureArea = new Rectangle(textureLocation, textureSize); + + Image texture = tileInfos.IndexInRange(i) ? atlas.GetArea(textureArea) : p.value; + return new AtlasTile(i, atlasArea, tileInfo, texture); + } + + _tiles = new List(images.enumerate().Select(MakeTile)); SelectedIndex = 0; - bool isParticles = _atlasType.Category == ResourceCategory.ParticleAtlas; + animationButton.Enabled = + _resourceLocation.Category == ResourceCategory.BlockAtlas || + _resourceLocation.Category == ResourceCategory.ItemAtlas; // this is directly based on Java's source code for handling enchanted hits // the particle is assigned a random grayscale color between roughly 154 and 230 // since critical hit is the only particle with this distinction, we just need to check the atlas type - colorSlider.Maximum = isParticles ? 230 : 255; - colorSlider.Minimum = isParticles ? 154 : 0; - colorSlider.Value = isParticles ? colorSlider.Maximum : colorSlider.Minimum; + if (_resourceLocation.Category == ResourceCategory.ParticleAtlas) + { + colorSlider.Minimum = 154; + colorSlider.Maximum = 230; + colorSlider.Value = colorSlider.Maximum; + } } private bool AcquireColorTable(PckFile pckFile) @@ -184,23 +182,14 @@ private bool AcquireColorTable(PckFile pckFile) private void UpdateAtlasDisplay() { - var graphicsConfig = new GraphicsConfig() - { - InterpolationMode = selectTilePictureBox.InterpolationMode, - PixelOffsetMode = PixelOffsetMode.HighQuality - }; using (var g = Graphics.FromImage(originalPictureBox.Image)) { - g.ApplyConfig(graphicsConfig); + g.ApplyConfig(_graphicsConfig); g.Clear(Color.Transparent); - g.DrawImage(_workingTexture, 0, 0, _workingTexture.Width, _workingTexture.Height); - - SolidBrush brush = new SolidBrush(Color.FromArgb(127, 255, 255, 255)); - - var rect = new Rectangle(_selectedTile.Area.X, _selectedTile.Area.Y, - _areaSize.Width, _areaSize.Height); + g.DrawImage(_atlasTexture, 0, 0, _atlasTexture.Width, _atlasTexture.Height); - g.FillRectangle(brush, rect); + SolidBrush brush = new SolidBrush(Color.FromArgb(127, Color.White)); + g.FillRectangle(brush, _selectedTile.Area); } originalPictureBox.Invalidate(); @@ -214,9 +203,11 @@ private void SetImageDisplayed(int index) colorSlider.Visible = false; colorSliderLabel.Visible = false; variantComboBox.Visible = false; - variantComboBox.Items.Clear(); + variantComboBox.SelectedItem = null; variantComboBox.Enabled = false; + variantComboBox.Items.Clear(); + clearColorButton.Enabled = false; if (selectTilePictureBox.IsPlaying) selectTilePictureBox.Stop(); @@ -226,33 +217,34 @@ private void SetImageDisplayed(int index) if (_tiles is null || !_tiles.IndexInRange(index) || (_selectedTile = _tiles[index]) is null) return; - dataTile = _selectedTile; - UpdateAtlasDisplay(); + dataTile = _selectedTile; if (string.IsNullOrEmpty(dataTile.Tile.DisplayName) && !string.IsNullOrEmpty(dataTile.Tile.InternalName)) { dataTile = _tiles.Find(t => t.Tile.InternalName == _selectedTile.Tile.InternalName); } selectTilePictureBox.Image = dataTile.Texture; - tileNameLabel.Text = $"{dataTile.Tile.DisplayName}"; - internalTileNameLabel.Text = $"{dataTile.Tile.InternalName}"; selectTilePictureBox.BlendColor = GetBlendColor(); selectTilePictureBox.UseBlendColor = applyColorMaskToolStripMenuItem.Checked; - if (animationButton.Enabled = _atlasType.Category == ResourceCategory.BlockAtlas || _atlasType.Category == ResourceCategory.ItemAtlas) + tileNameLabel.Text = $"{dataTile.Tile.DisplayName}"; + internalTileNameLabel.Text = $"{dataTile.Tile.InternalName}"; + + if (animationButton.Enabled) { PckAsset animationAsset; + ResourceCategory animationResourceCategory = _resourceLocation.Category == ResourceCategory.ItemAtlas ? ResourceCategory.ItemAnimation : ResourceCategory.BlockAnimation; + string animationAssetPath = $"{ResourceLocation.GetPathFromCategory(animationResourceCategory)}/{dataTile.Tile.InternalName}"; bool hasAnimation = - _pckFile.TryGetValue($"res/textures/{_atlasType}/{dataTile.Tile.InternalName}.png", PckAssetType.TextureFile, out animationAsset) || - _pckFile.TryGetValue($"res/textures/{_atlasType}/{dataTile.Tile.InternalName}.tga", PckAssetType.TextureFile, out animationAsset); + _pckFile.TryGetValue($"{animationAssetPath}.png", PckAssetType.TextureFile, out animationAsset) || + _pckFile.TryGetValue($"{animationAssetPath}.tga", PckAssetType.TextureFile, out animationAsset); animationButton.Text = hasAnimation ? "Edit Animation" : "Create Animation"; - if (playAnimationsToolStripMenuItem.Checked && - hasAnimation && - animationAsset.Size > 0) + // asset size check dont have to be done here the deserializer handles it. -Miku + if (playAnimationsToolStripMenuItem.Checked && hasAnimation) { var animation = animationAsset.GetDeserializedData(AnimationDeserializer.DefaultDeserializer); selectTilePictureBox.Image = animation.CreateAnimationImage(); @@ -260,27 +252,25 @@ private void SetImageDisplayed(int index) } } - if (setColorButton.Enabled = clearColorButton.Enabled = dataTile.Tile.HasColourEntry) - { - setColorButton.Enabled = clearColorButton.Enabled = dataTile.Tile.ColourEntry.HasCustomColour; - clearColorButton.Enabled = false; - - variantComboBox.Enabled = variantComboBox.Visible = dataTile.Tile.ColourEntry.Variants.Length > 1; + setColorButton.Enabled = dataTile.Tile.AllowCustomColour; - if (dataTile.Tile.ColourEntry.IsWaterColour && _colourTable.WaterColors.Count > 0) + variantComboBox.Enabled = variantComboBox.Visible = dataTile.Tile.HasColourEntry && dataTile.Tile.ColourEntry?.Variants?.Length > 1; + if (variantComboBox.Enabled) + { + if (dataTile.Tile.ColourEntry.IsWaterColour) { - foreach (var col in _colourTable.WaterColors) + foreach (ColorContainer.WaterColor col in _colourTable.WaterColors) { if(!variantComboBox.Items.Contains(col.Name)) variantComboBox.Items.Add(col.Name); } - - dataTile.Tile.ColourEntry.DefaultName = _colourTable.WaterColors[0].Name; } + // TODO: only add variants that are available in the color table variantComboBox.Items.AddRange(dataTile.Tile.ColourEntry.Variants); - - variantComboBox.SelectedItem = dataTile.Tile.ColourEntry.DefaultName; + + if (variantComboBox.Items.Count > 0) + variantComboBox.SelectedIndex = 0; } } @@ -367,11 +357,11 @@ private static int GetSelectedIndex(int x, int y, int rowCount, int columnCount, }; } - private static Rectangle GetAtlasArea(int index, int width, int height, int rowCount, int columnCount, Size size, ImageLayoutDirection imageLayout) + private static Rectangle GetAtlasArea(int index, int tileWidth, int tileHeight, int rowCount, int columnCount, Size size, ImageLayoutDirection imageLayout) { var p = GetSelectedPoint(index, rowCount, columnCount, imageLayout); var ap = new Point(p.X * size.Width, p.Y * size.Height); - return new Rectangle(ap, new Size(size.Width * width, size.Height * height)); + return new Rectangle(ap, new Size(size.Width * tileWidth, size.Height * tileHeight)); } private static Point GetSelectedPoint(int index, int rowCount, int columnCount, ImageLayoutDirection imageLayout) @@ -384,28 +374,19 @@ private static Point GetSelectedPoint(int index, int rowCount, int columnCount, private void SetTile(Image texture) { - var graphicsConfig = new GraphicsConfig() - { - InterpolationMode = selectTilePictureBox.InterpolationMode, - PixelOffsetMode = PixelOffsetMode.HighQuality - }; - if (texture.Size != _areaSize) - texture = texture.Resize(_areaSize, graphicsConfig); - using (var g = Graphics.FromImage(_workingTexture)) + if (texture.Size != _tileAreaSize) + texture = texture.Resize(_tileAreaSize, _graphicsConfig); + + using (var g = Graphics.FromImage(_atlasTexture)) { - g.ApplyConfig(graphicsConfig); + g.ApplyConfig(_graphicsConfig); g.Fill(dataTile.Area, Color.Transparent); g.DrawImage(texture, dataTile.Area); } - var _finalTexture = _workingTexture.GetArea(new Rectangle(dataTile.Area.X, dataTile.Area.Y, dataTile.Area.Width, dataTile.Area.Height)); - - if(_selectedTile != dataTile) - _tiles[dataTile.Index] = new AtlasTile(dataTile.Index, dataTile.Area, dataTile.Tile, _finalTexture); - else - _tiles[_selectedTile.Index] = new AtlasTile(_selectedTile.Index, _selectedTile.Area, _selectedTile.Tile, _finalTexture); - selectTilePictureBox.Image = _finalTexture; - + var tile = _selectedTile != dataTile ? dataTile : _selectedTile; + _tiles[tile.Index] = new AtlasTile(tile.Index, tile.Area, tile.Tile, texture); + selectTilePictureBox.Image = texture; UpdateAtlasDisplay(); } @@ -420,22 +401,24 @@ private Color GetBlendColor() return Color.White; } - private Color HandleSpecialTiles(string colorKey) + private Color GetSpecificBlendColor(string colorKey) { colorSlider.Visible = colorSliderLabel.Visible = true; // Simply, Experience orbs red value is just sliding between 255 and 0 - if (colorKey == "experience_orb") return Color.FromArgb(colorSlider.Value, 255, 0); + if (colorKey == "experience_orb") + return Color.FromArgb(colorSlider.Value, 255, 0); - //similar story for critical hits, but for all values + // Similar story for critical hits, but for all values var final_color = Color.FromArgb(colorSlider.Value, colorSlider.Value, colorSlider.Value); - // enchanted hits are modified critical hit particles + // Enchanted hits are modified critical hit particles if (dataTile.Tile.InternalName == "enchanted_hit") - // this is directly based on Java's source code for handling enchanted hits + { + // This is directly based on Java's source code for handling enchanted hits // it just multiplies the red by 0.3 and green by .8 of the color assigned to the critical hit particle final_color = Color.FromArgb((int)(final_color.R * 0.3f), (int)(final_color.R * 0.8f), final_color.B); - + } return final_color; } @@ -443,11 +426,9 @@ private Color FindBlendColorByKey(string colorKey) { // The following tiles are hardcoded within a range and do not have color table entries if (colorKey == "experience_orb" || colorKey == "critical_hit") - return HandleSpecialTiles(colorKey); + return GetSpecificBlendColor(colorKey); - if (_colourTable is not null && - dataTile.Tile.HasColourEntry && - dataTile.Tile.ColourEntry is not null) + if (dataTile.Tile.HasColourEntry && dataTile.Tile.ColourEntry is not null) { // basic way to check for classic water colors if(!dataTile.Tile.ColourEntry.IsWaterColour || colorKey.StartsWith("Water_")) @@ -463,6 +444,7 @@ private Color FindBlendColorByKey(string colorKey) } } + Debug.WriteLine("Could not find: " + colorKey); return Color.White; } @@ -500,8 +482,8 @@ private void originalPictureBox_MouseClick(object sender, MouseEventArgs e) int index = GetSelectedImageIndex( originalPictureBox.Size, - _workingTexture.Size, - _areaSize, + _atlasTexture.Size, + _tileAreaSize, e.Location, originalPictureBox.SizeMode, _imageLayout); @@ -516,7 +498,7 @@ private void replaceButton_Click(object sender, EventArgs e) { OpenFileDialog fileDialog = new OpenFileDialog() { - Filter = "PNG Image|*.png", + Filter = "Tile Texture(*.png)|*.png", Title = "Select Texture" }; @@ -534,22 +516,19 @@ private void saveToolStripMenuItem_Click(object sender, EventArgs e) private void animationButton_Click(object sender, EventArgs e) { - var file = _pckFile.GetOrCreate( - $"res/textures/{_atlasType}/{_selectedTile.Tile.InternalName}.png", - PckAssetType.TextureFile - ); + ResourceCategory animationResourceCategory = _resourceLocation.Category == ResourceCategory.ItemAtlas ? ResourceCategory.ItemAnimation : ResourceCategory.BlockAnimation; + string animationAssetPath = $"{ResourceLocation.GetPathFromCategory(animationResourceCategory)}/{_selectedTile.Tile.InternalName}.png"; + var file = _pckFile.GetOrCreate(animationAssetPath, PckAssetType.TextureFile); var animation = file.GetDeserializedData(AnimationDeserializer.DefaultDeserializer); - var animationEditor = new AnimationEditor(animation, _selectedTile.Tile.InternalName, GetBlendColor()); - if (animationEditor.ShowDialog(this) != DialogResult.OK) + var animationEditor = new AnimationEditor(animation, _selectedTile.Tile.DisplayName); + if (animationEditor.ShowDialog(this) == DialogResult.OK) { - return; + file.SetSerializedData(animationEditor.Result, AnimationSerializer.DefaultSerializer); + // so animations can automatically update upon saving + SelectedIndex = _selectedTile.Index; } - - file.SetSerializedData(animationEditor.Result, AnimationSerializer.DefaultSerializer); - // so animations can automatically update upon saving - SelectedIndex = _selectedTile.Index; } private void extractTileToolStripMenuItem_Click(object sender, EventArgs e) @@ -567,7 +546,7 @@ private void extractTileToolStripMenuItem_Click(object sender, EventArgs e) private void variantComboBox_SelectedIndexChanged(object sender, EventArgs e) { - if (dataTile.Tile.ColourEntry is not null) + if (dataTile.Tile.ColourEntry is not null && variantComboBox.SelectedItem is not null) { string colorKey = variantComboBox.SelectedItem.ToString(); @@ -599,27 +578,24 @@ private void setColorButton_Click(object sender, EventArgs e) colorPick.AnyColor = true; colorPick.SolidColorOnly = true; - // custom colors are read as BGR for some reason, so hex values are "backwards" - // values below are the default Minecraft dyed leather armor values for convenience - - colorPick.CustomColors = new int[] { - 0xfefff9, // White - 0x1d80f9, // Orange - 0xbd4ec7, // Magenta - 0xdab33a, // Light Blue - 0x3dd8fe, // Yellow - 0x1fc780, // Lime - 0xaa8bf3, // Pink - 0x524f47, // Gray - 0x979d9d, // Light Gray - 0x9c9c16, // Cyan - 0xb83289, // Purple - 0xaa443c, // Blue - 0x325483, // Brown - 0x167c5e, // Green - 0x262eb0, // Red - 0x211d1d // Black - }; + //Debug.Assert(Color.FromArgb(0xf9fffe).ToBGR() == 0xfefff9); // White + //Debug.Assert(Color.FromArgb(0xf9801d).ToBGR() == 0x1d80f9); // Orange + //Debug.Assert(Color.FromArgb(0xc74ebd).ToBGR() == 0xbd4ec7); // Magenta + //Debug.Assert(Color.FromArgb(0x3ab3da).ToBGR() == 0xdab33a); // Light Blue + //Debug.Assert(Color.FromArgb(0xfed83d).ToBGR() == 0x3dd8fe); // Yellow + //Debug.Assert(Color.FromArgb(0x80c71f).ToBGR() == 0x1fc780); // Lime + //Debug.Assert(Color.FromArgb(0xf38baa).ToBGR() == 0xaa8bf3); // Pink + //Debug.Assert(Color.FromArgb(0x474f52).ToBGR() == 0x524f47); // Gray + //Debug.Assert(Color.FromArgb(0x9d9d97).ToBGR() == 0x979d9d); // Light Gray + //Debug.Assert(Color.FromArgb(0x169c9c).ToBGR() == 0x9c9c16); // Cyan + //Debug.Assert(Color.FromArgb(0x8932b8).ToBGR() == 0xb83289); // Purple + //Debug.Assert(Color.FromArgb(0x3c44aa).ToBGR() == 0xaa443c); // Blue + //Debug.Assert(Color.FromArgb(0x835432).ToBGR() == 0x325483); // Brown + //Debug.Assert(Color.FromArgb(0x5e7c16).ToBGR() == 0x167c5e); // Green + //Debug.Assert(Color.FromArgb(0xb02e26).ToBGR() == 0x262eb0); // Red + //Debug.Assert(Color.FromArgb(0x1d1d21).ToBGR() == 0x211d1d); // Black + + colorPick.CustomColors = GameConstants.DyeColors.Select(c => c.ToBGR()).ToArray(); if (colorPick.ShowDialog(this) != DialogResult.OK) return; diff --git a/PCK-Studio/Internal/Deserializer/ImageDeserializer.cs b/PCK-Studio/Internal/Deserializer/ImageDeserializer.cs index eb00b243..09d27721 100644 --- a/PCK-Studio/Internal/Deserializer/ImageDeserializer.cs +++ b/PCK-Studio/Internal/Deserializer/ImageDeserializer.cs @@ -16,10 +16,15 @@ namespace PckStudio.Internal.Deserializer internal sealed class ImageDeserializer : IPckAssetDeserializer { public static readonly ImageDeserializer DefaultDeserializer = new ImageDeserializer(); + // TODO: replace empty image with image displaying something went wrong private static Image EmptyImage = new Bitmap(1, 1, PixelFormat.Format32bppArgb); public Image Deserialize(PckAsset asset) { + _ = asset ?? throw new ArgumentNullException(nameof(asset)); + if (asset.Size == 0) + return EmptyImage; + using var stream = new MemoryStream(asset.Data); try { diff --git a/PCK-Studio/Internal/GameConstants.cs b/PCK-Studio/Internal/GameConstants.cs new file mode 100644 index 00000000..6f055546 --- /dev/null +++ b/PCK-Studio/Internal/GameConstants.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PckStudio.Internal +{ + internal static class GameConstants + { + // See: https://minecraft.fandom.com/wiki/Dye#Color_values for more information. + public static readonly Color[] DyeColors = [ + Color.FromArgb(0xf9fffe), // White + Color.FromArgb(0xf9801d), // Orange + Color.FromArgb(0xc74ebd), // Magenta + Color.FromArgb(0x3ab3da), // Light Blue + Color.FromArgb(0xfed83d), // Yellow + Color.FromArgb(0x80c71f), // Lime + Color.FromArgb(0xf38baa), // Pink + Color.FromArgb(0x474f52), // Gray + Color.FromArgb(0x9d9d97), // Light Gray + Color.FromArgb(0x169c9c), // Cyan + Color.FromArgb(0x8932b8), // Purple + Color.FromArgb(0x3c44aa), // Blue + Color.FromArgb(0x835432), // Brown + Color.FromArgb(0x5e7c16), // Green + Color.FromArgb(0xb02e26), // Red + Color.FromArgb(0x1d1d21), // Black + ]; + } +} diff --git a/PCK-Studio/Internal/Json/ColorEntry.cs b/PCK-Studio/Internal/Json/ColorEntry.cs index 39390d81..8523a311 100644 --- a/PCK-Studio/Internal/Json/ColorEntry.cs +++ b/PCK-Studio/Internal/Json/ColorEntry.cs @@ -15,9 +15,6 @@ internal class JsonColorEntry [JsonProperty("isWaterColour", DefaultValueHandling = DefaultValueHandling.Populate)] public bool IsWaterColour { get; set; } - [JsonProperty("hasCustomColour", DefaultValueHandling = DefaultValueHandling.Populate)] - public bool HasCustomColour { get; set; } - [JsonProperty("variants", DefaultValueHandling = DefaultValueHandling.Populate)] public string[] Variants { get; set; } } diff --git a/PCK-Studio/Internal/Json/TileInfo.cs b/PCK-Studio/Internal/Json/TileInfo.cs index 54e27d2f..b5fb0510 100644 --- a/PCK-Studio/Internal/Json/TileInfo.cs +++ b/PCK-Studio/Internal/Json/TileInfo.cs @@ -16,10 +16,10 @@ internal class JsonTileInfo public string InternalName { get; set; } [JsonProperty("width")] - public int Width { get; set; } = 1; + public int TileWidth { get; set; } = 1; [JsonProperty("height")] - public int Height { get; set; } = 1; + public int TileHeight { get; set; } = 1; [JsonProperty("hasColourEntry", DefaultValueHandling = DefaultValueHandling.Populate)] public bool HasColourEntry { get; set; } @@ -27,6 +27,9 @@ internal class JsonTileInfo [JsonProperty("colourEntry", DefaultValueHandling = DefaultValueHandling.Populate)] public JsonColorEntry ColourEntry { get; set; } + [JsonProperty("allowCustomColour", DefaultValueHandling = DefaultValueHandling.Populate)] + public bool AllowCustomColour { get; set; } + public JsonTileInfo(string displayName, string internalName) { DisplayName = displayName; diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 71e83106..8a843832 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -459,7 +459,7 @@ private void HandleTextureFile(PckAsset asset) } ResourceLocation resourceLocation = ResourceLocation.GetFromPath(asset.Filename); - Debug.WriteLine("Handling Resource file: " + resourceLocation.ToString()); + Debug.WriteLine("Handling Resource file: " + resourceLocation?.ToString()); if (resourceLocation is null || resourceLocation.Category == ResourceCategory.Unknown) return; diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index d281b0ca..ceeba42f 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -152,6 +152,7 @@ + diff --git a/PCK-Studio/Resources/atlases/blockData.json b/PCK-Studio/Resources/atlases/blockData.json index c2cb1b8f..2b9e4550 100644 --- a/PCK-Studio/Resources/atlases/blockData.json +++ b/PCK-Studio/Resources/atlases/blockData.json @@ -2317,11 +2317,11 @@ { "internalName": "cauldron_water", "displayName": "Cauldron Water", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "Cauldron_Water", - "variants": [ + "variants": [ "Cauldron_Water", "Effect_MovementSpeed", "Effect_MovementSlowDown", diff --git a/PCK-Studio/Resources/atlases/itemData.json b/PCK-Studio/Resources/atlases/itemData.json index 0c49ee02..51c380b7 100644 --- a/PCK-Studio/Resources/atlases/itemData.json +++ b/PCK-Studio/Resources/atlases/itemData.json @@ -5,9 +5,9 @@ { "internalName": "helmetCloth", "displayName": "Leather Cap", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "Armour_Default_Leather_Colour", "variants": [ "Armour_Default_Leather_Colour" ] } @@ -75,9 +75,9 @@ { "internalName": "chestplateCloth", "displayName": "Leather Tunic", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "Armour_Default_Leather_Colour", "variants": [ "Armour_Default_Leather_Colour" ] } @@ -145,9 +145,9 @@ { "internalName": "leggingsCloth", "displayName": "Leather Pants", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "Armour_Default_Leather_Colour", "variants": [ "Armour_Default_Leather_Colour" ] } @@ -215,9 +215,9 @@ { "internalName": "bootsCloth", "displayName": "Leather Boots", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "Armour_Default_Leather_Colour", "variants": [ "Armour_Default_Leather_Colour" ] } @@ -593,11 +593,11 @@ { "internalName": "potion_contents", "displayName": "Potion (Overlay)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1013,12 +1013,7 @@ { "internalName": "fireworks_charge_overlay", "displayName": "Firework Star (Overlay)", - "hasColourEntry": true, - "colourEntry": { - "hasCustomColour": true, - "defaultName": "", - "variants": [""] - } + "allowCustomColour": true }, { "internalName": "netherquartz", @@ -1099,9 +1094,9 @@ { "internalName": "leather_horse_armor_base", "displayName": "Leather Horse Armor", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "Armour_Default_Leather_Colour", "variants": [ "Armour_Default_Leather_Colour" ] } diff --git a/PCK-Studio/Resources/atlases/particleData.json b/PCK-Studio/Resources/atlases/particleData.json index e89bcf85..f4dae017 100644 --- a/PCK-Studio/Resources/atlases/particleData.json +++ b/PCK-Studio/Resources/atlases/particleData.json @@ -301,12 +301,7 @@ "displayName": "Firework Flash", "width": 4, "height": 4, - "hasColourEntry": true, - "colourEntry": { - "hasCustomColour": true, - "defaultName": "", - "variants": [""] - } + "allowCustomColour": true }, { "internalName": "flash", @@ -754,10 +749,10 @@ "internalName": "effect_0", "displayName": "Effect (Stage 1)", "hasColourEntry": true, + "allowCustomColour": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -794,10 +789,10 @@ "internalName": "effect_1", "displayName": "Effect (Stage 2)", "hasColourEntry": true, + "allowCustomColour": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -833,11 +828,11 @@ { "internalName": "effect_2", "displayName": "Effect (Stage 3)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -873,11 +868,11 @@ { "internalName": "effect_3", "displayName": "Effect (Stage 4)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -913,11 +908,11 @@ { "internalName": "effect_4", "displayName": "Effect (Stage 5)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -953,11 +948,11 @@ { "internalName": "effect_5", "displayName": "Effect (Stage 6)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -993,11 +988,11 @@ { "internalName": "effect_6", "displayName": "Effect (Stage 7)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1033,11 +1028,11 @@ { "internalName": "effect_7", "displayName": "Effect (Stage 8)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1105,11 +1100,11 @@ { "internalName": "spell_0", "displayName": "Splash Effect (Stage 1)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1145,11 +1140,11 @@ { "internalName": "spell_1", "displayName": "Splash Effect (Stage 2)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1185,11 +1180,11 @@ { "internalName": "spell_2", "displayName": "Splash Effect (Stage 3)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1225,11 +1220,11 @@ { "internalName": "spell_3", "displayName": "Splash Effect (Stage 4)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1265,11 +1260,11 @@ { "internalName": "spell_4", "displayName": "Splash Effect (Stage 5)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1305,11 +1300,11 @@ { "internalName": "spell_5", "displayName": "Splash Effect (Stage 6)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1345,11 +1340,11 @@ { "internalName": "spell_6", "displayName": "Splash Effect (Stage 7)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1385,11 +1380,11 @@ { "internalName": "spell_7", "displayName": "Splash Effect (Stage 8)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { "defaultName": "Potion_BaseColour", - "hasCustomColour": true, - "variants": [ + "variants": [ "Potion_BaseColour", "Effect_MovementSpeed", "Effect_MovementSlowDown", @@ -1457,9 +1452,9 @@ { "internalName": "spark_0", "displayName": "Firework Spark (Stage 1)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "None", "variants": [ "None", @@ -1472,9 +1467,9 @@ { "internalName": "spark_1", "displayName": "Firework Spark (Stage 2)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "None", "variants": [ "None", @@ -1487,9 +1482,9 @@ { "internalName": "spark_2", "displayName": "Firework Spark (Stage 3)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "None", "variants": [ "None", @@ -1502,9 +1497,9 @@ { "internalName": "spark_3", "displayName": "Firework Spark (Stage 4)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "None", "variants": [ "None", @@ -1517,9 +1512,9 @@ { "internalName": "spark_4", "displayName": "Firework Spark (Stage 5)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "None", "variants": [ "None", @@ -1532,9 +1527,9 @@ { "internalName": "spark_5", "displayName": "Firework Spark (Stage 6)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "None", "variants": [ "None", @@ -1547,9 +1542,9 @@ { "internalName": "spark_6", "displayName": "Firework Spark (Stage 7)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "None", "variants": [ "None", @@ -1562,9 +1557,9 @@ { "internalName": "spark_7", "displayName": "Firework Spark (Stage 8)", + "allowCustomColour": true, "hasColourEntry": true, "colourEntry": { - "hasCustomColour": true, "defaultName": "None", "variants": [ "None",