This commit is contained in:
miku-666
2024-03-15 23:27:33 +01:00
23 changed files with 1554 additions and 1440 deletions

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OMI.Formats.Languages;
namespace PckStudio.Extensions
{
internal static class LocFileExtensions
{
public static void InitializeDefault(this LOCFile locFile, string packName) => locFile.Initialize("en-EN", ("IDS_DISPLAY_NAME", packName));
public static void Initialize(this LOCFile locFile, string language, params (string, string)[] locKeyValuePairs)
{
locFile.AddLanguage(language);
foreach (var locKeyValue in locKeyValuePairs)
locFile.AddLocKey(locKeyValue.Item1, locKeyValue.Item2);
}
}
}

View File

@@ -78,11 +78,11 @@ namespace PckStudio.Extensions
int skinId = file.GetSkinId();
string name = file.Properties.GetPropertyValue("DISPLAYNAME");
string name = file.GetProperty("DISPLAYNAME");
Image texture = file.GetTexture();
SkinANIM anim = file.Properties.GetPropertyValue("ANIM", SkinANIM.FromString);
IEnumerable<SkinBOX> boxes = file.Properties.GetProperties("BOX").Select(kv => SkinBOX.FromString(kv.Value));
IEnumerable<SkinPartOffset> offsets = file.Properties.GetProperties("OFFSET").Select(kv => SkinPartOffset.FromString(kv.Value));
SkinANIM anim = file.GetProperty("ANIM", SkinANIM.FromString);
IEnumerable<SkinBOX> boxes = file.GetMultipleProperties("BOX").Select(kv => SkinBOX.FromString(kv.Value));
IEnumerable<SkinPartOffset> offsets = file.GetMultipleProperties("OFFSET").Select(kv => SkinPartOffset.FromString(kv.Value));
return new Skin(name, skinId, texture, anim, boxes, offsets);
}
@@ -99,36 +99,36 @@ namespace PckStudio.Extensions
file.Filename = $"dlcskin{skinId}.png";
string skinLocKey = $"IDS_dlcskin{skinId}_DISPLAYNAME";
file.Properties.SetProperty("DISPLAYNAME", skin.Name);
file.Properties.SetProperty("DISPLAYNAMEID", skinLocKey);
file.SetProperty("DISPLAYNAME", skin.Name);
file.SetProperty("DISPLAYNAMEID", skinLocKey);
localizationFile.AddLocKey(skinLocKey, skin.Name);
if (!string.IsNullOrEmpty(skin.Theme))
{
file.Properties.SetProperty("THEMENAME", skin.Theme);
file.Properties.SetProperty("THEMENAMEID", $"IDS_dlcskin{skinId}_THEMENAME");
file.SetProperty("THEMENAME", skin.Theme);
file.SetProperty("THEMENAMEID", $"IDS_dlcskin{skinId}_THEMENAME");
localizationFile.AddLocKey($"IDS_dlcskin{skinId}_THEMENAME", skin.Theme);
}
if (skin.HasCape)
{
file.Properties.SetProperty("CAPEPATH", $"dlccape{skinId}.png");
file.SetProperty("CAPEPATH", $"dlccape{skinId}.png");
}
file.Properties.SetProperty("ANIM", skin.ANIM.ToString());
file.Properties.SetProperty("GAME_FLAGS", "0x18");
file.Properties.SetProperty("FREE", "1");
file.SetProperty("ANIM", skin.ANIM.ToString());
file.SetProperty("GAME_FLAGS", "0x18");
file.SetProperty("FREE", "1");
file.Properties.RemoveAll(kv => kv.Key == "BOX");
file.Properties.RemoveAll(kv => kv.Key == "OFFSET");
file.RemoveProperties("BOX");
file.RemoveProperties("OFFSET");
foreach (SkinBOX box in skin.AdditionalBoxes)
{
file.Properties.Add(box.ToProperty());
file.AddProperty(box.ToProperty());
}
foreach (SkinPartOffset offset in skin.PartOffsets)
{
file.Properties.Add(offset.ToProperty());
file.AddProperty(offset.ToProperty());
}
}

View File

@@ -17,34 +17,40 @@ namespace PckStudio.Extensions
string skinId = skin.Id.ToString("d08");
PckFileData skinFile = new PckFileData($"dlcskin{skinId}.png", PckFileType.SkinFile);
string skinLocKey = $"IDS_dlcskin{skinId}_DISPLAYNAME";
skinFile.Properties.Add("DISPLAYNAME", skin.Name);
skinFile.Properties.Add("DISPLAYNAMEID", skinLocKey);
localizationFile.AddLocKey(skinLocKey, skin.Name);
skinFile.AddProperty("DISPLAYNAME", skin.Name);
if (localizationFile is not null)
{
string skinLocKey = $"IDS_dlcskin{skinId}_DISPLAYNAME";
skinFile.AddProperty("DISPLAYNAMEID", skinLocKey);
localizationFile.AddLocKey(skinLocKey, skin.Name);
}
if (!string.IsNullOrEmpty(skin.Theme))
{
skinFile.Properties.Add("THEMENAME", skin.Theme);
skinFile.Properties.Add("THEMENAMEID", $"IDS_dlcskin{skinId}_THEMENAME");
localizationFile.AddLocKey($"IDS_dlcskin{skinId}_THEMENAME", skin.Theme);
skinFile.AddProperty("THEMENAME", skin.Theme);
if (localizationFile is not null)
{
skinFile.AddProperty("THEMENAMEID", $"IDS_dlcskin{skinId}_THEMENAME");
localizationFile.AddLocKey($"IDS_dlcskin{skinId}_THEMENAME", skin.Theme);
}
}
if (skin.HasCape)
{
skinFile.Properties.Add("CAPEPATH", $"dlccape{skinId}.png");
skinFile.AddProperty("CAPEPATH", $"dlccape{skinId}.png");
}
skinFile.Properties.Add("ANIM", skin.ANIM);
skinFile.Properties.Add("GAME_FLAGS", "0x18");
skinFile.Properties.Add("FREE", "1");
skinFile.AddProperty("ANIM", skin.ANIM);
skinFile.AddProperty("GAME_FLAGS", "0x18");
skinFile.AddProperty("FREE", "1");
foreach (SkinBOX box in skin.AdditionalBoxes)
{
skinFile.Properties.Add(box.ToProperty());
skinFile.AddProperty(box.ToProperty());
}
foreach (SkinPartOffset offset in skin.PartOffsets)
{
skinFile.Properties.Add(offset.ToProperty());
skinFile.AddProperty(offset.ToProperty());
}
skinFile.SetData(skin.Texture, ImageFormat.Png);

View File

@@ -237,7 +237,7 @@ namespace PckStudio.Features
currentPCK = reader.FromFile(filepath);
if (currentPCK is null) return string.Empty;
return currentPCK.TryGetFile("0", PckFileType.InfoFile, out var file)
? file.Properties.GetPropertyValue("PACKID")
? file.GetProperty("PACKID")
: string.Empty;
}

View File

@@ -54,12 +54,11 @@
this.treeView1.Location = new System.Drawing.Point(20, 84);
this.treeView1.Margin = new System.Windows.Forms.Padding(0);
this.treeView1.Name = "treeView1";
this.treeView1.Size = new System.Drawing.Size(136, 176);
this.treeView1.Size = new System.Drawing.Size(246, 234);
this.treeView1.TabIndex = 13;
this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterSelect);
this.treeView1.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeView1_NodeMouseClick);
this.treeView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeView1_KeyDown);
this.treeView1.MouseHover += new System.EventHandler(this.treeView1_MouseHover);
//
// metroContextMenu1
//
@@ -92,7 +91,7 @@
this.helpToolStripMenuItem});
this.menuStrip.Location = new System.Drawing.Point(20, 60);
this.menuStrip.Name = "menuStrip";
this.menuStrip.Size = new System.Drawing.Size(348, 24);
this.menuStrip.Size = new System.Drawing.Size(246, 24);
this.menuStrip.TabIndex = 14;
this.menuStrip.Text = "menuStrip1";
//
@@ -123,7 +122,7 @@
// xLabel
//
this.xLabel.AutoSize = true;
this.xLabel.Location = new System.Drawing.Point(159, 147);
this.xLabel.Location = new System.Drawing.Point(98, 325);
this.xLabel.Name = "xLabel";
this.xLabel.Size = new System.Drawing.Size(91, 19);
this.xLabel.TabIndex = 30;
@@ -141,9 +140,9 @@
"entity_emissive_alpha_only",
"entity_alphatest_change_color",
"entity_change_color"});
this.materialComboBox.Location = new System.Drawing.Point(159, 169);
this.materialComboBox.Location = new System.Drawing.Point(20, 347);
this.materialComboBox.Name = "materialComboBox";
this.materialComboBox.Size = new System.Drawing.Size(209, 29);
this.materialComboBox.Size = new System.Drawing.Size(246, 29);
this.materialComboBox.TabIndex = 31;
this.materialComboBox.Theme = MetroFramework.MetroThemeStyle.Dark;
this.materialComboBox.UseSelectable = true;
@@ -153,7 +152,7 @@
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(388, 280);
this.ClientSize = new System.Drawing.Size(286, 399);
this.Controls.Add(this.materialComboBox);
this.Controls.Add(this.xLabel);
this.Controls.Add(this.menuStrip);

View File

@@ -23,6 +23,11 @@ namespace PckStudio.Forms.Editor
private readonly JObject EntityJSONData = JObject.Parse(Properties.Resources.entityData);
private bool showInvalidEntries;
//Holds invalid entries so they can be added back to the material file on save should the user decide to hide them
List<MaterialContainer.Material> hiddenInvalidEntries = new List<MaterialContainer.Material>();
void SetUpTree()
{
treeView1.BeginUpdate();
@@ -31,6 +36,8 @@ namespace PckStudio.Forms.Editor
{
TreeNode EntryNode = new TreeNode(entry.Name);
EntryNode.ImageIndex = -1;
foreach (JObject content in EntityJSONData["materials"].Children())
{
var prop = content.Properties().FirstOrDefault(prop => prop.Name == entry.Name);
@@ -38,13 +45,27 @@ namespace PckStudio.Forms.Editor
{
EntryNode.Text = (string)prop.Value;
EntryNode.ImageIndex = EntityJSONData["materials"].Children().ToList().IndexOf(content);
EntryNode.SelectedImageIndex = EntryNode.ImageIndex;
break;
}
}
EntryNode.Tag = entry;
// check for invalid material entry
if (EntryNode.ImageIndex == -1)
{
EntryNode.ImageIndex = 127; // icon for invalid entry
EntryNode.Text += " (Invalid)";
if (!showInvalidEntries)
{
hiddenInvalidEntries.Add(entry);
continue;
}
}
EntryNode.SelectedImageIndex = EntryNode.ImageIndex;
treeView1.Nodes.Add(EntryNode);
}
treeView1.EndUpdate();
@@ -58,13 +79,20 @@ namespace PckStudio.Forms.Editor
using (var stream = new MemoryStream(file.Data))
{
var reader = new MaterialFileReader();
materialFile = reader.FromStream(stream);
}
materialFile = reader.FromStream(stream);
treeView1.ImageList = new ImageList();
ApplicationScope.EntityImages.ToList().ForEach(treeView1.ImageList.Images.Add);
treeView1.ImageList.ColorDepth = ColorDepth.Depth32Bit;
SetUpTree();
if (materialFile.hasInvalidEntries())
{
DialogResult dr = MessageBox.Show(this, "Unsupported entities were found in this file. Would you like to display them?", "Invalid data found", MessageBoxButtons.YesNo);
showInvalidEntries = dr == DialogResult.Yes;
}
treeView1.ImageList = new ImageList();
ApplicationScope.EntityImages.ToList().ForEach(treeView1.ImageList.Images.Add);
treeView1.ImageList.ColorDepth = ColorDepth.Depth32Bit;
SetUpTree();
}
}
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
@@ -93,26 +121,11 @@ namespace PckStudio.Forms.Editor
materialComboBox.Enabled = false;
}
private void addNewPositionOverrideToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void addNewEntryToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void treeView1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Delete) removeToolStripMenuItem_Click(sender, e);
}
private void treeView1_MouseHover(object sender, EventArgs e)
{
}
private void saveToolStripMenuItem1_Click(object sender, EventArgs e)
{
materialFile = new MaterialContainer();
@@ -125,6 +138,11 @@ namespace PckStudio.Forms.Editor
}
}
foreach (MaterialContainer.Material mat in hiddenInvalidEntries)
{
materialFile.Add(mat);
}
_file.SetData(new MaterialFileWriter(materialFile));
DialogResult = DialogResult.OK;
@@ -158,8 +176,6 @@ namespace PckStudio.Forms.Editor
}
}
treeView1.Nodes.Add(NewEntryNode);
addNewPositionOverrideToolStripMenuItem_Click(sender, e); // adds a Position Override to the new Override
}
}

View File

@@ -127,11 +127,11 @@
<data name="saveToolStripMenuItem1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4yMfEgaZUAAADfSURBVDhPYxg8
QLt++3yTGbf/Fm599P/Nh49wfPXxq/+rTt37f+Dak/8gOSBgAGEMANIMxGBFyAasPf/0v8GE8//z1t8C
y4HU4DIALIluwLpLL+HiMANAGKoNAWASCavv/n/57gPcgOvP3oENOXj7NViOoAFGU6791+k4ghWD5Aga
QCyGakMAkODcU89R/I8Ng9TgNADk14dPn/8/c+kqVgySgwUqVBsCwAx49urN/zsPHmPFIDmaGvAXJInN
38gYasBfqDYE0K7dOn/Wvut/sfkdGYPUgJI9VNuAAwYGAGn6yvdevWgPAAAAAElFTkSuQmCC
vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4yMfEgaZUAAADdSURBVDhPzZJB
CoJQEIa9jy0iPFAnCDpAtG3ZooUE4b6oVtIuClpJIAgqZEVlKpqEHUAm5pGPmhTbRA18G//5P5iHgvA3
I7ZniiQ7aVM9QZzcOKYbwVDbw8I6A2YAICBvg2VJdtjSs2Cse1Dt6tCYbliGO0UCFlLBxAj590yA0D4X
1Ec7CK8JF9j+lUmWzoVlpYJaz4JKZ5ULZqWCT6F9Jhhowcv9eeBOoQBvPXoBrA0zF8yyR6V9LvCjGLYH
NxfMvipIMaQ3Ux6ClPYFsaUq/bmd0rspuIO/Pe3/bu5p+sr3gTvFEQAAAABJRU5ErkJggg==
</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">

View File

@@ -90,14 +90,14 @@
// saveToolStripMenuItem
//
this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
this.saveToolStripMenuItem.Size = new System.Drawing.Size(131, 22);
this.saveToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.saveToolStripMenuItem.Text = "Save";
this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click);
//
// extractTileToolStripMenuItem
//
this.extractTileToolStripMenuItem.Name = "extractTileToolStripMenuItem";
this.extractTileToolStripMenuItem.Size = new System.Drawing.Size(131, 22);
this.extractTileToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.extractTileToolStripMenuItem.Text = "Extract Tile";
this.extractTileToolStripMenuItem.Click += new System.EventHandler(this.extractTileToolStripMenuItem_Click);
//
@@ -117,7 +117,7 @@
this.applyColorMaskToolStripMenuItem.CheckOnClick = true;
this.applyColorMaskToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.applyColorMaskToolStripMenuItem.Name = "applyColorMaskToolStripMenuItem";
this.applyColorMaskToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
this.applyColorMaskToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.applyColorMaskToolStripMenuItem.Text = "Apply Color Mask";
this.applyColorMaskToolStripMenuItem.CheckedChanged += new System.EventHandler(this.applyColorMaskToolStripMenuItem_CheckedChanged);
//
@@ -127,7 +127,7 @@
this.playAnimationsToolStripMenuItem.CheckOnClick = true;
this.playAnimationsToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
this.playAnimationsToolStripMenuItem.Name = "playAnimationsToolStripMenuItem";
this.playAnimationsToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
this.playAnimationsToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.playAnimationsToolStripMenuItem.Text = "Play Animations";
this.playAnimationsToolStripMenuItem.CheckedChanged += new System.EventHandler(this.playAnimationsToolStripMenuItem_CheckedChanged);
//

View File

@@ -56,6 +56,8 @@ namespace PckStudio.Forms.Editor
private readonly List<AtlasTile> _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;
@@ -137,18 +139,20 @@ namespace PckStudio.Forms.Editor
if (_tiles is null || !_tiles.IndexInRange(index) || (_selectedTile = _tiles[index]) is null)
return;
if(string.IsNullOrEmpty(_selectedTile.Tile.DisplayName))
{
// changes the selected tile to the base flowing tile (carries all properties over) - Matt
_selectedTile = _tiles.Find(t => t.Tile.InternalName == _selectedTile.Tile.InternalName);
}
dataTile = _selectedTile;
tileNameLabel.Text = $"{_selectedTile.Tile.DisplayName}";
if (string.IsNullOrEmpty(dataTile.Tile.DisplayName))
{
dataTile = _tiles.Find(t => t.Tile.InternalName == _selectedTile.Tile.InternalName);
}
selectTilePictureBox.Image = dataTile.Texture;
tileNameLabel.Text = $"{dataTile.Tile.DisplayName}";
selectTilePictureBox.BlendColor = GetBlendColor();
selectTilePictureBox.UseBlendColor = applyColorMaskToolStripMenuItem.Checked;
bool hasAnimation =
_pckFile.TryGetValue($"res/textures/{_atlasType}/{_selectedTile.Tile.InternalName}.png", PckFileType.TextureFile, out var animationFile);
_pckFile.TryGetValue($"res/textures/{_atlasType}/{dataTile.Tile.InternalName}.png", PckFileType.TextureFile, out var animationFile);
animationButton.Text = hasAnimation ? "Edit Animation" : "Create Animation";
replaceButton.Enabled = !hasAnimation;
@@ -158,16 +162,29 @@ namespace PckStudio.Forms.Editor
{
var animation = AnimationHelper.GetAnimationFromFile(animationFile);
selectTilePictureBox.Start(animation);
return;
}
if (variantComboBox.Enabled = variantLabel.Visible = variantComboBox.Visible = _selectedTile.Tile.HasColourEntry && _selectedTile.Tile.ColourEntry.Variants.Length > 1)
if (variantComboBox.Enabled = variantLabel.Visible = variantComboBox.Visible =
dataTile.Tile.HasColourEntry)
{
variantComboBox.Items.AddRange(_selectedTile.Tile.ColourEntry.Variants);
variantComboBox.SelectedItem = _selectedTile.Tile.ColourEntry.DefaultName;
if (dataTile.Tile.ColourEntry.IsWaterColour && _colourTable.WaterColors.Count > 0)
{
foreach (var col in _colourTable.WaterColors)
{
if(!variantComboBox.Items.Contains(col.Name))
variantComboBox.Items.Add(col.Name);
}
dataTile.Tile.ColourEntry.DefaultName = _colourTable.WaterColors[0].Name;
}
if (dataTile.Tile.ColourEntry.Variants.Length > 1)
{
variantComboBox.Items.AddRange(dataTile.Tile.ColourEntry.Variants);
}
variantComboBox.SelectedItem = dataTile.Tile.ColourEntry.DefaultName;
}
selectTilePictureBox.Image = _selectedTile.Texture;
}
private static int GetSelectedImageIndex(
@@ -291,26 +308,32 @@ namespace PckStudio.Forms.Editor
private Color GetBlendColor()
{
if (_selectedTile.Tile.HasColourEntry && _selectedTile.Tile.ColourEntry is not null)
return FindBlendColorByKey(_selectedTile.Tile.ColourEntry.DefaultName);
if (dataTile.Tile.HasColourEntry && dataTile.Tile.ColourEntry is not null)
{
var col = FindBlendColorByKey(dataTile.Tile.ColourEntry.DefaultName);
return col;
}
return Color.White;
}
private Color FindBlendColorByKey(string colorKey)
{
if (_colourTable is not null &&
_selectedTile.Tile.HasColourEntry &&
_selectedTile.Tile.ColourEntry is not null)
dataTile.Tile.HasColourEntry &&
dataTile.Tile.ColourEntry is not null)
{
if (_selectedTile.Tile.ColourEntry.IsWaterColour &&
_colourTable.WaterColors.FirstOrDefault(entry => entry.Name == colorKey) is ColorContainer.WaterColor waterColor)
// basic way to check for classic water colors
if(!dataTile.Tile.ColourEntry.IsWaterColour || colorKey.StartsWith("Water_"))
{
if (_colourTable.Colors.FirstOrDefault(entry => entry.Name == colorKey) is ColorContainer.Color color)
{
return color.ColorPallette;
}
}
else if (_colourTable.WaterColors.FirstOrDefault(entry => entry.Name == colorKey) is ColorContainer.WaterColor waterColor)
{
return waterColor.SurfaceColor;
}
else if (_colourTable.Colors.FirstOrDefault(entry => entry.Name == colorKey) is ColorContainer.Color color)
{
return color.ColorPallette;
}
}
return Color.White;
}
@@ -408,6 +431,8 @@ namespace PckStudio.Forms.Editor
}
AnimationHelper.SaveAnimationToFile(file, animation);
// so animations can automatically update upon saving
SelectedIndex = _selectedTile.Index;
}
private void extractTileToolStripMenuItem_Click(object sender, EventArgs e)
@@ -425,12 +450,12 @@ namespace PckStudio.Forms.Editor
private void variantComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (_selectedTile.Tile.ColourEntry is not null &&
_selectedTile.Tile.ColourEntry.Variants.IndexInRange(variantComboBox.SelectedIndex))
if (dataTile.Tile.ColourEntry is not null)
{
string colorKey = _selectedTile.Tile.ColourEntry.Variants[variantComboBox.SelectedIndex];
string colorKey = variantComboBox.SelectedItem.ToString();
selectTilePictureBox.BlendColor = FindBlendColorByKey(colorKey);
selectTilePictureBox.Image = _selectedTile.Texture;
selectTilePictureBox.Image = dataTile.Texture;
}
}

View File

@@ -21,20 +21,12 @@ namespace PckStudio.Popups
{
public Skin NewSkin => newSkin;
//public PckFileData SkinFile => _skinFile;
//public PckFileData CapeFile => cape;
//public bool HasCape => cape is not null;
private LOCFile currentLoc;
//private PckFileData _skinFile = new PckFileData("dlcskinXYXYXYXY", PckFileType.SkinFile);
//private PckFileData cape;
private Skin newSkin;
private Random rng = new Random();
public AddNewSkin(LOCFile loc)
public AddNewSkin()
{
InitializeComponent();
currentLoc = loc;
newSkin = new Skin("", 0, Resources.classic_template, new SkinANIM(), Enumerable.Empty<SkinBOX>(), Enumerable.Empty<SkinPartOffset>());
}

View File

@@ -67,7 +67,7 @@ namespace PckStudio.Popups
if (index == -1 || (Enum.IsDefined(typeof(PckFileType), index) && (int)file.Filetype == index))
{
file.Properties.Add(propertyKeyTextBox.Text, propertyValueTextBox.Text);
file.AddProperty(propertyKeyTextBox.Text, propertyValueTextBox.Text);
}
}

View File

@@ -182,7 +182,7 @@ namespace PckStudio.Forms
string capePath = "";
bool hasCape = false;
foreach (var entry in newSkin.Properties)
foreach (var entry in newSkin.GetProperties())
{
if (entry.Key == "DISPLAYNAME")
{
@@ -264,7 +264,7 @@ namespace PckStudio.Forms
if (skinPicture.Height == skinPicture.Width)
{
//determines skin type based on image dimensions, existence of BOX tags, and the ANIM value
foreach (var entry in newSkin.Properties)
foreach (var entry in newSkin.GetProperties())
{
if (entry.Key == "BOX")
{

View File

@@ -18,7 +18,7 @@ namespace PckStudio.Helper
internal static void SaveAnimationToFile(PckFileData file, Animation animation)
{
string anim = animation.BuildAnim();
file.Properties.SetProperty("ANIM", anim);
file.SetProperty("ANIM", anim);
var texture = animation.BuildTexture();
file.SetData(texture, ImageFormat.Png);
}
@@ -30,7 +30,7 @@ namespace PckStudio.Helper
{
var texture = file.GetTexture();
var frameTextures = texture.Split(ImageLayoutDirection.Vertical);
var _animation = new Animation(frameTextures, file.Properties.GetPropertyValue("ANIM"));
var _animation = new Animation(frameTextures, file.GetProperty("ANIM"));
_animation.Category = file.Filename.Split('/').Contains("items")
? AnimationCategory.Items
: AnimationCategory.Blocks;

View File

@@ -16,6 +16,7 @@
* 3. This notice may not be removed or altered from any source distribution.
**/
using System;
using System.Collections.Generic;
using System.Numerics;
namespace PckStudio.Internal
@@ -65,9 +66,9 @@ namespace PckStudio.Internal
return skinBox;
}
public ValueTuple<string, string> ToProperty()
public KeyValuePair<string, string> ToProperty()
{
return new ValueTuple<string, string>("BOX", ToString());
return new KeyValuePair<string, string>("BOX", ToString());
}
public override string ToString()

View File

@@ -4,6 +4,7 @@ using System.IO;
using PckStudio.Extensions;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Collections.Generic;
namespace PckStudio.Internal
{
@@ -71,10 +72,10 @@ namespace PckStudio.Internal
return new SkinPartOffset(type, value);
}
public (string, string) ToProperty()
public KeyValuePair<string, string> ToProperty()
{
string value = $"{Type} Y {Value}";
return ("OFFSET", value.Replace(',', '.'));
return new KeyValuePair<string, string>("OFFSET", value.Replace(',', '.'));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,20 @@ namespace PckStudio
private PckManager PckManager = null;
string saveLocation = string.Empty;
PckFile currentPCK = null;
bool wasModified = false;
bool __modified = false;
bool wasModified
{
get => __modified;
set
{
if (__modified == value)
return;
__modified = value;
pckFileLabel.Text = !pckFileLabel.Text.StartsWith("*") && __modified ? "*" + pckFileLabel.Text : pckFileLabel.Text.Substring(1);
}
}
bool isTemplateFile = false;
bool isSelectingTab = false;
@@ -79,19 +92,49 @@ namespace PckStudio
[PckFileType.TextureFile] = HandleTextureFile,
[PckFileType.UIDataFile] = _ => throw new NotSupportedException("unused in-game"),
[PckFileType.InfoFile] = null,
[PckFileType.TexturePackInfoFile] = null,
[PckFileType.TexturePackInfoFile] = HandleInnerPckFile,
[PckFileType.LocalisationFile] = HandleLocalisationFile,
[PckFileType.GameRulesFile] = HandleGameRuleFile,
[PckFileType.AudioFile] = HandleAudioFile,
[PckFileType.ColourTableFile] = HandleColourFile,
[PckFileType.GameRulesHeader] = HandleGameRuleFile,
[PckFileType.SkinDataFile] = null,
[PckFileType.SkinDataFile] = HandleInnerPckFile,
[PckFileType.ModelsFile] = HandleModelsFile,
[PckFileType.BehavioursFile] = HandleBehavioursFile,
[PckFileType.MaterialFile] = HandleMaterialFile,
};
}
private void HandleInnerPckFile(PckFileData file)
{
if (Settings.Default.LoadSubPcks &&
(file.Filetype == PckFileType.SkinDataFile || file.Filetype == PckFileType.TexturePackInfoFile) &&
file.Size > 0 && treeViewMain.SelectedNode.Nodes.Count == 0)
{
using (var stream = new MemoryStream(file.Data))
{
try
{
var reader = new PckFileReader(LittleEndianCheckBox.Checked ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian);
PckFile subPCKfile = reader.FromStream(stream);
BuildPckTreeView(treeViewMain.SelectedNode.Nodes, subPCKfile);
treeViewMain.SelectedNode.ExpandAll();
}
catch (OverflowException ex)
{
MessageBox.Show("Failed to open pck\n" +
"Try checking the 'Open/Save as Switch/Vita/PS4 pck' checkbox in the upper right corner.",
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(ex.Message);
}
}
return;
}
treeViewMain.SelectedNode.Nodes.Clear();
treeViewMain.SelectedNode.Collapse();
}
public void InitPckFromFile(string filepath)
{
saveLocation = filepath;
@@ -203,7 +246,7 @@ namespace PckStudio
{
if (currentPCK.TryGetFile("0", PckFileType.InfoFile, out PckFileData file))
{
file.Properties.RemoveAll(t => t.Key.Equals("LOCK"));
file.RemoveProperties("LOCK");
}
}
@@ -213,7 +256,7 @@ namespace PckStudio
if (isTemplateFile)
pckFileLabel.Text = "Unsaved File!";
else
pckFileLabel.Text = "Current PCK File: " + Path.GetFileName(saveLocation);
pckFileLabel.Text = Path.GetFileName(saveLocation);
treeViewMain.Enabled = treeMeta.Enabled = true;
closeToolStripMenuItem.Visible = true;
fullBoxSupportToolStripMenuItem.Checked = currentPCK.HasVerionString;
@@ -222,8 +265,6 @@ namespace PckStudio
saveToolStripMenuItem.Enabled = true;
saveToolStripMenuItem1.Enabled = true;
quickChangeToolStripMenuItem.Enabled = true;
convertToBedrockToolStripMenuItem.Enabled = true;
addCustomPackImageToolStripMenuItem.Enabled = true;
BuildMainTreeView();
isSelectingTab = true;
tabControl.SelectTab(1);
@@ -250,8 +291,6 @@ namespace PckStudio
quickChangeToolStripMenuItem.Enabled = false;
closeToolStripMenuItem.Visible = false;
packSettingsToolStripMenuItem.Visible = false;
convertToBedrockToolStripMenuItem.Enabled = false;
addCustomPackImageToolStripMenuItem.Enabled = false;
fileEntryCountLabel.Text = string.Empty;
pckFileLabel.Text = string.Empty;
UpdateRichPresence();
@@ -302,7 +341,7 @@ namespace PckStudio
return BuildNodeTreeBySeperator(subNode.Nodes, subPath, seperator);
}
private void BuildPckTreeView(TreeNodeCollection root, PckFile pckFile, string parentPath = "")
private void BuildPckTreeView(TreeNodeCollection root, PckFile pckFile)
{
foreach (var file in pckFile.GetFiles())
{
@@ -311,28 +350,6 @@ namespace PckStudio
// file.Filename = file.Filename.Remove(0, parentPath.Length);
TreeNode node = BuildNodeTreeBySeperator(root, file.Filename, '/');
node.Tag = file;
if (Settings.Default.LoadSubPcks &&
(file.Filetype == PckFileType.SkinDataFile || file.Filetype == PckFileType.TexturePackInfoFile) &&
file.Size > 0)
{
using (var stream = new MemoryStream(file.Data))
{
try
{
var reader = new PckFileReader(LittleEndianCheckBox.Checked ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian);
PckFile subPCKfile = reader.FromStream(stream);
// passes parent path to remove from sub pck filepaths
BuildPckTreeView(node.Nodes, subPCKfile, file.Filename + "/");
}
catch (OverflowException ex)
{
MessageBox.Show("Failed to open pck\n" +
"Try checking the 'Open/Save as Switch/Vita/PS4 pck' checkbox in the upper right corner.",
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Debug.WriteLine(ex.Message);
}
}
}
SetNodeIcon(node, file.Filetype);
};
}
@@ -433,9 +450,9 @@ namespace PckStudio
public void HandleSkinFile(PckFileData file)
{
var skin = file.GetSkin();
if (file.Properties.Contains("CAPEPATH"))
if (file.HasProperty("CAPEPATH"))
{
string capePath = file.Properties.GetPropertyValue("CAPEPATH");
string capePath = file.GetProperty("CAPEPATH");
if (currentPCK.TryGetFile(capePath, PckFileType.CapeFile, out var cape))
{
skin.CapeTexture = cape.GetTexture();
@@ -482,13 +499,13 @@ namespace PckStudio
if (e.Node.TryGetTagData(out PckFileData file))
{
viewFileInfoToolStripMenuItem.Visible = true;
if (file.Properties.HasProperty("BOX"))
if (file.HasProperty("BOX"))
{
buttonEdit.Text = "EDIT BOXES";
buttonEdit.Visible = true;
}
else if (file.Properties.HasProperty("ANIM") &&
file.Properties.GetPropertyValue("ANIM", s => SkinANIM.FromString(s) == (SkinAnimMask.RESOLUTION_64x64 | SkinAnimMask.SLIM_MODEL)))
else if (file.HasProperty("ANIM") &&
file.GetProperty("ANIM", s => SkinANIM.FromString(s) == (SkinAnimMask.RESOLUTION_64x64 | SkinAnimMask.SLIM_MODEL)))
{
buttonEdit.Text = "View Skin";
buttonEdit.Visible = true;
@@ -561,74 +578,100 @@ namespace PckStudio
}
}
private void extractFile(string outFilePath, PckFileData file)
{
File.WriteAllBytes(outFilePath, file.Data);
if (file.PropertyCount > 0)
{
using var fs = File.CreateText($"{outFilePath}.txt");
foreach (var property in file.GetProperties())
{
fs.WriteLine($"{property.Key}: {property.Value}");
}
}
}
private void extractFolderFile(string outPath, PckFileData file)
{
TreeNode node = treeViewMain.SelectedNode;
// abb = "Abbreviated Path"
string abbPath = Path.GetDirectoryName(file.Filename);
int startIndex = abbPath.IndexOf(node.Text);
abbPath = abbPath.Substring(startIndex, abbPath.Length - startIndex);
string finalPath = ($"{outPath}/{abbPath}/").Replace('\\', '/');
if (!Directory.Exists(finalPath)) Directory.CreateDirectory(finalPath);
extractFile(finalPath + "/" + Path.GetFileName(file.Filename), file);
}
private void extractFolder(string outPath)
{
TreeNode node = treeViewMain.SelectedNode;
string selectedFolder = node.FullPath;
if (IsSubPCKNode(node.FullPath))
{
GetAllChildNodes(node.Nodes).ForEach(fileNode =>
{
if (fileNode.TryGetTagData(out PckFileData file))
{
extractFolderFile(outPath, file);
}
}
);
}
else
{
foreach (var _file in currentPCK.GetFiles())
{
if (_file.Filename.StartsWith(selectedFolder))
{
extractFolderFile(outPath, _file);
}
};
}
}
private void extractToolStripMenuItem_Click(object sender, EventArgs e)
{
var node = treeViewMain.SelectedNode;
if (node == null)
{
MessageBox.Show(this, "The selected node was null. Please select a node and try again.", "Node not extracted");
return;
if (node.TryGetTagData(out PckFileData file))
}
if (node.Tag == null)
{
OpenFolderDialog dialog = new OpenFolderDialog();
dialog.Title = @"Select destination folder";
if (dialog.ShowDialog(Handle) == true) extractFolder(dialog.ResultPath);
}
else if (node.TryGetTagData(out PckFileData file))
{
using SaveFileDialog exFile = new SaveFileDialog();
exFile.FileName = Path.GetFileName(file.Filename);
exFile.Filter = Path.GetExtension(file.Filename).Replace(".", string.Empty) + " File|*" + Path.GetExtension(file.Filename);
if (exFile.ShowDialog() != DialogResult.OK ||
// Makes sure chosen directory isn't null or whitespace AKA makes sure its usable
string.IsNullOrWhiteSpace(Path.GetDirectoryName(exFile.FileName))) return;
string extractFilePath = exFile.FileName;
string.IsNullOrWhiteSpace(Path.GetDirectoryName(exFile.FileName)))
{
MessageBox.Show(this, "The chosen directory is invalid. Please choose a different one and try again.", "Node not extracted");
File.WriteAllBytes(extractFilePath, file.Data);
if (file.Properties.Count > 0)
{
using var fs = File.CreateText($"{extractFilePath}.txt");
file.Properties.ForEach(property => fs.WriteLine($"{property.Key}: {property.Value}"));
return;
}
// Verification that file extraction path was successful
MessageBox.Show("File Extracted");
return;
extractFile(exFile.FileName, file);
}
string selectedFolder = node.FullPath;
OpenFolderDialog dialog = new OpenFolderDialog();
dialog.Title = @"Select destination folder";
if (dialog.ShowDialog() == true)
{
string extractPath = dialog.ResultPath;
if (IsSubPCKNode(node.FullPath) && node.Tag == null)
{
GetAllChildNodes(node.Nodes).ForEach(fileNode =>
{
if (fileNode.TryGetTagData(out PckFileData file))
{
Directory.CreateDirectory($"{extractPath}/{Path.GetDirectoryName(file.Filename)}");
File.WriteAllBytes($"{extractPath}/{file.Filename}", file.Data);
if (file.Properties.Count > 0)
{
using var fs = File.CreateText($"{extractPath}/{file.Filename}.txt");
file.Properties.ForEach(property => fs.WriteLine($"{property.Key}: {property.Value}"));
}
}
}
);
}
else
{
foreach (var _file in currentPCK.GetFiles())
{
if (_file.Filename.StartsWith(selectedFolder))
{
Directory.CreateDirectory($"{extractPath}/{Path.GetDirectoryName(_file.Filename)}");
File.WriteAllBytes($"{extractPath}/{_file.Filename}", _file.Data);
if (_file.Properties.Count > 0)
{
using var fs = File.CreateText($"{extractPath}/{_file.Filename}.txt");
_file.Properties.ForEach(property => fs.WriteLine($"{property.Key}: {property.Value}"));
}
}
};
}
MessageBox.Show("Folder Extracted");
}
// Verification that file extraction path was successful
MessageBox.Show($"\"{node.Text}\" successfully extracted");
}
private void SaveTemplate()
@@ -640,7 +683,7 @@ namespace PckStudio
{
Save(saveFileDialog.FileName);
saveLocation = saveFileDialog.FileName;
pckFileLabel.Text = "Current PCK File: " + Path.GetFileName(saveLocation);
pckFileLabel.Text = Path.GetFileName(saveLocation);
isTemplateFile = false;
}
}
@@ -710,8 +753,10 @@ namespace PckStudio
{
if (TryGetLocFile(out LOCFile locFile))
{
locFile.RemoveLocKey(file.Properties.GetPropertyValue("THEMENAMEID"));
locFile.RemoveLocKey(file.Properties.GetPropertyValue("DISPLAYNAMEID"));
if (file.TryGetProperty("THEMENAMEID", out string value))
locFile.RemoveLocKey(value);
if (file.TryGetProperty("DISPLAYNAMEID", out value))
locFile.RemoveLocKey(value);
TrySetLocFile(locFile);
}
}
@@ -784,14 +829,10 @@ namespace PckStudio
private void createSkinToolStripMenuItem_Click(object sender, EventArgs e)
{
if (!TryGetLocFile(out LOCFile locFile))
{
MessageBox.Show("No .loc file found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
using (AddNewSkin addNewSkinDialog = new AddNewSkin(locFile))
using (AddNewSkin addNewSkinDialog = new AddNewSkin())
if (addNewSkinDialog.ShowDialog() == DialogResult.OK)
{
TryGetLocFile(out LOCFile locFile);
var skinFile = addNewSkinDialog.NewSkin.CreateFile(locFile);
currentPCK.AddFile(skinFile);
if (currentPCK.HasFile("Skins.pck", PckFileType.SkinDataFile)) // Prioritize Skins.pck
@@ -836,10 +877,10 @@ namespace PckStudio
}
}
TrySetLocFile(locFile);
wasModified = true;
BuildMainTreeView();
}
TrySetLocFile(locFile);
wasModified = true;
BuildMainTreeView();
}
}
private static PckFileData CreateNewAudioFile(bool isLittle)
@@ -973,7 +1014,8 @@ namespace PckStudio
if (node.Tag is PckFileData node_file)
{
PckFileData new_file = newPCKFile.CreateNewFile(node_file.Filename.Replace(parent_file.Filename + "/", String.Empty), node_file.Filetype);
foreach (var prop in node_file.Properties) new_file.Properties.Add(prop);
foreach (var prop in node_file.GetProperties())
new_file.AddProperty(prop);
new_file.SetData(node_file.Data);
}
}
@@ -1012,8 +1054,7 @@ namespace PckStudio
if (treeMeta.SelectedNode is TreeNode subnode && subnode.Tag is KeyValuePair<string, string> property &&
treeViewMain.SelectedNode is TreeNode node && node.Tag is PckFileData file)
{
int i = file.Properties.IndexOf(property);
if (i != -1)
if (file.HasProperty(property.Key))
{
switch (property.Key)
{
@@ -1023,7 +1064,7 @@ namespace PckStudio
using ANIMEditor diag = new ANIMEditor(property.Value);
if (diag.ShowDialog(this) == DialogResult.OK)
{
file.Properties[i] = new KeyValuePair<string, string>("ANIM", diag.ResultAnim.ToString());
file.SetProperty(file.GetPropertyIndex(property), new KeyValuePair<string, string>("ANIM", diag.ResultAnim.ToString()));
RebuildSubPCK(treeViewMain.SelectedNode.FullPath);
ReloadMetaTreeView();
wasModified = true;
@@ -1044,7 +1085,7 @@ namespace PckStudio
using BoxEditor diag = new BoxEditor(property.Value, IsSubPCKNode(treeViewMain.SelectedNode.FullPath));
if (diag.ShowDialog(this) == DialogResult.OK)
{
file.Properties[i] = new KeyValuePair<string, string>("BOX", diag.Result.ToString());
file.SetProperty(file.GetPropertyIndex(property), new KeyValuePair<string, string>("BOX", diag.Result.ToString()));
RebuildSubPCK(treeViewMain.SelectedNode.FullPath);
ReloadMetaTreeView();
wasModified = true;
@@ -1068,7 +1109,7 @@ namespace PckStudio
{
if (addProperty.ShowDialog() == DialogResult.OK)
{
file.Properties[i] = addProperty.Property;
file.SetProperty(file.GetPropertyIndex(property), addProperty.Property);
RebuildSubPCK(treeViewMain.SelectedNode.FullPath);
ReloadMetaTreeView();
wasModified = true;
@@ -1095,7 +1136,10 @@ namespace PckStudio
TreeNode newNode = new TreeNode();
newNode.Text = Path.GetFileName(diag.NewText);
var newFile = new PckFileData(diag.NewText, file.Filetype);
file.Properties.ForEach(newFile.Properties.Add);
foreach (var property in file.GetProperties())
{
newFile.AddProperty(property);
}
newFile.SetData(file.Data);
newFile.Filename = diag.NewText;
newNode.Tag = newFile;
@@ -1127,7 +1171,7 @@ namespace PckStudio
{
if (treeMeta.SelectedNode is TreeNode t && t.Tag is KeyValuePair<string, string> property &&
treeViewMain.SelectedNode is TreeNode main && main.Tag is PckFileData file &&
file.Properties.Remove(property))
file.RemoveProperty(property))
{
treeMeta.SelectedNode.Remove();
RebuildSubPCK(treeViewMain.SelectedNode.FullPath);
@@ -1141,7 +1185,7 @@ namespace PckStudio
if (treeViewMain.SelectedNode is TreeNode node &&
node.Tag is PckFileData file)
{
foreach (var property in file.Properties)
foreach (var property in file.GetProperties())
{
treeMeta.Nodes.Add(CreateNode(property.Key, property));
}
@@ -1156,7 +1200,7 @@ namespace PckStudio
using AddPropertyPrompt addProperty = new AddPropertyPrompt();
if (addProperty.ShowDialog() == DialogResult.OK)
{
file.Properties.Add(addProperty.Property);
file.AddProperty(addProperty.Property);
RebuildSubPCK(treeViewMain.SelectedNode.FullPath);
ReloadMetaTreeView();
wasModified = true;
@@ -1200,8 +1244,8 @@ namespace PckStudio
var pack = new PckFile(3);
var zeroFile = pack.CreateNewFile("0", PckFileType.InfoFile);
zeroFile.Properties.Add("PACKID", packId.ToString());
zeroFile.Properties.Add("PACKVERSION", packVersion.ToString());
zeroFile.AddProperty("PACKID", packId);
zeroFile.AddProperty("PACKVERSION", packVersion);
var locFile = new LOCFile();
locFile.InitializeDefault(packName);
@@ -1229,8 +1273,8 @@ namespace PckStudio
var texturepackInfo = pack.CreateNewFile($"{res}/{res}Info.pck", PckFileType.TexturePackInfoFile);
texturepackInfo.Properties.Add("PACKID", "0");
texturepackInfo.Properties.Add("DATAPATH", $"{res}Data.pck");
texturepackInfo.AddProperty("PACKID", "0");
texturepackInfo.AddProperty("DATAPATH", $"{res}Data.pck");
texturepackInfo.SetData(new PckFileWriter(infoPCK, LittleEndianCheckBox.Checked ? OMI.Endianness.LittleEndian : OMI.Endianness.BigEndian));
@@ -1385,7 +1429,7 @@ namespace PckStudio
//attempts to generate reimportable metadata file out of minefiles metadata
string metaData = "";
foreach (var entry in file.Properties)
foreach (var entry in file.GetProperties())
{
metaData += $"{entry.Key}: {entry.Value}{Environment.NewLine}";
}
@@ -1463,7 +1507,7 @@ namespace PckStudio
{
string[] param = property.Split(':');
if (param.Length < 2) continue;
newFile.Properties.Add((param[0], param[1]));
newFile.AddProperty(param[0], param[1]);
//switch (param[0])
//{
// case "DISPLAYNAMEID":
@@ -1597,7 +1641,7 @@ namespace PckStudio
{
}
mfNew.Properties.Add(new KeyValuePair<string, string>(key, value));
mfNew.AddProperty(key, value);
}
wasModified = true;
}
@@ -1639,11 +1683,6 @@ namespace PckStudio
}
}
private void convertToBedrockToolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show("This feature is currently being reworked.", "Currently unavailable", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void openPckCenterToolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show("This feature is currently being reworked.", "Currently unavailable", MessageBoxButtons.OK, MessageBoxIcon.Information);
@@ -1884,7 +1923,7 @@ namespace PckStudio
"File path: " + file.Filename +
"\nAssigned File type: " + (int)file.Filetype + " (" + file.Filetype + ")" +
"\nFile size: " + file.Size +
"\nProperties count: " + file.Properties.Count
"\nProperties count: " + file.PropertyCount
, Path.GetFileName(file.Filename) + " file info");
}
}
@@ -1995,7 +2034,7 @@ namespace PckStudio
int idx = line.IndexOf(' ');
if (idx == -1 || line.Length - 1 == idx)
continue;
file.Properties.Add((line.Substring(0, idx), line.Substring(idx + 1)));
file.AddProperty(line.Substring(0, idx), line.Substring(idx + 1));
}
ReloadMetaTreeView();
RebuildSubPCK(treeViewMain.SelectedNode.FullPath);
@@ -2010,9 +2049,10 @@ namespace PckStudio
if (treeViewMain.SelectedNode.TryGetTagData(out PckFileData file) &&
file.Filetype == PckFileType.SkinFile)
{
foreach (var p in file.Properties.FindAll(s => s.Key == "BOX" || s.Key == "OFFSET"))
foreach (var p in file.GetProperties())
{
file.Properties[file.Properties.IndexOf(p)] = new KeyValuePair<string, string>(p.Key, p.Value.Replace(',', '.'));
if (p.Key == "BOX" || p.Key == "OFFSET")
file.SetProperty(file.GetPropertyIndex(p), new KeyValuePair<string, string>(p.Key, p.Value.Replace(',', '.')));
}
ReloadMetaTreeView();
RebuildSubPCK(treeViewMain.SelectedNode.FullPath);
@@ -2020,91 +2060,6 @@ namespace PckStudio
}
}
private void addCustomPackIconToolStripMenuItem_Click(object sender, EventArgs e)
{
string packID = "0";
using NumericPrompt numericPrompt = new NumericPrompt(0);
numericPrompt.Minimum = 0; // TODO: put min pack ID value (keeping this 0 just to be safe)
numericPrompt.Maximum = int.MinValue; // TODO: put max pack ID value
numericPrompt.ContextLabel.Text = "Please insert the desired Pack ID";
numericPrompt.TextLabel.Text = "Pack ID";
if (currentPCK is not null)
{
DialogResult prompt = MessageBox.Show(this,
"Would you like to use the current PackID? You can enter any PackID if not.",
"",
MessageBoxButtons.YesNoCancel);
switch (prompt)
{
case DialogResult.Yes:
if (!currentPCK.TryGetFile("0", PckFileType.InfoFile, out PckFileData file) ||
string.IsNullOrEmpty(file.Properties.GetPropertyValue("PACKID")))
{
MessageBox.Show(this,
"No PackID is present in this PCK. " +
"To avoid this error, ensure that the PCK has a proper PackID property on the \"0\" Info file before trying again.",
"Operation Aborted", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
packID = file.Properties.GetPropertyValue("PACKID");
break;
case DialogResult.No:
break;
case DialogResult.Cancel:
default:
MessageBox.Show(this, "Operation cancelled");
return;
}
}
else if (numericPrompt.ShowDialog(this) == DialogResult.OK) packID = numericPrompt.SelectedValue.ToString();
else
{
MessageBox.Show(this, "Operation cancelled");
return;
}
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Filter = "Minecraft Archive|*.arc";
if (fileDialog.ShowDialog(this) == DialogResult.OK)
{
var reader = new ARCFileReader();
ConsoleArchive archive = reader.FromFile(fileDialog.FileName);
fileDialog.Filter = "Pack Icon|*.png";
if (fileDialog.ShowDialog(this) == DialogResult.OK)
{
string key = string.Format("Graphics\\PackGraphics\\{0}.png", packID);
if (archive.Keys.Contains(key))
{
DialogResult prompt = MessageBox.Show(this,
"This pack already has a pack icon present in the chosen file. Would you like to replace the pack icon?",
"Icon already exists",
MessageBoxButtons.YesNoCancel);
switch (prompt)
{
case DialogResult.Yes:
archive.Remove(key); // remove file so it can be injected
break;
case DialogResult.No:
case DialogResult.Cancel:
default:
Trace.WriteLine("Operation cancelled", category: nameof(addCustomPackIconToolStripMenuItem_Click));
return;
}
}
archive.Add(key, File.ReadAllBytes(fileDialog.FileName));
var writer = new ARCFileWriter(archive);
writer.WriteToFile(fileDialog.FileName);
MessageBox.Show($"Successfully added {key} to Archive!", "Successfully Added", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
private void CreateSkinsPCKToolStripMenuItem1_Click(object sender, EventArgs e)
{
if (currentPCK.TryGetFile("Skins.pck", PckFileType.SkinDataFile, out _))
@@ -2129,18 +2084,18 @@ namespace PckStudio
{
if (treeViewMain.SelectedNode.TryGetTagData(out PckFileData file))
{
var props = file.Properties.Select(p => p.Key + " " + p.Value);
var props = file.GetProperties().Select(p => p.Key + " " + p.Value);
using (var input = new MultiTextPrompt(props.ToArray()))
{
if (input.ShowDialog(this) == DialogResult.OK)
{
file.Properties.Clear();
file.ClearProperties();
foreach (var line in input.TextOutput)
{
int idx = line.IndexOf(' ');
if (idx == -1 || line.Length - 1 == idx)
continue;
file.Properties.Add((line.Substring(0, idx).Replace(":", string.Empty), line.Substring(idx + 1)));
file.AddProperty(line.Substring(0, idx).Replace(":", string.Empty), line.Substring(idx + 1));
}
ReloadMetaTreeView();
RebuildSubPCK(treeViewMain.SelectedNode.FullPath);
@@ -2268,7 +2223,7 @@ namespace PckStudio
using BoxEditor diag = new BoxEditor(SkinBOX.Empty, IsSubPCKNode(treeViewMain.SelectedNode.FullPath));
if (diag.ShowDialog(this) == DialogResult.OK)
{
file.Properties.Add("BOX", diag.Result);
file.AddProperty("BOX", diag.Result);
RebuildSubPCK(treeViewMain.SelectedNode.FullPath);
ReloadMetaTreeView();
wasModified = true;
@@ -2284,7 +2239,7 @@ namespace PckStudio
using ANIMEditor diag = new ANIMEditor(SkinANIM.Empty);
if (diag.ShowDialog(this) == DialogResult.OK)
{
file.Properties.Add("ANIM", diag.ResultAnim);
file.AddProperty("ANIM", diag.ResultAnim);
RebuildSubPCK(treeViewMain.SelectedNode.FullPath);
ReloadMetaTreeView();
wasModified = true;

View File

@@ -924,7 +924,7 @@
</value>
</data>
<data name="createToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="createToolStripMenuItem.Text" xml:space="preserve">
<value>Create</value>
@@ -991,7 +991,7 @@
</value>
</data>
<data name="importSkinsToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="importSkinsToolStripMenuItem.Text" xml:space="preserve">
<value>Import</value>
@@ -1003,7 +1003,7 @@
<value>Export as 3DS Texture</value>
</data>
<data name="exportToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="exportToolStripMenuItem.Text" xml:space="preserve">
<value>Export</value>
@@ -1081,7 +1081,7 @@
<value>Entity Materials File (.BIN)</value>
</data>
<data name="setFileTypeToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="setFileTypeToolStripMenuItem.Text" xml:space="preserve">
<value>Set File Type</value>
@@ -1105,19 +1105,19 @@
<value>Correct Skin Decimals</value>
</data>
<data name="miscFunctionsToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="miscFunctionsToolStripMenuItem.Text" xml:space="preserve">
<value>Misc. Functions</value>
</data>
<data name="moveUpToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="moveUpToolStripMenuItem.Text" xml:space="preserve">
<value>Move Up</value>
</data>
<data name="moveDownToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="moveDownToolStripMenuItem.Text" xml:space="preserve">
<value>Move Down</value>
@@ -1132,13 +1132,13 @@
</value>
</data>
<data name="extractToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="extractToolStripMenuItem.Text" xml:space="preserve">
<value>Extract</value>
</data>
<data name="cloneFileToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="cloneFileToolStripMenuItem.Text" xml:space="preserve">
<value>Clone</value>
@@ -1151,7 +1151,7 @@
</value>
</data>
<data name="renameFileToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="renameFileToolStripMenuItem.Text" xml:space="preserve">
<value>Rename</value>
@@ -1167,7 +1167,7 @@
</value>
</data>
<data name="replaceToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="replaceToolStripMenuItem.Text" xml:space="preserve">
<value>Replace</value>
@@ -1182,13 +1182,13 @@
</value>
</data>
<data name="deleteFileToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>180, 22</value>
<value>157, 22</value>
</data>
<data name="deleteFileToolStripMenuItem.Text" xml:space="preserve">
<value>Delete</value>
</data>
<data name="contextMenuPCKEntries.Size" type="System.Drawing.Size, System.Drawing">
<value>181, 290</value>
<value>158, 268</value>
</data>
<data name="&gt;&gt;contextMenuPCKEntries.Name" xml:space="preserve">
<value>contextMenuPCKEntries</value>
@@ -1369,46 +1369,14 @@
<data name="quickChangeToolStripMenuItem.Text" xml:space="preserve">
<value>Quick Change</value>
</data>
<data name="convertToBedrockToolStripMenuItem.Enabled" type="System.Boolean, mscorlib">
<value>False</value>
</data>
<data name="convertToBedrockToolStripMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
vAAADrwBlbxySQAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+wAAAJeSURBVDhPhVFp
TxNRFH1/RbGdlsQElaWzdaQgbadFtnkznWlLCm2Q2UCxTqdFFAzTRONSYheIoCjRpmoErBiKW/hi4q+q
bxpoSPzgyfnw7r3nvHvveyD92W/UQ5l9Vt6h5B1S2/Wntnr1977lHxDltVr/7FtaqTLJbc/YU+f8x0GQ
rgfmPgw9aoj390dX6uMSgWlVMvkGT7zqLR5PF34lzL3w9HZXunZNfuedr/nAw+9RnnZt/dHl1+SN2lWO
cS3sDsVxbOEgsPwTFo9Tz38nRdIRK15MvvRIlBtIFKboSoTGRMp5e4+VaEeEdoi0Y2r7kkBjyqcBjsEW
x3s4xomUWUiAkhoweLqiBRurEFLujVl/lvfkICESFyK0M0qc1xU5KxAlOSzQbtuQm+iWiHMVjd2Q++9A
b0X3C2SHSHYIpNPgGZMnRbIzLeBZrs8QmH1rEuw+iEVo1xLfl+O6nqzcvQd7MpDay6cQm2fwTBnO8sQL
xQcaFq+GLm/eGtm8OfY4N2NN+VBhbWawmhmzhQDYbDatSSafGECDgC/WFFLUrdTBanRNGUbLoDADiTVt
5KwBJQvaaFG9Dspq0Ji4YghEWQtlJvCCHLJ1bZwa2rANJZ2VvO5FAUdEh1a6pfuXJ4a5EdTxWz6GaPL4
fw0hkydysK+khdFUh5ZkG9o41bUBDA6HjGsd7Qo9ZR0tzR5ZcdRwietu1U8M6NKv+XjDioIM5ylqYfRB
izwRoZwmpCoqW9KDJjwzW7N5aMXLGoveEBRV1uQ9EarzKB/LQlyiXOj/JS+GmtiGU6BwXQ2sa8G/5oRp
fQPDL0EAAAAASUVORK5CYII=
</value>
</data>
<data name="convertToBedrockToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>192, 22</value>
</data>
<data name="convertToBedrockToolStripMenuItem.Text" xml:space="preserve">
<value>Convert to Bedrock</value>
</data>
<data name="editToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>39, 20</value>
</data>
<data name="editToolStripMenuItem.Text" xml:space="preserve">
<value>Edit</value>
</data>
<data name="addCustomPackImageToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>195, 22</value>
</data>
<data name="addCustomPackImageToolStripMenuItem.Text" xml:space="preserve">
<value>Add Custom Pack Icon</value>
</data>
<data name="openPckManagerToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>195, 22</value>
<value>180, 22</value>
</data>
<data name="openPckManagerToolStripMenuItem.Text" xml:space="preserve">
<value>Pck Manager</value>
@@ -1426,7 +1394,7 @@
<value>Binka -&gt; Wav</value>
</data>
<data name="convertMusicFilesToolStripMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>195, 22</value>
<value>180, 22</value>
</data>
<data name="convertMusicFilesToolStripMenuItem.Text" xml:space="preserve">
<value>Audio Converter</value>
@@ -6771,24 +6739,12 @@
<data name="&gt;&gt;quickChangeToolStripMenuItem.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;convertToBedrockToolStripMenuItem.Name" xml:space="preserve">
<value>convertToBedrockToolStripMenuItem</value>
</data>
<data name="&gt;&gt;convertToBedrockToolStripMenuItem.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;miscToolStripMenuItem.Name" xml:space="preserve">
<value>miscToolStripMenuItem</value>
</data>
<data name="&gt;&gt;miscToolStripMenuItem.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;addCustomPackImageToolStripMenuItem.Name" xml:space="preserve">
<value>addCustomPackImageToolStripMenuItem</value>
</data>
<data name="&gt;&gt;addCustomPackImageToolStripMenuItem.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;openPckManagerToolStripMenuItem.Name" xml:space="preserve">
<value>openPckManagerToolStripMenuItem</value>
</data>

View File

@@ -134,6 +134,7 @@
<Reference Include="WindowsFormsIntegration" />
</ItemGroup>
<ItemGroup>
<Compile Include="Extensions\LocFileExtensions.cs" />
<Compile Include="Extensions\CursorExtensions.cs" />
<Compile Include="Extensions\PckFileDataExtensions.cs" />
<Compile Include="Extensions\SkinBOXExtensions.cs" />
@@ -480,6 +481,7 @@
</EmbeddedResource>
<EmbeddedResource Include="Forms\Additional-Popups\EntityForms\AddEntry.resx">
<DependentUpon>AddEntry.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Additional-Popups\Loc\AddLanguage.resx">
<DependentUpon>AddLanguage.cs</DependentUpon>
@@ -555,6 +557,7 @@
</EmbeddedResource>
<EmbeddedResource Include="Forms\Additional-Popups\Grf\AddParameter.resx">
<DependentUpon>AddParameter.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Additional-Popups\InProgressPrompt.resx">
<DependentUpon>InProgressPrompt.cs</DependentUpon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -225,7 +225,7 @@
{ "": "" },
{ "": "" },
{ "villager": "Villager (PS4 EXCLUSIVE)" },
{ "zombie_villager": "Villager (PS4 EXCLUSIVE)" },
{ "zombie_villager": "Zombie Villager (PS4 EXCLUSIVE)" },
{ "": "" },
{ "phantom_invisible": "Phantom (Second Layer)" },
{ "enderman_invisible": "Enderman (Second Layer)" },

View File

@@ -521,7 +521,16 @@
},
{
"internalName": "stem_straight",
"displayName": "Stem"
"displayName": "Stem",
"hasColourEntry": true,
"colourEntry": {
"isWaterColour": false,
"defaultName": "Tile_StemMin",
"variants": [
"Tile_StemMin",
"Tile_StemMax"
]
}
},
{
"internalName": "rail_normal_turned",
@@ -585,7 +594,16 @@
},
{
"internalName": "stem_bent",
"displayName": "Stem (Attached)"
"displayName": "Stem (Attached)",
"hasColourEntry": true,
"colourEntry": {
"isWaterColour": false,
"defaultName": "Tile_StemMin",
"variants": [
"Tile_StemMin",
"Tile_StemMax"
]
}
},
{
"internalName": "rail_normal",
@@ -673,7 +691,19 @@
},
{
"internalName": "vine",
"displayName": "Vines"
"displayName": "Vines",
"hasColourEntry": true,
"colourEntry": {
"isWaterColour": false,
"defaultName": "Foliage_Default",
"variants": [
"Foliage_Default",
"Foliage_Evergreen",
"Foliage_Birch",
"Foliage_Mesa",
"Foliage_Swampland"
]
}
},
{
"internalName": "lapis_block",
@@ -971,8 +1001,49 @@
"hasColourEntry": true,
"colourEntry": {
"isWaterColour": true,
"defaultName": "default",
"variants": [ "default" ]
"defaultName": "Water_Plains",
"variants": [
"Water_Ocean",
"Water_Plains",
"Water_Desert",
"Water_ExtremeHills",
"Water_Forest",
"Water_Taiga",
"Water_Swampland",
"Water_River",
"Water_Hell",
"Water_Sky",
"Water_FrozenOcean",
"Water_FrozenRiver",
"Water_IcePlains",
"Water_IceMountains",
"Water_MushroomIsland",
"Water_MushroomIslandShore",
"Water_Beach",
"Water_DesertHills",
"Water_ForestHills",
"Water_TaigaHills",
"Water_ExtremeHillsEdge",
"Water_Jungle",
"Water_JungleHills",
"Water_JungleEdge",
"Water_DeepOcean",
"Water_StoneBeach",
"Water_ColdBeach",
"Water_BirchForest",
"Water_BirchForestHills",
"Water_RoofedForest",
"Water_ColdTaiga",
"Water_ColdTaigaHills",
"Water_MegaTaiga",
"Water_MegaTaigaHills",
"Water_ExtremeHillsPlus",
"Water_Savanna",
"Water_SavannaPlateau",
"Water_Mesa",
"Water_MesaPlateauF",
"Water_MesaPlateau"
]
}
},
{
@@ -981,8 +1052,49 @@
"hasColourEntry": true,
"colourEntry": {
"isWaterColour": true,
"defaultName": "default",
"variants": [ "default" ]
"defaultName": "Water_Plains",
"variants": [
"Water_Ocean",
"Water_Plains",
"Water_Desert",
"Water_ExtremeHills",
"Water_Forest",
"Water_Taiga",
"Water_Swampland",
"Water_River",
"Water_Hell",
"Water_Sky",
"Water_FrozenOcean",
"Water_FrozenRiver",
"Water_IcePlains",
"Water_IceMountains",
"Water_MushroomIsland",
"Water_MushroomIslandShore",
"Water_Beach",
"Water_DesertHills",
"Water_ForestHills",
"Water_TaigaHills",
"Water_ExtremeHillsEdge",
"Water_Jungle",
"Water_JungleHills",
"Water_JungleEdge",
"Water_DeepOcean",
"Water_StoneBeach",
"Water_ColdBeach",
"Water_BirchForest",
"Water_BirchForestHills",
"Water_RoofedForest",
"Water_ColdTaiga",
"Water_ColdTaigaHills",
"Water_MegaTaiga",
"Water_MegaTaigaHills",
"Water_ExtremeHillsPlus",
"Water_Savanna",
"Water_SavannaPlateau",
"Water_Mesa",
"Water_MesaPlateauF",
"Water_MesaPlateau"
]
}
},
{
@@ -1439,11 +1551,33 @@
},
{
"internalName": "double_plant_fern_top",
"displayName": "Large Fern (Top)"
"displayName": "Large Fern (Top)",
"hasColourEntry": true,
"colourEntry": {
"isWaterColour": false,
"defaultName": "Grass_Common",
"variants": [
"Grass_Common",
"Grass_Mesa",
"Grass_Swamp1",
"Grass_Swamp2"
]
}
},
{
"internalName": "double_plant_grass_top",
"displayName": "Double Tall Grass (Top)"
"displayName": "Double Tall Grass (Top)",
"hasColourEntry": true,
"colourEntry": {
"isWaterColour": false,
"defaultName": "Grass_Common",
"variants": [
"Grass_Common",
"Grass_Mesa",
"Grass_Swamp1",
"Grass_Swamp2"
]
}
},
{
"internalName": "double_plant_paeonia_top",
@@ -1527,11 +1661,33 @@
},
{
"internalName": "double_plant_fern_bottom",
"displayName": "Large Fern (Bottom)"
"displayName": "Large Fern (Bottom)",
"hasColourEntry": true,
"colourEntry": {
"isWaterColour": false,
"defaultName": "Grass_Common",
"variants": [
"Grass_Common",
"Grass_Mesa",
"Grass_Swamp1",
"Grass_Swamp2"
]
}
},
{
"internalName": "double_plant_grass_bottom",
"displayName": "Double Tall Grass (Bottom)"
"displayName": "Double Tall Grass (Bottom)",
"hasColourEntry": true,
"colourEntry": {
"isWaterColour": false,
"defaultName": "Grass_Common",
"variants": [
"Grass_Common",
"Grass_Mesa",
"Grass_Swamp1",
"Grass_Swamp2"
]
}
},
{
"internalName": "double_plant_paeonia_bottom",
@@ -2318,15 +2474,15 @@
"displayName": "Kelp (Bottom)"
},
{
"internalName": "",
"internalName": "kelp_a",
"displayName": ""
},
{
"internalName": "",
"internalName": "kelp_a",
"displayName": ""
},
{
"internalName": "",
"internalName": "kelp_a",
"displayName": ""
},
{
@@ -2334,15 +2490,15 @@
"displayName": "Kelp (Top)"
},
{
"internalName": "",
"internalName": "kelp_top_a",
"displayName": ""
},
{
"internalName": "",
"internalName": "kelp_top_a",
"displayName": ""
},
{
"internalName": "",
"internalName": "kelp_top_a",
"displayName": ""
},
{

2
Vendor/OMI-Lib vendored