From b875069c32e2a95cd33a4614ff598932c3b2cb86 Mon Sep 17 00:00:00 2001 From: ManlyMarco <39247311+ManlyMarco@users.noreply.github.com> Date: Fri, 30 Aug 2024 21:23:06 +0200 Subject: [PATCH] Add support for SamabakeScramble (#182) --- .../Data/Cards/{AI => }/BlockHeader.cs | 2 +- src/KKManager.Core/Data/Cards/CardLoader.cs | 15 +- src/KKManager.Core/Data/Cards/CardType.cs | 2 + .../Data/Cards/EC/BlockHeader.cs | 28 ---- .../Data/Cards/HC/BlockHeader.cs | 25 --- .../Data/Cards/KK/BlockHeader.cs | 28 ---- .../Data/Cards/KKS/BlockHeader.cs | 28 ---- .../Data/Cards/RG/BlockHeader.cs | 25 --- src/KKManager.Core/Data/Cards/SVS/About.cs | 22 +++ .../Data/Cards/SVS/ChaFileExtended.cs | 9 ++ .../Data/Cards/SVS/GameInfo_SV.cs | 20 +++ .../Data/Cards/SVS/GameParameter_SV.cs | 51 ++++++ src/KKManager.Core/Data/Cards/SVS/Graphic.cs | 22 +++ .../Data/Cards/SVS/Parameter.cs | 27 ++++ .../Data/Cards/SVS/SamabakeCard.cs | 150 ++++++++++++++++++ src/KKManager.Core/Data/Cards/Utility.cs | 64 +++++++- src/KKManager.Core/Functions/GameType.cs | 3 +- .../Functions/InstallDirectoryHelper.cs | 4 +- src/KKManager.Core/KKManager.Core.csproj | 19 ++- 19 files changed, 396 insertions(+), 148 deletions(-) rename src/KKManager.Core/Data/Cards/{AI => }/BlockHeader.cs (93%) delete mode 100644 src/KKManager.Core/Data/Cards/EC/BlockHeader.cs delete mode 100644 src/KKManager.Core/Data/Cards/HC/BlockHeader.cs delete mode 100644 src/KKManager.Core/Data/Cards/KK/BlockHeader.cs delete mode 100644 src/KKManager.Core/Data/Cards/KKS/BlockHeader.cs delete mode 100644 src/KKManager.Core/Data/Cards/RG/BlockHeader.cs create mode 100644 src/KKManager.Core/Data/Cards/SVS/About.cs create mode 100644 src/KKManager.Core/Data/Cards/SVS/ChaFileExtended.cs create mode 100644 src/KKManager.Core/Data/Cards/SVS/GameInfo_SV.cs create mode 100644 src/KKManager.Core/Data/Cards/SVS/GameParameter_SV.cs create mode 100644 src/KKManager.Core/Data/Cards/SVS/Graphic.cs create mode 100644 src/KKManager.Core/Data/Cards/SVS/Parameter.cs create mode 100644 src/KKManager.Core/Data/Cards/SVS/SamabakeCard.cs diff --git a/src/KKManager.Core/Data/Cards/AI/BlockHeader.cs b/src/KKManager.Core/Data/Cards/BlockHeader.cs similarity index 93% rename from src/KKManager.Core/Data/Cards/AI/BlockHeader.cs rename to src/KKManager.Core/Data/Cards/BlockHeader.cs index 6132f664..69cd385b 100644 --- a/src/KKManager.Core/Data/Cards/AI/BlockHeader.cs +++ b/src/KKManager.Core/Data/Cards/BlockHeader.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using MessagePack; -namespace KKManager.Data.Cards.AI +namespace KKManager.Data.Cards { [MessagePackObject(true)] public class BlockHeader diff --git a/src/KKManager.Core/Data/Cards/CardLoader.cs b/src/KKManager.Core/Data/Cards/CardLoader.cs index 20c6d015..8fc288f6 100644 --- a/src/KKManager.Core/Data/Cards/CardLoader.cs +++ b/src/KKManager.Core/Data/Cards/CardLoader.cs @@ -17,6 +17,7 @@ using KKManager.Data.Cards.KK; using KKManager.Data.Cards.KKS; using KKManager.Data.Cards.RG; +using KKManager.Data.Cards.SVS; using KKManager.Data.Plugins; using KKManager.Data.Zipmods; using KKManager.Util; @@ -159,9 +160,7 @@ public static Card ParseCard(FileInfo file) { var loadProductNo = reader.ReadInt32(); //if (loadProductNo > 100) - //{ // return null; - //} var marker = reader.ReadString(); var gameType = GetGameType(marker, true); @@ -195,6 +194,10 @@ public static Card ParseCard(FileInfo file) card = HoneyCoomCard.ParseHCPChara(file, reader, gameType); break; + case CardType.SamabakeScramble: + card = SamabakeCard.ParseSvsChara(file, reader, gameType); + break; + case CardType.KoikatuClothes: card = KoiCoordCard.ParseKoiClothes(file, reader, gameType); break; @@ -202,6 +205,7 @@ public static Card ParseCard(FileInfo file) card = AiCoordCard.ParseAiClothes(file, reader, gameType); break; + case CardType.SamabakeScrambleClothes: case CardType.Unknown: default: throw new ArgumentOutOfRangeException($"GameType={gameType} is not supported"); @@ -256,13 +260,20 @@ private static CardType GetGameType(string marker, bool throwOnUnknown) return CardType.HoneyCome; case "【HCPChara】": return CardType.HoneyComeccp; + case "【SVChara】": + return CardType.SamabakeScramble; + // todo differnt format, saved at very end of data //case "【KStudio】": // return CardType.KoikatuStudio; + case "【KoiKatuClothes】": return CardType.KoikatuClothes; case "【AIS_Clothes】": return CardType.AiSyoujyoClothes; + case "【SVClothes】": + return CardType.SamabakeScrambleClothes; + default: if (throwOnUnknown) throw new ArgumentOutOfRangeException($"Unknown game tag: {PathTools.SanitizeFileName(marker.Left(20))}"); diff --git a/src/KKManager.Core/Data/Cards/CardType.cs b/src/KKManager.Core/Data/Cards/CardType.cs index 5855b593..a2e441a9 100644 --- a/src/KKManager.Core/Data/Cards/CardType.cs +++ b/src/KKManager.Core/Data/Cards/CardType.cs @@ -12,7 +12,9 @@ public enum CardType RoomGirl, HoneyCome, HoneyComeccp, + SamabakeScramble, KoikatuClothes, AiSyoujyoClothes, + SamabakeScrambleClothes, } } \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/EC/BlockHeader.cs b/src/KKManager.Core/Data/Cards/EC/BlockHeader.cs deleted file mode 100644 index b6d9cb01..00000000 --- a/src/KKManager.Core/Data/Cards/EC/BlockHeader.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Collections.Generic; -using MessagePack; - -namespace KKManager.Data.Cards.EC -{ - [MessagePackObject(true)] - public class BlockHeader - { - public List lstInfo { get; set; } = new List(); - - public Info SearchInfo(string name) - { - return lstInfo.Find(x => x.name == name); - } - - [MessagePackObject(true)] - public class Info - { - public string name { get; set; } - - public string version { get; set; } - - public long pos { get; set; } - - public long size { get; set; } - } - } -} \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/HC/BlockHeader.cs b/src/KKManager.Core/Data/Cards/HC/BlockHeader.cs deleted file mode 100644 index 5edbe21e..00000000 --- a/src/KKManager.Core/Data/Cards/HC/BlockHeader.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using MessagePack; - -namespace KKManager.Data.Cards.HC -{ - [MessagePackObject(true)] - public class BlockHeader - { - public List lstInfo { get; set; } = new List(); - - public Info SearchInfo(string name) - { - return lstInfo.Find(x => x.name == name); - } - - [MessagePackObject(true)] - public class Info - { - public string name { get; set; } - public string version { get; set; } - public long pos { get; set; } - public long size { get; set; } - } - } -} \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/KK/BlockHeader.cs b/src/KKManager.Core/Data/Cards/KK/BlockHeader.cs deleted file mode 100644 index c35c5f9b..00000000 --- a/src/KKManager.Core/Data/Cards/KK/BlockHeader.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Collections.Generic; -using MessagePack; - -namespace KKManager.Data.Cards.KK -{ - [MessagePackObject(true)] - public class BlockHeader - { - public List lstInfo { get; set; } = new List(); - - public Info SearchInfo(string name) - { - return lstInfo.Find(x => x.name == name); - } - - [MessagePackObject(true)] - public class Info - { - public string name { get; set; } - - public string version { get; set; } - - public long pos { get; set; } - - public long size { get; set; } - } - } -} \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/KKS/BlockHeader.cs b/src/KKManager.Core/Data/Cards/KKS/BlockHeader.cs deleted file mode 100644 index a7d7e587..00000000 --- a/src/KKManager.Core/Data/Cards/KKS/BlockHeader.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Collections.Generic; -using MessagePack; - -namespace KKManager.Data.Cards.KKS -{ - [MessagePackObject(true)] - public class BlockHeader - { - public List lstInfo { get; set; } = new List(); - - public Info SearchInfo(string name) - { - return lstInfo.Find(x => x.name == name); - } - - [MessagePackObject(true)] - public class Info - { - public string name { get; set; } - - public string version { get; set; } - - public long pos { get; set; } - - public long size { get; set; } - } - } -} \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/RG/BlockHeader.cs b/src/KKManager.Core/Data/Cards/RG/BlockHeader.cs deleted file mode 100644 index 72b4cb31..00000000 --- a/src/KKManager.Core/Data/Cards/RG/BlockHeader.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; -using MessagePack; - -namespace KKManager.Data.Cards.RG -{ - [MessagePackObject(true)] - public class BlockHeader - { - public List lstInfo { get; set; } = new List(); - - public Info SearchInfo(string name) - { - return lstInfo.Find(x => x.name == name); - } - - [MessagePackObject(true)] - public class Info - { - public string name { get; set; } - public string version { get; set; } - public long pos { get; set; } - public long size { get; set; } - } - } -} \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/SVS/About.cs b/src/KKManager.Core/Data/Cards/SVS/About.cs new file mode 100644 index 00000000..08520eb7 --- /dev/null +++ b/src/KKManager.Core/Data/Cards/SVS/About.cs @@ -0,0 +1,22 @@ +using System; +using System.ComponentModel; +using MessagePack; + +namespace KKManager.Data.Cards.SVS +{ + [MessagePackObject(true)] + [ReadOnly(true)] + [TypeConverter(typeof(ExpandableObjectConverter))] + public class About + { + [IgnoreMember] public static readonly string BlockName = "About"; + [IgnoreMember] public static readonly Version CurrentVersion = new Version("0.0.0"); + public Version version { get; set; } + + public string dataID { get; set; } + + public int language { get; set; } + + public string userID { get; set; } + } +} diff --git a/src/KKManager.Core/Data/Cards/SVS/ChaFileExtended.cs b/src/KKManager.Core/Data/Cards/SVS/ChaFileExtended.cs new file mode 100644 index 00000000..6b96a166 --- /dev/null +++ b/src/KKManager.Core/Data/Cards/SVS/ChaFileExtended.cs @@ -0,0 +1,9 @@ +using MessagePack; + +namespace KKManager.Data.Cards.SVS +{ + public class ChaFileExtended + { + [IgnoreMember] public static readonly string BlockName = "KKEx"; + } +} \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/SVS/GameInfo_SV.cs b/src/KKManager.Core/Data/Cards/SVS/GameInfo_SV.cs new file mode 100644 index 00000000..c0a18768 --- /dev/null +++ b/src/KKManager.Core/Data/Cards/SVS/GameInfo_SV.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using MessagePack; + +namespace KKManager.Data.Cards.SVS +{ + [MessagePackObject(true)] + [ReadOnly(true)] + [TypeConverter(typeof(ExpandableObjectConverter))] + public class GameInfo_SV + { + [IgnoreMember] public static readonly string BlockName = "GameInfo_SV"; + [IgnoreMember] public static readonly Version CurrentVersion = new Version("0.0.0"); + + public Version version { get; set; } + + // TODO Empty class? Check contents once metadata is available + } +} \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/SVS/GameParameter_SV.cs b/src/KKManager.Core/Data/Cards/SVS/GameParameter_SV.cs new file mode 100644 index 00000000..466c7a16 --- /dev/null +++ b/src/KKManager.Core/Data/Cards/SVS/GameParameter_SV.cs @@ -0,0 +1,51 @@ +using System; +using System.ComponentModel; +using MessagePack; + +namespace KKManager.Data.Cards.SVS +{ + [MessagePackObject(true)] + [ReadOnly(true)] + [TypeConverter(typeof(ExpandableObjectConverter))] + public class GameParameter_SV + { + [IgnoreMember] public static readonly string BlockName = "GameParameter_SV"; + [IgnoreMember] public static readonly Version CurrentVersion = new Version("0.0.0"); + public Version version { get; set; } + + [Browsable(false)] public byte[] imageData { get; set; } // Profile picture + + public int job { get; set; } + public int sexualTarget { get; set; } + public int lvChastity { get; set; } + public int lvSociability { get; set; } + public int lvTalk { get; set; } + public int lvStudy { get; set; } + public int lvLiving { get; set; } + public int lvPhysical { get; set; } + public int lvDefeat { get; set; } + public int[] belongings { get; set; } + public bool isVirgin { get; set; } + public bool isAnalVirgin { get; set; } + public bool isMaleVirgin { get; set; } + public bool isMaleAnalVirgin { get; set; } + public Individuality individuality { get; set; } + public PreferenceH preferenceH { get; set; } + + [MessagePackObject(true)] + [ReadOnly(true)] + [TypeConverter(typeof(ExpandableObjectConverter))] + public class Individuality + { + public int[] answer { get; set; } + } + + [MessagePackObject(true)] + [ReadOnly(true)] + [TypeConverter(typeof(ExpandableObjectConverter))] + public class PreferenceH + { + public int[] answer { get; set; } + } + } +} \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/SVS/Graphic.cs b/src/KKManager.Core/Data/Cards/SVS/Graphic.cs new file mode 100644 index 00000000..0aa3b94d --- /dev/null +++ b/src/KKManager.Core/Data/Cards/SVS/Graphic.cs @@ -0,0 +1,22 @@ +using System; +using System.ComponentModel; +using MessagePack; + +namespace KKManager.Data.Cards.SVS +{ + [MessagePackObject(true)] + [ReadOnly(true)] + [TypeConverter(typeof(ExpandableObjectConverter))] + public class Graphic + { + [IgnoreMember] public static readonly string BlockName = "Graphic"; + [IgnoreMember] public static readonly Version CurrentVersion = new Version("0.0.0"); + public Version version { get; set; } + + public int RampID { get; set; } + + public float ShadowDepth { get; set; } + + public float LineWidth { get; set; } + } +} diff --git a/src/KKManager.Core/Data/Cards/SVS/Parameter.cs b/src/KKManager.Core/Data/Cards/SVS/Parameter.cs new file mode 100644 index 00000000..3214a899 --- /dev/null +++ b/src/KKManager.Core/Data/Cards/SVS/Parameter.cs @@ -0,0 +1,27 @@ +using System; +using System.ComponentModel; +using MessagePack; + +namespace KKManager.Data.Cards.SVS +{ + [MessagePackObject(true)] + [ReadOnly(true)] + [TypeConverter(typeof(ExpandableObjectConverter))] + public class Parameter + { + [IgnoreMember] public static readonly string BlockName = "Parameter"; + [IgnoreMember] public static readonly Version CurrentVersion = new Version("0.0.0"); + [IgnoreMember] public string fullname => lastname + " " + firstname; + public byte birthDay { get; set; } + public byte birthMonth { get; set; } + public byte bloodType { get; set; } + public string firstname { get; set; } + public bool isFutanari { get; set; } + public string lastname { get; set; } + public int personality { get; set; } + public byte sex { get; set; } + public Version version { get; set; } + public float voicePitch { get; set; } + public float voiceRate { get; set; } + } +} \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/SVS/SamabakeCard.cs b/src/KKManager.Core/Data/Cards/SVS/SamabakeCard.cs new file mode 100644 index 00000000..fc14e694 --- /dev/null +++ b/src/KKManager.Core/Data/Cards/SVS/SamabakeCard.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using KKManager.Util; +using MessagePack; + +namespace KKManager.Data.Cards.SVS +{ + public class SamabakeCard : Card + { + public override string Name => Parameter?.fullname ?? base.Name; + public override CharaSex Sex => Parameter == null ? CharaSex.Unknown : Parameter.sex == 0 ? CharaSex.Male : CharaSex.Female; + public override string PersonalityName => GetProfession(Parameter?.personality ?? -1); + public string Birthday => $"{GetBirthMonth(Parameter.birthMonth)} {Parameter.birthDay}"; + [ReadOnly(true)] public Parameter Parameter { get; } + [ReadOnly(true)] public Graphic Graphic { get; } + [ReadOnly(true)] public GameInfo_SV GameInfo { get; } + [ReadOnly(true)] public GameParameter_SV GameParameter { get; } + + private SamabakeCard( + FileInfo cardFile, + CardType type, + Dictionary extended, + FileSize extendedSize, + Parameter parameter, + Graphic graphic, + Version version, + GameInfo_SV gameInfo, + GameParameter_SV gameParameter) : base(cardFile, type, extended, extendedSize, version) + { + Parameter = parameter; + Graphic = graphic; + GameInfo = gameInfo; + GameParameter = gameParameter; + } + + public static SamabakeCard ParseSvsChara(FileInfo file, BinaryReader reader, CardType gameType) + { + var loadVersion = new Version(reader.ReadString()); + //if (0 > new Version("1.0.1").CompareTo(loadVersion)) + // return null; + + //TODO Is this actually correct? The face is now serialized inside Parameter it seems + // the next int32 contains a byte-offset value from the beginning of the file + // to the end of the 2nd PNG file, which is where the juicy metadata is + var faceLength = reader.ReadInt32(); + if (faceLength > 0) + { + //this.facePngData = reader.ReadBytes(num); + // fast forward to the end of the 2nd PNG file + reader.BaseStream.Seek(faceLength, SeekOrigin.Current); + } + + // Get the BlockHeader + var count = reader.ReadInt32(); + var bytes = reader.ReadBytes(count); + var deserializeOptions = MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.UntrustedData); + var blockHeader = MessagePackSerializer.Deserialize(bytes, deserializeOptions); + + // Some sort of ID, ignore + _ = reader.ReadInt64(); + + // Position used to calculate where the blocks are by adding offset from header infos + var basePosition = reader.BaseStream.Position; + + //blockHeader.DumpBlocksToJson(reader, basePosition, new DirectoryInfo("E:\\block_dump")); + + // ---------- blocks ------------ + //Custom + //Coordinate + blockHeader.TryGetObject(reader, basePosition, Parameter.BlockName, out var parameter, out _); + //blockHeader.TryGetObject(reader, position, Status.BlockName, out var status, out _); //TODO broken + blockHeader.TryGetObject(reader, basePosition, Graphic.BlockName, out var graphic, out _); + blockHeader.TryGetObject(reader, basePosition, About.BlockName, out var about, out _); + blockHeader.TryGetObject(reader, basePosition, GameParameter_SV.BlockName, out var gameParameter, out _); + blockHeader.TryGetObject(reader, basePosition, GameInfo_SV.BlockName, out var gameInfo, out _); + // Modded + blockHeader.TryGetObject>(reader, basePosition, ChaFileExtended.BlockName, out var extData, out var info); + var extendedSize = info.GetSize(); + // ---------- end blocks ---------- + + var card = new SamabakeCard(file, gameType, extData, extendedSize, parameter, graphic, loadVersion, gameInfo, gameParameter) + { + Language = about?.language ?? -1, + UserID = about?.userID, + DataID = about?.dataID, + }; + + return card; + } + + public override Image GetCardFaceImage() + { + if (GameParameter != null) + { + using (var str = new MemoryStream(GameParameter.imageData)) + return Image.FromStream(str); + } + + return base.GetCardFaceImage(); + } + + public static string GetProfession(int profession) + { + if (profession < 100) + { + var femalePersonalities = new[] { "Ordinary", "Cheeky", "Cool", "Gyaru", "Brave", "Bewitching", "Innocent", "Motherly", "Devilish", "Yankee" }; + return GetValue(profession, femalePersonalities); + } + else + { + var malePersonalities = new[] { "Gentle", "Bold" }; + return GetValue(profession - 100, malePersonalities); + } + + string GetValue(int idx, string[] values) + { + if (idx < 0) return "Invalid"; + if (idx >= values.Length) return Properties.Resources.Unknown; + return values[idx]; + } + } + + public static string GetBirthMonth(int birthMonth) + { + string[] birthMonthLookup = + { + "Invalid", + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" + }; + + if (birthMonth < 1 || birthMonth > 12) return "Invalid"; + else if (birthMonthLookup.Length > birthMonth) return birthMonthLookup[birthMonth]; + else return KKManager.Properties.Resources.Unknown; + } + } +} \ No newline at end of file diff --git a/src/KKManager.Core/Data/Cards/Utility.cs b/src/KKManager.Core/Data/Cards/Utility.cs index 3dc71857..4f466a6e 100644 --- a/src/KKManager.Core/Data/Cards/Utility.cs +++ b/src/KKManager.Core/Data/Cards/Utility.cs @@ -1,4 +1,8 @@ -using System.IO; +using System; +using System.IO; +using KKManager.Util; +using MessagePack; +using Newtonsoft.Json; namespace KKManager.Data.Cards { @@ -67,5 +71,63 @@ public static long SearchForPngStart(Stream stream) { return SearchForSequence(stream, _pngStartChunk); } + + public static bool TryGetObject(this BlockHeader blockHeader, BinaryReader reader, long basePosition, string blockName, out TObj blockInfo, out BlockHeader.Info info) + { + if (blockHeader == null) throw new ArgumentNullException(nameof(blockHeader)); + if (reader == null) throw new ArgumentNullException(nameof(reader)); + if (blockName == null) throw new ArgumentNullException(nameof(blockName)); + + if (!reader.BaseStream.CanRead) throw new ArgumentException(@"stream is not readable", nameof(reader)); + if (basePosition < 0 || reader.BaseStream.Length <= basePosition) throw new ArgumentOutOfRangeException(nameof(basePosition), basePosition, @"position must be inside the stream"); + + blockInfo = default; + info = blockHeader.SearchInfo(blockName); + if (info != null) + { + reader.BaseStream.Seek(basePosition + info.pos, SeekOrigin.Begin); + var parameterBytes = reader.ReadBytes((int)info.size); + + try + { + blockInfo = MessagePackSerializer.Deserialize(parameterBytes); + + if (blockInfo != null) + return true; + } + catch (Exception e) + { + Console.WriteLine($@"Failed to deserialize block ""{blockName}"" from BlockHeader - {e}"); + } + } + return false; + } + + public static FileSize GetSize(this BlockHeader.Info info) + { + return info != null ? FileSize.FromBytes((int)info.size) : FileSize.Empty; + } + + public static void DumpBlocksToJson(this BlockHeader blockHeader, BinaryReader reader, long basePosition, DirectoryInfo targetDirectory) + { + if (blockHeader == null) throw new ArgumentNullException(nameof(blockHeader)); + if (reader == null) throw new ArgumentNullException(nameof(reader)); + if (targetDirectory == null) throw new ArgumentNullException(nameof(targetDirectory)); + + targetDirectory.Create(); + + foreach (var blockInfo in blockHeader.lstInfo) + { + reader.BaseStream.Seek(basePosition + blockInfo.pos, SeekOrigin.Begin); + var parameterBytes = reader.ReadBytes((int)blockInfo.size); + + var jsn = MessagePackSerializer.ConvertToJson(parameterBytes); + + dynamic parsedJson = JsonConvert.DeserializeObject(jsn); + jsn = JsonConvert.SerializeObject((object)parsedJson, Formatting.Indented); + + File.WriteAllText(Path.Combine(targetDirectory.FullName, $@"BLOCK_{blockInfo.name}.json"), jsn); + } + } } } diff --git a/src/KKManager.Core/Functions/GameType.cs b/src/KKManager.Core/Functions/GameType.cs index e77067f1..e9304ac4 100644 --- a/src/KKManager.Core/Functions/GameType.cs +++ b/src/KKManager.Core/Functions/GameType.cs @@ -13,6 +13,7 @@ public enum GameType KoikatsuSunshine, RoomGirl, HoneyCome, - HoneyComeSteam + HoneyComeSteam, + SamabakeScramble } } \ No newline at end of file diff --git a/src/KKManager.Core/Functions/InstallDirectoryHelper.cs b/src/KKManager.Core/Functions/InstallDirectoryHelper.cs index 035dd521..6ef6fde5 100644 --- a/src/KKManager.Core/Functions/InstallDirectoryHelper.cs +++ b/src/KKManager.Core/Functions/InstallDirectoryHelper.cs @@ -95,6 +95,7 @@ public static void Initialize(DirectoryInfo gameDirectory) new Tuple("RoomGirl.exe", GameType.RoomGirl), new Tuple("HoneyCome.exe", GameType.HoneyCome), new Tuple("HoneyComeccp.exe", GameType.HoneyComeSteam), + new Tuple("SamabakeScramble.exe", GameType.SamabakeScramble), }; GameType = gameCheck.FirstOrDefault(x => File.Exists(Path.Combine(path, x.Item1)))?.Item2 ?? GameType.Unknown; @@ -142,7 +143,7 @@ public static bool IsValidGamePath(string path) var anyDatas = Directory.GetDirectories(path) .Any(x => x.EndsWith("_Data", StringComparison.OrdinalIgnoreCase)); - var abdataExist = File.Exists(Path.Combine(path, "abdata/abdata")); + var abdataExist = File.Exists(Path.Combine(path, "abdata/abdata")) || File.Exists(Path.Combine(path, "abdata/sv_abdata")); // todo use this to offer to install bepinex and other mods / run update wizzard //var modsExist = Directory.Exists(Path.Combine(path, "bepinex")) && Directory.Exists(Path.Combine(path, "mods")); @@ -171,6 +172,7 @@ public static string GetFancyGameName(this GameType gameType) case GameType.RoomGirl: return "Room Girl"; case GameType.HoneyCome: return "HoneyCome"; case GameType.HoneyComeSteam: return "HoneyCome come come party"; + case GameType.SamabakeScramble: return "Summer Vacation Scramble"; default: throw new ArgumentOutOfRangeException(nameof(gameType), gameType, null); } } diff --git a/src/KKManager.Core/KKManager.Core.csproj b/src/KKManager.Core/KKManager.Core.csproj index 8ebc1ac8..ebb47f1a 100644 --- a/src/KKManager.Core/KKManager.Core.csproj +++ b/src/KKManager.Core/KKManager.Core.csproj @@ -67,6 +67,7 @@ ..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + ..\packages\Microsoft.NET.StringTools.17.11.4\lib\net472\Microsoft.NET.StringTools.dll @@ -151,29 +152,32 @@ LogControl.cs - + - - + + - + + + + + + + - - - @@ -182,7 +186,6 @@ -