using System.Text.Json;
using System.Collections.Generic;
using UnityEngine;
using BepInEx.Logging;
using HarmonyLib;
using ExposureUnnoticed2.Master.Cosplay;
using ExposureUnnoticed2.Object3D.Player.Scripts;
namespace SFM_CosplayPatch;
public class CosplayPatcher : MonoBehaviour
{
internal static ManualLogSource Log;
private enum binaryMode
{
Subtract = 0,
Add = 1
}
private Dictionary<string, Dictionary<string, dynamic>> PatchDict;
private List<int> PatchedParts = new();
public CosplayPatcher(Dictionary<string, Dictionary<string, dynamic>> inputPatchDict, ManualLogSource logger)
{
PatchDict = inputPatchDict;
Log = logger;
}
public void ReRunPatch()
{
int[] tempPartArray = PatchedParts.ToArray();
PatchedParts.Clear();
foreach (int part in tempPartArray)
{
PatchCosplayPartById(part);
}
}
public void PatchCosplayPartById(int uniqueId)
{
var cosplayPart = ExposureUnnoticed2.Master.Cosplay.MCosplay.GetParts(uniqueId);
if (!PatchedParts.Contains(uniqueId))
{
PatchCosplayPart(cosplayPart);
PatchedParts.Add(uniqueId);
}
}
public void PatchCosplayPart(RCosplayParts cosplayPart)
{
Traverse trav = Traverse.Create(cosplayPart);
PlayerStateModel.HiddenBodyPartsByCostumeType hiddenParts = trav.Property("HiddenPartsType").GetValue<PlayerStateModel.HiddenBodyPartsByCostumeType>();
if (PatchDict.ContainsKey(cosplayPart.NameKey))
{
Dictionary<string, dynamic> patch = PatchDict[cosplayPart.NameKey];
if (patch != null)
{
foreach (KeyValuePair<string, dynamic> prop in patch)
{
if (prop.Key == "HiddenPartsType") SetPropertyHiddenPartsType(trav, prop);
else SetPropertyOther(trav, prop);
}
}
}
}
private PlayerStateModel.HiddenBodyPartsByCostumeType HiddenPartsBinaryOp(
PlayerStateModel.HiddenBodyPartsByCostumeType oldFlags, PlayerStateModel.HiddenBodyPartsByCostumeType newFlag, binaryMode mode)
{
if (mode == binaryMode.Add) return (oldFlags | newFlag);
else return (oldFlags ^ newFlag);
}
private void SetPropertyOther(Traverse trav, KeyValuePair<string, dynamic> prop)
{
var target = trav.Property(prop.Key);
if (target == null)
var targetVal = target.GetValue();
if (targetVal is int)
{
int value = JsonSerializer.Deserialize<int>(prop.Value);
trav.Property(prop.Key).SetValue(value);
}
else if (targetVal is float)
{
float value = JsonSerializer.Deserialize<float>(prop.Value);
trav.Property(prop.Key).SetValue(value);
}
else if (targetVal is double)
{
double value = JsonSerializer.Deserialize<double>(prop.Value);
trav.Property(prop.Key).SetValue(value);
}
else if (targetVal is bool)
{
bool value = JsonSerializer.Deserialize<bool>(prop.Value);
trav.Property(prop.Key).SetValue(value);
}
}
private void SetPropertyHiddenPartsType(Traverse trav, KeyValuePair<string, dynamic> prop)
{
PlayerStateModel.HiddenBodyPartsByCostumeType newFlags = trav.Property(prop.Key).GetValue<PlayerStateModel.HiddenBodyPartsByCostumeType>();
string[] flags = JsonSerializer.Deserialize<string[]>(prop.Value);
foreach (string f in flags)
{
string flag;
binaryMode mode = binaryMode.Add;
if (f.StartsWith('-'))
{
mode = binaryMode.Subtract;
flag = f.Trim('-');
}
else flag = f;
switch (flag)
{
case "Boobs":
newFlags = HiddenPartsBinaryOp(newFlags, PlayerStateModel.HiddenBodyPartsByCostumeType.Boobs, mode);
break;
case "Hip":
newFlags = HiddenPartsBinaryOp(newFlags, PlayerStateModel.HiddenBodyPartsByCostumeType.Hip, mode);
break;
case "Genitals":
newFlags = HiddenPartsBinaryOp(newFlags, PlayerStateModel.HiddenBodyPartsByCostumeType.Genitals, mode);
break;
case "SideOrBackUpper":
newFlags = HiddenPartsBinaryOp(newFlags, PlayerStateModel.HiddenBodyPartsByCostumeType.SideOrBackUpperBody, mode);
break;
case "HipCrouch":
newFlags = HiddenPartsBinaryOp(newFlags, PlayerStateModel.HiddenBodyPartsByCostumeType.HipCrouch, mode);
break;
default:
Log.LogWarning($"JSON error in patching {trav.Property("NameKey").GetValue<string>()}: {flag} is not a valid HiddenPartsType");
break;
}
}
trav.Property(prop.Key).SetValue(newFlags);
}
}