diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index cc80eed..f37e5c2 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -34,7 +34,7 @@ jobs: with: PROJECT_FILE_PATH: ./SatisfactorySaveNet.Abstracts/SatisfactorySaveNet.Abstracts.csproj PACKAGE_NAME: SatisfactorySaveNet - VERSION_STATIC: 0.0.12 + VERSION_STATIC: 0.0.13 TAG_COMMIT: false NUGET_KEY: ${{secrets.NUGET_API_KEY}} NUGET_SOURCE: https://api.nuget.org @@ -45,7 +45,7 @@ jobs: with: PROJECT_FILE_PATH: ./SatisfactorySaveNet/SatisfactorySaveNet.csproj PACKAGE_NAME: SatisfactorySaveNet - VERSION_STATIC: 0.0.12 + VERSION_STATIC: 0.0.13 TAG_COMMIT: false NUGET_KEY: ${{secrets.NUGET_API_KEY}} NUGET_SOURCE: https://api.nuget.org diff --git a/Directory.Build.props b/Directory.Build.props index 10c7efc..235cdfd 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,7 +11,7 @@ false false - 0.0.12 + 0.0.13 $(VersionPrefix)-$(VersionSuffix) $(VersionPrefix) diff --git a/SatisfactorySaveNet.Abstracts/Exceptions/BadReadException.cs b/SatisfactorySaveNet.Abstracts/Exceptions/BadReadException.cs new file mode 100644 index 0000000..55e07fb --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Exceptions/BadReadException.cs @@ -0,0 +1,24 @@ +using System.Runtime.Serialization; +using System; + +namespace SatisfactorySaveNet.Abstracts.Exceptions; + +[Serializable] +public class BadReadException : SatisFactoryException +{ + public BadReadException() + { + } + + public BadReadException(string? message) : base(message) + { + } + + public BadReadException(string? message, Exception? innerException) : base(message, innerException) + { + } + + protected BadReadException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } +} diff --git a/SatisfactorySaveNet.Abstracts/Extra/BlueprintData.cs b/SatisfactorySaveNet.Abstracts/Extra/BlueprintData.cs new file mode 100644 index 0000000..cb9c55e --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/BlueprintData.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace SatisfactorySaveNet.Abstracts.Model.Extra; + +public class BlueprintData : ExtraData +{ + public override ExtraDataConstraint Type => ExtraDataConstraint.BlueprintData; + + public int Count { get; set; } + public required ICollection Objects { get; set; } +} \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Extra/CargoObject.cs b/SatisfactorySaveNet.Abstracts/Extra/CargoObject.cs new file mode 100644 index 0000000..a1b79e9 --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/CargoObject.cs @@ -0,0 +1,7 @@ +namespace SatisfactorySaveNet.Abstracts.Extra; + +public class CargoObject +{ + public string Name { get; set; } = string.Empty; + public string Unknown { get; set; } = string.Empty; +} diff --git a/SatisfactorySaveNet.Abstracts/Extra/Circuit.cs b/SatisfactorySaveNet.Abstracts/Extra/Circuit.cs new file mode 100644 index 0000000..30acbaf --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/Circuit.cs @@ -0,0 +1,9 @@ +using SatisfactorySaveNet.Abstracts.Model; + +namespace SatisfactorySaveNet.Abstracts.Extra; + +public class Circuit +{ + public int CircuitId { get; set; } + public required ObjectReference ObjectReference { get; set; } +} diff --git a/SatisfactorySaveNet.Abstracts/Extra/CircuitData.cs b/SatisfactorySaveNet.Abstracts/Extra/CircuitData.cs new file mode 100644 index 0000000..4b97c18 --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/CircuitData.cs @@ -0,0 +1,12 @@ +using SatisfactorySaveNet.Abstracts.Model.Extra; +using System.Collections.Generic; + +namespace SatisfactorySaveNet.Abstracts.Extra; + +public class CircuitData : ExtraData +{ + public override ExtraDataConstraint Type => ExtraDataConstraint.CircuitData; + + public int Count { get; set; } + public required ICollection Circuits { get; set; } +} diff --git a/SatisfactorySaveNet.Abstracts/Extra/ConveyorData.cs b/SatisfactorySaveNet.Abstracts/Extra/ConveyorData.cs new file mode 100644 index 0000000..f2a1d11 --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/ConveyorData.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace SatisfactorySaveNet.Abstracts.Model.Extra; + +public class ConveyorData : ExtraData +{ + public override ExtraDataConstraint Type => ExtraDataConstraint.Conveyor; + + public int Count { get; set; } + public required ICollection Items { get; set; } +} \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Extra/DroneStationAction.cs b/SatisfactorySaveNet.Abstracts/Extra/DroneStationAction.cs new file mode 100644 index 0000000..b14e587 --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/DroneStationAction.cs @@ -0,0 +1,10 @@ +using SatisfactorySaveNet.Abstracts.Model.Properties; +using System.Collections.Generic; + +namespace SatisfactorySaveNet.Abstracts.Extra; + +public class DroneStationAction +{ + public string Name { get; set; } = string.Empty; + public required ICollection Properties { get; set; } +} diff --git a/SatisfactorySaveNet.Abstracts/Extra/DroneStationData.cs b/SatisfactorySaveNet.Abstracts/Extra/DroneStationData.cs new file mode 100644 index 0000000..d2adb56 --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/DroneStationData.cs @@ -0,0 +1,21 @@ +using SatisfactorySaveNet.Abstracts.Model.Extra; +using System.Collections.Generic; + +namespace SatisfactorySaveNet.Abstracts.Extra; + +public class DroneStationData : ExtraData +{ + public override ExtraDataConstraint Type => ExtraDataConstraint.DroneStationData; + + public int Unknown1 { get; set; } + public int Unknown2 { get; set; } + /// + /// Should only be null if Missing is filled, which indicates that there were unparseable data + /// + public ICollection? ActiveActions { get; set; } + /// + /// Should only be null if Missing is filled, which indicates that there were unparseable data + /// + public ICollection? ActionQueue { get; set; } + public string? Missing { get; set; } +} diff --git a/SatisfactorySaveNet.Abstracts/Extra/ExtraData.cs b/SatisfactorySaveNet.Abstracts/Extra/ExtraData.cs new file mode 100644 index 0000000..70f5897 --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/ExtraData.cs @@ -0,0 +1,6 @@ +namespace SatisfactorySaveNet.Abstracts.Model.Extra; + +public abstract class ExtraData +{ + public abstract ExtraDataConstraint Type { get; } +} \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Extra/ExtraDataConstraint.cs b/SatisfactorySaveNet.Abstracts/Extra/ExtraDataConstraint.cs new file mode 100644 index 0000000..25b52bb --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/ExtraDataConstraint.cs @@ -0,0 +1,14 @@ +namespace SatisfactorySaveNet.Abstracts.Model.Extra; + +public enum ExtraDataConstraint +{ + Conveyor, + BlueprintData, + PlayerData, + PowerLineData, + VehicleData, + LocomotiveData, + DroneStationData, + CircuitData, + UnknownExtraData +} \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Extra/LocomotiveData.cs b/SatisfactorySaveNet.Abstracts/Extra/LocomotiveData.cs new file mode 100644 index 0000000..27a3a80 --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/LocomotiveData.cs @@ -0,0 +1,15 @@ +using SatisfactorySaveNet.Abstracts.Model; +using SatisfactorySaveNet.Abstracts.Model.Extra; +using System.Collections.Generic; + +namespace SatisfactorySaveNet.Abstracts.Extra; + +public class LocomotiveData : ExtraData +{ + public override ExtraDataConstraint Type => ExtraDataConstraint.LocomotiveData; + + public int Count { get; set; } + public required ICollection CargoObjects { get; set; } + public required ObjectReference Previous { get; set; } + public required ObjectReference Next { get; set; } +} diff --git a/SatisfactorySaveNet.Abstracts/Extra/PlayerData.cs b/SatisfactorySaveNet.Abstracts/Extra/PlayerData.cs new file mode 100644 index 0000000..1532d0b --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/PlayerData.cs @@ -0,0 +1,12 @@ +namespace SatisfactorySaveNet.Abstracts.Model.Extra; + +public class PlayerData : ExtraData +{ + public override ExtraDataConstraint Type => ExtraDataConstraint.PlayerData; + + public string? Missing { get; set; } + public byte PlayerType { get; set; } + public string? EpicOnlineServicesId { get; set; } + public string? SteamId { get; set; } + public string? PlatformId { get; set; } +} \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Extra/PowerLineData.cs b/SatisfactorySaveNet.Abstracts/Extra/PowerLineData.cs new file mode 100644 index 0000000..07b184c --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/PowerLineData.cs @@ -0,0 +1,16 @@ +using SatisfactorySaveNet.Abstracts.Maths.Vector; +using SatisfactorySaveNet.Abstracts.Model; +using SatisfactorySaveNet.Abstracts.Model.Extra; + +namespace SatisfactorySaveNet.Abstracts.Extra; + +public class PowerLineData : ExtraData +{ + public override ExtraDataConstraint Type => ExtraDataConstraint.PowerLineData; + + public int Count { get; set; } + public required ObjectReference Source { get; set; } + public required ObjectReference Target { get; set; } + public Vector3? SourceTranslation { get; set; } + public Vector3? TargetTranslation { get; set;} +} diff --git a/SatisfactorySaveNet.Abstracts/Extra/UnknownExtraData.cs b/SatisfactorySaveNet.Abstracts/Extra/UnknownExtraData.cs new file mode 100644 index 0000000..bc5172a --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/UnknownExtraData.cs @@ -0,0 +1,10 @@ +using SatisfactorySaveNet.Abstracts.Model.Extra; + +namespace SatisfactorySaveNet.Abstracts.Extra; + +public class UnknownExtraData : ExtraData +{ + public override ExtraDataConstraint Type => ExtraDataConstraint.UnknownExtraData; + + public string Missing { get; set; } = string.Empty; +} diff --git a/SatisfactorySaveNet.Abstracts/Extra/VehicleData.cs b/SatisfactorySaveNet.Abstracts/Extra/VehicleData.cs new file mode 100644 index 0000000..2756313 --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Extra/VehicleData.cs @@ -0,0 +1,12 @@ +using SatisfactorySaveNet.Abstracts.Model.Extra; +using System.Collections.Generic; + +namespace SatisfactorySaveNet.Abstracts.Extra; + +public class VehicleData : ExtraData +{ + public override ExtraDataConstraint Type => ExtraDataConstraint.VehicleData; + + public int Count { get; set; } + public required ICollection CargoObjects { get; set; } +} diff --git a/SatisfactorySaveNet.Abstracts/IExtraDataSerializer.cs b/SatisfactorySaveNet.Abstracts/IExtraDataSerializer.cs new file mode 100644 index 0000000..46b272b --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/IExtraDataSerializer.cs @@ -0,0 +1,10 @@ +using SatisfactorySaveNet.Abstracts.Model; +using SatisfactorySaveNet.Abstracts.Model.Extra; +using System.IO; + +namespace SatisfactorySaveNet.Abstracts; + +public interface IExtraDataSerializer +{ + public ExtraData? Deserialize(BinaryReader reader, string typePath, Header header, long expectedPosition); +} diff --git a/SatisfactorySaveNet.Abstracts/IPropertySerializer.cs b/SatisfactorySaveNet.Abstracts/IPropertySerializer.cs index b5d6756..251da14 100644 --- a/SatisfactorySaveNet.Abstracts/IPropertySerializer.cs +++ b/SatisfactorySaveNet.Abstracts/IPropertySerializer.cs @@ -7,6 +7,6 @@ namespace SatisfactorySaveNet.Abstracts; public interface IPropertySerializer { - public IEnumerable DeserializeProperties(BinaryReader reader, Header? header = null, string? type = null); + public IEnumerable DeserializeProperties(BinaryReader reader, Header? header = null, string? type = null, long? expectedPosition = null); public Property? DeserializeProperty(BinaryReader reader, Header? header = null, string? type = null); } diff --git a/SatisfactorySaveNet.Abstracts/ITypedDataSerializer.cs b/SatisfactorySaveNet.Abstracts/ITypedDataSerializer.cs index 0f04895..4ad00be 100644 --- a/SatisfactorySaveNet.Abstracts/ITypedDataSerializer.cs +++ b/SatisfactorySaveNet.Abstracts/ITypedDataSerializer.cs @@ -6,5 +6,5 @@ namespace SatisfactorySaveNet.Abstracts; public interface ITypedDataSerializer { - public TypedData Deserialize(BinaryReader reader, Header header, string type); + public TypedData Deserialize(BinaryReader reader, Header header, string type, bool isArrayProperty); } diff --git a/SatisfactorySaveNet.Abstracts/Model/ActorObject.cs b/SatisfactorySaveNet.Abstracts/Model/ActorObject.cs index 755f9a9..123e97b 100644 --- a/SatisfactorySaveNet.Abstracts/Model/ActorObject.cs +++ b/SatisfactorySaveNet.Abstracts/Model/ActorObject.cs @@ -22,5 +22,5 @@ public class ActorObject : ComponentObject public string ParentObjectRoot { get; set; } = string.Empty; public string ParentObjectName { get; set; } = string.Empty; - public IList Components { get; set; } = []; + public ICollection Components { get; set; } = []; } \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Model/Body.cs b/SatisfactorySaveNet.Abstracts/Model/Body.cs index a596edc..3e995a9 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Body.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Body.cs @@ -8,7 +8,7 @@ public class Body /// /// Levels and the persistent level. There is one more level than the level count above, the last entry being the persistent level (See SCIM). For the format of one level /// - public IList Levels { get; set; } = []; + public ICollection Levels { get; set; } = []; /// /// Unknown grid related data @@ -19,5 +19,5 @@ public class Body /// A list of object references, can also be ignored. for the format of one such ObjectReference /// [Obsolete("These information seem to be obsolete")] - public IList? ObjectReferences { get; set; } + public ICollection? ObjectReferences { get; set; } } \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Model/ComponentObject.cs b/SatisfactorySaveNet.Abstracts/Model/ComponentObject.cs index 496e5d4..9e0f5ff 100644 --- a/SatisfactorySaveNet.Abstracts/Model/ComponentObject.cs +++ b/SatisfactorySaveNet.Abstracts/Model/ComponentObject.cs @@ -1,3 +1,4 @@ +using SatisfactorySaveNet.Abstracts.Model.Extra; using SatisfactorySaveNet.Abstracts.Model.Properties; using System.Collections.Generic; @@ -14,6 +15,7 @@ public class ComponentObject public string ParentActorName { get; set; } = string.Empty; - public IList Properties { get; set; } = []; + public ICollection Properties { get; set; } = []; + public ExtraData? ExtraData { get; set; } public int? EntitySaveVersion { get; set; } } \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Model/Grid.cs b/SatisfactorySaveNet.Abstracts/Model/Grid.cs index 09a95ce..ff09170 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Grid.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Grid.cs @@ -9,5 +9,5 @@ public class Grid public int Unknown3 { get; set; } public string Unknown4 { get; set; } = string.Empty; public int Unknown5 { get; set; } - public IList Data { get; set; } = []; + public ICollection Data { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/GridData.cs b/SatisfactorySaveNet.Abstracts/Model/GridData.cs index c2f234e..12c7394 100644 --- a/SatisfactorySaveNet.Abstracts/Model/GridData.cs +++ b/SatisfactorySaveNet.Abstracts/Model/GridData.cs @@ -7,5 +7,5 @@ public class GridData public string Unknown1 { get; set; } = string.Empty; public int Unknown2 { get; set; } public int Unknown3 { get; set; } - public IList Levels { get; set; } = []; + public ICollection Levels { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Item.cs b/SatisfactorySaveNet.Abstracts/Model/Item.cs new file mode 100644 index 0000000..fba650b --- /dev/null +++ b/SatisfactorySaveNet.Abstracts/Model/Item.cs @@ -0,0 +1,14 @@ +using SatisfactorySaveNet.Abstracts.Maths.Vector; + +namespace SatisfactorySaveNet.Abstracts.Model; + +public class Item +{ + public string Name { get; set; } = string.Empty; + public required ObjectReference ObjectReference { get; set; } + /// + /// Supposed to be a float, but Vec4 seems to be logical? + /// + public Vector4I Position { get; set; } + public int Length { get; set; } +} \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Model/Level.cs b/SatisfactorySaveNet.Abstracts/Model/Level.cs index 129ab6d..03c2288 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Level.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Level.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; namespace SatisfactorySaveNet.Abstracts.Model; @@ -6,8 +6,8 @@ namespace SatisfactorySaveNet.Abstracts.Model; public class Level { public string Name { get; set; } = string.Empty; - public IList Collectables { get; set; } = []; - public IList Objects { get; set; } = []; + public ICollection Collectables { get; set; } = []; + public ICollection Objects { get; set; } = []; [Obsolete("These information seem to be obsolete")] - public IList? SecondCollectables { get; set; } = []; + public ICollection? SecondCollectables { get; set; } = []; } \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayBoolProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayBoolProperty.cs index c89cba0..42e75bc 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayBoolProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayBoolProperty.cs @@ -7,5 +7,5 @@ public class ArrayBoolProperty : IArrayProperty /// /// Values[x] != 0 <=> True /// - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayByteProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayByteProperty.cs index 7e14d10..e24ddef 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayByteProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayByteProperty.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArrayByteProperty : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayDoubleProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayDoubleProperty.cs index a252f05..17c9d63 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayDoubleProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayDoubleProperty.cs @@ -3,5 +3,5 @@ namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArrayDoubleProperty : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayEnumProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayEnumProperty.cs index 01f915b..b9336bb 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayEnumProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayEnumProperty.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArrayEnumProperty : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayFloatProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayFloatProperty.cs index cb581cb..b3b6bf6 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayFloatProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayFloatProperty.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArrayFloatProperty : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayInt64Property.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayInt64Property.cs index a3760c0..aba5474 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayInt64Property.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayInt64Property.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArrayInt64Property : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayIntProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayIntProperty.cs index 52c7bf9..afbe3a1 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayIntProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayIntProperty.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArrayIntProperty : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayInterfaceProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayInterfaceProperty.cs index 5851ee7..c107ed1 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayInterfaceProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayInterfaceProperty.cs @@ -3,5 +3,5 @@ namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArrayInterfaceProperty : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayObjectProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayObjectProperty.cs index 46da97b..5ed3913 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayObjectProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayObjectProperty.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArrayObjectProperty : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArraySoftObjectProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArraySoftObjectProperty.cs index 7d70666..a163930 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArraySoftObjectProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArraySoftObjectProperty.cs @@ -4,5 +4,5 @@ namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArraySoftObjectProperty : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayStrProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayStrProperty.cs index 142a6cc..771fb07 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayStrProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayStrProperty.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArrayStrProperty : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayStructProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayStructProperty.cs index 030a396..346135f 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayStructProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayStructProperty.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace SatisfactorySaveNet.Abstracts.Model.Properties; @@ -8,5 +8,5 @@ public class ArrayStructProperty : IArrayProperty public string PropertyType { get; set; } = string.Empty; public (int, int, int, int) UUID { get; set; } = new(0, 0, 0, 0); public string ElementType { get; set; } = string.Empty; - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayTextProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayTextProperty.cs index 86ad673..4cc7e4c 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayTextProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/ArrayTextProperty.cs @@ -4,5 +4,5 @@ namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class ArrayTextProperty : IArrayProperty { - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/FINNetworkProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/FINNetworkProperty.cs index 1f753b4..a551593 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/FINNetworkProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/FINNetworkProperty.cs @@ -2,8 +2,7 @@ namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class FINNetworkProperty : Property { - public string LevelName { get; set; } = string.Empty; //ToDo: ObjectReference - public string PathName { get; set; } = string.Empty; + public required ObjectReference ObjectReference { get; set; } public FINNetworkProperty? Previous { get; set; } public string? Step { get; set; } } diff --git a/SatisfactorySaveNet.Abstracts/Model/Properties/SetProperty.cs b/SatisfactorySaveNet.Abstracts/Model/Properties/SetProperty.cs index dbba4d4..44be587 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Properties/SetProperty.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Properties/SetProperty.cs @@ -6,5 +6,5 @@ namespace SatisfactorySaveNet.Abstracts.Model.Properties; public class SetProperty : Property { public string Type { get; set; } = string.Empty; - public IList Elements { get; set; } = []; + public ICollection Elements { get; set; } = []; } \ No newline at end of file diff --git a/SatisfactorySaveNet.Abstracts/Model/TypedData/ArrayProperties.cs b/SatisfactorySaveNet.Abstracts/Model/TypedData/ArrayProperties.cs index 42087f5..10064a7 100644 --- a/SatisfactorySaveNet.Abstracts/Model/TypedData/ArrayProperties.cs +++ b/SatisfactorySaveNet.Abstracts/Model/TypedData/ArrayProperties.cs @@ -7,6 +7,6 @@ public class ArrayProperties : TypedData { public override TypedDataConstraint Type => TypedDataConstraint.ArrayProperties; - public IList Values { get; set; } = []; + public ICollection Values { get; set; } = []; public string TypeName { get; set; } = string.Empty; } diff --git a/SatisfactorySaveNet.Abstracts/Model/TypedData/FINGPUT1Buffer.cs b/SatisfactorySaveNet.Abstracts/Model/TypedData/FINGPUT1Buffer.cs index 802588f..0c15963 100644 --- a/SatisfactorySaveNet.Abstracts/Model/TypedData/FINGPUT1Buffer.cs +++ b/SatisfactorySaveNet.Abstracts/Model/TypedData/FINGPUT1Buffer.cs @@ -11,6 +11,6 @@ public class FINGPUT1Buffer : TypedData public string Name { get; set; } = string.Empty; public string TypeName { get; set; } = string.Empty; public int Length { get; set; } - public IList Buffer { get; set; } = []; + public ICollection Buffer { get; set; } = []; public string Unknown { get; set; } = string.Empty; } diff --git a/SatisfactorySaveNet.Abstracts/Model/TypedData/FINLuaProcessorStateStorage.cs b/SatisfactorySaveNet.Abstracts/Model/TypedData/FINLuaProcessorStateStorage.cs index c34fe7b..5d77c79 100644 --- a/SatisfactorySaveNet.Abstracts/Model/TypedData/FINLuaProcessorStateStorage.cs +++ b/SatisfactorySaveNet.Abstracts/Model/TypedData/FINLuaProcessorStateStorage.cs @@ -6,9 +6,9 @@ public class FINLuaProcessorStateStorage : TypedData { public override TypedDataConstraint Type => TypedDataConstraint.FINLuaProcessorStateStorage; - public IList Traces { get; set; } = []; - public IList ObjectReferences { get; set; } = []; + public ICollection Traces { get; set; } = []; + public ICollection ObjectReferences { get; set; } = []; public string Thread { get; set; } = string.Empty; public string Globals { get; set; } = string.Empty; - public IList TypedData { get; set; } = []; + public ICollection TypedData { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/TypedData/FactoryCustomizationColorSlot.cs b/SatisfactorySaveNet.Abstracts/Model/TypedData/FactoryCustomizationColorSlot.cs index 1fb1ede..152b28c 100644 --- a/SatisfactorySaveNet.Abstracts/Model/TypedData/FactoryCustomizationColorSlot.cs +++ b/SatisfactorySaveNet.Abstracts/Model/TypedData/FactoryCustomizationColorSlot.cs @@ -7,5 +7,5 @@ public class FactoryCustomizationColorSlot : TypedData { public override TypedDataConstraint Type => TypedDataConstraint.FactoryCustomizationColorSlot; - public IList Properties { get; set; } = []; + public ICollection Properties { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/TypedData/SpawnData.cs b/SatisfactorySaveNet.Abstracts/Model/TypedData/SpawnData.cs index 23e4619..10efa32 100644 --- a/SatisfactorySaveNet.Abstracts/Model/TypedData/SpawnData.cs +++ b/SatisfactorySaveNet.Abstracts/Model/TypedData/SpawnData.cs @@ -7,5 +7,5 @@ public class SpawnData : TypedData { public override TypedDataConstraint Type => TypedDataConstraint.SpawnData; - public IList Properties { get; set; } = []; + public ICollection Properties { get; set; } = []; } diff --git a/SatisfactorySaveNet.Abstracts/Model/Union/FINNetworkUnion.cs b/SatisfactorySaveNet.Abstracts/Model/Union/FINNetworkUnion.cs index ff36adf..b22be4f 100644 --- a/SatisfactorySaveNet.Abstracts/Model/Union/FINNetworkUnion.cs +++ b/SatisfactorySaveNet.Abstracts/Model/Union/FINNetworkUnion.cs @@ -5,5 +5,5 @@ namespace SatisfactorySaveNet.Abstracts.Model.Union; public class FINNetworkUnion : UnionBase { public override UnionConstraint Type => UnionConstraint.FINNetwork; - public FINNetworkProperty Value { get; set; } = new(); + public required FINNetworkProperty Value { get; set; } } diff --git a/SatisfactorySaveNet/BodySerializer.cs b/SatisfactorySaveNet/BodySerializer.cs index 3d91187..7f7fef8 100644 --- a/SatisfactorySaveNet/BodySerializer.cs +++ b/SatisfactorySaveNet/BodySerializer.cs @@ -129,6 +129,7 @@ public BodySerializer(IStringSerializer stringSerializer, IObjectHeaderSerialize } var binarySizeObjects = header.SaveVersion >= 41 ? reader.ReadInt64() : reader.ReadInt32(); + var positionStart = reader.BaseStream.Position; var nrObjects = reader.ReadInt32(); if (nrObjects != nrObjectHeaders) @@ -139,6 +140,10 @@ public BodySerializer(IStringSerializer stringSerializer, IObjectHeaderSerialize objects[j] = _objectSerializer.Deserialize(reader, header, objects[j]); } + var expectedPosition = positionStart + binarySizeObjects; + if (expectedPosition != reader.BaseStream.Position) + throw new BadReadException("Expected stream position does not match actual position"); + var nrSecondCollectables = reader.ReadInt32(); var secondCollectables = new List(nrSecondCollectables); diff --git a/SatisfactorySaveNet/ExtraDataSerializer.cs b/SatisfactorySaveNet/ExtraDataSerializer.cs new file mode 100644 index 0000000..e29b206 --- /dev/null +++ b/SatisfactorySaveNet/ExtraDataSerializer.cs @@ -0,0 +1,363 @@ +using SatisfactorySaveNet.Abstracts; +using SatisfactorySaveNet.Abstracts.Extra; +using SatisfactorySaveNet.Abstracts.Maths.Vector; +using SatisfactorySaveNet.Abstracts.Model; +using SatisfactorySaveNet.Abstracts.Model.Extra; +using System; +using System.IO; +using System.Linq; +using System.Text; + +namespace SatisfactorySaveNet; + +public class ExtraDataSerializer : IExtraDataSerializer +{ + public static readonly IExtraDataSerializer Instance = new ExtraDataSerializer(StringSerializer.Instance, ObjectReferenceSerializer.Instance, VectorSerializer.Instance, HexSerializer.Instance, PropertySerializer.Instance); + + private readonly IStringSerializer _stringSerializer; + private readonly IObjectReferenceSerializer _objectReferenceSerializer; + private readonly IVectorSerializer _vectorSerializer; + private readonly IHexSerializer _hexSerializer; + private readonly IPropertySerializer _propertySerializer; + + public ExtraDataSerializer(IStringSerializer stringSerializer, IObjectReferenceSerializer objectReferenceSerializer, IVectorSerializer vectorSerializer, IHexSerializer hexSerializer, IPropertySerializer propertySerializer) + { + _stringSerializer = stringSerializer; + _objectReferenceSerializer = objectReferenceSerializer; + _vectorSerializer = vectorSerializer; + _hexSerializer = hexSerializer; + _propertySerializer = propertySerializer; + } + + public ExtraData? Deserialize(BinaryReader reader, string typePath, Header header, long expectedPosition) + { + if (KnownConstants.IsConveyor(typePath)) + return DeserializeConveyor(reader); + if (KnownConstants.IsPowerLine(typePath)) + return DeserializePowerLine(reader, header); + if (KnownConstants.IsVehicle(typePath)) + return DeserializeVehicle(reader, header); + if (KnownConstants.IsLocomotive(typePath) || KnownConstants.IsFreightWagon(typePath)) + return DeserializeLocomotiveData(reader, header); + + return typePath switch + { + "/Game/FactoryGame/-Shared/Blueprint/BP_GameState.BP_GameState_C" or "/Game/FactoryGame/-Shared/Blueprint/BP_GameMode.BP_GameMode_C" => DeserializeBlueprint(reader), + "/Game/FactoryGame/Character/Player/BP_PlayerState.BP_PlayerState_C" => DeserializePlayerData(reader, expectedPosition), + "/Game/FactoryGame/Buildable/Factory/DroneStation/BP_DroneTransport.BP_DroneTransport_C" => DeserializeDroneStation(reader, header, expectedPosition), + "/Game/FactoryGame/-Shared/Blueprint/BP_CircuitSubsystem.BP_CircuitSubsystem_C" => DeserializeCircuitData(reader), + _ => DeserializeUnknownData(reader, header, typePath, expectedPosition), + }; + } + + private UnknownExtraData? DeserializeUnknownData(BinaryReader reader, Header header, string typePath, long expectedPosition) + { + var bytesCount = expectedPosition - reader.BaseStream.Position; + + if (bytesCount > 4) + { + if (header.SaveVersion >= 41 && typePath.StartsWith("/Script/FactoryGame.FG", StringComparison.Ordinal)) + reader.BaseStream.Seek(8, SeekOrigin.Current); + else + { + var missing = _hexSerializer.Deserialize(reader, (int) bytesCount); + + return new UnknownExtraData + { + Missing = missing, + }; + } + } + else + { + reader.BaseStream.Seek(4, SeekOrigin.Current); + } + + return null; + } + + private CircuitData DeserializeCircuitData(BinaryReader reader) + { + var count = reader.ReadInt32(); + var nrElements = reader.ReadInt32(); + var circuits = new Circuit[nrElements]; + + for (var x = 0; x < nrElements; x++) + { + var circuitId = reader.ReadInt32(); + var objectReference = _objectReferenceSerializer.Deserialize(reader); + + circuits[x] = new Circuit + { + CircuitId = circuitId, + ObjectReference = objectReference + }; + } + + return new CircuitData + { + Count = count, + Circuits = circuits + }; + } + + private DroneStationData DeserializeDroneStation(BinaryReader reader, Header header, long expectedPosition) + { + if (header.SaveVersion >= 41) + { + var unknown1 = reader.ReadInt32(); + var unknown2 = reader.ReadInt32(); + + var nrActiveActions = reader.ReadInt32(); + var activeActions = new DroneStationAction[nrActiveActions]; + + for (var x = 0; x < nrActiveActions; x++) + { + var name = _stringSerializer.Deserialize(reader); + var properties = _propertySerializer.DeserializeProperties(reader, header).ToArray(); + + activeActions[x] = new DroneStationAction + { + Properties = properties, + Name = name + }; + } + + var nrQueuedActions = reader.ReadInt32(); + var queuedActions = new DroneStationAction[nrQueuedActions]; + + for (var x = 0; x < nrQueuedActions; x++) + { + var name = _stringSerializer.Deserialize(reader); + var properties = _propertySerializer.DeserializeProperties(reader, header).ToArray(); + + queuedActions[x] = new DroneStationAction + { + Properties = properties, + Name = name + }; + } + + return new DroneStationData + { + ActionQueue = queuedActions, + ActiveActions = activeActions, + Unknown1 = unknown1, + Unknown2 = unknown2, + }; + } + + var bytesCount = expectedPosition - reader.BaseStream.Position; + var missing = _hexSerializer.Deserialize(reader, (int)bytesCount); + + return new DroneStationData + { + Missing = missing + }; + } + + private PlayerData? DeserializePlayerData(BinaryReader reader, long expectedPosition) + { + var bytesCount = expectedPosition - reader.BaseStream.Position; + var playerData = new PlayerData(); + + if (bytesCount > 0) + { + var missing = _hexSerializer.Deserialize(reader, (int)bytesCount); + reader.BaseStream.Seek(-bytesCount, SeekOrigin.Current); + _ = reader.ReadInt32(); + var mode = reader.ReadByte(); + + playerData.PlayerType = mode; + + switch (mode) + { + case 241: + _ = reader.ReadByte(); + + var nrElements1 = reader.ReadInt32(); + var sb1 = new StringBuilder(); + + for (var x = 0; x < nrElements1; x++) + { + sb1.Append(reader.ReadByte().ToString("X2")); + } + + playerData.EpicOnlineServicesId = sb1.ToString().TrimStart('0'); //.Substring(1, 32); + return playerData; + case 248: + var value = _stringSerializer.Deserialize(reader); + playerData.EpicOnlineServicesId = value.Split("|")[0]; + return playerData; + case 249: + _ = _stringSerializer.Deserialize(reader); + break; + case 17: + var nrElements2 = reader.ReadByte(); + var sb2 = new StringBuilder(); + + for (var x = 0; x < nrElements2; x++) + { + sb2.Append(reader.ReadByte().ToString("X2")); + } + + playerData.EpicOnlineServicesId = sb2.ToString().TrimStart('0'); + return playerData; + case 25: + case 29: + var nrElements3 = reader.ReadByte(); + var sb3 = new StringBuilder(); + + for (var x = 0; x < nrElements3; x++) + { + sb3.Append(reader.ReadByte().ToString("X2")); + } + + playerData.SteamId = sb3.ToString().TrimStart('0'); + return playerData; + case 8: + playerData.PlatformId = _stringSerializer.Deserialize(reader); + return playerData; + default: + playerData.Missing = missing; + reader.BaseStream.Seek(-5, SeekOrigin.Current); + break; + } + + return playerData; + } + + return null; + } + + private BlueprintData DeserializeBlueprint(BinaryReader reader) + { + var count = reader.ReadInt32(); + var nrElements = reader.ReadInt32(); + var objectReferences = new ObjectReference[nrElements]; + + for (var x = 0; x < nrElements; x++) + { + objectReferences[x] = _objectReferenceSerializer.Deserialize(reader); + } + + return new BlueprintData + { + Count = count, + Objects = objectReferences + }; + } + + private ConveyorData DeserializeConveyor(BinaryReader reader) + { + var count = reader.ReadInt32(); + var nrElements = reader.ReadInt32(); + + var items = new Item[nrElements]; + + for (var x = 0; x < nrElements; x++) + { + var length = reader.ReadInt32(); + var name = _stringSerializer.Deserialize(reader); + var objectReference = _objectReferenceSerializer.Deserialize(reader); + var position = VectorSerializer.Instance.DeserializeVec4B(reader); + + items[x] = new Item + { + Name = name, + ObjectReference = objectReference, + Position = position, + Length = length + }; + } + + return new ConveyorData + { + Items = items, + Count = count + }; + } + + private LocomotiveData DeserializeLocomotiveData(BinaryReader reader, Header header) + { + var count = reader.ReadInt32(); + var nrElements = reader.ReadInt32(); + var vehicleObjects = new CargoObject[nrElements]; + + var unknownSize = header.SaveVersion >= 41 ? 105 : 53; + + for (var x = 0; x < nrElements; x++) + { + var name = _stringSerializer.Deserialize(reader); + var unknown = _hexSerializer.Deserialize(reader, unknownSize); + + vehicleObjects[x] = new CargoObject + { + Name = name, + Unknown = unknown, + }; + } + + var previous = _objectReferenceSerializer.Deserialize(reader); + var next = _objectReferenceSerializer.Deserialize(reader); + + return new LocomotiveData + { + Count = count, + CargoObjects = vehicleObjects, + Previous = previous, + Next = next + }; + } + + private PowerLineData DeserializePowerLine(BinaryReader reader, Header header) + { + var count = reader.ReadInt32(); + var source = _objectReferenceSerializer.Deserialize(reader); + var target = _objectReferenceSerializer.Deserialize(reader); + Vector3? sourceTranslation = null; + Vector3? targetTranslation = null; + + if (header.SaveVersion >= 33 && header.SaveVersion < 41) + { + sourceTranslation = _vectorSerializer.DeserializeVec3(reader); + targetTranslation = _vectorSerializer.DeserializeVec3(reader); + } + + return new PowerLineData + { + Count = count, + Source = source, + Target = target, + SourceTranslation = sourceTranslation, + TargetTranslation = targetTranslation + }; + } + + private VehicleData DeserializeVehicle(BinaryReader reader, Header header) + { + var count = reader.ReadInt32(); + var nrElements = reader.ReadInt32(); + var vehicleObjects = new CargoObject[nrElements]; + + var unknownSize = header.SaveVersion >= 41 ? 105 : 53; + + for (var x = 0; x < nrElements; x++) + { + var name = _stringSerializer.Deserialize(reader); + var unknown = _hexSerializer.Deserialize(reader, unknownSize); + + vehicleObjects[x] = new CargoObject + { + Name = name, + Unknown = unknown, + }; + } + + return new VehicleData + { + Count = count, + CargoObjects = vehicleObjects + }; + } +} \ No newline at end of file diff --git a/SatisfactorySaveNet/KnownConstants.cs b/SatisfactorySaveNet/KnownConstants.cs index c8e223e..51b76f5 100644 --- a/SatisfactorySaveNet/KnownConstants.cs +++ b/SatisfactorySaveNet/KnownConstants.cs @@ -1,17 +1,22 @@ -using System; -using System.Collections.Generic; +using System; +using System.Collections.Frozen; +using System.Linq; namespace SatisfactorySaveNet; public static class KnownConstants { - public static readonly IReadOnlySet ConveyorBelts = new HashSet(StringComparer.Ordinal) + public static readonly FrozenSet ConveyorBelts = new[] { "/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk1/Build_ConveyorBeltMk1.Build_ConveyorBeltMk1_C", "/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk2/Build_ConveyorBeltMk2.Build_ConveyorBeltMk2_C", "/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk3/Build_ConveyorBeltMk3.Build_ConveyorBeltMk3_C", "/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk4/Build_ConveyorBeltMk4.Build_ConveyorBeltMk4_C", - "/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk5/Build_ConveyorBeltMk5.Build_ConveyorBeltMk5_C", + "/Game/FactoryGame/Buildable/Factory/ConveyorBeltMk5/Build_ConveyorBeltMk5.Build_ConveyorBeltMk5_C" + }.ToFrozenSet(StringComparer.Ordinal); + + public static readonly string[] ModConveyorBelts = + [ "/Conveyors_Mod/Build_BeltMk", "/Game/Conveyors_Mod/Build_BeltMk", "/UltraFastLogistics/Buildable/build_conveyorbeltMK", @@ -19,15 +24,19 @@ public static class KnownConstants "/conveyorbeltmod/Belt/mk", "/minerplus/content/buildable/Factory/belt_", "/bamfp/content/buildable/Factory/belt_" - }; + ]; - public static readonly IReadOnlySet ConveyorLifts = new HashSet(StringComparer.Ordinal) + public static readonly FrozenSet ConveyorLifts = new[] { "/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk1/Build_ConveyorLiftMk1.Build_ConveyorLiftMk1_C", "/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk2/Build_ConveyorLiftMk2.Build_ConveyorLiftMk2_C", "/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk3/Build_ConveyorLiftMk3.Build_ConveyorLiftMk3_C", "/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk4/Build_ConveyorLiftMk4.Build_ConveyorLiftMk4_C", - "/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk5/Build_ConveyorLiftMk5.Build_ConveyorLiftMk5_C", + "/Game/FactoryGame/Buildable/Factory/ConveyorLiftMk5/Build_ConveyorLiftMk5.Build_ConveyorLiftMk5_C" + }.ToFrozenSet(StringComparer.Ordinal); + + public static readonly string[] ModConveyorLifts = + [ "/minerplus/content/buildable/Factory/lift", "/bamfp/content/buildable/Factory/lift", "/Game/Conveyors_Mod/Build_LiftMk", @@ -35,20 +44,97 @@ public static class KnownConstants "/Game/CoveredConveyor", "/CoveredConveyor", "/conveyorbeltmod/lift/" - }; + ]; + + public static readonly FrozenSet PowerLines = new[] + { + "/Game/FactoryGame/Buildable/Factory/PowerLine/Build_PowerLine.Build_PowerLine_C", + "/Game/FactoryGame/Events/Christmas/Buildings/PowerLineLights/Build_XmassLightsLine.Build_XmassLightsLine_C" + }.ToFrozenSet(StringComparer.Ordinal); + + public static readonly string[] ModPowerLines = + [ + "/FlexSplines/PowerLine/Build_FlexPowerline.Build_FlexPowerline_C", + "/AB_CableMod/Visuals1/Build_AB-PLCopper.Build_AB-PLCopper_C", + "/AB_CableMod/Visuals1/Build_AB-PLCaterium.Build_AB-PLCaterium_C", + "/AB_CableMod/Visuals3/Build_AB-PLHeavy.Build_AB-PLHeavy_C", + "/AB_CableMod/Visuals4/Build_AB-SPLight.Build_AB-SPLight_C", + "/AB_CableMod/Visuals3/Build_AB-PLPaintable.Build_AB-PLPaintable_C", + "/AB_CableMod/Cables_Heavy/Build_AB-PLHeavy-Cu.Build_AB-PLHeavy-Cu_C", + "/AB_CableMod/Cables_Standard/Build_AB-PLStandard-Cu.Build_AB-PLStandard-Cu_C", + "/AB_CableMod/Cables_Wire/Build_AB-PLWire-Si.Build_AB-PLWire-Si_C", + "/AB_CableMod/Cables_Wire/Build_AB-PLWire-Au.Build_AB-PLWire-Au_C" + ]; + + public static readonly FrozenSet Vehicles = new[] + { + "/Game/FactoryGame/Buildable/Vehicle/Tractor/BP_Tractor.BP_Tractor_C", + "/Game/FactoryGame/Buildable/Vehicle/Truck/BP_Truck.BP_Truck_C", + "/Game/FactoryGame/Buildable/Vehicle/Explorer/BP_Explorer.BP_Explorer_C", + "/Game/FactoryGame/Buildable/Vehicle/Cyberwagon/Testa_BP_WB.Testa_BP_WB_C", + "/Game/FactoryGame/Buildable/Vehicle/Golfcart/BP_Golfcart.BP_Golfcart_C", + "/Game/FactoryGame/Buildable/Vehicle/Golfcart/BP_GolfcartGold.BP_GolfcartGold_C" + }.ToFrozenSet(StringComparer.Ordinal); + + public static readonly string[] ModVehicles = + [ + "/x3_mavegrag/Vehicles/Trucks/TruckMk1/BP_X3Truck_Mk1.BP_X3Truck_Mk1_C" + ]; + + public static readonly FrozenSet Locomotives = new[] + { + "/Game/FactoryGame/Buildable/Vehicle/Train/Locomotive/BP_Locomotive.BP_Locomotive_C" + }.ToFrozenSet(StringComparer.Ordinal); + + public static readonly string[] ModLocomotives = + [ + "/x3_mavegrag/Vehicles/Trains/Locomotive_Mk1/BP_X3Locomotive_Mk1.BP_X3Locomotive_Mk1_C", + "/DI_Transportation_Darkplate/Trains/Locomotive/DI_Locomotive_400/Build_DI_Locomotive_400.Build_DI_Locomotive_400_C" + ]; + + public static readonly FrozenSet FreightWagon = new[] + { + "/Game/FactoryGame/Buildable/Vehicle/Train/Wagon/BP_FreightWagon.BP_FreightWagon_C" + }.ToFrozenSet(StringComparer.Ordinal); + + public static readonly string[] ModFreightWagon = + [ + "/x3_mavegrag/Vehicles/Trains/CargoWagon_Mk1/BP_X3CargoWagon_Mk1.BP_X3CargoWagon_Mk1_C", + "/DI_Transportation_Darkplate/Trains/Wagon/DI_Wagon_512/Build_DI_FrieghtWagon512.Build_DI_FrieghtWagon512_C" + ]; public static bool IsConveyorLift(string path) { - return ConveyorLifts.Contains(path); + return ConveyorLifts.Contains(path) || ModConveyorLifts.Any(x => x.StartsWith(path, StringComparison.Ordinal)); } public static bool IsConveyorBelt(string path) { - return ConveyorBelts.Contains(path); + return ConveyorBelts.Contains(path) || ModConveyorBelts.Any(x => x.StartsWith(path, StringComparison.Ordinal)); } public static bool IsConveyor(string path) { return IsConveyorLift(path) || IsConveyorBelt(path); } + + public static bool IsPowerLine(string path) + { + return PowerLines.Contains(path) || ModPowerLines.Any(x => x.StartsWith(path, StringComparison.Ordinal)); + } + + public static bool IsVehicle(string path) + { + return Vehicles.Contains(path) || ModVehicles.Any(x => x.StartsWith(path, StringComparison.Ordinal)); + } + + public static bool IsLocomotive(string path) + { + return Locomotives.Contains(path) || ModLocomotives.Any(x => x.StartsWith(path, StringComparison.Ordinal)); + } + + public static bool IsFreightWagon(string path) + { + return FreightWagon.Contains(path) || ModFreightWagon.Any(x => x.StartsWith(path, StringComparison.Ordinal)); + } } \ No newline at end of file diff --git a/SatisfactorySaveNet/ObjectSerializer.cs b/SatisfactorySaveNet/ObjectSerializer.cs index b58f83c..4c0ed22 100644 --- a/SatisfactorySaveNet/ObjectSerializer.cs +++ b/SatisfactorySaveNet/ObjectSerializer.cs @@ -10,17 +10,19 @@ namespace SatisfactorySaveNet; public class ObjectSerializer : IObjectSerializer { - public static readonly IObjectSerializer Instance = new ObjectSerializer(StringSerializer.Instance, ObjectReferenceSerializer.Instance, PropertySerializer.Instance); + public static readonly IObjectSerializer Instance = new ObjectSerializer(StringSerializer.Instance, ObjectReferenceSerializer.Instance, PropertySerializer.Instance, ExtraDataSerializer.Instance); private readonly IStringSerializer _stringSerializer; private readonly IObjectReferenceSerializer _objectReferenceSerializer; private readonly IPropertySerializer _propertySerializer; + private readonly IExtraDataSerializer _extraDataSerializer; - public ObjectSerializer(IStringSerializer stringSerializer, IObjectReferenceSerializer objectReferenceSerializer, IPropertySerializer propertySerializer) + public ObjectSerializer(IStringSerializer stringSerializer, IObjectReferenceSerializer objectReferenceSerializer, IPropertySerializer propertySerializer, IExtraDataSerializer extraDataSerializer) { _stringSerializer = stringSerializer; _objectReferenceSerializer = objectReferenceSerializer; _propertySerializer = propertySerializer; + _extraDataSerializer = extraDataSerializer; } public ComponentObject Deserialize(BinaryReader reader, Header header, ComponentObject componentObject) @@ -62,24 +64,25 @@ private ActorObject DeserializeActor(BinaryReader reader, Header header, ActorOb actorObject.ParentObjectName = parentObjectName; var expectedPosition = positionStart + binarySize; + actorObject.Components = components; if (expectedPosition == reader.BaseStream.Position) return actorObject; - var properties = _propertySerializer.DeserializeProperties(reader, header).ToList(); + var properties = _propertySerializer.DeserializeProperties(reader, header, expectedPosition: expectedPosition).ToList(); - actorObject.Components = components; actorObject.Properties = properties; + actorObject.ExtraData = _extraDataSerializer.Deserialize(reader, actorObject.TypePath, header, expectedPosition); var missingBytes = expectedPosition - reader.BaseStream.Position; if (missingBytes > 4) { var binary = reader.ReadBytes(Cast(missingBytes)); - //var hex = new string(binary.Select(Convert.ToChar).ToArray()); + var hex = new string(binary.Select(Convert.ToChar).ToArray()); } else - reader.BaseStream.Seek(4, SeekOrigin.Current); + reader.BaseStream.Seek(missingBytes, SeekOrigin.Current); return actorObject; } @@ -113,10 +116,10 @@ private ComponentObject DeserializeComponent(BinaryReader reader, Header header, if (missingBytes > 4) { var binary = reader.ReadBytes(Cast(missingBytes)); - //var hex = new string(binary.Select(Convert.ToChar).ToArray()); + var hex = new string(binary.Select(Convert.ToChar).ToArray()); } else - reader.BaseStream.Seek(4, SeekOrigin.Current); + reader.BaseStream.Seek(missingBytes, SeekOrigin.Current); return componentObject; } diff --git a/SatisfactorySaveNet/PropertySerializer.cs b/SatisfactorySaveNet/PropertySerializer.cs index e757136..be0d41d 100644 --- a/SatisfactorySaveNet/PropertySerializer.cs +++ b/SatisfactorySaveNet/PropertySerializer.cs @@ -5,6 +5,7 @@ using SatisfactorySaveNet.Abstracts.Model.Union; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -42,11 +43,19 @@ public PropertySerializer(IStringSerializer stringSerializer, IObjectReferenceSe _softObjectReferenceSerializer = softObjectReferenceSerializer; } - public IEnumerable DeserializeProperties(BinaryReader reader, Header? header = null, string? type = null) + public IEnumerable DeserializeProperties(BinaryReader reader, Header? header = null, string? type = null, long? expectedPosition = null) { + if (expectedPosition != null && expectedPosition < reader.BaseStream.Position) + yield break; + Property? property; while ((property = DeserializeProperty(reader, header, type)) != null) + { yield return property; + + if (expectedPosition != null && expectedPosition < reader.BaseStream.Position) + yield break; + } } [return: NotNullIfNotNull(nameof(type))] @@ -58,11 +67,9 @@ public IEnumerable DeserializeProperties(BinaryReader reader, Header? { propertyName = _stringSerializer.Deserialize(reader); - if (string.Equals(propertyName, "None", StringComparison.Ordinal)) + if (string.Equals(propertyName, "None", StringComparison.Ordinal) || string.IsNullOrWhiteSpace(propertyName)) return null; - //if (reader.ReadByte() != 0) reader.BaseStream.Seek(-1, SeekOrigin.Current); //ToDo: Dead code? - type = _stringSerializer.Deserialize(reader); } @@ -332,23 +339,6 @@ private ArrayProperty DeserializeArrayProperty(BinaryReader reader, Header heade private TextProperty DeserializeTextProperty(BinaryReader reader, Header header) { - //var binarySize = reader.ReadInt32(); - //var index = reader.ReadInt32(); - //var padding = reader.ReadSByte(); - //var flags = reader.ReadInt32(); - //var historyType = reader.ReadSByte(); - //var isCultureInvariant = reader.ReadInt32() != 0; - //var value = _stringSerializer.Deserialize(reader); - // - //return new TextProperty - //{ - // Index = index, - // Flags = flags, - // HistoryType = historyType, - // IsCultureInvariant = isCultureInvariant, - // Value = value, - //}; - var binarySize = reader.ReadInt32(); var index = reader.ReadInt32(); var padding = reader.ReadSByte(); @@ -436,7 +426,6 @@ private ArrayStructProperty DeserializeArrayStructProperty(BinaryReader reader, var propertyType = _stringSerializer.Deserialize(reader); var binarySize = reader.ReadInt32(); - var startPosition = reader.BaseStream.Position; var padding1 = reader.ReadInt32(); var elementType = _stringSerializer.Deserialize(reader); @@ -446,13 +435,11 @@ private ArrayStructProperty DeserializeArrayStructProperty(BinaryReader reader, var uuid4 = reader.ReadInt32(); var padding2 = reader.ReadSByte(); - var endPosition = startPosition + binarySize; - var values = new TypedData[length]; for (var x = 0; x < length; x++) { - values[x] = _typedDataSerializer.Deserialize(reader, header, elementType); + values[x] = _typedDataSerializer.Deserialize(reader, header, elementType, true); } var property = new ArrayStructProperty @@ -866,8 +853,7 @@ private SetProperty DeserializeSetProperty(BinaryReader reader, string propertyN private FINNetworkProperty DeserializeFINNetworkProperty(BinaryReader reader) { - var levelName = _stringSerializer.Deserialize(reader); //ToDo: ObjectReference - var pathName = _stringSerializer.Deserialize(reader); + var objectReference = _objectReferenceSerializer.Deserialize(reader); FINNetworkProperty? previous = null; string? step = null; if (reader.ReadInt32() == 1) @@ -875,7 +861,7 @@ private FINNetworkProperty DeserializeFINNetworkProperty(BinaryReader reader) if (reader.ReadInt32() == 1) step = _stringSerializer.Deserialize(reader); - return new FINNetworkProperty { LevelName = levelName, PathName = pathName, Previous = previous, Step = step }; + return new FINNetworkProperty { ObjectReference = objectReference, Previous = previous, Step = step }; } private StrProperty DeserializeStrProperty(BinaryReader reader) @@ -897,13 +883,12 @@ private StrProperty DeserializeStrProperty(BinaryReader reader) private StructProperty DeserializeStructProperty(BinaryReader reader, Header header) { var binarySize = reader.ReadInt32(); - var startPosition = reader.BaseStream.Position; var index = reader.ReadInt32(); var type = _stringSerializer.Deserialize(reader); var padding1 = reader.ReadInt64(); var padding2 = reader.ReadInt64(); var padding3 = reader.ReadSByte(); - var typedData = _typedDataSerializer.Deserialize(reader, header, type); + var typedData = _typedDataSerializer.Deserialize(reader, header, type, false); var property = new StructProperty { diff --git a/SatisfactorySaveNet/TypedDataSerializer.cs b/SatisfactorySaveNet/TypedDataSerializer.cs index d2e24f1..8417586 100644 --- a/SatisfactorySaveNet/TypedDataSerializer.cs +++ b/SatisfactorySaveNet/TypedDataSerializer.cs @@ -38,7 +38,7 @@ public TypedDataSerializer(IVectorSerializer vectorSerializer, IStringSerializer _objectReferenceSerializer = objectReferenceSerializer; } - public TypedData Deserialize(BinaryReader reader, Header header, string type) + public TypedData Deserialize(BinaryReader reader, Header header, string type, bool isArrayProperty) { return type switch { @@ -53,7 +53,7 @@ public TypedData Deserialize(BinaryReader reader, Header header, string type) nameof(RailroadTrackPosition) => DeserializeRailroadTrackPosition(reader), nameof(TimerHandle) => DeserializeTimerHandle(reader), nameof(Guid) => DeserializeGuid(reader), - nameof(InventoryItem) => DeserializeInventoryItem(reader, header), + nameof(InventoryItem) => DeserializeInventoryItem(reader, header, isArrayProperty), nameof(FluidBox) => DeserializeFluidBox(reader), nameof(SlateBrush) => DeserializeSlateBrush(reader), nameof(DateTime) => DeserializeDateTime(reader), @@ -386,6 +386,7 @@ private LinearColor DeserializeLinearColor(BinaryReader reader) }; } + //Seems to be dead code private TypedData DeserializeInventoryStack(BinaryReader reader, Header header) { if (header.SaveVersion >= 42) @@ -426,7 +427,7 @@ private TypedData DeserializeInventoryStack(BinaryReader reader, Header header) } } - private InventoryItem DeserializeInventoryItem(BinaryReader reader, Header header) + private InventoryItem DeserializeInventoryItem(BinaryReader reader, Header header, bool isArrayProperty) { var padding = reader.ReadInt32(); var itemType = _stringSerializer.Deserialize(reader); @@ -438,7 +439,10 @@ private InventoryItem DeserializeInventoryItem(BinaryReader reader, Header heade else unknown1 = _stringSerializer.Deserialize(reader); - var property = _propertySerializer.DeserializeProperty(reader, header); + Property? property = null; + + if (!isArrayProperty) + property = _propertySerializer.DeserializeProperty(reader, header); return new InventoryItem {