Can you tell me more about how this plugin do the job?
In fact I have no skill on writing plugins, and this author's other games usually have the same problem.
Maybe I can do the job myself if I know the theory.
Even using plungin, the insert(piston) scene is censored. is right working?
hm.. This game is IL2CPP type unity. So if you want mod app, there are 2 options.
- edit hex bytes.
- make plugin of BepInEx(or other framework(ex. MelonLoader, etc))
Both methods are needed to study... assembly, c#, etc...
flow making plugin of this game.(making plugin)
Analyze app
Make a dummy Assembly-CSharp.dll with Il2CppDumper to analyze.
Decompile with IDA Pro.
Find Mosaic (open Assembly-CSharp.dll with dnSpy)
At Start(), calls SetValue(blahblah)
C:
public unsafe void SetValue(bool off, float size, float penisSize)
{
IL2CPP.Il2CppObjectBaseToPtrNotNull(this);
IntPtr* ptr;
checked
{
ptr = stackalloc IntPtr[unchecked((UIntPtr)3) * (UIntPtr)sizeof(IntPtr)];
*ptr = ref off;
}
ptr[checked(unchecked((UIntPtr)1) * (UIntPtr)sizeof(IntPtr)) / (UIntPtr)sizeof(IntPtr)] = ref size;
ptr[checked(unchecked((UIntPtr)2) * (UIntPtr)sizeof(IntPtr)) / (UIntPtr)sizeof(IntPtr)] = ref penisSize;
IntPtr intPtr2;
IntPtr intPtr = IL2CPP.il2cpp_runtime_invoke(R18Mosaic.NativeMethodInfoPtr_SetValue_Private_Void_Boolean_Single_Single_0, IL2CPP.Il2CppObjectBaseToPtrNotNull(this), (void**)ptr, ref intPtr2);
Il2CppException.RaiseExceptionIfNecessary(intPtr2);
}
Guess parameters
View at IDA
C:
void __stdcall MyLibrary_R18Mosaic__SetValue(MyLibrary_R18Mosaic_o *this, bool off, float size, float penisSize, const MethodInfo *method)
...
if ( !off )
{
UnityEngine_Material__SetFloat((UnityEngine_Material_o *)v17, str__Mosa_On, 1.0, 0i64);
UnityEngine_Material__SetFloat((UnityEngine_Material_o *)v17, str__MosaPixSize2, v19, 0i64);
goto LABEL_20;
}
UnityEngine_Material__SetFloat((UnityEngine_Material_o *)v17, str__Mosa_On, 0.0, 0i64);
...
Parameter "bool off" may be means "NoMosaic". If the value is true, "_Mosa_On"(Material) set to 0.0.
Making plugin
It's hard to explain how to make a plugin. Let's see the just code.
C:
using System;
using BepInEx;
using BepInEx.IL2CPP;
using BepInEx.Logging;
using HarmonyLib;
using UnhollowerRuntimeLib;
using UnityEngine;
namespace PantyCard_unc
{
[BepInPlugin(GUID, MODNAME, VERSION)]
public class Loader : BasePlugin
{
public const string
MODNAME = "PantyCard_unc",
AUTHOR = "kumarin",
GUID = "com." + AUTHOR + "." + MODNAME,
VERSION = "1.0.0.0";
internal static ManualLogSource log;
public override void Load()
{
log = base.Log;
ClassInjector.RegisterTypeInIl2Cpp<PantyCard_unc>();
AddComponent<PantyCard_unc>();
}
}
public class PantyCard_unc : MonoBehaviour
{
public void Awake()
{
Harmony harmony = new Harmony(Loader.GUID + ".patch");
harmony.PatchAll();
}
[HarmonyPatch(typeof(MyLibrary.R18Mosaic), "SetValue", new Type[] { typeof(bool), typeof(float), typeof(float) })]
public class R18Mosaic_SetValue
{
[HarmonyPrefix]
public static void Prefix(ref bool off, float size, float penisSize)
{
off = true;
}
}
}
}
Important line is just
off = true;
It change the value of parameter "bool off" to "true" before enter the "SetValue" method.
generally unity game's uncensor is 2 type. soft and hard.
soft uncensor is recommend to use
UniversalUnityDemosaics(not ManlyMarco's original)
one of hard uncensor is use
Texture Replacer. some games are using it. (ex.
Imouto Uncensor & Cheats plugin,
Beat Refle Cheats + Decensor plugin Pack, and so on) of course, needed graphic designer(?)