using System; using System.Text.RegularExpressions; using System.IO; using System.Reflection; using UnityEngine; namespace COM3D2.MeidoPhotoStudio.Plugin { internal static class Utility { internal static readonly byte[] pngHeader = { 137, 80, 78, 71, 13, 10, 26, 10 }; internal static readonly byte[] pngEnd = System.Text.Encoding.ASCII.GetBytes("IEND"); internal static readonly Regex guidRegEx = new Regex( @"^[a-f0-9]{8}(\-[a-f0-9]{4}){3}\-[a-f0-9]{12}$", RegexOptions.IgnoreCase ); public static readonly BepInEx.Logging.ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource(MeidoPhotoStudio.pluginName); public enum ModKey { Control, Shift, Alt } public static void LogInfo(object data) => Logger.LogInfo(data); public static void LogMessage(object data) => Logger.LogInfo(data); public static void LogWarning(object data) => Logger.LogWarning(data); public static void LogError(object data) => Logger.LogError(data); public static void LogDebug(object data) => Logger.LogDebug(data); public static int Wrap(int value, int min, int max) { max -= 1; return value < min ? max : value > max ? min : value; } public static int GetPix(int num) { return (int)((1f + (Screen.width / 1280f - 1f) * 0.6f) * num); } public static float Bound(float value, float left, float right) { if ((double)left > (double)right) return Mathf.Clamp(value, right, left); else return Mathf.Clamp(value, left, right); } public static int Bound(int value, int left, int right) { if (left > right) return Mathf.Clamp(value, right, left); else return Mathf.Clamp(value, left, right); } public static Texture2D MakeTex(int width, int height, Color color) { Color[] colors = new Color[width * height]; for (int i = 0; i < colors.Length; i++) { colors[i] = color; } Texture2D texture2D = new Texture2D(width, height); texture2D.SetPixels(colors); texture2D.Apply(); return texture2D; } public static FieldInfo GetFieldInfo(string field) { BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; return typeof(T).GetField(field, bindingFlags); } public static TValue GetFieldValue(TType instance, string field) { FieldInfo fieldInfo = GetFieldInfo(field); if (fieldInfo == null || !fieldInfo.IsStatic && instance == null) return default(TValue); return (TValue)fieldInfo.GetValue(instance); } public static void SetFieldValue(TType instance, string name, TValue value) { GetFieldInfo(name).SetValue(instance, value); } public static bool AnyMouseDown() { return Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2); } public static string ScreenshotFilename() { string screenShotDir = Path.Combine( GameMain.Instance.SerializeStorageManager.StoreDirectoryPath, "ScreenShot" ); if (!Directory.Exists(screenShotDir)) { Directory.CreateDirectory(screenShotDir); } return Path.Combine(screenShotDir, $"img{DateTime.Now:yyyyMMddHHmmss}.png"); } public static string TempScreenshotFilename() { return Path.Combine(Path.GetTempPath(), $"cm3d2_{System.Guid.NewGuid().ToString()}.png"); } public static void ShowMouseExposition(string text, float time = 2f) { MouseExposition mouseExposition = MouseExposition.GetObject(); mouseExposition.SetText(text, time); } public static bool IsGuidString(string guid) { if (string.IsNullOrEmpty(guid) || guid.Length != 36) return false; return guidRegEx.IsMatch(guid); } public static string HandItemToOdogu(string menu) { menu = menu.Substring(menu.IndexOf('_') + 1); menu = menu.Substring(0, menu.IndexOf("_i_.menu")); menu = $"odogu_{menu}"; return menu; } public static void FixGameObjectScale(GameObject go) { Vector3 scale = go.transform.localScale; float largest = Mathf.Max(scale.x, Mathf.Max(scale.y, scale.z)); go.transform.localScale = Vector3.one * (float)Math.Round(largest, 3); } public static string SanitizePathPortion(string path) { char[] invalid = Path.GetInvalidFileNameChars(); path = path.Trim(); path = string.Join("_", path.Split(invalid)).Replace(".", "").Trim('_'); return path; } public static string GP01FbFaceHash(TMorph face, string hash) { if ((face.bodyskin.PartsVersion >= 120) && (hash != "eyeclose3") && hash.StartsWith("eyeclose")) { if (hash == "eyeclose") hash += '1'; hash += TMorph.crcFaceTypesStr[(int)face.GetFaceTypeGP01FB()]; } return hash; } public static void ResizeToFit(Texture2D texture, int maxWidth, int maxHeight) { int width = texture.width; int height = texture.height; if (width != maxWidth || height != maxHeight) { float scale = Mathf.Min((float)maxWidth / (float)width, (float)maxHeight / (float)height); width = Mathf.RoundToInt((float)width * scale); height = Mathf.RoundToInt((float)height * scale); TextureScale.Bilinear(texture, width, height); } } public static bool BytesEqual(byte[] buffer, byte[] other) { if (buffer.Length != other.Length) return false; for (int i = 0; i < buffer.Length; i++) { if (buffer[i] != other[i]) return false; } return true; } public static bool IsPngFile(Stream stream) { byte[] buffer = new byte[8]; stream.Read(buffer, 0, 8); stream.Position = 0L; return BytesEqual(buffer, pngHeader); } public static bool SeekPngEnd(Stream stream) { byte[] buffer = new byte[8]; stream.Read(buffer, 0, 8); if (!BytesEqual(buffer, pngHeader)) return false; buffer = new byte[4]; do { stream.Read(buffer, 0, 4); if (BitConverter.IsLittleEndian) Array.Reverse(buffer); uint length = System.BitConverter.ToUInt32(buffer, 0); stream.Read(buffer, 0, 4); stream.Seek(length + 4L, SeekOrigin.Current); } while (!BytesEqual(buffer, pngEnd)); return true; } } internal static class BinaryExtensions { public static string ReadNullableString(this BinaryReader binaryReader) { return binaryReader.ReadBoolean() ? binaryReader.ReadString() : null; } public static void WriteNullableString(this BinaryWriter binaryWriter, string str) { binaryWriter.Write(str != null); if (str != null) binaryWriter.Write(str); } public static void WriteVector3(this BinaryWriter binaryWriter, UnityEngine.Vector3 vector3) { binaryWriter.Write(vector3.x); binaryWriter.Write(vector3.y); binaryWriter.Write(vector3.z); } public static UnityEngine.Vector3 ReadVector3(this BinaryReader binaryReader) { return new UnityEngine.Vector3( binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle() ); } public static void WriteQuaternion(this BinaryWriter binaryWriter, UnityEngine.Quaternion quaternion) { binaryWriter.Write(quaternion.x); binaryWriter.Write(quaternion.y); binaryWriter.Write(quaternion.z); binaryWriter.Write(quaternion.w); } public static UnityEngine.Quaternion ReadQuaternion(this BinaryReader binaryReader) { return new UnityEngine.Quaternion ( binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle() ); } 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 UnityEngine.Color ReadColour(this BinaryReader binaryReader) { return new Color( binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle() ); } } }