|
@@ -7,8 +7,9 @@ using ExIni;
|
|
using BepInEx;
|
|
using BepInEx;
|
|
using UnityEngine;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
+using MyRoomCustom;
|
|
|
|
|
|
-namespace COM3D2.MeidoPhotoStudio.Plugin
|
|
|
|
|
|
+namespace COM3D2.MeidoPhotoStudio.Converter
|
|
{
|
|
{
|
|
[BepInPlugin(pluginGuid, pluginName, pluginVersion)]
|
|
[BepInPlugin(pluginGuid, pluginName, pluginVersion)]
|
|
public class SceneConverter : BaseUnityPlugin
|
|
public class SceneConverter : BaseUnityPlugin
|
|
@@ -16,7 +17,52 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
|
|
private const string pluginGuid = "com.habeebweeb.com3d2.meidophotostudio.converter";
|
|
private const string pluginGuid = "com.habeebweeb.com3d2.meidophotostudio.converter";
|
|
public const string pluginName = "MeidoPhotoStudio Converter";
|
|
public const string pluginName = "MeidoPhotoStudio Converter";
|
|
public const string pluginVersion = "0.0.0";
|
|
public const string pluginVersion = "0.0.0";
|
|
|
|
+ private readonly byte[] noThumb = {
|
|
|
|
+ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
|
|
|
|
+ 0x00, 0x32, 0x00, 0x00, 0x00, 0x32, 0x08, 0x02, 0x00, 0x00, 0x00, 0x91, 0x5D, 0x1F, 0xE6, 0x00, 0x00, 0x00,
|
|
|
|
+ 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41,
|
|
|
|
+ 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,
|
|
|
|
+ 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7, 0x6F, 0xA8, 0x64, 0x00, 0x00, 0x01, 0x4E, 0x49, 0x44, 0x41,
|
|
|
|
+ 0x54, 0x58, 0x47, 0xDD, 0xD2, 0x5B, 0x8E, 0x83, 0x30, 0x10, 0x44, 0xD1, 0x2C, 0x84, 0x4F, 0xF6, 0xBF, 0xB3,
|
|
|
|
+ 0xAC, 0x21, 0xA9, 0xA8, 0x90, 0x01, 0x63, 0xEC, 0x7E, 0xD9, 0x46, 0xB9, 0xCA, 0xCF, 0x44, 0x72, 0xD7, 0x89,
|
|
|
|
+ 0x34, 0xAF, 0xF7, 0xB2, 0x3E, 0xF0, 0xB3, 0xB1, 0x3E, 0x8F, 0x69, 0x67, 0xF1, 0x0F, 0x7E, 0x3B, 0xB7, 0x84,
|
|
|
|
+ 0xD9, 0x58, 0xE9, 0xAB, 0x89, 0x1D, 0x25, 0x3B, 0x0B, 0x4D, 0x94, 0x65, 0x8C, 0x13, 0x0B, 0x4D, 0x91, 0x5D,
|
|
|
|
+ 0x0D, 0x39, 0x0B, 0x0D, 0x96, 0x15, 0x01, 0x05, 0x16, 0x1A, 0x26, 0xBB, 0x5B, 0x2F, 0xB3, 0xD0, 0x00, 0x59,
|
|
|
|
+ 0x65, 0xFA, 0x96, 0x85, 0xBA, 0xCA, 0xEA, 0xBB, 0x35, 0x16, 0xEA, 0x24, 0x6B, 0x8E, 0x36, 0x58, 0x28, 0x5C,
|
|
|
|
+ 0x26, 0x59, 0x6C, 0xB3, 0x50, 0xA0, 0x4C, 0x38, 0x27, 0x62, 0xA1, 0x10, 0x99, 0x7C, 0x4B, 0xCA, 0x42, 0x4E,
|
|
|
|
+ 0x99, 0x6A, 0x48, 0xC1, 0x42, 0x66, 0x99, 0x76, 0x45, 0xC7, 0x42, 0x06, 0x99, 0x61, 0x42, 0xCD, 0x42, 0xAA,
|
|
|
|
+ 0x27, 0xB6, 0xFB, 0x16, 0x16, 0x12, 0xBE, 0x32, 0x1F, 0x37, 0xB2, 0x50, 0xF3, 0xA1, 0xE7, 0xB2, 0x9D, 0x85,
|
|
|
|
+ 0x2A, 0x6F, 0x9D, 0x67, 0x5D, 0x2C, 0x54, 0x7C, 0xEE, 0xBF, 0xE9, 0x65, 0xA1, 0xEC, 0x42, 0xC8, 0xC1, 0x00,
|
|
|
|
+ 0x16, 0x4A, 0x47, 0xA2, 0xAE, 0xC5, 0xB0, 0x10, 0xEE, 0x04, 0x9E, 0xFA, 0x6B, 0x56, 0x3A, 0x12, 0x75, 0xED,
|
|
|
|
+ 0x4F, 0xFF, 0xE5, 0x8B, 0xCF, 0xFD, 0x37, 0x5D, 0xAC, 0xCA, 0x5B, 0xE7, 0x59, 0x3B, 0xAB, 0xF9, 0xD0, 0x73,
|
|
|
|
+ 0xD9, 0xC8, 0x12, 0xBE, 0x32, 0x1F, 0xB7, 0xB0, 0x54, 0x4F, 0x6C, 0xF7, 0xD5, 0xAC, 0xDE, 0x3F, 0x03, 0xA9,
|
|
|
|
+ 0x59, 0x06, 0x13, 0xD3, 0xAE, 0x28, 0x58, 0x66, 0x13, 0x53, 0x0D, 0x49, 0x59, 0x4E, 0x13, 0x93, 0x6F, 0x89,
|
|
|
|
+ 0x58, 0x21, 0x26, 0x26, 0x9C, 0x6B, 0xB3, 0x02, 0x4D, 0x4C, 0xB2, 0xD8, 0x60, 0x85, 0x9B, 0x58, 0x73, 0xB4,
|
|
|
|
+ 0xC6, 0xEA, 0x64, 0x62, 0xF5, 0xDD, 0x5B, 0x56, 0x57, 0x13, 0xAB, 0x4C, 0x97, 0x59, 0x03, 0x4C, 0xEC, 0x6E,
|
|
|
|
+ 0xBD, 0xC0, 0x1A, 0x66, 0x62, 0x45, 0x40, 0xCE, 0x1A, 0x6C, 0x62, 0x57, 0xC3, 0x89, 0x35, 0xC5, 0xC4, 0x32,
|
|
|
|
+ 0xC6, 0xCE, 0x9A, 0x68, 0x62, 0x47, 0xC9, 0xC6, 0x9A, 0x6E, 0x62, 0x09, 0xF3, 0x63, 0x3D, 0xC4, 0xC4, 0xE8,
|
|
|
|
+ 0xD9, 0x58, 0xCF, 0xFA, 0x2C, 0xEB, 0x17, 0xC3, 0x4F, 0x1F, 0x0A, 0xB7, 0x49, 0x8A, 0x9E, 0x00, 0x00, 0x00,
|
|
|
|
+ 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82
|
|
|
|
+ };
|
|
private const string converterDirectoryName = "Converter";
|
|
private const string converterDirectoryName = "Converter";
|
|
|
|
+ private static Dictionary<string, PlacementData.Data> myrAssetNameToData
|
|
|
|
+ = new Dictionary<string, PlacementData.Data>(StringComparer.InvariantCultureIgnoreCase);
|
|
|
|
+ private static readonly string[] faceKeys = {
|
|
|
|
+ "eyeclose", "eyeclose2", "eyeclose3", "eyeclose6", "hitomih", "hitomis", "mayuha",
|
|
|
|
+ "mayuup", "mayuv", "mayuvhalf", "moutha", "mouths", "mouthdw", "mouthup", "tangout",
|
|
|
|
+ "tangup", "eyebig", "eyeclose5", "mayuw", "mouthhe", "mouthc", "mouthi", "mouthuphalf",
|
|
|
|
+ "tangopen",
|
|
|
|
+ "namida", "tear1", "tear2", "tear3", "shock", "yodare", "hoho", "hoho2", "hohos", "hohol",
|
|
|
|
+ "toothoff", "nosefook"
|
|
|
|
+ };
|
|
|
|
+ private static readonly int[] bodyRotations =
|
|
|
|
+ {
|
|
|
|
+ 71, 44, 40, 41, 42, 43, 57, 68, 69, 46, 49, 47, 50, 52, 55, 53, 56, 45, 48, 51, 54
|
|
|
|
+ };
|
|
|
|
+ public const int sceneVersion = 1100;
|
|
|
|
+ public const int kankyoMagic = -765;
|
|
|
|
+ private static BepInEx.Logging.ManualLogSource Log;
|
|
|
|
+ private static readonly int faceToggleIndex = Array.IndexOf(faceKeys, "tangopen") + 1;
|
|
private static string configPath = Path.Combine(Paths.ConfigPath, converterDirectoryName);
|
|
private static string configPath = Path.Combine(Paths.ConfigPath, converterDirectoryName);
|
|
private bool active = false;
|
|
private bool active = false;
|
|
private Rect windowRect = new Rect(30f, 30f, 300f, 200f);
|
|
private Rect windowRect = new Rect(30f, 30f, 300f, 200f);
|
|
@@ -26,9 +72,20 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
|
|
DontDestroyOnLoad(this);
|
|
DontDestroyOnLoad(this);
|
|
|
|
|
|
if (!Directory.Exists(configPath)) Directory.CreateDirectory(configPath);
|
|
if (!Directory.Exists(configPath)) Directory.CreateDirectory(configPath);
|
|
|
|
+ Log = Logger;
|
|
}
|
|
}
|
|
|
|
|
|
- private void Start() => UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded;
|
|
|
|
|
|
+ private void Start()
|
|
|
|
+ {
|
|
|
|
+ UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded;
|
|
|
|
+ List<PlacementData.Data> dataList = PlacementData.GetAllDatas(false);
|
|
|
|
+
|
|
|
|
+ foreach (var data in dataList)
|
|
|
|
+ {
|
|
|
|
+ string assetName = string.IsNullOrEmpty(data.assetName) ? data.resourceName : data.assetName;
|
|
|
|
+ myrAssetNameToData[assetName] = data;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
private void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode)
|
|
private void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode)
|
|
{
|
|
{
|
|
@@ -52,6 +109,8 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
|
|
{
|
|
{
|
|
if (GUILayout.Button("Convert ModifiedMM")) ProcessModifedMM();
|
|
if (GUILayout.Button("Convert ModifiedMM")) ProcessModifedMM();
|
|
if (GUILayout.Button("Convert ModifiedMM (Scene Manager)")) ProcessModifiedMMPng();
|
|
if (GUILayout.Button("Convert ModifiedMM (Scene Manager)")) ProcessModifiedMMPng();
|
|
|
|
+ GUILayout.Space(30f);
|
|
|
|
+ if (GUILayout.Button("Convert modifedMM quickSave")) ProcessQuickSave();
|
|
// GUILayout.Button("Convert MultipleMaids");
|
|
// GUILayout.Button("Convert MultipleMaids");
|
|
}
|
|
}
|
|
|
|
|
|
@@ -67,10 +126,35 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
|
|
return String.Empty;
|
|
return String.Empty;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private void ProcessQuickSave()
|
|
|
|
+ {
|
|
|
|
+ string sybarisPath = Path.Combine(Paths.GameRootPath, "Sybaris");
|
|
|
|
+ string iniPath = BepInEx.Utility.CombinePaths(sybarisPath, "UnityInjector", "Config", "MultipleMaids.ini");
|
|
|
|
+
|
|
|
|
+ IniFile mmIniFile = IniFile.FromFile(iniPath);
|
|
|
|
+
|
|
|
|
+ IniSection sceneSection = mmIniFile.GetSection("scene");
|
|
|
|
+
|
|
|
|
+ if (sceneSection != null)
|
|
|
|
+ {
|
|
|
|
+ if (sceneSection.HasKey("s9999"))
|
|
|
|
+ {
|
|
|
|
+ string sceneData = sceneSection["s9999"].Value;
|
|
|
|
+
|
|
|
|
+ if (!string.IsNullOrEmpty(sceneData))
|
|
|
|
+ {
|
|
|
|
+ byte[] convertedSceneData = ProcessScene(sceneData, false);
|
|
|
|
+ string path = Path.Combine(configPath, $"mmtempscene{GetMMDateString(sceneData)}.png");
|
|
|
|
+ SaveSceneToFile(path, convertedSceneData, noThumb);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
private void ProcessModifedMM()
|
|
private void ProcessModifedMM()
|
|
{
|
|
{
|
|
string sybarisPath = Path.Combine(Paths.GameRootPath, "Sybaris");
|
|
string sybarisPath = Path.Combine(Paths.GameRootPath, "Sybaris");
|
|
- string iniPath = Utility.CombinePaths(sybarisPath, "UnityInjector", "Config", "MultipleMaids.ini");
|
|
|
|
|
|
+ string iniPath = BepInEx.Utility.CombinePaths(sybarisPath, "UnityInjector", "Config", "MultipleMaids.ini");
|
|
|
|
|
|
IniFile mmIniFile = IniFile.FromFile(iniPath);
|
|
IniFile mmIniFile = IniFile.FromFile(iniPath);
|
|
|
|
|
|
@@ -81,17 +165,54 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
|
|
foreach (IniKey key in sceneSection.Keys)
|
|
foreach (IniKey key in sceneSection.Keys)
|
|
{
|
|
{
|
|
if (key.Key.StartsWith("ss")) continue;
|
|
if (key.Key.StartsWith("ss")) continue;
|
|
|
|
+
|
|
|
|
+ bool kankyo = int.Parse(key.Key.Substring(1)) >= 10000;
|
|
string sceneData = key.Value;
|
|
string sceneData = key.Value;
|
|
- ProcessScene(sceneData);
|
|
|
|
|
|
+
|
|
|
|
+ if (!string.IsNullOrEmpty(sceneData))
|
|
|
|
+ {
|
|
|
|
+ byte[] convertedSceneData = ProcessScene(sceneData, kankyo);
|
|
|
|
+
|
|
|
|
+ string prefix = kankyo ? "mmkankyo" : "mmscene";
|
|
|
|
+
|
|
|
|
+ string path = Path.Combine(configPath, $"{prefix}_{key.Key}{GetMMDateString(sceneData)}.png");
|
|
|
|
+
|
|
|
|
+ byte[] thumbnail = noThumb;
|
|
|
|
+
|
|
|
|
+ string screenshotKey = $"s{key.Key}";
|
|
|
|
+ if (sceneSection.HasKey(screenshotKey))
|
|
|
|
+ {
|
|
|
|
+ string screenshotBase64 = sceneSection[screenshotKey].Value;
|
|
|
|
+ if (!string.IsNullOrEmpty(screenshotBase64))
|
|
|
|
+ {
|
|
|
|
+ thumbnail = Convert.FromBase64String(screenshotBase64);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ SaveSceneToFile(path, convertedSceneData, thumbnail);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public static void ProcessScene(string sceneData)
|
|
|
|
|
|
+ public static void SaveSceneToFile(string path, byte[] sceneData, byte[] thumbnailData)
|
|
{
|
|
{
|
|
|
|
+ using (FileStream fileStream = File.Create(path))
|
|
|
|
+ {
|
|
|
|
+ fileStream.Write(thumbnailData, 0, thumbnailData.Length);
|
|
|
|
+ fileStream.Write(sceneData, 0, sceneData.Length);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- if (string.IsNullOrEmpty(sceneData)) return;
|
|
|
|
|
|
+ public static string GetMMDateString(string sceneData)
|
|
|
|
+ {
|
|
|
|
+ string dateString = sceneData.Split('_')[0].Split(',')[0];
|
|
|
|
+ DateTime date = DateTime.Parse(dateString);
|
|
|
|
+ return $"{date:yyyyMMddHHmm}";
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ public static byte[] ProcessScene(string sceneData, bool kankyo)
|
|
|
|
+ {
|
|
string[] strArray1 = sceneData.Split('_');
|
|
string[] strArray1 = sceneData.Split('_');
|
|
string[] strArray2 = strArray1[1].Split(';');
|
|
string[] strArray2 = strArray1[1].Split(';');
|
|
string[] strArray3 = strArray1[0].Split(',');
|
|
string[] strArray3 = strArray1[0].Split(',');
|
|
@@ -112,43 +233,310 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
|
|
strArray7 = strArray1[5].Split(';');
|
|
strArray7 = strArray1[5].Split(';');
|
|
}
|
|
}
|
|
|
|
|
|
- // Environment
|
|
|
|
|
|
+ using (MemoryStream memoryStream = new MemoryStream())
|
|
|
|
+ using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress))
|
|
|
|
+ using (BinaryWriter binaryWriter = new BinaryWriter(deflateStream, System.Text.Encoding.UTF8))
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.Write("MPS_SCENE");
|
|
|
|
+ binaryWriter.Write(sceneVersion);
|
|
|
|
|
|
- int bgIndex;
|
|
|
|
|
|
+ binaryWriter.Write(kankyo ? kankyoMagic : int.Parse(strArray3[1]));
|
|
|
|
|
|
- string bgAsset = "Theater";
|
|
|
|
|
|
+ SerializeEnvironment(strArray3, binaryWriter, kankyo);
|
|
|
|
+
|
|
|
|
+ SerializeLights(strArray3, strArray4, strArray5, strArray7, binaryWriter);
|
|
|
|
+
|
|
|
|
+ SerializeMessage(strArray3, binaryWriter);
|
|
|
|
|
|
- if (!int.TryParse(strArray3[2], out bgIndex))
|
|
|
|
|
|
+ SerializeEffect(strArray4, binaryWriter);
|
|
|
|
+
|
|
|
|
+ SerializeProp(strArray3, strArray6, binaryWriter);
|
|
|
|
+
|
|
|
|
+ SerializeMaid(strArray2, binaryWriter);
|
|
|
|
+
|
|
|
|
+ binaryWriter.Write("END");
|
|
|
|
+
|
|
|
|
+ deflateStream.Close();
|
|
|
|
+
|
|
|
|
+ return memoryStream.ToArray();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static void SerializeMaid(string[] strArray2, BinaryWriter binaryWriter)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.Write("MEIDO");
|
|
|
|
+ // MM scene converted to MPS
|
|
|
|
+ binaryWriter.Write(true);
|
|
|
|
+
|
|
|
|
+ int numberOfMaids = strArray2.Length;
|
|
|
|
+
|
|
|
|
+ binaryWriter.Write(numberOfMaids);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ TODO: Investigate why serialized maid data may only have 64 items.
|
|
|
|
+ https://git.coder.horse/meidomustard/modifiedMM/src/master/MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.Update.cs#L3745
|
|
|
|
+
|
|
|
|
+ The difference affects whether or not rotations are local or world.
|
|
|
|
+ Certain body rotations would be missing as well particularly the toes.
|
|
|
|
+ Other data like free look and attached items like hand/vag/anl would be missing.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < numberOfMaids; i++)
|
|
{
|
|
{
|
|
- bgAsset = strArray3[2].Replace(" ", "_");
|
|
|
|
|
|
+ using (MemoryStream memoryStream = new MemoryStream())
|
|
|
|
+ using (BinaryWriter tempWriter = new BinaryWriter(memoryStream))
|
|
|
|
+ {
|
|
|
|
+ string[] maidData = strArray2[i].Split(':');
|
|
|
|
+ tempWriter.WriteVector3(Utility.Vector3String(maidData[59])); // position
|
|
|
|
+ tempWriter.WriteQuaternion(Utility.EulerString(maidData[58])); // rotation
|
|
|
|
+ tempWriter.WriteVector3(Utility.Vector3String(maidData[60])); // scale
|
|
|
|
+
|
|
|
|
+ // fingers
|
|
|
|
+ for (int j = 0; j < 40; j++)
|
|
|
|
+ {
|
|
|
|
+ tempWriter.WriteQuaternion(Utility.EulerString(maidData[j]));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // toes
|
|
|
|
+ for (int k = 0; k < 2; k++)
|
|
|
|
+ {
|
|
|
|
+ for (int j = 72 + k; j < 90; j += 2)
|
|
|
|
+ {
|
|
|
|
+ tempWriter.WriteQuaternion(Utility.EulerString(maidData[j]));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // the rest of the limbs
|
|
|
|
+ foreach (int j in bodyRotations)
|
|
|
|
+ {
|
|
|
|
+ tempWriter.WriteQuaternion(Utility.EulerString(maidData[j]));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tempWriter.WriteVector3(Utility.Vector3String(maidData[96])); // hip position
|
|
|
|
+
|
|
|
|
+ // cached pose stuff
|
|
|
|
+ tempWriter.Write("normal");
|
|
|
|
+ tempWriter.Write("pose_taiki_f");
|
|
|
|
+ tempWriter.Write(false);
|
|
|
|
+
|
|
|
|
+ // eye rotation delta
|
|
|
|
+ // MM saves the rotations directly so just save the identity
|
|
|
|
+ tempWriter.WriteQuaternion(Quaternion.identity);
|
|
|
|
+ tempWriter.WriteQuaternion(Quaternion.identity);
|
|
|
|
+
|
|
|
|
+ string[] freeLookData = maidData[64].Split(',');
|
|
|
|
+
|
|
|
|
+ tempWriter.Write(int.Parse(freeLookData[0]) == 1);
|
|
|
|
+ tempWriter.WriteVector3(new Vector3(
|
|
|
|
+ float.Parse(freeLookData[2]), 1f, float.Parse(freeLookData[1])
|
|
|
|
+ ));
|
|
|
|
+
|
|
|
|
+ string[] faceValues = maidData[63].Split(',');
|
|
|
|
+
|
|
|
|
+ tempWriter.Write("MPS_FACE");
|
|
|
|
+ for (int j = 0; j < faceKeys.Length - 2; j++)
|
|
|
|
+ {
|
|
|
|
+ tempWriter.Write(faceKeys[j]);
|
|
|
|
+ if (j >= faceToggleIndex) tempWriter.Write(float.Parse(faceValues[j]) > 0f);
|
|
|
|
+ else tempWriter.Write(float.Parse(faceValues[j]));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (faceValues.Length > 65)
|
|
|
|
+ {
|
|
|
|
+ tempWriter.Write(faceKeys[faceKeys.Length - 1]);
|
|
|
|
+ tempWriter.Write(float.Parse(faceValues[faceValues.Length - 1]) > 0f);
|
|
|
|
+ }
|
|
|
|
+ tempWriter.Write("END_FACE");
|
|
|
|
+
|
|
|
|
+ tempWriter.Write(true); // body visible
|
|
|
|
+
|
|
|
|
+ // MM does not serialize clothing
|
|
|
|
+ for (int j = 0; j < 29; j++) tempWriter.Write(true);
|
|
|
|
+
|
|
|
|
+ // MM does not serialize curling
|
|
|
|
+ tempWriter.Write(false);
|
|
|
|
+ tempWriter.Write(false);
|
|
|
|
+ tempWriter.Write(false);
|
|
|
|
+
|
|
|
|
+ binaryWriter.Write(memoryStream.Length);
|
|
|
|
+ binaryWriter.Write(memoryStream.ToArray());
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- Quaternion bgRotation = Quaternion.Euler(
|
|
|
|
- float.Parse(strArray3[3]), float.Parse(strArray3[4]), float.Parse(strArray3[5])
|
|
|
|
- );
|
|
|
|
|
|
+ private static void SerializeProp(string[] strArray3, string[] strArray6, BinaryWriter binaryWriter)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.Write("PROP");
|
|
|
|
|
|
- Vector3 bgPosition = new Vector3(
|
|
|
|
- float.Parse(strArray3[6]), float.Parse(strArray3[7]), float.Parse(strArray3[8])
|
|
|
|
- );
|
|
|
|
|
|
+ bool hasWProp = strArray3.Length > 37 && !string.IsNullOrEmpty(strArray3[37]);
|
|
|
|
+ int numberOfProps = hasWProp ? 1 : 0;
|
|
|
|
+ numberOfProps += strArray6 == null ? 0 : strArray6.Length - 1;
|
|
|
|
|
|
- Vector3 bgLocalScale = new Vector3(
|
|
|
|
- float.Parse(strArray3[9]), float.Parse(strArray3[10]), float.Parse(strArray3[11])
|
|
|
|
- );
|
|
|
|
|
|
+ binaryWriter.Write(numberOfProps);
|
|
|
|
|
|
- if (strArray3.Length > 16)
|
|
|
|
|
|
+ if (hasWProp)
|
|
{
|
|
{
|
|
- Vector3 cameraTargetPos = new Vector3(
|
|
|
|
- float.Parse(strArray3[27]), float.Parse(strArray3[28]), float.Parse(strArray3[29])
|
|
|
|
- );
|
|
|
|
|
|
+ // For the prop that spawns when you push (shift +) W
|
|
|
|
+ binaryWriter.Write(strArray3[37].Replace(' ', '_'));
|
|
|
|
|
|
- float cameraDistance = float.Parse(strArray3[30]);
|
|
|
|
|
|
+ SerializeAttachPoint(binaryWriter);
|
|
|
|
|
|
- Quaternion cameraRotation = Quaternion.Euler(
|
|
|
|
- float.Parse(strArray3[31]), float.Parse(strArray3[32]), float.Parse(strArray3[33])
|
|
|
|
- );
|
|
|
|
|
|
+ binaryWriter.WriteVector3(new Vector3(
|
|
|
|
+ float.Parse(strArray3[41]), float.Parse(strArray3[42]), float.Parse(strArray3[43])
|
|
|
|
+ ));
|
|
|
|
+
|
|
|
|
+ binaryWriter.WriteQuaternion(Quaternion.Euler(
|
|
|
|
+ float.Parse(strArray3[38]), float.Parse(strArray3[39]), float.Parse(strArray3[40])
|
|
|
|
+ ));
|
|
|
|
+
|
|
|
|
+ binaryWriter.WriteVector3(new Vector3(
|
|
|
|
+ float.Parse(strArray3[44]), float.Parse(strArray3[45]), float.Parse(strArray3[46])
|
|
|
|
+ ));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (strArray6 != null)
|
|
|
|
+ {
|
|
|
|
+ for (int i = 0; i < strArray6.Length - 1; i++)
|
|
|
|
+ {
|
|
|
|
+ string[] assetParts = strArray6[i].Split(',');
|
|
|
|
+ string assetName = assetParts[0].Replace(' ', '_');
|
|
|
|
+
|
|
|
|
+ if (assetName.StartsWith("creative_"))
|
|
|
|
+ {
|
|
|
|
+ // modifiedMM my room creative prop
|
|
|
|
+ // modifiedMM serializes the prefabName rather than the ID.
|
|
|
|
+ assetName = assetName.Replace("creative_", String.Empty);
|
|
|
|
+ assetName = $"MYR_{myrAssetNameToData[assetName].ID}#{assetName}";
|
|
|
|
+ }
|
|
|
|
+ else if (assetName.StartsWith("MYR_"))
|
|
|
|
+ {
|
|
|
|
+ // MM 23.0+ my room creative prop
|
|
|
|
+ PlacementData.Data data = myrAssetNameToData[assetName];
|
|
|
|
+ string asset = string.IsNullOrEmpty(data.assetName) ? data.resourceName : data.assetName;
|
|
|
|
+
|
|
|
|
+ assetName = $"{assetName}#{asset}";
|
|
|
|
+ }
|
|
|
|
+ else if (assetName.Contains('#'))
|
|
|
|
+ {
|
|
|
|
+ if (assetName.Contains(".menu"))
|
|
|
|
+ {
|
|
|
|
+ // modifiedMM official mod prop
|
|
|
|
+ string[] modComponents = assetParts[0].Split('#');
|
|
|
|
+ string baseMenuFile = modComponents[0].Replace(' ', '_');
|
|
|
|
+ string modItem = modComponents[1].Replace(' ', '_');
|
|
|
|
+ assetName = $"{modItem}#{baseMenuFile}";
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ assetName = assetName.Split('#')[1].Replace(' ', '_');
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ binaryWriter.Write(assetName);
|
|
|
|
+
|
|
|
|
+ SerializeAttachPoint(binaryWriter);
|
|
|
|
+
|
|
|
|
+ binaryWriter.WriteVector3(new Vector3(
|
|
|
|
+ float.Parse(assetParts[4]), float.Parse(assetParts[5]), float.Parse(assetParts[6])
|
|
|
|
+ ));
|
|
|
|
+
|
|
|
|
+ binaryWriter.WriteQuaternion(Quaternion.Euler(
|
|
|
|
+ float.Parse(assetParts[1]), float.Parse(assetParts[2]), float.Parse(assetParts[3])
|
|
|
|
+ ));
|
|
|
|
+
|
|
|
|
+ binaryWriter.WriteVector3(new Vector3(
|
|
|
|
+ float.Parse(assetParts[7]), float.Parse(assetParts[8]), float.Parse(assetParts[9])
|
|
|
|
+ ));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static void SerializeEffect(string[] strArray4, BinaryWriter binaryWriter)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.Write("EFFECT");
|
|
|
|
+
|
|
|
|
+ if (strArray4 != null)
|
|
|
|
+ {
|
|
|
|
+ // bloom
|
|
|
|
+ binaryWriter.Write("EFFECT_BLOOM");
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[2])); // intensity
|
|
|
|
+ binaryWriter.Write((int)float.Parse(strArray4[3])); // blur iterations
|
|
|
|
+ binaryWriter.WriteColour(new Color( // bloom threshold colour
|
|
|
|
+ float.Parse(strArray4[4]), float.Parse(strArray4[5]), float.Parse(strArray4[6]), 1f
|
|
|
|
+ ));
|
|
|
|
+ binaryWriter.Write(int.Parse(strArray4[7]) == 1); // hdr
|
|
|
|
+ binaryWriter.Write(int.Parse(strArray4[1]) == 1); // active
|
|
|
|
+
|
|
|
|
+ // vignetting
|
|
|
|
+ binaryWriter.Write("EFFECT_VIGNETTE");
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[9])); // intensity
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[10])); // blur
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[11])); // blur spread
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[12])); // chromatic aberration
|
|
|
|
+ binaryWriter.Write(int.Parse(strArray4[8]) == 1); // active
|
|
|
|
+
|
|
|
|
+ // bokashi
|
|
|
|
+ // TODO: implement bokashi in MPS
|
|
|
|
+ float bokashi = float.Parse(strArray4[13]);
|
|
|
|
+
|
|
|
|
+ // TODO: implement sepia in MPS too
|
|
|
|
+
|
|
|
|
+ if (strArray4.Length > 15)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.Write("EFFECT_DOF");
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[16])); // focal length
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[17])); // focal size
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[18])); // aperture
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[19])); // max blur size
|
|
|
|
+ binaryWriter.Write(int.Parse(strArray4[20]) == 1); // visualize focus
|
|
|
|
+ binaryWriter.Write(int.Parse(strArray4[15]) == 1); // active
|
|
|
|
+
|
|
|
|
+ binaryWriter.Write("EFFECT_FOG");
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[22])); // fog distance
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[23])); // density
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[24])); // height scale
|
|
|
|
+ binaryWriter.Write(float.Parse(strArray4[25])); // height
|
|
|
|
+ binaryWriter.WriteColour(new Color( // fog colour
|
|
|
|
+ float.Parse(strArray4[26]), float.Parse(strArray4[27]), float.Parse(strArray4[28]), 1f
|
|
|
|
+ ));
|
|
|
|
+ binaryWriter.Write(int.Parse(strArray4[21]) == 1); // active
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ binaryWriter.Write("END_EFFECT");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static void SerializeMessage(string[] strArray3, BinaryWriter binaryWriter)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.Write("TEXTBOX");
|
|
|
|
+
|
|
|
|
+ bool showingMessage = false;
|
|
|
|
+ string name = "Maid";
|
|
|
|
+ string message = "Hello world";
|
|
|
|
+
|
|
|
|
+ if (strArray3.Length > 16)
|
|
|
|
+ {
|
|
|
|
+ showingMessage = int.Parse(strArray3[34]) == 1;
|
|
|
|
+ name = strArray3[35];
|
|
|
|
+ message = strArray3[36].Replace("&kaigyo", "\n");
|
|
|
|
+ // MM does not serialize message font size
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ binaryWriter.Write(showingMessage);
|
|
|
|
+ binaryWriter.Write(25);
|
|
|
|
+ binaryWriter.WriteNullableString(name);
|
|
|
|
+ binaryWriter.WriteNullableString(message);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static void SerializeLights(string[] strArray3, string[] strArray4, string[] strArray5, string[] strArray7, BinaryWriter binaryWriter)
|
|
|
|
+ {
|
|
// Lights
|
|
// Lights
|
|
|
|
+ binaryWriter.Write("LIGHT");
|
|
|
|
+
|
|
|
|
+ int numberOfLights = 1;
|
|
|
|
+ numberOfLights += strArray5 == null ? 0 : strArray5.Length - 1;
|
|
|
|
+
|
|
|
|
+ binaryWriter.Write(numberOfLights);
|
|
|
|
|
|
if (strArray3.Length > 16)
|
|
if (strArray3.Length > 16)
|
|
{
|
|
{
|
|
@@ -160,7 +548,7 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
|
|
3 = Directional (Colour Mode)
|
|
3 = Directional (Colour Mode)
|
|
*/
|
|
*/
|
|
int lightType = int.Parse(strArray3[17]);
|
|
int lightType = int.Parse(strArray3[17]);
|
|
- Color lightColor = new Color(
|
|
|
|
|
|
+ Color lightColour = new Color(
|
|
float.Parse(strArray3[18]), float.Parse(strArray3[19]), float.Parse(strArray3[20]), 1f
|
|
float.Parse(strArray3[18]), float.Parse(strArray3[19]), float.Parse(strArray3[20]), 1f
|
|
);
|
|
);
|
|
|
|
|
|
@@ -169,191 +557,155 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
|
|
);
|
|
);
|
|
|
|
|
|
// MM uses spotAngle for both range and spotAngle based on which light type is used
|
|
// MM uses spotAngle for both range and spotAngle based on which light type is used
|
|
- // TODO: assign value from spot angle appropriately
|
|
|
|
float intensity = float.Parse(strArray3[24]);
|
|
float intensity = float.Parse(strArray3[24]);
|
|
float spotAngle = float.Parse(strArray3[25]);
|
|
float spotAngle = float.Parse(strArray3[25]);
|
|
- float range = float.Parse(strArray3[26]);
|
|
|
|
|
|
+ float range = lightType == 2 ? spotAngle / 5f : spotAngle; ;
|
|
float shadowStrength = 0.098f;
|
|
float shadowStrength = 0.098f;
|
|
if (strArray4 != null) shadowStrength = float.Parse(strArray4[0]);
|
|
if (strArray4 != null) shadowStrength = float.Parse(strArray4[0]);
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < 3; i++)
|
|
|
|
+ {
|
|
|
|
+ if (i == lightType || (i == 0 && lightType == 3))
|
|
|
|
+ {
|
|
|
|
+ SerializeLightProperty(
|
|
|
|
+ binaryWriter, lightRotation, lightColour, intensity, spotAngle, range, shadowStrength
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ else SerializeDefaultLight(binaryWriter);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (strArray7 != null)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.WriteVector3(Utility.Vector3String(strArray7[0]));
|
|
|
|
+ }
|
|
|
|
+ else binaryWriter.WriteVector3(new Vector3(0f, 1.9f, 0.4f));
|
|
|
|
+ binaryWriter.Write(lightType == 3 ? 0 : lightType);
|
|
|
|
+ binaryWriter.Write(lightType == 3);
|
|
|
|
+ binaryWriter.Write(false);
|
|
// lightKage[0] is the only value that's serialized
|
|
// lightKage[0] is the only value that's serialized
|
|
}
|
|
}
|
|
|
|
|
|
- int lights = 1;
|
|
|
|
|
|
|
|
if (strArray5 != null)
|
|
if (strArray5 != null)
|
|
{
|
|
{
|
|
- int numberOfLights = strArray5.Length - 1;
|
|
|
|
- lights += numberOfLights;
|
|
|
|
-
|
|
|
|
- for (int i = 0; i < numberOfLights; i++)
|
|
|
|
|
|
+ int otherLights = strArray5.Length - 1;
|
|
|
|
+ for (int i = 0; i < otherLights; i++)
|
|
{
|
|
{
|
|
string[] lightProperties = strArray5[i].Split(',');
|
|
string[] lightProperties = strArray5[i].Split(',');
|
|
|
|
|
|
int lightType = int.Parse(lightProperties[0]);
|
|
int lightType = int.Parse(lightProperties[0]);
|
|
|
|
|
|
- Color lightColor = new Color(
|
|
|
|
- float.Parse(lightProperties[1]), float.Parse(lightProperties[1]),
|
|
|
|
- float.Parse(lightProperties[1]), 1f
|
|
|
|
|
|
+ Color lightColour = new Color(
|
|
|
|
+ float.Parse(lightProperties[1]), float.Parse(lightProperties[2]),
|
|
|
|
+ float.Parse(lightProperties[3]), 1f
|
|
);
|
|
);
|
|
|
|
|
|
- Quaternion lightAngle = Quaternion.Euler(
|
|
|
|
|
|
+ Quaternion lightRotation = Quaternion.Euler(
|
|
float.Parse(lightProperties[4]), float.Parse(lightProperties[5]), 18f
|
|
float.Parse(lightProperties[4]), float.Parse(lightProperties[5]), 18f
|
|
);
|
|
);
|
|
|
|
|
|
float intensity = float.Parse(lightProperties[6]);
|
|
float intensity = float.Parse(lightProperties[6]);
|
|
float spotAngle = float.Parse(lightProperties[7]);
|
|
float spotAngle = float.Parse(lightProperties[7]);
|
|
- float range = spotAngle / 5f;
|
|
|
|
|
|
+ float range = lightType == 2 ? spotAngle / 5f : spotAngle;
|
|
float shadowStrength = 0.098f;
|
|
float shadowStrength = 0.098f;
|
|
|
|
+ for (int j = 0; j < 3; j++)
|
|
|
|
+ {
|
|
|
|
+ if (j == lightType)
|
|
|
|
+ {
|
|
|
|
+ SerializeLightProperty(
|
|
|
|
+ binaryWriter, lightRotation, lightColour, intensity, spotAngle, range, shadowStrength
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ else SerializeDefaultLight(binaryWriter);
|
|
|
|
+ }
|
|
|
|
+ if (strArray7 != null)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.WriteVector3(Utility.Vector3String(strArray7[i + 1]));
|
|
|
|
+ }
|
|
|
|
+ else binaryWriter.WriteVector3(new Vector3(0f, 1.9f, 0.4f));
|
|
|
|
+ binaryWriter.Write(lightType == 3 ? 0 : lightType);
|
|
|
|
+ binaryWriter.Write(false);
|
|
|
|
+ binaryWriter.Write(lightType == 3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- if (strArray7 != null)
|
|
|
|
- {
|
|
|
|
- for (int i = 0; i < lights; i++)
|
|
|
|
- {
|
|
|
|
- string[] lightPosString = strArray7[i].Split(',');
|
|
|
|
- Vector3 lightPosition = new Vector3(
|
|
|
|
- float.Parse(lightPosString[0]), float.Parse(lightPosString[1]), float.Parse(lightPosString[2])
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ private static void SerializeEnvironment(string[] data, BinaryWriter binaryWriter, bool kankyo)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.Write("ENVIRONMENT");
|
|
|
|
|
|
- // Message
|
|
|
|
|
|
+ int bgIndex;
|
|
|
|
|
|
- if (strArray3.Length > 16)
|
|
|
|
|
|
+ string bgAsset = "Theater";
|
|
|
|
+
|
|
|
|
+ if (!int.TryParse(data[2], out bgIndex))
|
|
{
|
|
{
|
|
- bool showingMessage = int.Parse(strArray3[34]) == 1;
|
|
|
|
- string name = strArray3[35];
|
|
|
|
- string message = strArray3[36].Replace("&kaigyo", "\n");
|
|
|
|
- // MM does not serialize message font size
|
|
|
|
|
|
+ bgAsset = data[2].Replace(" ", "_");
|
|
}
|
|
}
|
|
|
|
|
|
- // effect
|
|
|
|
|
|
+ binaryWriter.Write(bgAsset);
|
|
|
|
|
|
- if (strArray4 != null)
|
|
|
|
- {
|
|
|
|
- // bloom
|
|
|
|
- bool bloomActive = int.Parse(strArray4[1]) == 1;
|
|
|
|
- float bloomIntensity = float.Parse(strArray4[2]);
|
|
|
|
- float bloomBlurIterations = float.Parse(strArray4[3]);
|
|
|
|
- Color bloomColour = new Color(
|
|
|
|
- float.Parse(strArray4[4]), float.Parse(strArray4[5]), float.Parse(strArray4[6]), 1f
|
|
|
|
- );
|
|
|
|
- bool bloomHdr = int.Parse(strArray4[7]) == 1;
|
|
|
|
|
|
+ binaryWriter.WriteVector3(new Vector3(
|
|
|
|
+ float.Parse(data[6]), float.Parse(data[7]), float.Parse(data[8])
|
|
|
|
+ ));
|
|
|
|
|
|
- // vignetting
|
|
|
|
- bool vignetteActive = int.Parse(strArray4[8]) == 1;
|
|
|
|
- float vignetteIntensity = float.Parse(strArray4[9]);
|
|
|
|
- float vignetteBlur = float.Parse(strArray4[10]);
|
|
|
|
- float vignetteBlurSpread = float.Parse(strArray4[11]);
|
|
|
|
- float vignetteChromaticAberration = float.Parse(strArray4[12]);
|
|
|
|
|
|
+ binaryWriter.WriteQuaternion(Quaternion.Euler(
|
|
|
|
+ float.Parse(data[3]), float.Parse(data[4]), float.Parse(data[5])
|
|
|
|
+ ));
|
|
|
|
|
|
- // bokashi
|
|
|
|
- // TODO: implement bokashi in MPS
|
|
|
|
- float bokashi = float.Parse(strArray4[13]);
|
|
|
|
|
|
+ binaryWriter.WriteVector3(new Vector3(
|
|
|
|
+ float.Parse(data[9]), float.Parse(data[10]), float.Parse(data[11])
|
|
|
|
+ ));
|
|
|
|
|
|
- // TODO: implement sepia in MPS too
|
|
|
|
|
|
+ binaryWriter.Write(kankyo);
|
|
|
|
|
|
- if (strArray4.Length > 15)
|
|
|
|
- {
|
|
|
|
- bool dofActive = int.Parse(strArray4[15]) == 1;
|
|
|
|
- float dofFocalLength = float.Parse(strArray4[16]);
|
|
|
|
- float dofFocalSize = float.Parse(strArray4[17]);
|
|
|
|
- float dofAperture = float.Parse(strArray4[18]);
|
|
|
|
- float dofMaxBlurSize = float.Parse(strArray4[19]);
|
|
|
|
- bool dofVisualizeFocus = int.Parse(strArray4[20]) == 1;
|
|
|
|
-
|
|
|
|
- bool fogActive = int.Parse(strArray4[21]) == 1;
|
|
|
|
- float fogStartDistance = float.Parse(strArray4[22]);
|
|
|
|
- float fogDensity = float.Parse(strArray4[23]);
|
|
|
|
- float fogHeightScale = float.Parse(strArray4[24]);
|
|
|
|
- float fogHeight = float.Parse(strArray4[25]);
|
|
|
|
- Color fogColor = new Color(
|
|
|
|
- float.Parse(strArray4[26]), float.Parse(strArray4[27]), float.Parse(strArray4[28]), 1f
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ Vector3 cameraTargetPos = new Vector3(0f, 0.9f, 0f);
|
|
|
|
+ float cameraDistance = 3f;
|
|
|
|
+ Quaternion cameraRotation = Quaternion.identity;
|
|
|
|
|
|
- // prop
|
|
|
|
- if (strArray3.Length > 37 && !string.IsNullOrEmpty(strArray3[37]))
|
|
|
|
|
|
+ if (data.Length > 16)
|
|
{
|
|
{
|
|
- // For the prop that spawns when you push (shift +) W
|
|
|
|
- string assetName = strArray3[37].Replace(' ', '_');
|
|
|
|
- Vector3 position = new Vector3(
|
|
|
|
- float.Parse(strArray3[41]), float.Parse(strArray3[42]), float.Parse(strArray3[43])
|
|
|
|
- );
|
|
|
|
- Quaternion rotation = Quaternion.Euler(
|
|
|
|
- float.Parse(strArray3[38]), float.Parse(strArray3[39]), float.Parse(strArray3[40])
|
|
|
|
|
|
+ cameraTargetPos = new Vector3(
|
|
|
|
+ float.Parse(data[27]), float.Parse(data[28]), float.Parse(data[29])
|
|
);
|
|
);
|
|
- Vector3 localScale = new Vector3(
|
|
|
|
- float.Parse(strArray3[44]), float.Parse(strArray3[45]), float.Parse(strArray3[46])
|
|
|
|
|
|
+
|
|
|
|
+ cameraDistance = float.Parse(data[30]);
|
|
|
|
+
|
|
|
|
+ cameraRotation = Quaternion.Euler(
|
|
|
|
+ float.Parse(data[31]), float.Parse(data[32]), float.Parse(data[33])
|
|
);
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
- if (strArray6 != null)
|
|
|
|
- {
|
|
|
|
- for (int i = 0; i < strArray6.Length - 1; i++)
|
|
|
|
- {
|
|
|
|
- string[] assetParts = strArray6[i].Split(',');
|
|
|
|
- string assetName = assetParts[0].Replace(' ', '_');
|
|
|
|
-
|
|
|
|
- if (assetName.StartsWith("creative_"))
|
|
|
|
- {
|
|
|
|
- // modifiedMM my room creative prop
|
|
|
|
- // modifiedMM serializes the prefabName rather than the ID.
|
|
|
|
- // TODO: Either write a special case for MPS or rewrite for use in game
|
|
|
|
- assetName.Replace("creative_", String.Empty);
|
|
|
|
- assetName = $"MYR_#{assetName}";
|
|
|
|
- }
|
|
|
|
- // else if (assetName.StartsWith("MYR_"))
|
|
|
|
- // {
|
|
|
|
- // // MM 23.0+ my room creative prop
|
|
|
|
- // assetName = assetName + "#";
|
|
|
|
- // }
|
|
|
|
- else if (assetName.Contains('#'))
|
|
|
|
- {
|
|
|
|
- if (assetName.Contains(".menu"))
|
|
|
|
- {
|
|
|
|
- // modifiedMM official mod prop
|
|
|
|
- string[] modComponents = assetParts[0].Split('#');
|
|
|
|
- string baseMenuFile = modComponents[0].Replace(' ', '_');
|
|
|
|
- string modItem = modComponents[1].Replace(' ', '_');
|
|
|
|
- assetName = $"{modComponents[0]}#{modComponents[1]}";
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- assetName = assetName.Split('#')[1].Replace(' ', '_');
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ binaryWriter.WriteVector3(cameraTargetPos);
|
|
|
|
|
|
- Vector3 position = new Vector3(
|
|
|
|
- float.Parse(assetParts[4]), float.Parse(assetParts[5]), float.Parse(assetParts[6])
|
|
|
|
- );
|
|
|
|
- Quaternion rotation = Quaternion.Euler(
|
|
|
|
- float.Parse(assetParts[1]), float.Parse(assetParts[2]), float.Parse(assetParts[3])
|
|
|
|
- );
|
|
|
|
- Vector3 scale = new Vector3(
|
|
|
|
- float.Parse(assetParts[7]), float.Parse(assetParts[8]), float.Parse(assetParts[9])
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ binaryWriter.Write(cameraDistance);
|
|
|
|
|
|
- // meido
|
|
|
|
|
|
+ binaryWriter.WriteQuaternion(cameraRotation);
|
|
|
|
+ }
|
|
|
|
|
|
- int numberOfMaids = strArray2.Length;
|
|
|
|
|
|
+ public static void SerializeAttachPoint(BinaryWriter binaryWriter)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.Write(0);
|
|
|
|
+ binaryWriter.Write(-1);
|
|
|
|
+ }
|
|
|
|
|
|
- for (int i = 0; i < numberOfMaids; i++)
|
|
|
|
- {
|
|
|
|
- List<Quaternion> fingerRotation = new List<Quaternion>();
|
|
|
|
- string[] maidData = strArray2[i].Split(':');
|
|
|
|
- for (int j = 0; j < 40; j++)
|
|
|
|
- {
|
|
|
|
- string fingerString = maidData[j];
|
|
|
|
- fingerRotation.Add(UnityStructExtensions.EulerString(fingerString));
|
|
|
|
- }
|
|
|
|
|
|
+ public static void SerializeDefaultLight(BinaryWriter binaryWriter)
|
|
|
|
+ {
|
|
|
|
+ SerializeLightProperty(binaryWriter, Quaternion.Euler(40f, 180f, 0f), Color.white);
|
|
|
|
+ }
|
|
|
|
|
|
- // TODO: Other maid related things
|
|
|
|
- }
|
|
|
|
|
|
+ public static void SerializeLightProperty(
|
|
|
|
+ BinaryWriter binaryWriter,
|
|
|
|
+ Quaternion rotation, Color colour, float intensity = 0.95f, float range = 50f,
|
|
|
|
+ float spotAngle = 50f, float shadowStrength = 0.1f
|
|
|
|
+ )
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.WriteQuaternion(rotation);
|
|
|
|
+ binaryWriter.Write(intensity);
|
|
|
|
+ binaryWriter.Write(range);
|
|
|
|
+ binaryWriter.Write(spotAngle);
|
|
|
|
+ binaryWriter.Write(shadowStrength);
|
|
|
|
+ binaryWriter.WriteColour(colour);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -373,9 +725,24 @@ namespace COM3D2.MeidoPhotoStudio.Plugin
|
|
binaryWriter.Write(quaternion.z);
|
|
binaryWriter.Write(quaternion.z);
|
|
binaryWriter.Write(quaternion.w);
|
|
binaryWriter.Write(quaternion.w);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ public static void WriteColour(this BinaryWriter binaryWriter, UnityEngine.Color colour)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.Write(colour.r);
|
|
|
|
+ binaryWriter.Write(colour.g);
|
|
|
|
+ binaryWriter.Write(colour.b);
|
|
|
|
+ binaryWriter.Write(colour.a);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void WriteNullableString(this BinaryWriter binaryWriter, string str)
|
|
|
|
+ {
|
|
|
|
+ binaryWriter.Write(str != null);
|
|
|
|
+ if (str != null) binaryWriter.Write(str);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- public static class UnityStructExtensions
|
|
|
|
|
|
+
|
|
|
|
+ public static class Utility
|
|
{
|
|
{
|
|
public static Quaternion EulerString(string euler)
|
|
public static Quaternion EulerString(string euler)
|
|
{
|
|
{
|