diff --git a/Dat/Objects/BuildingObject.cs b/Dat/Objects/BuildingObject.cs index 26b7d284..a2aa975e 100644 --- a/Dat/Objects/BuildingObject.cs +++ b/Dat/Objects/BuildingObject.cs @@ -22,11 +22,11 @@ public enum BuildingObjectFlags : uint8_t public record BuildingObject( [property: LocoStructOffset(0x00), LocoString, Browsable(false)] string_id Name, [property: LocoStructOffset(0x02), Browsable(false)] image_id Image, - [property: LocoStructOffset(0x06)] uint8_t NumBuildingParts, - [property: LocoStructOffset(0x07)] uint8_t NumBuildingVariations, - [property: LocoStructOffset(0x08), LocoStructVariableLoad, LocoArrayLength(BuildingObject.BuildingHeightCount)] List BuildingHeights, - [property: LocoStructOffset(0x0C), LocoStructVariableLoad, LocoArrayLength(BuildingObject.BuildingAnimationCount)] List BuildingAnimations, - [property: LocoStructOffset(0x10), LocoStructVariableLoad, LocoArrayLength(BuildingObject.BuildingVariationCount)] List> BuildingVariations, + [property: LocoStructOffset(0x06)] uint8_t NumParts, + [property: LocoStructOffset(0x07)] uint8_t NumVariations, + [property: LocoStructOffset(0x08), LocoStructVariableLoad, LocoArrayLength(BuildingObject.MaxNumParts)] List PartHeights, + [property: LocoStructOffset(0x0C), LocoStructVariableLoad, LocoArrayLength(BuildingObject.MaxNumParts)] List PartAnimations, + [property: LocoStructOffset(0x10), LocoStructVariableLoad, LocoArrayLength(BuildingObject.VariationPartCount)] List> VariationParts, [property: LocoStructOffset(0x90)] uint32_t Colours, [property: LocoStructOffset(0x94)] uint16_t DesignedYear, [property: LocoStructOffset(0x96)] uint16_t ObsoleteYear, @@ -48,9 +48,8 @@ public record BuildingObject( [property: LocoStructOffset(0xAE), LocoStructVariableLoad, LocoArrayLength(BuildingObject.MaxElevatorHeightSequences)] List _ElevatorHeightSequences // 0xAE ->0xB2->0xB6->0xBA->0xBE (4 byte pointers) ) : ILocoStruct, ILocoStructVariableData { - public const int BuildingVariationCount = 32; - public const int BuildingHeightCount = 4; - public const int BuildingAnimationCount = 2; + public const int MaxNumParts = 4; + public const int VariationPartCount = 32; public const int MaxProducedCargoType = 2; public const int MaxRequiredCargoType = 2; public const int MaxElevatorHeightSequences = 4; @@ -62,20 +61,20 @@ public record BuildingObject( public ReadOnlySpan Load(ReadOnlySpan remainingData) { // variation heights - BuildingHeights.Clear(); - BuildingHeights.AddRange(ByteReaderT.Read_Array(remainingData[..(NumBuildingParts * 1)], NumBuildingParts)); - remainingData = remainingData[(NumBuildingParts * 1)..]; // uint8_t* + PartHeights.Clear(); + PartHeights.AddRange(ByteReaderT.Read_Array(remainingData[..(NumParts * 1)], NumParts)); + remainingData = remainingData[(NumParts * 1)..]; // uint8_t* // variation animations - BuildingAnimations.Clear(); + PartAnimations.Clear(); var buildingAnimationSize = ObjectAttributes.StructSize(); - BuildingAnimations.AddRange(ByteReader.ReadLocoStructArray(remainingData[..(NumBuildingParts * buildingAnimationSize)], typeof(BuildingPartAnimation), NumBuildingParts, buildingAnimationSize) + PartAnimations.AddRange(ByteReader.ReadLocoStructArray(remainingData[..(NumParts * buildingAnimationSize)], typeof(BuildingPartAnimation), NumParts, buildingAnimationSize) .Cast()); - remainingData = remainingData[(NumBuildingParts * 2)..]; // uint16_t* + remainingData = remainingData[(NumParts * 2)..]; // uint16_t* // variation parts - BuildingVariations.Clear(); - for (var i = 0; i < NumBuildingVariations; ++i) + VariationParts.Clear(); + for (var i = 0; i < NumVariations; ++i) { var ptr_10 = 0; while (remainingData[++ptr_10] != 0xFF) @@ -83,7 +82,7 @@ public ReadOnlySpan Load(ReadOnlySpan remainingData) ; } - BuildingVariations.Add(remainingData[..ptr_10].ToArray().ToList()); + VariationParts.Add(remainingData[..ptr_10].ToArray().ToList()); ptr_10++; remainingData = remainingData[ptr_10..]; } @@ -117,20 +116,20 @@ public ReadOnlySpan Save() var ms = new MemoryStream(); // variation heights - foreach (var x in BuildingHeights) + foreach (var x in PartHeights) { ms.WriteByte(x); } // variation animations - foreach (var x in BuildingAnimations) + foreach (var x in PartAnimations) { ms.WriteByte(x.NumFrames); ms.WriteByte(x.AnimationSpeed); } // variation parts - foreach (var x in BuildingVariations) + foreach (var x in VariationParts) { ms.Write(x.ToArray()); ms.WriteByte(0xFF); @@ -161,7 +160,7 @@ public ReadOnlySpan Save() } public bool Validate() - => NumBuildingParts is not 0 and not > 63 - && NumBuildingVariations is not 0 and <= 31; + => NumParts is not 0 and not > 63 + && NumVariations is not 0 and <= 31; } } diff --git a/Dat/Objects/Industry/IndustryObject.cs b/Dat/Objects/Industry/IndustryObject.cs index dfd711ea..1f5056ce 100644 --- a/Dat/Objects/Industry/IndustryObject.cs +++ b/Dat/Objects/Industry/IndustryObject.cs @@ -24,11 +24,11 @@ public record IndustryObject( [property: LocoStructOffset(0x1A), Browsable(false)] image_id _var_1A, [property: LocoStructOffset(0x1E)] uint8_t NumBuildingParts, [property: LocoStructOffset(0x1F)] uint8_t NumBuildingVariations, - [property: LocoStructOffset(0x20), LocoStructVariableLoad, LocoArrayLength(IndustryObject.BuildingHeightCount)] List BuildingHeights, // This is the height of a building image - [property: LocoStructOffset(0x24), LocoStructVariableLoad, LocoArrayLength(IndustryObject.BuildingAnimationCount)] List BuildingAnimations, + [property: LocoStructOffset(0x20), LocoStructVariableLoad, LocoArrayLength(IndustryObject.BuildingHeightCount)] List BuildingPartHeights, // This is the height of a building image + [property: LocoStructOffset(0x24), LocoStructVariableLoad, LocoArrayLength(IndustryObject.BuildingAnimationCount)] List BuildingPartAnimations, [property: LocoStructOffset(0x28), LocoStructVariableLoad, LocoArrayLength(IndustryObject.AnimationSequencesCount)] List> AnimationSequences, // Access with getAnimationSequence helper method [property: LocoStructOffset(0x38), LocoStructVariableLoad] List var_38, // Access with getUnk38 helper method - [property: LocoStructOffset(0x3C), LocoStructVariableLoad, LocoArrayLength(IndustryObject.BuildingVariationCount)] List> BuildingVariations, // Access with getBuildingParts helper method + [property: LocoStructOffset(0x3C), LocoStructVariableLoad, LocoArrayLength(IndustryObject.BuildingVariationCount)] List> BuildingVariationParts, // Access with getBuildingParts helper method [property: LocoStructOffset(0xBC)] uint8_t MinNumBuildings, [property: LocoStructOffset(0xBD)] uint8_t MaxNumBuildings, [property: LocoStructOffset(0xBE), LocoStructVariableLoad] List Buildings, @@ -67,8 +67,6 @@ public record IndustryObject( public const int MaxRequiredCargoType = 3; public const int MaxWallTypeCount = 4; - //public List UnkIndustry38 { get; set; } = []; - public S5Header? BuildingWall { get; set; } public S5Header? BuildingWallEntrance { get; set; } @@ -81,14 +79,14 @@ public record IndustryObject( public ReadOnlySpan Load(ReadOnlySpan remainingData) { // part heights - BuildingHeights.Clear(); - BuildingHeights.AddRange(ByteReaderT.Read_Array(remainingData[..(NumBuildingParts * 1)], NumBuildingParts)); + BuildingPartHeights.Clear(); + BuildingPartHeights.AddRange(ByteReaderT.Read_Array(remainingData[..(NumBuildingParts * 1)], NumBuildingParts)); remainingData = remainingData[(NumBuildingParts * 1)..]; // uint8_t* // part animations - BuildingAnimations.Clear(); + BuildingPartAnimations.Clear(); var buildingAnimationSize = ObjectAttributes.StructSize(); - BuildingAnimations.AddRange(ByteReader.ReadLocoStructArray(remainingData[..(NumBuildingParts * buildingAnimationSize)], typeof(BuildingPartAnimation), NumBuildingParts, buildingAnimationSize) + BuildingPartAnimations.AddRange(ByteReader.ReadLocoStructArray(remainingData[..(NumBuildingParts * buildingAnimationSize)], typeof(BuildingPartAnimation), NumBuildingParts, buildingAnimationSize) .Cast()); remainingData = remainingData[(NumBuildingParts * 2)..]; // uint16_t* @@ -119,7 +117,7 @@ public ReadOnlySpan Load(ReadOnlySpan remainingData) remainingData = remainingData[1..]; // skip final 0xFF byte // variation parts - BuildingVariations.Clear(); + BuildingVariationParts.Clear(); for (var i = 0; i < NumBuildingVariations; ++i) { var ptr_1F = 0; @@ -128,7 +126,7 @@ public ReadOnlySpan Load(ReadOnlySpan remainingData) ; } - BuildingVariations.Add(remainingData[..ptr_1F].ToArray().ToList()); + BuildingVariationParts.Add(remainingData[..ptr_1F].ToArray().ToList()); ptr_1F++; remainingData = remainingData[ptr_1F..]; } @@ -188,13 +186,13 @@ public ReadOnlySpan Save() using (var ms = new MemoryStream()) { // part heights - foreach (var x in BuildingHeights) + foreach (var x in BuildingPartHeights) { ms.WriteByte(x); } // part animations - foreach (var x in BuildingAnimations) + foreach (var x in BuildingPartAnimations) { ms.WriteByte(x.NumFrames); ms.WriteByte(x.AnimationSpeed); @@ -217,7 +215,7 @@ public ReadOnlySpan Save() ms.WriteByte(0xFF); // variation parts - foreach (var x in BuildingVariations) + foreach (var x in BuildingVariationParts) { ms.Write(x.ToArray()); ms.WriteByte(0xFF); diff --git a/Dat/Objects/TrackObject.cs b/Dat/Objects/TrackObject.cs index 4670e8d4..6771fe0e 100644 --- a/Dat/Objects/TrackObject.cs +++ b/Dat/Objects/TrackObject.cs @@ -22,6 +22,7 @@ public enum TrackTraitFlags : uint16_t Junction = 1 << 10, } + [Flags] public enum TrackObjectFlags : uint16_t { None = 0, diff --git a/Gui/Models/ObjectEditorModel.cs b/Gui/Models/ObjectEditorModel.cs index 488cef12..1877d7a1 100644 --- a/Gui/Models/ObjectEditorModel.cs +++ b/Gui/Models/ObjectEditorModel.cs @@ -251,8 +251,8 @@ public bool TryLoadObject(FileSystemItem filesystemItem, out UiDatLocoFile? uiLo return true; } - static Task? indexerTask; - static readonly SemaphoreSlim taskLock = new(1, 1); + static Task? _indexerTask; + static readonly SemaphoreSlim _taskLock = new(1, 1); public async Task LoadObjDirectoryAsync(string directory, IProgress progress, bool useExistingIndex) { @@ -277,10 +277,10 @@ public async Task LoadObjDirectoryAsync(string directory, IProgress progr } finally { - _ = taskLock.Release(); + _ = _taskLock.Release(); } - await indexerTask; + await _indexerTask; } async Task LoadObjDirectoryAsyncCore(string directory, IProgress progress, bool useExistingIndex) diff --git a/Gui/ViewModels/DatTypes/BaseLocoFileViewModel.cs b/Gui/ViewModels/DatTypes/BaseLocoFileViewModel.cs new file mode 100644 index 00000000..903271d6 --- /dev/null +++ b/Gui/ViewModels/DatTypes/BaseLocoFileViewModel.cs @@ -0,0 +1,50 @@ +using OpenLoco.Common.Logging; +using OpenLoco.Gui.Models; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; +using System.Reactive; + +namespace OpenLoco.Gui.ViewModels +{ + public abstract class BaseLocoFileViewModel : ReactiveObject, ILocoFileViewModel + { + protected BaseLocoFileViewModel(FileSystemItem currentFile, ObjectEditorModel model) + { + CurrentFile = currentFile; + Model = model; + + ReloadCommand = ReactiveCommand.Create(Load); + SaveCommand = ReactiveCommand.Create(Save); + SaveAsCommand = ReactiveCommand.Create(SaveAs); + DeleteLocalFileCommand = ReactiveCommand.Create(Delete); + } + + [Reactive] + public FileSystemItem CurrentFile { get; init; } + public ObjectEditorModel Model { get; init; } + + protected ILogger Logger => Model.Logger; + + public ReactiveCommand ReloadCommand { get; init; } + public ReactiveCommand SaveCommand { get; init; } + public ReactiveCommand SaveAsCommand { get; init; } + public ReactiveCommand DeleteLocalFileCommand { get; init; } + + public abstract void Load(); + + public abstract void Save(); + + public abstract void SaveAs(); + public virtual void Delete() { } + + public string ReloadText => CurrentFile.FileLocation == FileLocation.Local ? "Reload" : "Redownload"; + public string SaveText => CurrentFile.FileLocation == FileLocation.Local ? "Save" : "Download"; + public string SaveAsText => $"{SaveText} As"; + public string DeleteLocalFileText => "Delete File"; + + public string ReloadIcon => CurrentFile.FileLocation == FileLocation.Local ? "DatabaseRefresh" : "FileSync"; + public string SaveIcon => CurrentFile.FileLocation == FileLocation.Local ? "ContentSave" : "FileDownload"; + public string SaveAsIcon => CurrentFile.FileLocation == FileLocation.Local ? "ContentSavePlus" : "FileDownloadOutline"; + public string DeleteLocalFileIcon => "DeleteForever"; + } +} diff --git a/Gui/ViewModels/DatTypes/DatObjectEditorViewModel.cs b/Gui/ViewModels/DatTypes/DatObjectEditorViewModel.cs index 19a51dae..8ad906c2 100644 --- a/Gui/ViewModels/DatTypes/DatObjectEditorViewModel.cs +++ b/Gui/ViewModels/DatTypes/DatObjectEditorViewModel.cs @@ -5,6 +5,7 @@ using OpenLoco.Dat.Objects.Sound; using OpenLoco.Dat.Types; using OpenLoco.Gui.Models; +using PropertyModels.Extensions; using ReactiveUI; using ReactiveUI.Fody.Helpers; using System; @@ -99,6 +100,12 @@ public override void Load() if (CurrentObject?.LocoObject != null) { CurrentObjectViewModel = GetViewModelFromStruct(CurrentObject.LocoObject.Object); + + //if (CurrentObjectViewModel is BuildingViewModel bvm) + //{ + // bvm.Images = G1ImageConversion.CreateAvaloniaImages(CurrentObject.Images).Cast().ToBindingList(); + //} + StringTableViewModel = new(CurrentObject.LocoObject.StringTable); var imageNameProvider = (CurrentObject.LocoObject.Object is IImageTableNameProvider itnp) diff --git a/Gui/ViewModels/DatTypes/ILocoFileViewModel.cs b/Gui/ViewModels/DatTypes/ILocoFileViewModel.cs index 82df5726..f00c060b 100644 --- a/Gui/ViewModels/DatTypes/ILocoFileViewModel.cs +++ b/Gui/ViewModels/DatTypes/ILocoFileViewModel.cs @@ -1,4 +1,3 @@ -using OpenLoco.Common.Logging; using OpenLoco.Gui.Models; using ReactiveUI; using ReactiveUI.Fody.Helpers; @@ -6,16 +5,6 @@ namespace OpenLoco.Gui.ViewModels { - public record FileViewButton(ReactiveCommand Command, string Text, string Icon); - - public interface ILocoFileViewModelControl - { - [Reactive] - public FileSystemItem CurrentFile { get; init; } - - ListObservable Buttons { get; } - } - public interface ILocoFileViewModel { public ReactiveCommand ReloadCommand { get; init; } @@ -39,46 +28,4 @@ public interface ILocoFileViewModel public string SaveAsIcon { get; } public string DeleteLocalFileIcon { get; } } - - public abstract class BaseLocoFileViewModel : ReactiveObject, ILocoFileViewModel - { - protected BaseLocoFileViewModel(FileSystemItem currentFile, ObjectEditorModel model) - { - CurrentFile = currentFile; - Model = model; - - ReloadCommand = ReactiveCommand.Create(Load); - SaveCommand = ReactiveCommand.Create(Save); - SaveAsCommand = ReactiveCommand.Create(SaveAs); - DeleteLocalFileCommand = ReactiveCommand.Create(Delete); - } - - [Reactive] - public FileSystemItem CurrentFile { get; init; } - public ObjectEditorModel Model { get; init; } - - protected ILogger Logger => Model.Logger; - - public ReactiveCommand ReloadCommand { get; init; } - public ReactiveCommand SaveCommand { get; init; } - public ReactiveCommand SaveAsCommand { get; init; } - public ReactiveCommand DeleteLocalFileCommand { get; init; } - - public abstract void Load(); - - public abstract void Save(); - - public abstract void SaveAs(); - public virtual void Delete() { } - - public string ReloadText => CurrentFile.FileLocation == FileLocation.Local ? "Reload" : "Redownload"; - public string SaveText => CurrentFile.FileLocation == FileLocation.Local ? "Save" : "Download"; - public string SaveAsText => $"{SaveText} As"; - public string DeleteLocalFileText => "Delete File"; - - public string ReloadIcon => CurrentFile.FileLocation == FileLocation.Local ? "DatabaseRefresh" : "FileSync"; - public string SaveIcon => CurrentFile.FileLocation == FileLocation.Local ? "ContentSave" : "FileDownload"; - public string SaveAsIcon => CurrentFile.FileLocation == FileLocation.Local ? "ContentSavePlus" : "FileDownloadOutline"; - public string DeleteLocalFileIcon => "DeleteForever"; - } } diff --git a/Gui/ViewModels/DatTypes/Objects/BuildingViewModel.cs b/Gui/ViewModels/DatTypes/Objects/BuildingViewModel.cs index 74e86240..c93d3a4a 100644 --- a/Gui/ViewModels/DatTypes/Objects/BuildingViewModel.cs +++ b/Gui/ViewModels/DatTypes/Objects/BuildingViewModel.cs @@ -2,12 +2,20 @@ using OpenLoco.Dat.Objects; using PropertyModels.Extensions; using ReactiveUI.Fody.Helpers; +using SixLabors.ImageSharp; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; namespace OpenLoco.Gui.ViewModels { + [TypeConverter(typeof(ExpandableObjectConverter))] + public class BuildingPart + { + public uint8_t Height { get; set; } + public BuildingPartAnimation Animation { get; set; } + } + public class BuildingViewModel : LocoObjectViewModel { [Reactive] public BuildingObjectFlags Flags { get; set; } @@ -24,9 +32,8 @@ public class BuildingViewModel : LocoObjectViewModel [Reactive, Category("Production"), Length(0, BuildingObject.MaxProducedCargoType)] public BindingList ProducedCargo { get; set; } [Reactive, Category("Production"), Length(0, BuildingObject.MaxProducedCargoType)] public BindingList RequiredCargo { get; set; } [Reactive, Category("Production"), Length(1, BuildingObject.MaxProducedCargoType)] public BindingList ProducedQuantity { get; set; } - [Reactive, Category("Building"), Length(1, BuildingObject.BuildingVariationCount)] public BindingList> BuildingVariations { get; set; } // NumBuildingVariations - [Reactive, Category("Building"), Length(1, BuildingObject.BuildingHeightCount)] public BindingList BuildingHeights { get; set; } // NumBuildingParts - [Reactive, Category("Building"), Length(1, BuildingObject.BuildingAnimationCount)] public BindingList BuildingAnimations { get; set; } // NumBuildingParts + [Reactive, Category("Building"), Length(1, BuildingObject.MaxNumParts)] public BindingList Parts { get; set; } // NumParts + [Reactive, Category("Building"), Length(1, BuildingObject.VariationPartCount)] public BindingList> VariationParts { get; set; } // NumBuildingVariations // note: these height sequences are massive. BLDCTY28 has 2 sequences, 512 in length and 1024 in length. Avalonia PropertyGrid takes 30+ seconds to render this. todo: don't use property grid in future //[Reactive, Category("Building"), Length(1, BuildingObject.MaxElevatorHeightSequences), Browsable(false)] public BindingList> ElevatorHeightSequences { get; set; } // NumElevatorSequences @@ -35,6 +42,9 @@ public class BuildingViewModel : LocoObjectViewModel [Reactive, Category(""), Length(2, 2)] public BindingList var_A8 { get; set; } [Reactive, Category("")] public uint8_t var_AC { get; set; } + //[Reactive] + //public BindingList Images { get; set; } + public BuildingViewModel(BuildingObject bo) { Flags = bo.Flags; @@ -51,9 +61,21 @@ public BuildingViewModel(BuildingObject bo) ProducedCargo = new(bo.ProducedCargo.ConvertAll(x => new S5HeaderViewModel(x))); RequiredCargo = new(bo.RequiredCargo.ConvertAll(x => new S5HeaderViewModel(x))); ProducedQuantity = [.. bo.ProducedQuantity]; - BuildingHeights = new(bo.BuildingHeights); - BuildingAnimations = new(bo.BuildingAnimations); - BuildingVariations = new(bo.BuildingVariations.Select(x => new BindingList(x)).ToBindingList()); + Parts = bo.PartHeights + .Zip(bo.PartAnimations) + .Select(x => new BuildingPart() + { + Height = x.First, + Animation = new BuildingPartAnimation() + { + NumFrames = x.Second.NumFrames, + AnimationSpeed = x.Second.AnimationSpeed + } + }) + .ToBindingList(); + //PartHeights = new(bo.PartHeights); + //PartAnimations = new(bo.PartAnimations); + VariationParts = new(bo.VariationParts.Select(x => new BindingList(x)).ToBindingList()); //ElevatorHeightSequences = new(bo.ElevatorHeightSequences.Select(x => new BindingList(x)).ToBindingList()); var_A6 = new(bo.var_A6); var_A8 = new(bo.var_A8); @@ -77,8 +99,10 @@ public override BuildingObject GetAsStruct(BuildingObject bo) CostIndex = CostIndex, SellCostFactor = SellCostFactor, var_AC = var_AC, - NumBuildingParts = (uint8_t)bo.BuildingAnimations.Count, - NumBuildingVariations = (uint8_t)bo.BuildingVariations.Count, + NumParts = (uint8_t)Parts.Count, + PartHeights = Parts.Select(x => x.Height).ToList(), + PartAnimations = Parts.Select(x => x.Animation).ToList(), + NumVariations = (uint8_t)VariationParts.Count, ProducedQuantity = [.. ProducedQuantity], ProducedCargo = ProducedCargo.ToList().ConvertAll(x => x.GetAsUnderlyingType()), RequiredCargo = RequiredCargo.ToList().ConvertAll(x => x.GetAsUnderlyingType()), diff --git a/Gui/ViewModels/DatTypes/GenericObjectViewModel.cs b/Gui/ViewModels/DatTypes/Objects/GenericObjectViewModel.cs similarity index 100% rename from Gui/ViewModels/DatTypes/GenericObjectViewModel.cs rename to Gui/ViewModels/DatTypes/Objects/GenericObjectViewModel.cs diff --git a/Gui/ViewModels/DatTypes/Objects/IndustryViewModel.cs b/Gui/ViewModels/DatTypes/Objects/IndustryViewModel.cs index 848b958f..9e35e3a0 100644 --- a/Gui/ViewModels/DatTypes/Objects/IndustryViewModel.cs +++ b/Gui/ViewModels/DatTypes/Objects/IndustryViewModel.cs @@ -23,9 +23,9 @@ public class IndustryViewModel : LocoObjectViewModel [Reactive, Category("Cost")] public int16_t BuildCostFactor { get; set; } [Reactive, Category("Cost")] public int16_t SellCostFactor { get; set; } [Reactive, Category("Building"), Length(IndustryObject.AnimationSequencesCount, IndustryObject.AnimationSequencesCount)] public BindingList> AnimationSequences { get; set; } - [Reactive, Category("Building"), Length(1, IndustryObject.BuildingVariationCount)] public BindingList> BuildingVariations { get; set; } // NumBuildingVariations - [Reactive, Category("Building"), Length(1, IndustryObject.BuildingHeightCount)] public BindingList BuildingHeights { get; set; } // NumBuildingParts - [Reactive, Category("Building"), Length(1, IndustryObject.BuildingAnimationCount)] public BindingList BuildingAnimations { get; set; } // NumBuildingParts + [Reactive, Category("Building"), Length(1, IndustryObject.BuildingHeightCount)] public BindingList BuildingPartHeight { get; set; } // NumBuildingParts + [Reactive, Category("Building"), Length(1, IndustryObject.BuildingAnimationCount)] public BindingList BuildingPartAnimations { get; set; } // NumBuildingParts + [Reactive, Category("Building"), Length(1, IndustryObject.BuildingVariationCount)] public BindingList> BuildingVariationParts { get; set; } // NumBuildingVariations [Reactive, Category("Building")] public uint8_t MinNumBuildings { get; set; } [Reactive, Category("Building")] public uint8_t MaxNumBuildings { get; set; } [Reactive, Category("Building")] public BindingList Buildings { get; set; } @@ -47,9 +47,9 @@ public IndustryViewModel(IndustryObject io) { AnimationSequences = new(io.AnimationSequences.Select(x => new BindingList(x)).ToBindingList()); var_38 = new(io.var_38); - BuildingHeights = new(io.BuildingHeights); - BuildingAnimations = new(io.BuildingAnimations); - BuildingVariations = new(io.BuildingVariations.Select(x => new BindingList(x)).ToBindingList()); + BuildingPartHeight = new(io.BuildingPartHeights); + BuildingPartAnimations = new(io.BuildingPartAnimations); + BuildingVariationParts = new(io.BuildingVariationParts.Select(x => new BindingList(x)).ToBindingList()); Buildings = new(io.Buildings); BuildingSizeFlags = io.BuildingSizeFlags; BuildingWall = io.BuildingWall == null ? null : new(io.BuildingWall); @@ -89,8 +89,8 @@ public override IndustryObject GetAsStruct(IndustryObject io) BuildingWallEntrance = BuildingWallEntrance?.GetAsUnderlyingType(), MinNumBuildings = MinNumBuildings, MaxNumBuildings = MaxNumBuildings, - NumBuildingParts = (uint8_t)BuildingAnimations.Count, - NumBuildingVariations = (uint8_t)BuildingVariations.Count, + NumBuildingParts = (uint8_t)BuildingPartAnimations.Count, + NumBuildingVariations = (uint8_t)BuildingVariationParts.Count, ProducedCargo = ProducedCargo.ToList().ConvertAll(x => x.GetAsUnderlyingType()), RequiredCargo = RequiredCargo.ToList().ConvertAll(x => x.GetAsUnderlyingType()), WallTypes = WallTypes.ToList().ConvertAll(x => x.GetAsUnderlyingType()), diff --git a/Gui/ViewModels/FolderTreeViewModel.cs b/Gui/ViewModels/FolderTreeViewModel.cs index 2a661ec2..e5fa966d 100644 --- a/Gui/ViewModels/FolderTreeViewModel.cs +++ b/Gui/ViewModels/FolderTreeViewModel.cs @@ -151,6 +151,8 @@ void SwitchDirectoryItemsView() async Task ReloadDirectoryAsync(bool useExistingIndex) { + Model.Logger.Debug($"UseExistingIndex={useExistingIndex}"); + if (SelectedTabIndex == 0) { // local @@ -166,6 +168,8 @@ async Task ReloadDirectoryAsync(bool useExistingIndex) async Task LoadObjDirectoryAsync(string directory, bool useExistingIndex) { + Model.Logger.Debug($"Directory={directory} UseExistingIndex={useExistingIndex}"); + if (string.IsNullOrEmpty(directory) || !Directory.Exists(directory)) { //LocalDirectoryItems = []; @@ -188,6 +192,8 @@ async Task LoadOnlineDirectoryAsync(bool useExistingIndex) return; } + Model.Logger.Debug($"UseExistingIndex={useExistingIndex}"); + if ((!useExistingIndex || Model.ObjectIndexOnline == null) && Model.WebClient != null) { Model.ObjectIndexOnline = new ObjectIndex((await Client.GetObjectListAsync(Model.WebClient, Model.Logger)) diff --git a/Gui/ViewModels/SubObjectTypes/ColourSwatches.cs b/Gui/ViewModels/SubObjectTypes/ColourSwatches.cs new file mode 100644 index 00000000..ce1f2312 --- /dev/null +++ b/Gui/ViewModels/SubObjectTypes/ColourSwatches.cs @@ -0,0 +1,28 @@ +namespace OpenLoco.Gui.ViewModels +{ + public enum ColourSwatches + { + Black, + Bronze, + Copper, + Yellow, + Rose, + GrassGreen, + AvocadoGreen, + Green, + Brass, + Lavender, + Blue, + SeaGreen, + Purple, + Red, + Orange, + Teal, + Brown, + Amber, + MiscGrey, + MiscYellow, + PrimaryRemap, + SecondaryRemap, + } +} diff --git a/Gui/ViewModels/SubObjectTypes/ImageTableViewModel.cs b/Gui/ViewModels/SubObjectTypes/ImageTableViewModel.cs index b441bba7..7fcbfbf9 100644 --- a/Gui/ViewModels/SubObjectTypes/ImageTableViewModel.cs +++ b/Gui/ViewModels/SubObjectTypes/ImageTableViewModel.cs @@ -15,7 +15,6 @@ using System.Linq; using System.Reactive.Linq; using System.Text.Json; -using System.Text.Json.Serialization; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows.Input; @@ -23,37 +22,6 @@ namespace OpenLoco.Gui.ViewModels { - public enum ColourSwatches - { - Black, - Bronze, - Copper, - Yellow, - Rose, - GrassGreen, - AvocadoGreen, - Green, - Brass, - Lavender, - Blue, - SeaGreen, - Purple, - Red, - Orange, - Teal, - Brown, - Amber, - MiscGrey, - MiscYellow, - PrimaryRemap, - SecondaryRemap, - } - - public record SpriteOffset( - [property: JsonPropertyName("path")] string Path, - [property: JsonPropertyName("x")] int16_t X, - [property: JsonPropertyName("y")] int16_t Y); - public class ImageTableViewModel : ReactiveObject, IExtraContentViewModel { readonly IHasG1Elements G1Provider; diff --git a/Gui/ViewModels/SubObjectTypes/SpriteOffset.cs b/Gui/ViewModels/SubObjectTypes/SpriteOffset.cs new file mode 100644 index 00000000..edcc9c8a --- /dev/null +++ b/Gui/ViewModels/SubObjectTypes/SpriteOffset.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace OpenLoco.Gui.ViewModels +{ + public record SpriteOffset( + [property: JsonPropertyName("path")] string Path, + [property: JsonPropertyName("x")] int16_t X, + [property: JsonPropertyName("y")] int16_t Y); +} diff --git a/Tests/LoadSaveTests.cs b/Tests/LoadSaveTests.cs index 2c22cae2..88001a0a 100644 --- a/Tests/LoadSaveTests.cs +++ b/Tests/LoadSaveTests.cs @@ -192,7 +192,7 @@ void assertFunc(ILocoObject obj, BuildingObject struc) => Assert.Multiple(() => Assert.That(struc.Name, Is.EqualTo(0)); Assert.That(struc.Image, Is.EqualTo(0)); - Assert.That(struc.NumBuildingVariations, Is.EqualTo(5), nameof(struc.NumBuildingVariations)); + Assert.That(struc.NumVariations, Is.EqualTo(5), nameof(struc.NumVariations)); // CollectionAssert.AreEqual(struc.VariationHeights, Array.CreateInstance(typeof(byte), 4), nameof(struc.VariationHeights)); // VariationHeights // VariationAnimations @@ -359,46 +359,46 @@ void assertFunc(ILocoObject obj, IndustryObject struc) => Assert.Multiple(() => Assert.That(struc._BuildingWall, Is.EqualTo(0), nameof(struc._BuildingWall)); Assert.That(struc._BuildingWallEntrance, Is.EqualTo(0), nameof(struc._BuildingWallEntrance)); // BuildingPartHeights - Assert.That(struc.BuildingHeights, Is.EqualTo(new List() { 0, 56, 0, 66, 0, 122, 0, 48, 0, 36 })); + Assert.That(struc.BuildingPartHeights, Is.EqualTo(new List() { 0, 56, 0, 66, 0, 122, 0, 48, 0, 36 })); // BuildingPartAnimations - Assert.That(struc.BuildingAnimations, Has.Count.EqualTo(10)); - Assert.That(struc.BuildingAnimations[0].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[0].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[1].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[1].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[2].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[2].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[3].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[3].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[4].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[4].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[5].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[5].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[6].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[6].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[7].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[7].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[8].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[8].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[9].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[9].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations, Has.Count.EqualTo(10)); + Assert.That(struc.BuildingPartAnimations[0].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[0].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[1].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[1].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[2].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[2].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[3].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[3].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[4].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[4].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[5].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[5].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[6].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[6].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[7].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[7].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[8].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[8].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[9].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[9].AnimationSpeed, Is.EqualTo(0)); // BuildingParts - Assert.That(struc.BuildingVariations, Has.Count.EqualTo(5)); - Assert.That(struc.BuildingVariations[0], Has.Count.EqualTo(2)); - Assert.That(struc.BuildingVariations[0][0], Is.EqualTo(0)); - Assert.That(struc.BuildingVariations[0][1], Is.EqualTo(1)); - Assert.That(struc.BuildingVariations[1], Has.Count.EqualTo(2)); - Assert.That(struc.BuildingVariations[1][0], Is.EqualTo(2)); - Assert.That(struc.BuildingVariations[1][1], Is.EqualTo(3)); - Assert.That(struc.BuildingVariations[2], Has.Count.EqualTo(2)); - Assert.That(struc.BuildingVariations[2][0], Is.EqualTo(4)); - Assert.That(struc.BuildingVariations[2][1], Is.EqualTo(5)); - Assert.That(struc.BuildingVariations[3], Has.Count.EqualTo(2)); - Assert.That(struc.BuildingVariations[3][0], Is.EqualTo(6)); - Assert.That(struc.BuildingVariations[3][1], Is.EqualTo(7)); - Assert.That(struc.BuildingVariations[4], Has.Count.EqualTo(2)); - Assert.That(struc.BuildingVariations[4][0], Is.EqualTo(8)); - Assert.That(struc.BuildingVariations[4][1], Is.EqualTo(9)); + Assert.That(struc.BuildingVariationParts, Has.Count.EqualTo(5)); + Assert.That(struc.BuildingVariationParts[0], Has.Count.EqualTo(2)); + Assert.That(struc.BuildingVariationParts[0][0], Is.EqualTo(0)); + Assert.That(struc.BuildingVariationParts[0][1], Is.EqualTo(1)); + Assert.That(struc.BuildingVariationParts[1], Has.Count.EqualTo(2)); + Assert.That(struc.BuildingVariationParts[1][0], Is.EqualTo(2)); + Assert.That(struc.BuildingVariationParts[1][1], Is.EqualTo(3)); + Assert.That(struc.BuildingVariationParts[2], Has.Count.EqualTo(2)); + Assert.That(struc.BuildingVariationParts[2][0], Is.EqualTo(4)); + Assert.That(struc.BuildingVariationParts[2][1], Is.EqualTo(5)); + Assert.That(struc.BuildingVariationParts[3], Has.Count.EqualTo(2)); + Assert.That(struc.BuildingVariationParts[3][0], Is.EqualTo(6)); + Assert.That(struc.BuildingVariationParts[3][1], Is.EqualTo(7)); + Assert.That(struc.BuildingVariationParts[4], Has.Count.EqualTo(2)); + Assert.That(struc.BuildingVariationParts[4][0], Is.EqualTo(8)); + Assert.That(struc.BuildingVariationParts[4][1], Is.EqualTo(9)); // Rest of object Assert.That(struc.SellCostFactor, Is.EqualTo(240), nameof(struc.SellCostFactor)); Assert.That(struc.BuildCostFactor, Is.EqualTo(400), nameof(struc.BuildCostFactor)); @@ -460,25 +460,25 @@ void assertFunc(ILocoObject obj, IndustryObject struc) => Assert.Multiple(() => Assert.That(struc._BuildingWall, Is.EqualTo(0), nameof(struc._BuildingWall)); Assert.That(struc._BuildingWallEntrance, Is.EqualTo(0), nameof(struc._BuildingWallEntrance)); // BuildingPartHeights - Assert.That(struc.BuildingHeights, Is.EqualTo(new List() { 0, 166, 0, 64, })); + Assert.That(struc.BuildingPartHeights, Is.EqualTo(new List() { 0, 166, 0, 64, })); // BuildingPartAnimations - Assert.That(struc.BuildingAnimations, Has.Count.EqualTo(4)); - Assert.That(struc.BuildingAnimations[0].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[0].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[1].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[1].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[2].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[2].AnimationSpeed, Is.EqualTo(0)); - Assert.That(struc.BuildingAnimations[3].NumFrames, Is.EqualTo(1)); - Assert.That(struc.BuildingAnimations[3].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations, Has.Count.EqualTo(4)); + Assert.That(struc.BuildingPartAnimations[0].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[0].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[1].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[1].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[2].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[2].AnimationSpeed, Is.EqualTo(0)); + Assert.That(struc.BuildingPartAnimations[3].NumFrames, Is.EqualTo(1)); + Assert.That(struc.BuildingPartAnimations[3].AnimationSpeed, Is.EqualTo(0)); // BuildingParts - Assert.That(struc.BuildingVariations, Has.Count.EqualTo(2)); - Assert.That(struc.BuildingVariations[0], Has.Count.EqualTo(2)); - Assert.That(struc.BuildingVariations[0][0], Is.EqualTo(0)); - Assert.That(struc.BuildingVariations[0][1], Is.EqualTo(1)); - Assert.That(struc.BuildingVariations[1], Has.Count.EqualTo(2)); - Assert.That(struc.BuildingVariations[1][0], Is.EqualTo(2)); - Assert.That(struc.BuildingVariations[1][1], Is.EqualTo(3)); + Assert.That(struc.BuildingVariationParts, Has.Count.EqualTo(2)); + Assert.That(struc.BuildingVariationParts[0], Has.Count.EqualTo(2)); + Assert.That(struc.BuildingVariationParts[0][0], Is.EqualTo(0)); + Assert.That(struc.BuildingVariationParts[0][1], Is.EqualTo(1)); + Assert.That(struc.BuildingVariationParts[1], Has.Count.EqualTo(2)); + Assert.That(struc.BuildingVariationParts[1][0], Is.EqualTo(2)); + Assert.That(struc.BuildingVariationParts[1][1], Is.EqualTo(3)); // Rest of object Assert.That(struc.SellCostFactor, Is.EqualTo(240), nameof(struc.SellCostFactor));