Skip to content

Commit 758a43e

Browse files
committed
add region viewmodel, refactor viewmodels in general
1 parent bed059b commit 758a43e

14 files changed

+154
-141
lines changed

Dat/Objects/Vehicle/VehicleObject.cs

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -67,66 +67,52 @@ public record VehicleObject(
6767
public VehicleObject() : this(0, TransportMode.Rail, VehicleType.Train, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, [], [], [], [], [], 0, 0, 0, 0, VehicleObjectFlags.None, [], [[], []], [], 0, [], 0, 0, 0, 0, DrivingSoundType.None, [], [], 0, [])
6868
{ }
6969

70+
//public static object? GetSoundAs(DrivingSoundType soundType, ReadOnlySpan<byte> soundPropertiesData)
71+
// => soundType switch
72+
// {
73+
// DrivingSoundType.None => default,
74+
// DrivingSoundType.Friction => ByteReader.ReadLocoStruct<FrictionSound>(soundPropertiesData[..ObjectAttributes.StructSize<FrictionSound>()]),
75+
// DrivingSoundType.Engine1 => ByteReader.ReadLocoStruct<Engine1Sound>(soundPropertiesData[..ObjectAttributes.StructSize<Engine1Sound>()]),
76+
// DrivingSoundType.Engine2 => ByteReader.ReadLocoStruct<Engine2Sound>(soundPropertiesData[..ObjectAttributes.StructSize<Engine2Sound>()]),
77+
// _ => throw new ArgumentOutOfRangeException()
78+
// };
79+
80+
public T GetSoundAs<T>() where T : ILocoStruct
81+
=> (T)ByteReader.ReadLocoStruct(SoundPropertiesData.AsSpan()[..ObjectAttributes.StructSize<T>()], typeof(T));
82+
7083
public FrictionSound? SoundPropertyFriction
7184
{
72-
get => DrivingSoundType == DrivingSoundType.Friction
73-
? (FrictionSound)ByteReader.ReadLocoStruct(SoundPropertiesData.AsSpan()[..ObjectAttributes.StructSize<FrictionSound>()], typeof(FrictionSound))
74-
: null;
85+
get => DrivingSoundType == DrivingSoundType.Friction ? GetSoundAs<FrictionSound>() : null;
7586
set
7687
{
7788
if (value != null)
7889
{
7990
ByteWriter.WriteLocoStruct(value).CopyTo(SoundPropertiesData);
8091
}
81-
//else
82-
//{
83-
// for (var i = 0; i < MaxUnionSoundStructLength; ++i)
84-
// {
85-
// SoundPropertiesData[i] = 0;
86-
// }
87-
//}
8892
}
8993
}
9094

9195
public Engine1Sound? SoundPropertyEngine1
9296
{
93-
get => DrivingSoundType == DrivingSoundType.Engine1
94-
? (Engine1Sound)ByteReader.ReadLocoStruct(SoundPropertiesData.AsSpan()[..ObjectAttributes.StructSize<Engine1Sound>()], typeof(Engine1Sound))
95-
: null;
97+
get => DrivingSoundType == DrivingSoundType.Engine1 ? GetSoundAs<Engine1Sound>() : null;
9698
set
9799
{
98100
if (value != null)
99101
{
100102
ByteWriter.WriteLocoStruct(value).CopyTo(SoundPropertiesData);
101103
}
102-
//else
103-
//{
104-
// for (var i = 0; i < MaxUnionSoundStructLength; ++i)
105-
// {
106-
// SoundPropertiesData[i] = 0;
107-
// }
108-
//}
109104
}
110105
}
111106

112107
public Engine2Sound? SoundPropertyEngine2
113108
{
114-
get => DrivingSoundType == DrivingSoundType.Engine2
115-
? (Engine2Sound)ByteReader.ReadLocoStruct(SoundPropertiesData.AsSpan()[..ObjectAttributes.StructSize<Engine2Sound>()], typeof(Engine2Sound))
116-
: null;
109+
get => DrivingSoundType == DrivingSoundType.Engine2 ? GetSoundAs<Engine2Sound>() : null;
117110
set
118111
{
119112
if (value != null)
120113
{
121114
ByteWriter.WriteLocoStruct(value).CopyTo(SoundPropertiesData);
122115
}
123-
//else
124-
//{
125-
// for (var i = 0; i < MaxUnionSoundStructLength; ++i)
126-
// {
127-
// SoundPropertiesData[i] = 0;
128-
// }
129-
//}
130116
}
131117
}
132118

Gui/ViewModels/DatTypes/DatObjectEditorViewModel.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ public override void Load()
108108
{
109109
CurrentObjectViewModel = new TrackViewModel(to);
110110
}
111+
else if (CurrentObject.LocoObject.Object is RegionObject ro)
112+
{
113+
CurrentObjectViewModel = new RegionViewModel(ro);
114+
}
111115
else
112116
{
113117
CurrentObjectViewModel = new GenericObjectViewModel() { Object = CurrentObject.LocoObject.Object };
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1+
using OpenLoco.Dat.Types;
2+
using ReactiveUI;
3+
14
namespace OpenLoco.Gui.ViewModels
25
{
36
public interface IObjectViewModel<T>
47
{
58
T GetAsUnderlyingType(T underlyingType);
69
}
10+
11+
public abstract class LocoObjectViewModel<T> : ReactiveObject, IObjectViewModel<ILocoStruct> where T : class, ILocoStruct
12+
{
13+
public ILocoStruct GetAsUnderlyingType(ILocoStruct locoStruct)
14+
=> GetAsStruct((locoStruct as T)!);
15+
16+
public abstract T GetAsStruct(T input);
17+
}
718
}

Gui/ViewModels/DatTypes/Objects/AirportViewModel.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
using OpenLoco.Dat.Objects;
2-
using OpenLoco.Dat.Types;
32
using PropertyModels.Extensions;
4-
using ReactiveUI;
53
using ReactiveUI.Fody.Helpers;
64
using System.ComponentModel;
75
using System.ComponentModel.DataAnnotations;
86
using System.Linq;
97

108
namespace OpenLoco.Gui.ViewModels
119
{
12-
public class AirportViewModel : ReactiveObject, IObjectViewModel<ILocoStruct>
10+
public class AirportViewModel : LocoObjectViewModel<AirportObject>
1311
{
1412
[Reactive] public uint16_t AllowedPlaneTypes { get; set; }
1513
[Reactive] public int8_t MinX { get; set; }
@@ -54,12 +52,9 @@ public AirportViewModel(AirportObject ao)
5452
var_B6 = [.. ao.var_B6];
5553
}
5654

57-
public ILocoStruct GetAsUnderlyingType(ILocoStruct locoStruct)
58-
=> GetAsStruct((locoStruct as AirportObject)!);
59-
6055
// validation:
6156
// BuildingVariationHeights.Count MUST equal BuildingVariationAnimations.Count
62-
public AirportObject GetAsStruct(AirportObject ao)
57+
public override AirportObject GetAsStruct(AirportObject ao)
6358
=> ao with
6459
{
6560
BuildCostFactor = ao.BuildCostFactor,

Gui/ViewModels/DatTypes/Objects/BuildingViewModel.cs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
using OpenLoco.Dat.Data;
22
using OpenLoco.Dat.Objects;
3-
using OpenLoco.Dat.Types;
43
using PropertyModels.Extensions;
5-
using ReactiveUI;
64
using ReactiveUI.Fody.Helpers;
75
using System.ComponentModel;
86
using System.ComponentModel.DataAnnotations;
97
using System.Linq;
108

119
namespace OpenLoco.Gui.ViewModels
1210
{
13-
public class BuildingViewModel : ReactiveObject, IObjectViewModel<ILocoStruct>
11+
public class BuildingViewModel : LocoObjectViewModel<BuildingObject>
1412
{
1513
[Reactive] public BuildingObjectFlags Flags { get; set; }
1614
[Reactive] public uint32_t Colours { get; set; } // bitset
@@ -23,8 +21,8 @@ public class BuildingViewModel : ReactiveObject, IObjectViewModel<ILocoStruct>
2321
[Reactive, Category("Stats")] public uint16_t ObsoleteYear { get; set; }
2422
[Reactive, Category("Cost")] public uint8_t CostIndex { get; set; }
2523
[Reactive, Category("Cost")] public uint16_t SellCostFactor { get; set; }
26-
[Reactive, Category("Production"), Length(0, BuildingObject.MaxProducedCargoType)] public BindingList<S5Header> ProducedCargo { get; set; }
27-
[Reactive, Category("Production"), Length(0, BuildingObject.MaxProducedCargoType)] public BindingList<S5Header> RequiredCargo { get; set; }
24+
[Reactive, Category("Production"), Length(0, BuildingObject.MaxProducedCargoType)] public BindingList<S5HeaderViewModel> ProducedCargo { get; set; }
25+
[Reactive, Category("Production"), Length(0, BuildingObject.MaxProducedCargoType)] public BindingList<S5HeaderViewModel> RequiredCargo { get; set; }
2826
[Reactive, Category("Production"), Length(1, BuildingObject.MaxProducedCargoType)] public BindingList<uint8_t> ProducedQuantity { get; set; }
2927
[Reactive, Category("Building"), Length(1, BuildingObject.BuildingVariationCount)] public BindingList<BindingList<uint8_t>> BuildingVariations { get; set; } // NumBuildingVariations
3028
[Reactive, Category("Building"), Length(1, BuildingObject.BuildingHeightCount)] public BindingList<uint8_t> BuildingHeights { get; set; } // NumBuildingParts
@@ -50,8 +48,8 @@ public BuildingViewModel(BuildingObject bo)
5048
ObsoleteYear = bo.ObsoleteYear;
5149
CostIndex = bo.CostIndex;
5250
SellCostFactor = bo.SellCostFactor;
53-
ProducedCargo = new(bo.ProducedCargo);
54-
RequiredCargo = new(bo.RequiredCargo);
51+
ProducedCargo = new(bo.ProducedCargo.ConvertAll(x => new S5HeaderViewModel(x)));
52+
RequiredCargo = new(bo.RequiredCargo.ConvertAll(x => new S5HeaderViewModel(x)));
5553
ProducedQuantity = [.. bo.ProducedQuantity];
5654
BuildingHeights = new(bo.BuildingHeights);
5755
BuildingAnimations = new(bo.BuildingAnimations);
@@ -62,12 +60,9 @@ public BuildingViewModel(BuildingObject bo)
6260
var_AC = bo.var_AC;
6361
}
6462

65-
public ILocoStruct GetAsUnderlyingType(ILocoStruct locoStruct)
66-
=> GetAsStruct((locoStruct as BuildingObject)!);
67-
6863
// validation:
6964
// BuildingVariationHeights.Count MUST equal BuildingVariationAnimations.Count
70-
public BuildingObject GetAsStruct(BuildingObject bo)
65+
public override BuildingObject GetAsStruct(BuildingObject bo)
7166
=> bo with
7267
{
7368
Flags = Flags,
@@ -85,6 +80,8 @@ public BuildingObject GetAsStruct(BuildingObject bo)
8580
NumBuildingParts = (uint8_t)bo.BuildingAnimations.Count,
8681
NumBuildingVariations = (uint8_t)bo.BuildingVariations.Count,
8782
ProducedQuantity = [.. ProducedQuantity],
83+
ProducedCargo = ProducedCargo.ToList().ConvertAll(x => x.GetAsUnderlyingType()),
84+
RequiredCargo = RequiredCargo.ToList().ConvertAll(x => x.GetAsUnderlyingType()),
8885
//NumElevatorSequences = (uint8_t)bo.ElevatorHeightSequences.Count,
8986
};
9087
}

Gui/ViewModels/DatTypes/Objects/IndustryViewModel.cs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
using OpenLoco.Dat.Data;
22
using OpenLoco.Dat.Objects;
3-
using OpenLoco.Dat.Types;
43
using PropertyModels.Extensions;
5-
using ReactiveUI;
64
using ReactiveUI.Fody.Helpers;
75
using System.ComponentModel;
86
using System.ComponentModel.DataAnnotations;
97
using System.Linq;
108

119
namespace OpenLoco.Gui.ViewModels
1210
{
13-
public class IndustryViewModel : ReactiveObject, IObjectViewModel<ILocoStruct>
11+
public class IndustryViewModel : LocoObjectViewModel<IndustryObject>
1412
{
1513
[Reactive] public uint8_t TotalOfTypeInScenario { get; set; } // Total industries of this type that can be created in a scenario Note: this is not directly comparable to total industries and varies based on scenario total industries cap settings. At low industries cap this value is ~3x the amount of industries in a scenario.
1614
[Reactive] public uint16_t DesignedYear { get; set; }
@@ -19,8 +17,8 @@ public class IndustryViewModel : ReactiveObject, IObjectViewModel<ILocoStruct>
1917
[Reactive] public Colour MapColour { get; set; }
2018
[Reactive] public uint32_t Colours { get; set; } // bitset
2119
[Reactive, Category("Production")] public BindingList<IndustryObjectProductionRateRange> InitialProductionRate { get; set; }
22-
[Reactive, Category("Production"), Length(0, IndustryObject.MaxProducedCargoType)] public BindingList<S5Header> ProducedCargo { get; set; }
23-
[Reactive, Category("Production"), Length(0, IndustryObject.MaxProducedCargoType)] public BindingList<S5Header> RequiredCargo { get; set; }
20+
[Reactive, Category("Production"), Length(0, IndustryObject.MaxProducedCargoType)] public BindingList<S5HeaderViewModel> ProducedCargo { get; set; }
21+
[Reactive, Category("Production"), Length(0, IndustryObject.MaxProducedCargoType)] public BindingList<S5HeaderViewModel> RequiredCargo { get; set; }
2422
[Reactive, Category("Cost")] public uint8_t CostIndex { get; set; }
2523
[Reactive, Category("Cost")] public int16_t BuildCostFactor { get; set; }
2624
[Reactive, Category("Cost")] public int16_t SellCostFactor { get; set; }
@@ -34,9 +32,9 @@ public class IndustryViewModel : ReactiveObject, IObjectViewModel<ILocoStruct>
3432
[Reactive, Category("Building")] public uint32_t BuildingSizeFlags { get; set; }
3533
[Reactive, Category("Building")] public uint8_t ScaffoldingSegmentType { get; set; }
3634
[Reactive, Category("Building")] public Colour ScaffoldingColour { get; set; }
37-
[Reactive, Category("Building"), Length(0, IndustryObject.MaxWallTypeCount)] public BindingList<S5Header> WallTypes { get; set; }
38-
[Reactive, Category("Building")] public S5Header? BuildingWall { get; set; }
39-
[Reactive, Category("Building")] public S5Header? BuildingWallEntrance { get; set; }
35+
[Reactive, Category("Building"), Length(0, IndustryObject.MaxWallTypeCount)] public BindingList<S5HeaderViewModel> WallTypes { get; set; }
36+
[Reactive, Category("Building")] public S5HeaderViewModel? BuildingWall { get; set; }
37+
[Reactive, Category("Building")] public S5HeaderViewModel? BuildingWallEntrance { get; set; }
4038
[Reactive, Category("<unknown>")] public BindingList<IndustryObjectUnk38> var_38 { get; set; }
4139
[Reactive, Category("<unknown>")] public uint8_t var_E8 { get; set; }
4240
[Reactive, Category("<unknown>")] public uint8_t var_E9 { get; set; }
@@ -54,14 +52,14 @@ public IndustryViewModel(IndustryObject io)
5452
BuildingVariations = new(io.BuildingVariations.Select(x => new BindingList<uint8_t>(x)).ToBindingList());
5553
Buildings = new(io.Buildings);
5654
BuildingSizeFlags = io.BuildingSizeFlags;
57-
BuildingWall = io.BuildingWall;
58-
BuildingWallEntrance = io.BuildingWallEntrance;
55+
BuildingWall = io.BuildingWall == null ? null : new(io.BuildingWall);
56+
BuildingWallEntrance = io.BuildingWallEntrance == null ? null : new(io.BuildingWallEntrance);
5957
MinNumBuildings = io.MinNumBuildings;
6058
MaxNumBuildings = io.MaxNumBuildings;
6159
InitialProductionRate = new(io.InitialProductionRate);
62-
ProducedCargo = new(io.ProducedCargo);
63-
RequiredCargo = new(io.RequiredCargo);
64-
WallTypes = new(io.WallTypes);
60+
ProducedCargo = new(io.ProducedCargo.ConvertAll(x => new S5HeaderViewModel(x)));
61+
RequiredCargo = new(io.RequiredCargo.ConvertAll(x => new S5HeaderViewModel(x)));
62+
WallTypes = new(io.WallTypes.ConvertAll(x => new S5HeaderViewModel(x)));
6563
Colours = io.Colours;
6664
DesignedYear = io.DesignedYear;
6765
ObsoleteYear = io.ObsoleteYear;
@@ -81,21 +79,21 @@ public IndustryViewModel(IndustryObject io)
8179
var_F3 = io.var_E8;
8280
}
8381

84-
public ILocoStruct GetAsUnderlyingType(ILocoStruct locoStruct)
85-
=> GetAsStruct((locoStruct as IndustryObject)!);
86-
8782
// validation:
8883
// BuildingVariationHeights.Count MUST equal BuildingVariationAnimations.Count
89-
public IndustryObject GetAsStruct(IndustryObject io)
84+
public override IndustryObject GetAsStruct(IndustryObject io)
9085
=> io with
9186
{
9287
BuildingSizeFlags = BuildingSizeFlags,
93-
BuildingWall = BuildingWall,
94-
BuildingWallEntrance = BuildingWallEntrance,
88+
BuildingWall = BuildingWall?.GetAsUnderlyingType(),
89+
BuildingWallEntrance = BuildingWallEntrance?.GetAsUnderlyingType(),
9590
MinNumBuildings = MinNumBuildings,
9691
MaxNumBuildings = MaxNumBuildings,
9792
NumBuildingParts = (uint8_t)BuildingAnimations.Count,
9893
NumBuildingVariations = (uint8_t)BuildingVariations.Count,
94+
ProducedCargo = ProducedCargo.ToList().ConvertAll(x => x.GetAsUnderlyingType()),
95+
RequiredCargo = RequiredCargo.ToList().ConvertAll(x => x.GetAsUnderlyingType()),
96+
WallTypes = WallTypes.ToList().ConvertAll(x => x.GetAsUnderlyingType()),
9997
Colours = Colours,
10098
DesignedYear = DesignedYear,
10199
ObsoleteYear = ObsoleteYear,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using OpenLoco.Dat.Objects;
2+
using ReactiveUI.Fody.Helpers;
3+
using System.ComponentModel;
4+
using System.Linq;
5+
6+
namespace OpenLoco.Gui.ViewModels
7+
{
8+
public class RegionViewModel : LocoObjectViewModel<RegionObject>
9+
{
10+
[Reactive] public BindingList<S5HeaderViewModel> RequiredObjects { get; set; }
11+
[Reactive] public BindingList<uint8_t> var_06 { get; set; }
12+
[Reactive] public BindingList<uint8_t> var_0D { get; set; }
13+
14+
public RegionViewModel(RegionObject ro)
15+
{
16+
RequiredObjects = new(ro.RequiredObjects.ConvertAll(x => new S5HeaderViewModel(x)));
17+
var_06 = new(ro.var_06);
18+
var_0D = new(ro.var_0D);
19+
}
20+
21+
public override RegionObject GetAsStruct(RegionObject input)
22+
=> input with
23+
{
24+
RequiredObjects = RequiredObjects.ToList().ConvertAll(x => x.GetAsUnderlyingType()),
25+
RequiredObjectCount = (uint8_t)RequiredObjects.Count,
26+
// var_06 is bound
27+
// var_0D is bound
28+
};
29+
}
30+
}
Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,19 @@
11
using OpenLoco.Dat.Objects;
2-
using OpenLoco.Dat.Types;
3-
using ReactiveUI;
42
using ReactiveUI.Fody.Helpers;
53
using System.ComponentModel;
64
using System.ComponentModel.DataAnnotations;
75

86
namespace OpenLoco.Gui.ViewModels
97
{
10-
public class TownNamesViewModel : ReactiveObject, IObjectViewModel<ILocoStruct>
8+
public class TownNamesViewModel : LocoObjectViewModel<TownNamesObject>
119
{
1210
[Reactive, Length(6, 6), Editable(false)]
1311
public BindingList<Category> Categories { get; set; }
1412

1513
public TownNamesViewModel(TownNamesObject tno)
1614
=> Categories = new(tno.Categories);
1715

18-
public ILocoStruct GetAsUnderlyingType(ILocoStruct locoStruct)
19-
=> GetAsStruct((locoStruct as TownNamesObject)!);
20-
21-
public TownNamesObject GetAsStruct(TownNamesObject tno)
16+
public override TownNamesObject GetAsStruct(TownNamesObject tno)
2217
=> tno;
2318
}
2419
}

0 commit comments

Comments
 (0)