InOutAnimation.cs 111 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Text.RegularExpressions;
  8. using System.Xml;
  9. using System.Xml.Serialization;
  10. using UnityEngine;
  11. using UnityEngine.Rendering;
  12. using UnityEngine.SceneManagement;
  13. using UnityInjector;
  14. using UnityInjector.Attributes;
  15. using static UnityEngine.GUILayout;
  16. namespace COM3D2.InOutAnimation.Plugin
  17. {
  18. [PluginFilter(PluginFilter)]
  19. [PluginName(PluginName)]
  20. [PluginVersion(PluginVersion)]
  21. public class InOutAnimation : PluginBase
  22. {
  23. private const string PluginFilter = "com3d2x64",
  24. PluginName = "InOutAnimation",
  25. PluginVersion = "0.0.0.0";
  26. private const string PathConfig = @"IOAnim",
  27. FileNameConfig = @"Settings";
  28. private const string ConfigPanel = "ConfigPanel";
  29. private const string ResultPanel = "ResultPanel";
  30. private const string NameHideScrollField = "current_panel_display_",
  31. NameSkillSel = "SkillSelectViewer",
  32. NameParamView = "ParameterViewer";
  33. private const string HiddenShader = "Hidden/Internal-Colored";
  34. private const string NoZTestShader = "CM3D2/Toony_Lighted_Trans_NoZTest";
  35. private const string SE_CumShot = "SE016";
  36. private interface IInitializable
  37. {
  38. void Initialize();
  39. }
  40. #region Variables
  41. private readonly Version pluginGameVer = new Version("1.32.0");
  42. private Version currentGameVer;
  43. private bool isStudioMode;
  44. private Mediator mediator;
  45. private AnmScript script;
  46. private State current;
  47. private FlipAnim[] flipAnims;
  48. private PokoCam pokoCam;
  49. private FaceCam faceCam;
  50. private Controller controller;
  51. private static Settings settings;
  52. private int windowId;
  53. private IEnumerable<AudioSource> _playingSE;
  54. private HideScroll _hideScroll;
  55. private GameObject configPanel;
  56. private GameObject resultPanel;
  57. private WfScreenChildren screenChildren;
  58. private readonly BindingFlags bindingFlags =
  59. BindingFlags.GetField | BindingFlags.NonPublic |
  60. BindingFlags.DeclaredOnly | BindingFlags.Instance;
  61. private IInitializable[] _initializables;
  62. private MessageBox _msgbox;
  63. private static bool _debug;
  64. #endregion
  65. #region MonoBehavior
  66. private void Awake()
  67. {
  68. DontDestroyOnLoad(this);
  69. }
  70. private void Start()
  71. {
  72. currentGameVer = new Version(GameUty.GetBuildVersionText());
  73. if (pluginGameVer > currentGameVer)
  74. {
  75. enabled = false;
  76. return;
  77. }
  78. Initialize();
  79. SceneManager.sceneLoaded += (scene, mode) =>
  80. {
  81. foreach (var flipAnim in flipAnims)
  82. flipAnim.Load();
  83. settings = Settings.Load();
  84. isStudioMode = scene.name.Contains("ScenePhotoMode");
  85. };
  86. SceneManager.sceneUnloaded += scene =>
  87. {
  88. AllReset();
  89. controller.showController = false;
  90. Settings.Save();
  91. };
  92. }
  93. private void Update()
  94. {
  95. if (isStudioMode)
  96. return;
  97. if (Input.anyKey)
  98. CheckInput();
  99. if (!settings.enablePlugin)
  100. return;
  101. mediator.FindTarget(current);
  102. script.Parse(mediator);
  103. if (!mediator.TargetMaid.IsValid() || !current.isPlay)
  104. return;
  105. mediator.PrepareMuffs();
  106. mediator.PreparePokos(current);
  107. if (mediator.muffsPrepared && mediator.pokosPrepared)
  108. {
  109. mediator.ValidatePair(current);
  110. mediator.UpdateValues(current);
  111. switch (Time.frameCount % 30)
  112. {
  113. case 0:
  114. current.showSkillSelect = IsShowHideScrolls(NameSkillSel);
  115. break;
  116. case 10:
  117. current.showParameter = IsShowHideScrolls(NameParamView);
  118. break;
  119. case 15:
  120. current.showResultPanel = IsShowResultPanel();
  121. break;
  122. case 20:
  123. current.showConfigPanel = IsShowConfigPanel();
  124. break;
  125. }
  126. if (mediator.manLength > 0)
  127. current.isShooting = IsShooting();
  128. current.CanDrawOverlay = true;
  129. }
  130. if (Time.frameCount % 20 == 5)
  131. CheckScreenFade();
  132. if (!settings.enablePlugin || !mediator.TargetMan.IsValid()) return;
  133. var smr = mediator.TargetMan.GetComponentsInChildren<SkinnedMeshRenderer>().FirstOrDefault(s =>
  134. s.name.Equals("karada", StringComparison.InvariantCultureIgnoreCase));
  135. if (smr == null)
  136. return;
  137. var mat = smr.materials[1];
  138. if (origShader == null)
  139. origShader = mat.shader;
  140. if (!current.isPlay || mat.shader.name == "CM3D2/Man" && !settings.OnGUI_HidePenis)
  141. {
  142. mat.shader = origShader;
  143. }
  144. else if (mat.shader.name == origShader.name && settings.OnGUI_HidePenis)
  145. {
  146. mat.shader = manShader;
  147. mat.SetFloat("_FloatValue2", 0f);
  148. mat.renderQueue = 3500;
  149. }
  150. }
  151. private readonly Shader manShader = Shader.Find("CM3D2/Man");
  152. private Shader origShader;
  153. private void LateUpdate()
  154. {
  155. if (current.CanDrawOverlay)
  156. DrawOverlay();
  157. current.CanDrawOverlay = false;
  158. if (!_debug)
  159. return;
  160. if (_msgbox == null)
  161. {
  162. _msgbox = new MessageBox();
  163. FindObjectOfType<SystemInfoHUD>().enabled = true;
  164. return;
  165. }
  166. foreach (var poko in mediator.pokos)
  167. poko?.DrawTrails();
  168. }
  169. private void OnGUI()
  170. {
  171. if (isStudioMode)
  172. return;
  173. if (controller.showController)
  174. controller.Draw();
  175. if (settings.enablePlugin && mediator.TargetMaid.IsValid() && current.isPlay)
  176. {
  177. DrawFlipAnims();
  178. DrawPokoCam();
  179. DrawFaceCam();
  180. }
  181. if (_debug)
  182. _msgbox?.Draw(
  183. new GUIContent(
  184. $"maid:{script.MaidAnmName}\n" +
  185. $"man0:{script.ManAnmName}\n" +
  186. $"currentSkill:{current.CurrentSkill}\n" +
  187. $"prim:{current.PrimaryMuff.ToString()}\n" +
  188. $"mode:{current.PlayMode.ToString()}\n" +
  189. $"num:{current.MuffNum.ToString()}\n" +
  190. $"stat:{current.PlayState}\n" +
  191. $"play:{current.isPlay} onani:{current.isOnani}\n" +
  192. $"pokotype:{current.PokoType} \n" +
  193. $"poko[0]:{mediator.pokos[0]?.TargetMuff}\n" +
  194. $"poko[1]:{mediator.pokos[1]?.TargetMuff}\n" +
  195. $"poko[2]:{mediator.pokos[2]?.TargetMuff}\n" +
  196. $"skillSel:{current.showSkillSelect} " +
  197. $"paramVew:{current.showParameter} " +
  198. $"confPanel:{current.showConfigPanel}" +
  199. $"resPanel:{current.showResultPanel}" +
  200. $"isShot:{current.isShooting}"
  201. )
  202. );
  203. }
  204. #endregion
  205. #region Methods
  206. private void Initialize()
  207. {
  208. mediator = new Mediator();
  209. current = new State();
  210. script = new AnmScript(current);
  211. pokoCam = new PokoCam();
  212. faceCam = new FaceCam();
  213. windowId = PluginName.ToCharArray().Sum(x => x) * PluginVersion.ToCharArray().Sum(x => x);
  214. var dirInfoInjector = new DirectoryInfo($@"{Assembly.GetExecutingAssembly().Location}").Parent;
  215. var dirInfoConfig = new DirectoryInfo($@"{dirInfoInjector}\Config\{PathConfig}");
  216. settings = Settings.Load(new FileInfo($@"{dirInfoConfig}\{FileNameConfig}"));
  217. var pathTexSrcFront = new DirectoryInfo($@"{dirInfoConfig}\v");
  218. var pathTexSrcBack = new DirectoryInfo($@"{dirInfoConfig}\a");
  219. var pathTexSrcMouth = new DirectoryInfo($@"{dirInfoConfig}\o");
  220. flipAnims = new[]
  221. {
  222. new FlipAnim(pathTexSrcFront),
  223. new FlipAnim(pathTexSrcBack),
  224. new FlipAnim(pathTexSrcMouth)
  225. };
  226. _initializables = new IInitializable[]
  227. {
  228. mediator, current, script, pokoCam, faceCam, flipAnims[0], flipAnims[1], flipAnims[2]
  229. };
  230. controller = new Controller(this);
  231. }
  232. private void DrawFlipAnims()
  233. {
  234. for (var i = 0; i < 3; i++)
  235. {
  236. if ((current.PokoType == PokoType.Finger || current.PokoType == PokoType.Tongue) && i < 2)
  237. continue;
  238. flipAnims[i].Draw(i, current);
  239. }
  240. }
  241. private void DrawPokoCam()
  242. {
  243. if (settings.enablePokoCam && mediator.manLength > 0)
  244. {
  245. if (!pokoCam.SetupCam(mediator.TargetMaid, mediator.TargetMan, current.PrimaryMuff)) return;
  246. var n = (int) current.PrimaryMuff;
  247. if (n > 2) n = 2;
  248. if (flipAnims[n] == null && mediator.muffs[n] == null) return;
  249. pokoCam.Action();
  250. //var rect = settings.PokoCam_CustomPos && settings.PokoCam_Pos.size != Vector2.zero
  251. // ? settings.PokoCam_Pos
  252. // : settings.PokoCam_Pos = flipAnims[n].CalcRect(3, current.showParameter);
  253. var rect = FlipAnim.ScreenRect.Get(3, current.showParameter);
  254. pokoCam.Draw(current, rect);
  255. }
  256. else
  257. {
  258. pokoCam.Initialize();
  259. }
  260. }
  261. private void DrawFaceCam()
  262. {
  263. if (!settings.enableFaceCam || !faceCam.SetupCam(mediator.TargetMaid)) return;
  264. faceCam.Action();
  265. faceCam.Draw(current, FlipAnim.ScreenRect.Get(2, current.showParameter));
  266. }
  267. private void DrawOverlay()
  268. {
  269. for (var i = 0; i < 3; i++)
  270. {
  271. if (!current.isPlay || current.PokoType == PokoType.Finger || current.PokoType == PokoType.Tongue)
  272. {
  273. flipAnims[i].Overlay.Stop();
  274. return;
  275. }
  276. flipAnims[i].Overlay.Draw(mediator.muffs[i].GetOverlayPos(), i, current);
  277. }
  278. }
  279. private void CheckInput()
  280. {
  281. if (Input.GetKeyDown(settings.ControllerHotKey))
  282. controller.showController = !controller.showController;
  283. if (Input.GetKey(KeyCode.LeftAlt) && Input.GetKey(KeyCode.LeftShift)
  284. && Input.GetKeyDown(settings.ControllerHotKey))
  285. _debug = !_debug;
  286. //if (!settings.enablePlugin)
  287. // return;
  288. //
  289. //if (controller.showController && settings.enablePokoCam && settings.PokoCam_CustomPos)
  290. //{
  291. // if (Input.GetKey(KeyCode.Mouse0))
  292. // {
  293. // if (settings.PokoCam_Pos.Contains(Event.current.mousePosition))
  294. // {
  295. // settings.PokoCam_Pos.center =
  296. // Vector2.Lerp(settings.PokoCam_Pos.center, Event.current.mousePosition, 0.25f);
  297. // }
  298. // }
  299. //}
  300. }
  301. private bool IsShooting()
  302. {
  303. if (!current.shotReady)
  304. return false;
  305. _playingSE = FindObjectsOfType<AudioSource>()?.Where(x => x.isPlaying);
  306. if (_playingSE == null)
  307. return false;
  308. var count = 0;
  309. foreach (var se in _playingSE)
  310. {
  311. if (se == null)
  312. continue;
  313. if (!se.clip.name.Contains(SE_CumShot)) continue;
  314. if (current.PlayMode == PlayMode.Multiple)
  315. return true;
  316. count++;
  317. }
  318. return count == 1;
  319. }
  320. private bool IsShowHideScrolls(string hideName)
  321. {
  322. if (_hideScroll == null)
  323. {
  324. foreach (var x in FindObjectsOfType<HideScroll>().Where(x => x.isActiveAndEnabled))
  325. if (x.name == "Top" && x.ParentObject.name == hideName)
  326. {
  327. _hideScroll = x;
  328. break;
  329. }
  330. return false;
  331. }
  332. if (_hideScroll.ParentObject.name != hideName)
  333. return false;
  334. return (bool) (_hideScroll.GetType().GetField(NameHideScrollField, bindingFlags)?.GetValue(_hideScroll) ??
  335. false);
  336. }
  337. private bool IsShowConfigPanel()
  338. {
  339. if (configPanel != null)
  340. return configPanel.activeInHierarchy;
  341. configPanel = GameObject.Find(ConfigPanel);
  342. return false;
  343. }
  344. private bool IsShowResultPanel()
  345. {
  346. if (resultPanel != null)
  347. return resultPanel.activeInHierarchy;
  348. resultPanel = GameObject.Find(ResultPanel);
  349. return false;
  350. }
  351. private void CheckScreenFade()
  352. {
  353. if (screenChildren)
  354. {
  355. if (screenChildren.fade_status != WfScreenChildren.FadeStatus.Null)
  356. {
  357. if (screenChildren.fade_status != WfScreenChildren.FadeStatus.Wait)
  358. {
  359. mediator.Initialize();
  360. script.Initialize();
  361. }
  362. return;
  363. }
  364. screenChildren = null;
  365. }
  366. foreach (var children in FindObjectsOfType<WfScreenChildren>())
  367. if (children && children.fade_status != WfScreenChildren.FadeStatus.Null)
  368. {
  369. screenChildren = children;
  370. return;
  371. }
  372. if (GameMain.Instance.MainCamera.IsFadeOut())
  373. {
  374. mediator.Initialize();
  375. script.Initialize();
  376. }
  377. }
  378. private static void DestroyPluginObjects()
  379. {
  380. var objects = FindObjectsOfType<GameObject>();
  381. foreach (var obj in objects)
  382. if (obj.name.Contains($"{PluginName}"))
  383. DestroyObject(obj);
  384. }
  385. private void AllReset()
  386. {
  387. foreach (var ini in _initializables)
  388. ini?.Initialize();
  389. DestroyPluginObjects();
  390. }
  391. #endregion
  392. #region Classes
  393. private class Mediator : IInitializable
  394. {
  395. private readonly CharacterMgr charaMgr;
  396. private readonly Maid[] manArray;
  397. internal readonly Muff[] muffs;
  398. internal readonly Poko[] pokos;
  399. private bool initialized;
  400. private Vector3 maidOffset;
  401. public int manLength;
  402. public bool muffsPrepared;
  403. public bool pokosPrepared;
  404. public bool SwapTargetNPC;
  405. public Maid TargetMaid;
  406. public Maid TargetMan;
  407. public Mediator()
  408. {
  409. charaMgr = GameMain.Instance.CharacterMgr;
  410. manArray = new Maid[charaMgr.GetManCount()];
  411. muffs = new Muff[3];
  412. pokos = new Poko[charaMgr.GetManCount()];
  413. Initialize();
  414. }
  415. public void Initialize()
  416. {
  417. if (initialized)
  418. return;
  419. Array.Clear(manArray, 0, manArray.Length);
  420. Array.Clear(pokos, 0, pokos.Length);
  421. TargetMaid = null;
  422. TargetMan = null;
  423. manLength = 0;
  424. muffsPrepared = false;
  425. pokosPrepared = false;
  426. initialized = true;
  427. }
  428. public void FindTarget(State current)
  429. {
  430. if (charaMgr.IsBusy())
  431. return;
  432. if (current.PlayMode != PlayMode.Swap || !charaMgr.GetMaid(1).IsValid())
  433. SwapTargetNPC = false;
  434. var maid = current.PlayMode == PlayMode.Harem || SwapTargetNPC
  435. ? charaMgr.GetMaid(1)
  436. : charaMgr.GetMaid(0);
  437. if (maid == null)
  438. {
  439. if (TargetMaid.IsValid())
  440. {
  441. Initialize();
  442. current.Initialize();
  443. }
  444. return;
  445. }
  446. TargetMaid = maid;
  447. manLength = 0;
  448. for (var i = 0; i < manArray.Length; i++)
  449. {
  450. var man = charaMgr.GetMan(i);
  451. if (man.IsValid() && man.body0.GetChinkoVisible())
  452. {
  453. manArray[i] = man;
  454. manLength++;
  455. }
  456. }
  457. TargetMan = current.PlayMode == PlayMode.Swap && manArray[1] != null && !SwapTargetNPC
  458. ? manArray[1]
  459. : manArray[0];
  460. initialized = false;
  461. }
  462. public void PrepareMuffs()
  463. {
  464. if (muffsPrepared)
  465. return;
  466. if (!TargetMaid.IsValid())
  467. {
  468. muffsPrepared = false;
  469. return;
  470. }
  471. if (muffs[0] == null || !maidOffset.Equals(TargetMaid.body0.CenterBone.position))
  472. {
  473. muffs[0] = new Front(MuffType.Front, TargetMaid);
  474. muffs[1] = new Back(MuffType.Back, TargetMaid);
  475. muffs[2] = new Mouth(MuffType.Mouth, TargetMaid);
  476. maidOffset = TargetMaid.body0.CenterBone.position;
  477. }
  478. else
  479. {
  480. muffs[0].Set(MuffType.Front, TargetMaid);
  481. muffs[1].Set(MuffType.Back, TargetMaid);
  482. muffs[2].Set(MuffType.Mouth, TargetMaid);
  483. }
  484. muffsPrepared = muffs[0].Maid == TargetMaid;
  485. }
  486. public void PreparePokos(State current)
  487. {
  488. if (pokosPrepared || !muffsPrepared)
  489. return;
  490. switch (current.PlayMode)
  491. {
  492. case PlayMode.Self:
  493. for (var i = 0; i < pokos.Length; i++)
  494. if (pokos[i]?.GetType() == typeof(TNP))
  495. pokos[i] = null;
  496. break;
  497. case PlayMode.Normal:
  498. case PlayMode.Swap:
  499. case PlayMode.Harem:
  500. if (TargetMan == null)
  501. {
  502. pokosPrepared = false;
  503. return;
  504. }
  505. if (!(pokos[0] is TNP t) || !t.man.IsValid())
  506. pokos[0] = new TNP(TargetMan);
  507. break;
  508. case PlayMode.Multiple:
  509. for (var i = 0; i < pokos.Length; i++)
  510. {
  511. if (manArray[i] == null)
  512. break;
  513. if (!(pokos[i] is TNP g) || !g.man.IsValid())
  514. pokos[i] = new TNP(manArray[i]);
  515. }
  516. pokosPrepared = pokos[manLength > 1 ? manLength - 1 : 0] != null;
  517. return;
  518. }
  519. if (current.PokoType == PokoType.TNP)
  520. {
  521. pokosPrepared = pokos[0] != null;
  522. return;
  523. }
  524. var last = pokos.Length - 1;
  525. switch (current.PokoType)
  526. {
  527. case PokoType.Tongue:
  528. if (TargetMan.IsValid())
  529. if (!(pokos[last] is Tongue t) || !t.man.IsValid())
  530. pokos[last] = new Tongue(TargetMan);
  531. pokosPrepared = pokos[last] is Tongue tt && tt.man.IsValid();
  532. break;
  533. case PokoType.Dildo:
  534. if (TargetMaid.IsValid())
  535. if (!(pokos[last] is Dildo d) || !d.maid.IsValid())
  536. pokos[last] = new Dildo(TargetMaid);
  537. pokosPrepared = pokos[last] is Dildo dd && dd.maid.IsValid();
  538. break;
  539. case PokoType.Vibe:
  540. if (!(pokos[last] is Vibe))
  541. pokos[last] = new Vibe();
  542. pokosPrepared = true;
  543. break;
  544. case PokoType.Finger:
  545. var m = current.isOnani ? TargetMaid : TargetMan;
  546. if (!(pokos[last - 1] is Finger f) || !f.maid.IsValid() || f.maid != m)
  547. {
  548. pokos[last - 1] = new Finger(m, true);
  549. pokos[last] = new Finger(m, false);
  550. }
  551. pokosPrepared = pokos[last - 1] is Finger;
  552. break;
  553. }
  554. }
  555. public void ValidatePair(State current)
  556. {
  557. if (current.PrimaryMuff == MuffType.None)
  558. return;
  559. switch (current.PlayMode)
  560. {
  561. case PlayMode.Self:
  562. if (pokos.Any(poko => poko?.ValidateTargetMuff(muffs[(int) current.PrimaryMuff]) ?? false))
  563. return;
  564. pokosPrepared = false;
  565. return;
  566. case PlayMode.Normal:
  567. case PlayMode.Swap:
  568. case PlayMode.Harem:
  569. var n = (int) current.PrimaryMuff == 1 ? 1 : 0;
  570. switch (current.PokoType)
  571. {
  572. case PokoType.Finger:
  573. foreach (var poko in pokos)
  574. if (poko is Finger f && f.ValidateTargetMuff(muffs[n]))
  575. return;
  576. break;
  577. case PokoType.Vibe:
  578. foreach (var poko in pokos)
  579. if (poko is Vibe v && v.ValidateTargetMuff(muffs[n]))
  580. return;
  581. break;
  582. case PokoType.Tongue:
  583. foreach (var poko in pokos)
  584. if (poko is Tongue t && t.ValidateTargetMuff(muffs[0]))
  585. return;
  586. break;
  587. case PokoType.TNP:
  588. if (pokos[0] is TNP p && p.ValidateTargetMuff(muffs[(int) current.PrimaryMuff]))
  589. return;
  590. break;
  591. }
  592. pokosPrepared = false;
  593. return;
  594. case PlayMode.Multiple:
  595. pokos[0]?.ValidateTargetMuff(muffs[(int) current.PrimaryMuff]);
  596. switch (current.MuffNum)
  597. {
  598. case MuffNum.Double:
  599. pokos[1]?.ValidateTargetMuff(muffs[1 - (int) current.PrimaryMuff]);
  600. return;
  601. case MuffNum.Triple:
  602. case MuffNum.Unknown:
  603. for (var i = 1; i < manLength; i++)
  604. {
  605. if (pokos[i] == null)
  606. continue;
  607. for (var j = 2; j >= 0; j--)
  608. {
  609. if (j == (int) current.PrimaryMuff)
  610. continue;
  611. if (pokos[i].ValidateTargetMuff(muffs[j]))
  612. break;
  613. }
  614. }
  615. break;
  616. }
  617. break;
  618. }
  619. }
  620. public void UpdateValues(State current)
  621. {
  622. for (var i = 0; i < muffs.Length; i++)
  623. {
  624. var value = 0.0f;
  625. foreach (var poko in pokos)
  626. {
  627. if (poko == null || !poko.Validated)
  628. continue;
  629. if ((int) poko.TargetMuff != i) continue;
  630. var _v = muffs[i].GetInsertRate(current, poko);
  631. value = _v > value ? _v : value;
  632. var n = (int) current.PrimaryMuff == 1 ? 1 : 0;
  633. if ((current.PokoType == PokoType.Finger || current.PokoType == PokoType.Tongue)
  634. && i == n && value > 0.01f)
  635. value = settings.Morpher_Threshold * 0.5f;
  636. }
  637. current.rates[i] = Mathf.SmoothStep(current.rates[i], value, settings.Anim_Speed);
  638. muffs[i].SetBlendValue(current.rates[i]);
  639. }
  640. }
  641. }
  642. public class State : IInitializable
  643. {
  644. private string _recent;
  645. public bool isOnani;
  646. public bool isPlay;
  647. public bool isShooting, showSkillSelect, showParameter, showConfigPanel, showResultPanel, CanDrawOverlay;
  648. internal MuffNum MuffNum;
  649. internal PlayMode PlayMode;
  650. internal PlayState PlayState;
  651. internal PokoType PokoType;
  652. internal MuffType PrimaryMuff;
  653. internal InsertRates rates = new InsertRates();
  654. public State()
  655. {
  656. Initialize();
  657. }
  658. public string CurrentSkill
  659. {
  660. get => _recent;
  661. set
  662. {
  663. if (_recent != value)
  664. Initialize();
  665. _recent = value;
  666. }
  667. }
  668. public bool shotReady => PlayState == PlayState.Shot || PlayState == PlayState.ShotFin;
  669. public void Initialize()
  670. {
  671. isPlay = false;
  672. isOnani = false;
  673. isShooting = false;
  674. showSkillSelect = false;
  675. showParameter = false;
  676. CanDrawOverlay = false;
  677. PlayMode = PlayMode.Normal;
  678. MuffNum = MuffNum.Unknown;
  679. PlayState = PlayState.None;
  680. PrimaryMuff = MuffType.None;
  681. PokoType = PokoType.TNP;
  682. rates.Clear();
  683. }
  684. }
  685. public class InsertRates
  686. {
  687. private readonly float[] rate;
  688. public InsertRates()
  689. {
  690. rate = new float[3];
  691. }
  692. public float this[int i]
  693. {
  694. get => rate[i];
  695. set => rate[i] = value > 0.001f ? value : 0.0f;
  696. }
  697. public void Clear()
  698. {
  699. Array.Clear(rate, 0, 3);
  700. }
  701. }
  702. private class AnmScript : IInitializable
  703. {
  704. private const string C_ = "C_", A_ = "A_", A = "A";
  705. private const string _2ana = "2ana", _3ana = "3ana";
  706. private const string kunni = "kunni",
  707. dildo = "dildo",
  708. vibe = "vibe",
  709. aibu = "aibu",
  710. onani = "onani",
  711. _tubo = "_tubo";
  712. private const string _in = "_in", _taiki = "_taiki";
  713. private const string _ONCE = "_ONCE",
  714. _once = "_once",
  715. _shaseigo = "_shaseigo",
  716. _zeccyougo = "_zeccyougo",
  717. _tanetukego = "_tanetukego";
  718. private const string seijyou = "seijyou",
  719. taimen = "taimen",
  720. kouhai = "kouhai",
  721. haimen = "haimen",
  722. sokui = "sokui";
  723. private static readonly string[] ValidSkillNames =
  724. {
  725. "seijyou", "kouhai", "sokui", "kijyoui", "[th]aimenzai", "ritui", "manguri", "hekimen", "tinguri",
  726. "ekiben", "turusi", "matuba", "syumoku", "mzi", "kakae", "tekoki", "tekoona", "fera", "sixnine",
  727. "self_ir", "housi",
  728. "onani", "paizuri", "aibu", "kunni", "mp_arai", "arai2", "kousoku", "vibe", "mokuba", "harituke",
  729. "ran\\dp", "muri.*\\dp", ".*\\dp_", "sex"
  730. };
  731. private static readonly Regex PatternValidSkillNames =
  732. new Regex($@"{string.Join("|", ValidSkillNames)}", RegexOptions.Compiled);
  733. private readonly State _current;
  734. private readonly Regex patternMuffMouth =
  735. new Regex(@"fera|sixnine|self_ir|_kuti|housi", RegexOptions.Compiled);
  736. private readonly Regex patternMultiple = new Regex(@"(ran|muri|kousoku).*\dp", RegexOptions.Compiled);
  737. private readonly Regex patternNoneBreak = new Regex(@"name|suri|koki|tama|sumata", RegexOptions.Compiled);
  738. private readonly Regex patternNoneOutside = new Regex(@"^.*(_soto|_kao).*$", RegexOptions.Compiled);
  739. private readonly Regex patternPlaying = new Regex(@"^.*_\d([ab]0[12])?_|_gr|_momi", RegexOptions.Compiled);
  740. private readonly Regex Separator =
  741. new Regex(@"_taiki|_in|_ONCE|_once|_shaseigo|_tanetukego|_zeccyougo|_sissin|_\d[^p]",
  742. RegexOptions.Compiled);
  743. public string MaidAnmName, ManAnmName;
  744. public AnmScript(State current)
  745. {
  746. _current = current;
  747. Initialize();
  748. }
  749. public void Initialize()
  750. {
  751. _current.Initialize();
  752. }
  753. public void Parse(Mediator med)
  754. {
  755. if (!med.TargetMaid.IsValid() || med.TargetMan == null)
  756. return;
  757. MaidAnmName = med.TargetMaid.body0.LastAnimeFN;
  758. ManAnmName = med.manLength > 0
  759. ? med.TargetMan.body0.LastAnimeFN
  760. : "";
  761. if (!PatternValidSkillNames.IsMatch(MaidAnmName))
  762. {
  763. if (_current.isPlay)
  764. {
  765. _current.Initialize();
  766. med.Initialize();
  767. DestroyPluginObjects();
  768. }
  769. _current.CurrentSkill = null;
  770. return;
  771. }
  772. _current.isPlay = true;
  773. _current.CurrentSkill = ParseCurrentSkill();
  774. var muff = _current.PrimaryMuff;
  775. var poko = _current.PokoType;
  776. var ona = _current.isOnani;
  777. if (!string.IsNullOrEmpty(_current.CurrentSkill))
  778. {
  779. _current.PlayMode = ParsePlayMode();
  780. _current.PrimaryMuff = ParsePrimary();
  781. _current.MuffNum = ParseMuffNum();
  782. }
  783. _current.isOnani = MaidAnmName.Contains(onani);
  784. _current.PokoType = ParsePokoType();
  785. _current.PlayState = ParsePlayState();
  786. if (muff != _current.PrimaryMuff || poko != _current.PokoType || ona != _current.isOnani)
  787. med.Initialize();
  788. return;
  789. string ParseCurrentSkill()
  790. {
  791. if (!string.IsNullOrEmpty(_current.CurrentSkill) && MaidAnmName.Contains(_current.CurrentSkill))
  792. return _current.CurrentSkill;
  793. if (Separator.IsMatch(MaidAnmName))
  794. return Separator.Split(MaidAnmName)[0];
  795. return "";
  796. }
  797. PlayMode ParsePlayMode()
  798. {
  799. if (MaidAnmName.Contains(C_) || ManAnmName.Contains(C_))
  800. return PlayMode.Harem;
  801. if (patternMultiple.IsMatch(_current.CurrentSkill))
  802. return PlayMode.Multiple;
  803. switch (med.manLength)
  804. {
  805. case 0: return PlayMode.Self;
  806. case 2: return PlayMode.Swap;
  807. default: return PlayMode.Normal;
  808. }
  809. }
  810. MuffType ParsePrimary()
  811. {
  812. if (_current.PlayMode != PlayMode.Multiple && patternMuffMouth.IsMatch(MaidAnmName))
  813. return MuffType.Mouth;
  814. if (_current.CurrentSkill.Contains(A) || MaidAnmName.Contains(A_) || ManAnmName.Contains(A_))
  815. return MuffType.Back;
  816. return MuffType.Front;
  817. }
  818. MuffNum ParseMuffNum()
  819. {
  820. var str = _current.CurrentSkill;
  821. if (str.Contains(_2ana))
  822. return MuffNum.Double;
  823. if (str.Contains(_3ana))
  824. return MuffNum.Triple;
  825. return MuffNum.Unknown;
  826. }
  827. PokoType ParsePokoType()
  828. {
  829. return MaidAnmName switch
  830. {
  831. { } s when s.Contains(kunni) => PokoType.Tongue,
  832. { } s when s.Contains(dildo) => PokoType.Dildo,
  833. { } s when s.Contains(vibe) => PokoType.Vibe,
  834. { } s when s.Contains(aibu) || s.Contains(onani) || s.Contains(_tubo) => PokoType.Finger,
  835. _ => PokoType.TNP
  836. };
  837. }
  838. PlayState ParsePlayState()
  839. {
  840. if (MaidAnmName.Contains(_in))
  841. {
  842. if (_current.PlayState != PlayState.Insert)
  843. med.Initialize();
  844. return PlayState.Insert;
  845. }
  846. if (MaidAnmName.Contains(_taiki))
  847. return PlayState.Wait;
  848. if (patternNoneBreak.IsMatch(MaidAnmName) || patternNoneOutside.IsMatch(ManAnmName))
  849. return PlayState.Eject;
  850. if (MaidAnmName.Contains(_ONCE) || MaidAnmName.Contains(_once))
  851. return PlayState.Shot;
  852. if (MaidAnmName.Contains(_shaseigo) || MaidAnmName.Contains(_tanetukego)
  853. || MaidAnmName.Contains(_zeccyougo))
  854. return PlayState.ShotFin;
  855. if (patternPlaying.IsMatch(MaidAnmName))
  856. return PlayState.Play;
  857. return PlayState.None;
  858. }
  859. }
  860. internal sPosition GetsPosition(MuffType muffType)
  861. {
  862. if (_current.PlayMode != PlayMode.Self)
  863. if (muffType == MuffType.Front || muffType == MuffType.Back)
  864. {
  865. if (MaidAnmName.Contains(seijyou) || MaidAnmName.Contains(taimen))
  866. return sPosition.Normal;
  867. if (MaidAnmName.Contains(kouhai) || MaidAnmName.Contains(haimen))
  868. return sPosition.Dog;
  869. if (MaidAnmName.Contains(sokui))
  870. return sPosition.Side;
  871. }
  872. return sPosition.None;
  873. }
  874. }
  875. #region Muffs
  876. private class Front : Muff
  877. {
  878. internal Front(MuffType type, Maid maid)
  879. {
  880. Set(type, maid);
  881. }
  882. internal override void Set(MuffType type, Maid maid)
  883. {
  884. colliderSize = 1.0f;
  885. this.type = type;
  886. Maid = maid;
  887. body = Maid.body0;
  888. if (collider == null)
  889. collider = new MuffCollider(this.type);
  890. else
  891. collider.Set(this.type);
  892. if (morpher == null)
  893. morpher = new MuffMorpher(this.type, body);
  894. else
  895. morpher.Set(this.type, body);
  896. positions = new Positions();
  897. }
  898. protected override void CheckTransforms()
  899. {
  900. if (!_root)
  901. _root = body.Spine
  902. ? body.Spine
  903. : body.IKCtrl.GetIKBone(FullBodyIKCtrl.IKBoneType.Spine0);
  904. if (!_mid)
  905. _mid = body.Pelvis
  906. ? body.Pelvis
  907. : body.IKCtrl.GetIKBone(FullBodyIKCtrl.IKBoneType.Pelvis);
  908. if (!_top)
  909. _top = body.GetBone(VaginaBoneName);
  910. if (!_other)
  911. _other = body.GetBone(AnalBoneName);
  912. }
  913. public override Positions GetOverlayPos()
  914. {
  915. var cameraMain = GameMain.Instance.MainCamera;
  916. Update();
  917. var position = _top.position;
  918. var start = position;
  919. var end = _root.position - (_other.position - position) * 0.5f;
  920. var dir = start - end;
  921. start -= (start - cameraMain.GetPos()) * settings.Overlay_CameraDistance;
  922. end = end - dir * settings.Overlay_LineScale
  923. - (end - cameraMain.GetPos()) * settings.Overlay_CameraDistance;
  924. start += dir.normalized * settings.Overlay_DirectionalOffset;
  925. end += dir.normalized * settings.Overlay_DirectionalOffset;
  926. positions.Top = start;
  927. positions.Root = end;
  928. return positions;
  929. }
  930. public override float GetInsertRate(State current, Poko poko)
  931. {
  932. if (current.PlayState == PlayState.Wait || current.PlayState == PlayState.None)
  933. return 0.0f;
  934. Update();
  935. var pos = poko.GetPokoPos();
  936. var dstTop2mid = Distance(pos.Top, _mid.position);
  937. var tnkLength = Distance(pos.Root, pos.Top);
  938. if (__length < 0.001f)
  939. __length = Mathf.Sqrt(tnkLength);
  940. var position = _top.position;
  941. var dstRoot2top = Distance(pos.Root, position);
  942. var muffDepth = Distance(position, _root.position);
  943. if (tnkLength >= dstRoot2top && muffDepth >= dstTop2mid)
  944. {
  945. if (poko._lastTime > Time.frameCount)
  946. return Mathf.InverseLerp(__length, 0, Mathf.Sqrt(dstRoot2top));
  947. if (collider.ContainsAny(pos))
  948. {
  949. poko._lastTime = Time.frameCount + 5;
  950. return Mathf.InverseLerp(__length, 0, Mathf.Sqrt(dstRoot2top));
  951. }
  952. }
  953. return 0.0f;
  954. }
  955. }
  956. private class Back : Muff
  957. {
  958. internal Back(MuffType type, Maid maid)
  959. {
  960. Set(type, maid);
  961. }
  962. internal override void Set(MuffType type, Maid maid)
  963. {
  964. colliderSize = 1.0f;
  965. this.type = type;
  966. Maid = maid;
  967. body = Maid.body0;
  968. if (collider == null)
  969. collider = new MuffCollider(this.type);
  970. else
  971. collider.Set(this.type);
  972. if (morpher == null)
  973. morpher = new MuffMorpher(this.type, body);
  974. else
  975. morpher.Set(this.type, body);
  976. positions = new Positions();
  977. }
  978. protected override void CheckTransforms()
  979. {
  980. if (!_root)
  981. _root = body.Spine
  982. ? body.Spine
  983. : body.IKCtrl.GetIKBone(FullBodyIKCtrl.IKBoneType.Spine0);
  984. if (!_mid)
  985. _mid = body.Pelvis
  986. ? body.Pelvis
  987. : body.IKCtrl.GetIKBone(FullBodyIKCtrl.IKBoneType.Pelvis);
  988. if (!_top)
  989. _top = body.GetBone(AnalBoneName);
  990. if (!_other)
  991. _other = body.GetBone(VaginaBoneName);
  992. }
  993. public override Positions GetOverlayPos()
  994. {
  995. var cameraMain = GameMain.Instance.MainCamera;
  996. Update();
  997. var position = _top.position;
  998. var start = position;
  999. var end = _root.position - (_other.position - position) * 0.5f;
  1000. var dir = start - end;
  1001. start -= (start - cameraMain.GetPos()) * settings.Overlay_CameraDistance;
  1002. end = end - dir * settings.Overlay_LineScale
  1003. - (end - cameraMain.GetPos()) * settings.Overlay_CameraDistance;
  1004. start += dir.normalized * settings.Overlay_DirectionalOffset;
  1005. end += dir.normalized * settings.Overlay_DirectionalOffset;
  1006. positions.Top = start;
  1007. positions.Root = end;
  1008. return positions;
  1009. }
  1010. public override float GetInsertRate(State current, Poko poko)
  1011. {
  1012. if (current.PlayState == PlayState.Wait || current.PlayState == PlayState.None)
  1013. return 0.0f;
  1014. Update();
  1015. var pos = poko.GetPokoPos();
  1016. var dstTop2mid = Distance(pos.Top, _mid.position);
  1017. var tnkLength = Distance(pos.Root, pos.Top);
  1018. if (__length < 0.001f)
  1019. __length = Mathf.Sqrt(tnkLength);
  1020. var dstRoot2top = Distance(pos.Root, _top.position);
  1021. var muffDepth = Distance(_top.position, _root.position);
  1022. if (tnkLength >= dstRoot2top && muffDepth >= dstTop2mid)
  1023. {
  1024. if (poko._lastTime > Time.frameCount)
  1025. return Mathf.InverseLerp(__length, 0, Mathf.Sqrt(dstRoot2top));
  1026. if (collider.ContainsAny(pos))
  1027. {
  1028. poko._lastTime = Time.frameCount + 5;
  1029. return Mathf.InverseLerp(__length, 0, Mathf.Sqrt(dstRoot2top));
  1030. }
  1031. }
  1032. return 0.0f;
  1033. }
  1034. }
  1035. private class Mouth : Muff
  1036. {
  1037. internal static readonly Vector3 mouthOffset = new Vector3(0, -0.02f, 0.08f);
  1038. internal Mouth(MuffType type, Maid maid)
  1039. {
  1040. Set(type, maid);
  1041. }
  1042. internal override void Set(MuffType type, Maid maid)
  1043. {
  1044. this.type = type;
  1045. Maid = maid;
  1046. body = Maid.body0;
  1047. if (collider == null)
  1048. collider = new MuffCollider(this.type);
  1049. else
  1050. collider.Set(this.type);
  1051. positions = new Positions();
  1052. colliderSize = 1.75f;
  1053. }
  1054. protected override void CheckTransforms()
  1055. {
  1056. if (_top == null)
  1057. {
  1058. _top = new GameObject($"{PluginName}__mouth__").transform;
  1059. var parent = body.GetBone(MouthBoneName);
  1060. _top.SetParent(parent);
  1061. _top.SetPositionAndRotation(parent.position, parent.rotation);
  1062. _top.Translate(mouthOffset);
  1063. }
  1064. if (_root == null)
  1065. _root = body.trsHead;
  1066. }
  1067. public override Positions GetOverlayPos()
  1068. {
  1069. if (_top == null || _root == null)
  1070. return positions;
  1071. var cameraMain = GameMain.Instance.MainCamera;
  1072. Update();
  1073. var start = _top.position;
  1074. var end = _root.position - (_top.position - _root.position) * 0.5f;
  1075. var dir = start - end;
  1076. start -= (start - cameraMain.GetPos()) * settings.Overlay_CameraDistance;
  1077. end = end - dir * settings.Overlay_LineScale
  1078. - (end - cameraMain.GetPos()) * settings.Overlay_CameraDistance;
  1079. start += dir.normalized * settings.Overlay_DirectionalOffset;
  1080. end += dir.normalized * settings.Overlay_DirectionalOffset;
  1081. positions.Top = start;
  1082. positions.Root = end;
  1083. return positions;
  1084. }
  1085. public override float GetInsertRate(State current, Poko poko)
  1086. {
  1087. if (current.PlayState == PlayState.Wait || current.PlayState == PlayState.None)
  1088. return 0.0f;
  1089. Update();
  1090. var pos = poko.GetPokoPos();
  1091. var tnkLength = Distance(pos.Root, pos.Top);
  1092. if (__length < 0.001f)
  1093. __length = Mathf.Sqrt(tnkLength);
  1094. var dstRoot2top = Distance(pos.Root, _top.position);
  1095. if (tnkLength >= dstRoot2top)
  1096. {
  1097. if (poko._lastTime > Time.frameCount)
  1098. return Mathf.InverseLerp(__length, 0, Mathf.Sqrt(dstRoot2top));
  1099. if (collider.ContainsAny(pos))
  1100. {
  1101. poko._lastTime = Time.frameCount + 5;
  1102. return Mathf.InverseLerp(__length, 0, Mathf.Sqrt(dstRoot2top));
  1103. }
  1104. }
  1105. return 0.0f;
  1106. }
  1107. }
  1108. public abstract class Muff
  1109. {
  1110. internal const string VaginaBoneName = "_IK_vagina",
  1111. AnalBoneName = "_IK_anal",
  1112. MouthBoneName = "Mouth";
  1113. protected float __length;
  1114. protected Transform _top, _mid, _root, _other;
  1115. protected TBody body;
  1116. protected MuffCollider collider;
  1117. protected float colliderSize;
  1118. public Maid Maid;
  1119. internal MuffMorpher morpher;
  1120. protected Positions positions;
  1121. internal MuffType type;
  1122. private float depth => Vector3.Distance(_top.position, _root.position);
  1123. protected abstract void CheckTransforms();
  1124. public abstract Positions GetOverlayPos();
  1125. internal abstract void Set(MuffType type, Maid maid);
  1126. public MuffCollider GetCollider()
  1127. {
  1128. Update();
  1129. return collider;
  1130. }
  1131. protected void Update()
  1132. {
  1133. if (!Maid.IsValid())
  1134. return;
  1135. CheckTransforms();
  1136. collider.SetTransform(_top, _root != null ? _root : _mid, depth * colliderSize);
  1137. }
  1138. public void SetBlendValue(float value)
  1139. {
  1140. if (!settings.enableMorpher)
  1141. return;
  1142. morpher?.SetBlendEx(value);
  1143. if (!settings.Morpher_EnableFix)
  1144. return;
  1145. morpher?.FixBlendEx();
  1146. }
  1147. protected static float Distance(Vector3 from, Vector3 to)
  1148. {
  1149. var xD = from.x - to.x;
  1150. var yD = from.y - to.y;
  1151. var zD = from.z - to.z;
  1152. return xD * xD + yD * yD + zD * zD;
  1153. }
  1154. public abstract float GetInsertRate(State current, Poko poko);
  1155. }
  1156. public class MuffCollider
  1157. {
  1158. private const float distance = 0.55f;
  1159. private BoxCollider collider;
  1160. private GameObject obj;
  1161. private MeshRenderer renderer;
  1162. private Vector3 scale;
  1163. private Transform start, end;
  1164. private MuffType type;
  1165. internal MuffCollider(MuffType type)
  1166. {
  1167. Set(type);
  1168. }
  1169. internal void Set(MuffType type)
  1170. {
  1171. this.type = type;
  1172. }
  1173. public void SetTransform(Transform start, Transform end, float length)
  1174. {
  1175. this.start = start;
  1176. this.end = end;
  1177. scale.Set(length * 0.5f, length * 0.5f, length);
  1178. }
  1179. private bool SetUpCollider()
  1180. {
  1181. if (!start || !end)
  1182. return false;
  1183. if (obj == null)
  1184. {
  1185. obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
  1186. renderer = obj.GetComponent<MeshRenderer>();
  1187. obj.name = $"{PluginName}__muffcol__{type}";
  1188. collider = null;
  1189. }
  1190. else
  1191. {
  1192. if (collider == null)
  1193. {
  1194. collider = obj.GetComponent<BoxCollider>() ?? obj.AddComponent<BoxCollider>();
  1195. collider.isTrigger = true;
  1196. }
  1197. }
  1198. renderer.enabled = _debug;
  1199. return obj && collider;
  1200. }
  1201. public bool Contains(Vector3 point)
  1202. {
  1203. if (start.position != end.position && SetUpCollider())
  1204. {
  1205. var rot = Quaternion.LookRotation(start.position - end.position);
  1206. var pos = start.position - (start.position - end.position) * distance;
  1207. collider.transform.SetPositionAndRotation(pos, rot);
  1208. collider.transform.localScale = scale;
  1209. return collider.ClosestPoint(point) == point;
  1210. }
  1211. return false;
  1212. }
  1213. public bool ContainsAny(Positions pos)
  1214. {
  1215. return Contains(pos.Top) || Contains(pos.Mid) || Contains(pos.Root);
  1216. }
  1217. public bool ContainsAny(params Vector3[] points)
  1218. {
  1219. return points.Any(Contains);
  1220. }
  1221. ~MuffCollider()
  1222. {
  1223. DestroyObject(collider);
  1224. DestroyObject(renderer);
  1225. DestroyObject(obj);
  1226. }
  1227. }
  1228. internal class MuffMorpher
  1229. {
  1230. private TBody body;
  1231. private HashSet<int> keyAvailableSlot;
  1232. private string lastKey;
  1233. private float lastValue;
  1234. private MuffType type;
  1235. public MuffMorpher(MuffType type, TBody body)
  1236. {
  1237. Set(type, body);
  1238. }
  1239. private string Key
  1240. {
  1241. get
  1242. {
  1243. var ret = type == MuffType.Front
  1244. ? settings.Morpher_KeyV
  1245. : settings.Morpher_KeyA;
  1246. if (lastKey != ret)
  1247. CheckKeyAvailable(ret);
  1248. return lastKey = ret;
  1249. }
  1250. }
  1251. public void Set(MuffType type, TBody body)
  1252. {
  1253. lastValue = 0.0f;
  1254. if (keyAvailableSlot == null)
  1255. keyAvailableSlot = new HashSet<int>();
  1256. else
  1257. keyAvailableSlot.Clear();
  1258. this.body = body;
  1259. this.type = type;
  1260. CheckKeyAvailable(Key);
  1261. }
  1262. private void CheckKeyAvailable(string key)
  1263. {
  1264. keyAvailableSlot.Clear();
  1265. if (body == null) return;
  1266. for (var i = 0; i < (int) TBody.SlotID.end; i++)
  1267. if (body.goSlot?[i]?.morph is TMorph m && m.hash.ContainsKey(key))
  1268. keyAvailableSlot.Add(i);
  1269. }
  1270. public void SetBlendEx(float value)
  1271. {
  1272. if (!settings.enableMorpher || keyAvailableSlot.Count < 1)
  1273. return;
  1274. var result = Mathf.Clamp(
  1275. Mathf.InverseLerp(0.0f, settings.Morpher_Threshold, value),
  1276. settings.Morpher_Min,
  1277. settings.Morpher_Max
  1278. );
  1279. foreach (var slot in keyAvailableSlot)
  1280. if (body.goSlot[slot]?.morph?.hash[Key] is int idx)
  1281. {
  1282. body.goSlot[slot].morph.SetBlendValues(idx, result);
  1283. lastValue = result;
  1284. }
  1285. else
  1286. {
  1287. CheckKeyAvailable(Key);
  1288. return;
  1289. }
  1290. }
  1291. public void FixBlendEx()
  1292. {
  1293. if (!settings.Morpher_EnableFix || keyAvailableSlot.Count < 1 || type == MuffType.Back)
  1294. return;
  1295. if (Time.frameCount % Mathf.RoundToInt(settings.Morpher_Waitframe) != 0) return;
  1296. foreach (var i in keyAvailableSlot)
  1297. body.goSlot[i]?.morph?.FixBlendValues();
  1298. }
  1299. }
  1300. #endregion
  1301. #region Pokos
  1302. private class TNP : Poko
  1303. {
  1304. private const string TnpTopName = "chinko_nub",
  1305. TnpMidName = "chinko2",
  1306. TnpRootName = "chinko1";
  1307. public readonly Maid man;
  1308. private Transform tnkTop, tnkMid, tnkRoot;
  1309. public TNP(Maid man)
  1310. {
  1311. this.man = man;
  1312. Validated = false;
  1313. TargetMuff = MuffType.None;
  1314. }
  1315. protected override void UpdateTransforms()
  1316. {
  1317. foreach (var trs in man.body0.GetComponentsInChildren<Transform>())
  1318. {
  1319. if (trs == null)
  1320. continue;
  1321. switch (trs.name)
  1322. {
  1323. case TnpTopName:
  1324. tnkTop = trs;
  1325. break;
  1326. case TnpRootName:
  1327. tnkRoot = trs;
  1328. break;
  1329. case TnpMidName:
  1330. tnkMid = trs;
  1331. break;
  1332. }
  1333. if (tnkTop && tnkRoot && tnkMid)
  1334. {
  1335. positions.Top = tnkTop.position;
  1336. positions.Mid = tnkMid.position;
  1337. positions.Root = tnkRoot.position;
  1338. return;
  1339. }
  1340. }
  1341. }
  1342. }
  1343. private class Dildo : Poko
  1344. {
  1345. private const string DildoName = "ディルド&台";
  1346. private readonly Transform[] _transforms;
  1347. public readonly Maid maid;
  1348. public Dildo(Maid maid)
  1349. {
  1350. this.maid = maid;
  1351. _transforms = new Transform[4];
  1352. Validated = false;
  1353. TargetMuff = MuffType.None;
  1354. }
  1355. protected override void UpdateTransforms()
  1356. {
  1357. if (_transforms[0] == null)
  1358. {
  1359. _transforms[0] = GameObject.Find(DildoName)?.transform;
  1360. if (_transforms[0] != null)
  1361. return;
  1362. foreach (var x in FindObjectsOfType<Transform>())
  1363. {
  1364. if (x == null)
  1365. continue;
  1366. if (x.name.Contains(DildoName))
  1367. {
  1368. _transforms[0] = x;
  1369. break;
  1370. }
  1371. }
  1372. }
  1373. else
  1374. {
  1375. if (!maid.IsValid())
  1376. return;
  1377. if (!_transforms[1])
  1378. for (var i = 1; i < 4; i++)
  1379. {
  1380. if (_transforms[i] != null)
  1381. continue;
  1382. _transforms[i] = new GameObject($"{PluginName}__Dildo_{i}").transform;
  1383. _transforms[i].SetParent(_transforms[i - 1]);
  1384. _transforms[i].Translate(0.0f, 0.13f * i, 0.0f);
  1385. }
  1386. var offset = maid.body0.CenterBone.position;
  1387. positions.Top = _transforms[3].position + offset;
  1388. positions.Mid = _transforms[2].position + offset;
  1389. positions.Root = _transforms[1].position + offset;
  1390. }
  1391. }
  1392. }
  1393. private class Vibe : Poko
  1394. {
  1395. private const string VibeName = "vibe&cli", AnalVibeName = "analvibe", BigVibeName = "Predator";
  1396. private const float HalfLength = 0.1f;
  1397. private Transform _transform;
  1398. protected override void UpdateTransforms()
  1399. {
  1400. if (_transform == null)
  1401. _transform = GameObject.Find(VibeName)?.transform;
  1402. if (_transform == null)
  1403. _transform = GameObject.Find(AnalVibeName)?.transform;
  1404. if (_transform == null)
  1405. _transform = GameObject.Find(BigVibeName)?.transform;
  1406. if (_transform == null)
  1407. return;
  1408. var dir = _transform.right;
  1409. positions.Root = _transform.position;
  1410. positions.Mid = positions.Root + dir * HalfLength;
  1411. positions.Top = positions.Mid + dir * HalfLength;
  1412. }
  1413. }
  1414. private class Tongue : Poko
  1415. {
  1416. private const string HeadTopName = "mheadbone_nub";
  1417. private readonly Transform[] _transforms;
  1418. public readonly Maid man;
  1419. public Tongue(Maid man)
  1420. {
  1421. this.man = man;
  1422. _transforms = new Transform[2];
  1423. Validated = false;
  1424. TargetMuff = MuffType.None;
  1425. }
  1426. protected override void UpdateTransforms()
  1427. {
  1428. if (!man.IsValid())
  1429. return;
  1430. _transforms[0] = man.body0.GetComponentsInChildren<Transform>()
  1431. .FirstOrDefault(x => x.name.Contains(HeadTopName));
  1432. if (_transforms[1] == null)
  1433. {
  1434. _transforms[1] = new GameObject($"{PluginName}__mouth__").transform;
  1435. var parent = man.body0.GetBone(Muff.MouthBoneName);
  1436. _transforms[1].SetParent(parent);
  1437. _transforms[1].SetPositionAndRotation(parent.position, parent.rotation);
  1438. _transforms[1].Translate(Mouth.mouthOffset);
  1439. }
  1440. positions.Top = _transforms[0].position;
  1441. positions.Root = _transforms[1].position;
  1442. }
  1443. }
  1444. private class Finger : Poko
  1445. {
  1446. private readonly Transform[] _transforms;
  1447. public readonly Maid maid;
  1448. private readonly bool righthand;
  1449. public Finger(Maid maid, bool righthand)
  1450. {
  1451. this.maid = maid;
  1452. this.righthand = righthand;
  1453. _transforms = new Transform[4];
  1454. }
  1455. protected override void UpdateTransforms()
  1456. {
  1457. if (!maid.IsValid())
  1458. return;
  1459. if (_transforms[0] == null)
  1460. {
  1461. _transforms[0] = righthand
  1462. ? maid.body0.IKCtrl.GetIKBone(FullBodyIKCtrl.IKBoneType.Hand_R)
  1463. .GetComponentsInChildren<Transform>().FirstOrDefault(x => x.name.Contains("R Finger2"))
  1464. : maid.body0.IKCtrl.GetIKBone(FullBodyIKCtrl.IKBoneType.Hand_L)
  1465. .GetComponentsInChildren<Transform>().FirstOrDefault(x => x.name.Contains("L Finger2"));
  1466. }
  1467. else
  1468. {
  1469. _transforms[1] = GetFirstNonSCLChild(_transforms[0]);
  1470. _transforms[2] = GetFirstNonSCLChild(_transforms[1]);
  1471. _transforms[3] = GetFirstNonSCLChild(_transforms[2]);
  1472. positions.Top = _transforms[3].position;
  1473. positions.Mid = _transforms[2].position;
  1474. positions.Root = _transforms[1].position;
  1475. }
  1476. }
  1477. private Transform GetFirstNonSCLChild(Transform t)
  1478. {
  1479. var count = t.childCount;
  1480. for (var i = 0; i < count; i++)
  1481. {
  1482. var child = t.GetChild(i);
  1483. if (!child.name.Contains("_SCL_"))
  1484. return child;
  1485. }
  1486. return t;
  1487. }
  1488. }
  1489. public abstract class Poko
  1490. {
  1491. internal int _lastTime;
  1492. protected Positions positions;
  1493. internal MuffType TargetMuff;
  1494. protected PokoTrail[] trails;
  1495. public bool Validated;
  1496. protected Poko()
  1497. {
  1498. positions = new Positions();
  1499. TargetMuff = MuffType.None;
  1500. }
  1501. protected abstract void UpdateTransforms();
  1502. public bool ValidateTargetMuff(Muff muff)
  1503. {
  1504. if (Validated)
  1505. return true;
  1506. UpdateTransforms();
  1507. if (muff.GetCollider().ContainsAny(positions))
  1508. {
  1509. TargetMuff = muff.type;
  1510. Validated = true;
  1511. }
  1512. return Validated;
  1513. }
  1514. public Positions GetPokoPos()
  1515. {
  1516. UpdateTransforms();
  1517. return positions;
  1518. }
  1519. public void DrawTrails()
  1520. {
  1521. if (trails == null)
  1522. trails = new[] {new PokoTrail(), new PokoTrail(), new PokoTrail()};
  1523. trails[0].Draw(positions.Top, Color.cyan, Color.blue);
  1524. trails[1].Draw(positions.Mid, Color.magenta, Color.red);
  1525. trails[2].Draw(positions.Root, Color.yellow, Color.green);
  1526. }
  1527. }
  1528. #endregion
  1529. public struct Positions
  1530. {
  1531. public Vector3 Top, Mid, Root;
  1532. }
  1533. public class FlipAnim : IInitializable
  1534. {
  1535. private const int CumInterval = 200;
  1536. private static readonly Regex pattern_searchtex = new Regex(@"^.*\.(bmp|gif|tiff|jpeg|jpg|png)$");
  1537. private static readonly Texture2D blacktex = Texture2D.blackTexture;
  1538. public static ScreenRect ScreenRect = new ScreenRect();
  1539. private static Color alpha = new Color(1.0f, 1.0f, 1.0f, 0.0f);
  1540. private readonly Stopwatch sw;
  1541. public int MaxFrame, CurrentFrame;
  1542. public Overlay Overlay;
  1543. private DirectoryInfo srcPath, srcPathEx;
  1544. private Texture2D[] textures, texturesEx;
  1545. public FlipAnim(DirectoryInfo dir)
  1546. {
  1547. textures = new Texture2D[0];
  1548. srcPath = dir;
  1549. TextureLoaded = false;
  1550. texturesEx = new Texture2D[0];
  1551. srcPathEx = new DirectoryInfo($@"{srcPath.FullName}\ex");
  1552. TextureLoadedEx = false;
  1553. Overlay = new Overlay(this);
  1554. sw = new Stopwatch();
  1555. CheckDirExists();
  1556. Load();
  1557. }
  1558. public bool TextureLoaded { get; private set; }
  1559. public bool TextureLoadedEx { get; private set; }
  1560. public void Initialize()
  1561. {
  1562. if (!TextureLoaded)
  1563. return;
  1564. CurrentFrame = 0;
  1565. ScreenRect.Set(textures[0].width, textures[0].height);
  1566. MaxFrame = textures.Length;
  1567. }
  1568. ~FlipAnim()
  1569. {
  1570. textures = null;
  1571. texturesEx = null;
  1572. srcPath = null;
  1573. srcPathEx = null;
  1574. }
  1575. private bool LoadTextures(DirectoryInfo dir, ref Texture2D[] array)
  1576. {
  1577. var fileInfos = dir.GetFiles("*", SearchOption.TopDirectoryOnly)
  1578. .Where(x => pattern_searchtex.IsMatch(x.Name));
  1579. var infos = fileInfos as FileInfo[] ?? fileInfos.ToArray();
  1580. if (!infos.Any())
  1581. return false;
  1582. array = new Texture2D[infos.Length];
  1583. for (var i = 0; i < infos.Length; i++)
  1584. {
  1585. if (!infos[i].Exists)
  1586. return false;
  1587. var data = File.ReadAllBytes(infos[i].FullName);
  1588. array[i] = new Texture2D(1, 1, TextureFormat.ARGB32, true);
  1589. if (array[i].LoadImage(data))
  1590. array[i].Apply();
  1591. }
  1592. return true;
  1593. }
  1594. private void CheckDirExists()
  1595. {
  1596. if (srcPath.Exists) return;
  1597. srcPath.Create();
  1598. if (!srcPathEx.Exists)
  1599. srcPathEx.Create();
  1600. }
  1601. public void Load()
  1602. {
  1603. if (srcPath == null)
  1604. return;
  1605. CheckDirExists();
  1606. TextureLoaded = LoadTextures(srcPath, ref textures);
  1607. if (srcPathEx == null)
  1608. return;
  1609. TextureLoadedEx = LoadTextures(srcPathEx, ref texturesEx);
  1610. Initialize();
  1611. }
  1612. internal Texture2D GetCurrentTex()
  1613. {
  1614. return !TextureLoaded ? blacktex : textures[CurrentFrame];
  1615. }
  1616. internal Texture2D StartCumAnimation(bool shot)
  1617. {
  1618. if (!shot)
  1619. {
  1620. sw.Stop();
  1621. return GetCurrentTex();
  1622. }
  1623. if (!sw.IsRunning)
  1624. {
  1625. sw.Reset();
  1626. sw.Start();
  1627. }
  1628. else
  1629. {
  1630. var max = texturesEx.Length;
  1631. var rateEx = Mathf.InverseLerp(0, CumInterval, sw.ElapsedMilliseconds);
  1632. if (rateEx <= 1.0f)
  1633. {
  1634. if (TextureLoadedEx && max > 1)
  1635. return texturesEx[Mathf.RoundToInt((max - 1) * rateEx)];
  1636. }
  1637. else
  1638. {
  1639. sw.Stop();
  1640. }
  1641. }
  1642. return GetCurrentTex();
  1643. }
  1644. public void Draw(int number, State current)
  1645. {
  1646. CurrentFrame = Mathf.RoundToInt((MaxFrame - 1) * current.rates[number]);
  1647. if (!settings.enableOnGUI)
  1648. return;
  1649. alpha.a = current.showSkillSelect || current.showConfigPanel || current.showResultPanel
  1650. ? 0.0f
  1651. : settings.OnGUI_transparency * Mathf.Clamp01(current.rates[number] * 10);
  1652. var texture = current.shotReady
  1653. ? StartCumAnimation(current.isShooting)
  1654. : GetCurrentTex();
  1655. GUI.color = alpha;
  1656. GUI.DrawTexture(ScreenRect.Get(number, current.showParameter), texture, ScaleMode.StretchToFill, true,
  1657. 0.0f);
  1658. GUI.color = Color.white;
  1659. }
  1660. }
  1661. public class ScreenRect
  1662. {
  1663. private float aspect;
  1664. private Rect rect = Rect.zero;
  1665. private int width, height;
  1666. public void Set(int width, int height)
  1667. {
  1668. this.width = width;
  1669. this.height = height;
  1670. aspect = height != 0 ? (float) this.width / this.height : 1.0f;
  1671. }
  1672. public Rect Get(int n, bool flag)
  1673. {
  1674. if (aspect < 0.001f && aspect > -0.001f)
  1675. aspect = (float) Screen.width / Screen.height;
  1676. var stg = settings;
  1677. var h = Screen.height * 0.2f;
  1678. var w = rect.height * aspect;
  1679. var x = flag
  1680. ? Screen.width - rect.width - Screen.width * 0.17f
  1681. : Screen.width - rect.width - Screen.width * 0.0625f;
  1682. var y = Screen.height - (rect.height + stg.OnGUI_offset) * (n + 1) - Screen.height * 0.111f;
  1683. rect.Set(x + stg.OnGUI_x_offset, y + stg.OnGUI_y_offset,
  1684. w * stg.OnGUI_x_scale, h * stg.OnGUI_y_scale);
  1685. return rect;
  1686. }
  1687. }
  1688. public class Overlay
  1689. {
  1690. public const int OverlayLayer = 13;
  1691. private readonly FlipAnim flipAnim;
  1692. private Color color = new Color(1, 1, 1, 1);
  1693. private LineRenderer line;
  1694. private Material material;
  1695. private Shader sprite;
  1696. public Overlay(FlipAnim flipAnim)
  1697. {
  1698. this.flipAnim = flipAnim;
  1699. }
  1700. private bool SetUpLine()
  1701. {
  1702. if (line == null)
  1703. {
  1704. line = new GameObject($"{PluginName}__Overlay").AddComponent<LineRenderer>();
  1705. material = null;
  1706. sprite = null;
  1707. color = Color.white;
  1708. line.enabled = false;
  1709. }
  1710. else
  1711. {
  1712. line.gameObject.layer = OverlayLayer;
  1713. line.numCapVertices = 0;
  1714. line.shadowCastingMode = ShadowCastingMode.Off;
  1715. line.receiveShadows = false;
  1716. line.alignment = LineAlignment.View;
  1717. line.textureMode = LineTextureMode.Stretch;
  1718. line.useWorldSpace = true;
  1719. sprite = Shader.Find("Sprites/Default");
  1720. if (material == null && sprite)
  1721. {
  1722. material = line.material;
  1723. material.renderQueue = 3030;
  1724. material.shader = sprite;
  1725. material.color = color;
  1726. }
  1727. }
  1728. return line && material && sprite;
  1729. }
  1730. public void Draw(Positions pos, int number, State current)
  1731. {
  1732. if (!settings.enableOverlay)
  1733. {
  1734. Stop();
  1735. return;
  1736. }
  1737. var texture = current.shotReady
  1738. ? flipAnim.StartCumAnimation(current.isShooting)
  1739. : flipAnim.GetCurrentTex();
  1740. if (texture == null || !SetUpLine())
  1741. {
  1742. Stop();
  1743. return;
  1744. }
  1745. color.a = settings.Overlay_Transparency *
  1746. (current.showSkillSelect || current.showConfigPanel || current.showResultPanel
  1747. ? 0
  1748. : Mathf.Clamp01(current.rates[number] * 10));
  1749. material.renderQueue = (int) settings.Overlay_RenderQueue;
  1750. material.mainTexture = texture;
  1751. var aspect = texture.height == 0
  1752. ? (float) texture.width / texture.height
  1753. : 1.0f;
  1754. var dist = Vector3.Distance(pos.Top, pos.Root);
  1755. line.SetPosition(0, pos.Top);
  1756. line.SetPosition(1, pos.Root);
  1757. line.startWidth = dist / aspect * settings.Overlay_LineWidth * 0.5f;
  1758. line.endWidth = dist / aspect * settings.Overlay_LineWidth * 0.5f;
  1759. line.enabled = true;
  1760. if (material)
  1761. material.color = color;
  1762. }
  1763. public void Stop()
  1764. {
  1765. if (line == null)
  1766. return;
  1767. line.enabled = false;
  1768. }
  1769. }
  1770. #region Cams
  1771. private abstract class IOCam : IInitializable
  1772. {
  1773. public const int ManLayer = 9;
  1774. protected static GameObject bgObject;
  1775. protected Camera camera;
  1776. protected Transform cameraPosition, targetPosition;
  1777. protected Color color;
  1778. protected RenderTexture renderTexture;
  1779. protected int width, height;
  1780. public void Initialize()
  1781. {
  1782. renderTexture.Release();
  1783. if (camera)
  1784. camera.enabled = false;
  1785. cameraPosition = null;
  1786. targetPosition = null;
  1787. }
  1788. protected RenderTexture GetRenderTexture()
  1789. {
  1790. renderTexture.Create();
  1791. return renderTexture;
  1792. }
  1793. protected void SetRenderTexture(float width_, float height_)
  1794. {
  1795. if (width_ < 1 || height_ < 1)
  1796. return;
  1797. if (renderTexture.width == (int) width_ && renderTexture.height == (int) height_)
  1798. return;
  1799. width = (int) width_;
  1800. height = (int) height_;
  1801. renderTexture = new RenderTexture(width, height, 0);
  1802. }
  1803. protected static Vector3 SmoothCamPos(Vector3 from, Vector3 to, float shakewidth, float smoothspeed)
  1804. {
  1805. var t = Time.time;
  1806. var _x = (Mathf.PerlinNoise(0, t) - 0.5f) * shakewidth;
  1807. var _y = (Mathf.PerlinNoise(t, t) - 0.5f) * shakewidth;
  1808. var _z = (Mathf.PerlinNoise(t, 0) - 0.5f) * shakewidth;
  1809. return new Vector3(
  1810. Mathf.SmoothStep(from.x, to.x + _x, smoothspeed),
  1811. Mathf.SmoothStep(from.y, to.y + _y, smoothspeed),
  1812. Mathf.SmoothStep(from.z, to.z + _z, smoothspeed)
  1813. );
  1814. }
  1815. public abstract void Action();
  1816. public abstract void Draw(State current, Rect rect);
  1817. }
  1818. private class PokoCam : IOCam
  1819. {
  1820. private const string vagina = "_IK_vagina", anal = "_IK_anal", mouth = "Mouth";
  1821. private Vector3 offset;
  1822. public PokoCam()
  1823. {
  1824. color = Color.white;
  1825. renderTexture = new RenderTexture(1, 1, 0);
  1826. }
  1827. ~PokoCam()
  1828. {
  1829. Initialize();
  1830. DestroyObject(camera.gameObject);
  1831. }
  1832. public bool SetupCam(Maid maid, Maid man, MuffType type)
  1833. {
  1834. if (!maid.IsValid() || !man.IsValid())
  1835. return false;
  1836. if (camera == null)
  1837. {
  1838. camera = new GameObject($"{PluginName}__Cam").AddComponent<Camera>();
  1839. camera.nearClipPlane = 0.01f;
  1840. camera.farClipPlane = 100f;
  1841. }
  1842. else
  1843. {
  1844. camera.targetTexture = renderTexture;
  1845. camera.fieldOfView = settings.PokoCam_FOV;
  1846. camera.enabled = false;
  1847. }
  1848. cameraPosition = man.body0.trManChinko;
  1849. targetPosition = type switch
  1850. {
  1851. MuffType.Front => maid.body0.GetBone(vagina),
  1852. MuffType.Back => maid.body0.GetBone(anal),
  1853. MuffType.Mouth => maid.body0.GetBone(mouth),
  1854. _ => targetPosition
  1855. };
  1856. SetMask(man);
  1857. return camera && cameraPosition && targetPosition;
  1858. }
  1859. private void SetMask(Maid man)
  1860. {
  1861. if (camera == null)
  1862. return;
  1863. var mask = CreateMask();
  1864. camera.cullingMask = ~mask;
  1865. foreach (var m in man.GetComponentsInChildren<SkinnedMeshRenderer>())
  1866. if (m != null)
  1867. m.gameObject.layer = ManLayer;
  1868. }
  1869. private static int CreateMask()
  1870. {
  1871. var mask = 1 << Overlay.OverlayLayer;
  1872. if (settings.PokoCam_HideManBody)
  1873. mask += 1 << ManLayer;
  1874. if (settings.PokoCam_HideBG)
  1875. {
  1876. bgObject = GameMain.Instance.BgMgr.current_bg_object;
  1877. mask += 1 << bgObject.layer;
  1878. }
  1879. return mask;
  1880. }
  1881. public override void Action()
  1882. {
  1883. offset = settings.PokoCam_Offset;
  1884. var newpos = cameraPosition.position + offset;
  1885. var pos = SmoothCamPos(camera.transform.localPosition, newpos,
  1886. settings.PokoCam_ShakeWidth, settings.PokoCam_SmoothSpeed);
  1887. var up = cameraPosition.up;
  1888. var rot = Quaternion.LookRotation(targetPosition.position - newpos,
  1889. settings.PokoCam_UpsideDown ? -up : up);
  1890. camera.transform.SetPositionAndRotation(pos, rot);
  1891. camera.enabled = true;
  1892. }
  1893. public override void Draw(State current, Rect rect)
  1894. {
  1895. var muffType = current.PrimaryMuff;
  1896. if (muffType == MuffType.None)
  1897. return;
  1898. if (current.PokoType != PokoType.TNP && muffType != MuffType.Mouth)
  1899. return;
  1900. color.a = current.showSkillSelect || current.showConfigPanel || current.showResultPanel
  1901. ? 0.0f
  1902. : settings.PokoCam_Transparency * Mathf.Clamp01(current.rates[(int) current.PrimaryMuff] * 10);
  1903. GUI.color = color;
  1904. SetRenderTexture(rect.width, rect.height);
  1905. GUI.DrawTexture(rect, GetRenderTexture(), ScaleMode.ScaleToFit, true);
  1906. GUI.color = Color.white;
  1907. }
  1908. }
  1909. private class FaceCam : IOCam
  1910. {
  1911. private const string FaceNub = "Face_nub";
  1912. private const float FaceOffset = 0.008f;
  1913. public FaceCam()
  1914. {
  1915. color = Color.white;
  1916. renderTexture = new RenderTexture(1, 1, 0);
  1917. }
  1918. ~FaceCam()
  1919. {
  1920. Initialize();
  1921. DestroyObject(camera.gameObject);
  1922. }
  1923. public bool SetupCam(Maid maid)
  1924. {
  1925. if (!maid.IsValid())
  1926. return false;
  1927. if (camera == null)
  1928. {
  1929. camera = new GameObject($"{PluginName}__faceCam").AddComponent<Camera>();
  1930. camera.nearClipPlane = 0.01f;
  1931. camera.farClipPlane = 100f;
  1932. }
  1933. else
  1934. {
  1935. camera.targetTexture = renderTexture;
  1936. camera.fieldOfView = settings.FaceCam_FOV;
  1937. camera.enabled = false;
  1938. }
  1939. targetPosition = maid.IKCtrl.GetIKBone(FullBodyIKCtrl.IKBoneType.Head);
  1940. cameraPosition = GetCameraPos(maid);
  1941. bgObject = GameMain.Instance.BgMgr.current_bg_object;
  1942. var mask = (1 << Overlay.OverlayLayer) + (1 << ManLayer) + (1 << bgObject.layer);
  1943. if (camera != null)
  1944. camera.cullingMask = ~mask;
  1945. return camera && cameraPosition && targetPosition;
  1946. }
  1947. private Transform GetCameraPos(Maid maid)
  1948. {
  1949. var head = maid.body0.goSlot[(int) TBody.SlotID.head].obj_tr;
  1950. for (var j = 0; j < head.childCount; j++)
  1951. {
  1952. var h = head.GetChild(j);
  1953. for (var i = 0; i < h.childCount; i++)
  1954. {
  1955. var f = h.GetChild(i);
  1956. if (f.name.Equals(FaceNub))
  1957. return f;
  1958. }
  1959. }
  1960. return null;
  1961. }
  1962. public override void Draw(State current, Rect rect)
  1963. {
  1964. if (current.rates[2] > 0.01f)
  1965. return;
  1966. color.a = current.showSkillSelect || current.showConfigPanel || current.showResultPanel
  1967. ? 0.0f
  1968. : settings.FaceCam_Transparency;
  1969. GUI.color = color;
  1970. SetRenderTexture(rect.width, rect.height);
  1971. GUI.DrawTexture(rect, GetRenderTexture(), ScaleMode.ScaleToFit, true);
  1972. GUI.color = Color.white;
  1973. }
  1974. public override void Action()
  1975. {
  1976. var position = cameraPosition.position;
  1977. var dir = targetPosition.position - position;
  1978. var newpos = position - dir * settings.FaceCam_Distance;
  1979. var pos = SmoothCamPos(position, newpos,
  1980. settings.FaceCam_ShakeWidth, settings.FaceCam_SmoothSpeed);
  1981. var rot = Quaternion.LookRotation(dir + cameraPosition.up * FaceOffset, cameraPosition.up);
  1982. camera.transform.SetPositionAndRotation(pos, rot);
  1983. camera.enabled = true;
  1984. }
  1985. }
  1986. #endregion
  1987. public class PokoTrail
  1988. {
  1989. private GameObject obj;
  1990. private Shader shader;
  1991. private TrailRenderer trail;
  1992. private bool SetUpTrail()
  1993. {
  1994. if (shader && trail)
  1995. return true;
  1996. shader = Shader.Find(HiddenShader);
  1997. if (shader == null)
  1998. return false;
  1999. if (trail == null)
  2000. {
  2001. trail = new GameObject($"{PluginName}__trail__").AddComponent<TrailRenderer>();
  2002. obj = trail.gameObject;
  2003. trail.material.shader = shader;
  2004. trail.material.SetInt("_ZTest", (int) CompareFunction.Always);
  2005. trail.startWidth = 0.01f;
  2006. trail.endWidth = 0.0f;
  2007. trail.time = 2;
  2008. trail.minVertexDistance = 0.001f;
  2009. trail.alignment = LineAlignment.View;
  2010. trail.enabled = false;
  2011. }
  2012. return shader && trail;
  2013. }
  2014. public void Draw(Vector3 pos, Color startcolor, Color endcolor)
  2015. {
  2016. if (!SetUpTrail())
  2017. return;
  2018. trail.transform.localPosition = pos;
  2019. trail.startColor = startcolor;
  2020. trail.endColor = endcolor;
  2021. trail.enabled = true;
  2022. }
  2023. ~PokoTrail()
  2024. {
  2025. DestroyObject(trail);
  2026. DestroyObject(obj);
  2027. }
  2028. }
  2029. public class Settings
  2030. {
  2031. private static Settings _instance;
  2032. private static FileInfo fileInfo;
  2033. public float Anim_Speed = 0.5f;
  2034. public KeyCode ControllerHotKey = KeyCode.U;
  2035. //FaceCam
  2036. public bool enableFaceCam;
  2037. //Morpher
  2038. public bool enableMorpher;
  2039. //FlipAnim
  2040. public bool enableOnGUI;
  2041. //Overlay
  2042. public bool enableOverlay;
  2043. public bool enablePlugin;
  2044. //PokoCam
  2045. public bool enablePokoCam;
  2046. public float FaceCam_Distance = 20.0f;
  2047. public float FaceCam_FOV = 20.0f;
  2048. public float FaceCam_ShakeWidth = 0.01f;
  2049. public float FaceCam_SmoothSpeed = 0.3f;
  2050. public float FaceCam_Transparency = 1.0f;
  2051. public bool Morpher_EnableFix = true;
  2052. public string Morpher_KeyA = "analkupa";
  2053. public string Morpher_KeyV = "kupa";
  2054. public float Morpher_Max = 0.80f;
  2055. public float Morpher_Min = 0.05f;
  2056. public float Morpher_Threshold = 0.3f;
  2057. public float Morpher_Waitframe = 5.0f;
  2058. public bool OnGUI_HidePenis;
  2059. public float OnGUI_offset = 5.0f;
  2060. public float OnGUI_transparency = 1.0f;
  2061. public float OnGUI_x_offset;
  2062. public float OnGUI_x_scale = 1.0f;
  2063. public float OnGUI_y_offset;
  2064. public float OnGUI_y_scale = 1.0f;
  2065. public float Overlay_CameraDistance = 0.25f;
  2066. public float Overlay_DirectionalOffset;
  2067. public float Overlay_LineScale;
  2068. public float Overlay_LineWidth = 1.0f;
  2069. public float Overlay_RenderQueue = 4000f;
  2070. public float Overlay_Transparency = 0.7f;
  2071. //internal Rect PokoCam_Pos = Rect.zero;
  2072. //internal bool PokoCam_CustomPos = false;
  2073. public float PokoCam_FOV = 90.0f;
  2074. public bool PokoCam_HideBG = false;
  2075. public bool PokoCam_HideManBody = true;
  2076. public Vector3 PokoCam_Offset = Vector3.zero;
  2077. public float PokoCam_ShakeWidth = 0.03f;
  2078. public float PokoCam_SmoothSpeed = 0.3f;
  2079. public float PokoCam_Transparency = 1.0f;
  2080. public bool PokoCam_UpsideDown;
  2081. private Settings()
  2082. {
  2083. }
  2084. private static Settings Instance => _instance ?? (_instance = new Settings());
  2085. public static void Save()
  2086. {
  2087. if (fileInfo == null)
  2088. return;
  2089. using (var stream = fileInfo.Open(FileMode.Create))
  2090. {
  2091. var serializer = new XmlSerializer(typeof(Settings));
  2092. serializer.Serialize(stream, Instance);
  2093. }
  2094. }
  2095. public static Settings Load()
  2096. {
  2097. return Load(fileInfo);
  2098. }
  2099. public static Settings Load(FileInfo fileInfo)
  2100. {
  2101. Settings.fileInfo = fileInfo;
  2102. if (!fileInfo.Exists)
  2103. {
  2104. using (fileInfo.Create())
  2105. {
  2106. }
  2107. Save();
  2108. }
  2109. using (var stream = fileInfo.Open(FileMode.Open))
  2110. {
  2111. var serializer = new XmlSerializer(typeof(Settings));
  2112. var reader = XmlReader.Create(stream, new XmlReaderSettings());
  2113. return _instance = (Settings) serializer.Deserialize(reader);
  2114. }
  2115. }
  2116. public static Settings GetDef()
  2117. {
  2118. var _ = new Settings();
  2119. return ReferenceEquals(_, _instance) ? null : _;
  2120. }
  2121. public void OpenFile()
  2122. {
  2123. if (!fileInfo.Exists)
  2124. return;
  2125. var ps = new ProcessStartInfo
  2126. {
  2127. FileName = "notepad",
  2128. Arguments = fileInfo.FullName
  2129. };
  2130. using (var process = Process.Start(ps))
  2131. {
  2132. }
  2133. ;
  2134. }
  2135. }
  2136. private class Controller
  2137. {
  2138. private const string MuffNames = "前後口";
  2139. private const string TargetMaid = "対象メイド";
  2140. private const string PokoNames = "棒振張指舌";
  2141. private static Rect winRect;
  2142. private static readonly Color bgColor = Color.white, onColor = Color.green, offColor = Color.black;
  2143. private static readonly GUILayoutOption[] noOptions = new GUILayoutOption[0];
  2144. private static readonly GUILayoutOption noExpandWidth = ExpandWidth(false);
  2145. private static GUILayoutOption width010, width015, width020, width025;
  2146. private readonly Dictionary<string, Container> containers;
  2147. private readonly FlipAnimData[] fAData;
  2148. private readonly InOutAnimation plugin;
  2149. private readonly ToggleButton pluginEnabler;
  2150. private bool _show;
  2151. private Vector2 winScrollRect;
  2152. public Controller(InOutAnimation plugin)
  2153. {
  2154. this.plugin = plugin;
  2155. var s = settings;
  2156. var def = Settings.GetDef();
  2157. fAData = new[]
  2158. {
  2159. new FlipAnimData($"{MuffNames[0]}", plugin.flipAnims[0]),
  2160. new FlipAnimData($"{MuffNames[1]}", plugin.flipAnims[1]),
  2161. new FlipAnimData($"{MuffNames[2]}", plugin.flipAnims[2])
  2162. };
  2163. pluginEnabler = new ToggleButton("プラグイン有効", s.enablePlugin, b => settings.enablePlugin = b);
  2164. containers = new Dictionary<string, Container>
  2165. {
  2166. {"ongui", new Container("OnGUI表示")},
  2167. {"overlay", new Container("メイドに重ねて表示")},
  2168. {"morpher", new Container("シェイプキー連動")},
  2169. {"pokocam", new Container("股間視点")},
  2170. {"facecam", new Container("顔カメラ")}
  2171. };
  2172. containers["ongui"].Add(new ToggleButton("有効", s.enableOnGUI, b => settings.enableOnGUI = b));
  2173. containers["ongui"].Add(new LabelSlider("間隔", s.OnGUI_offset, -100.0f, 100.0f, def.OnGUI_offset,
  2174. f => settings.OnGUI_offset = f));
  2175. containers["ongui"].Add(new LabelSlider("横スケール", s.OnGUI_x_scale, 0.0f, 2.0f, def.OnGUI_x_scale,
  2176. f => settings.OnGUI_x_scale = f));
  2177. containers["ongui"].Add(new LabelSlider("縦スケール", s.OnGUI_y_scale, 0.0f, 2.0f, def.OnGUI_y_scale,
  2178. f => settings.OnGUI_y_scale = f));
  2179. containers["ongui"].Add(new LabelSlider("横オフセット", s.OnGUI_x_offset, -600.0f, 300.0f, def.OnGUI_x_offset,
  2180. f => settings.OnGUI_x_offset = f));
  2181. containers["ongui"].Add(new LabelSlider("縦オフセット", s.OnGUI_y_offset, -500.0f, 500.0f, def.OnGUI_y_offset,
  2182. f => settings.OnGUI_y_offset = f));
  2183. containers["ongui"].Add(new LabelSlider("透明度", s.OnGUI_transparency, 0.0f, 1.0f, def.OnGUI_transparency,
  2184. f => settings.OnGUI_transparency = f));
  2185. containers["ongui"]
  2186. .Add(new ToggleButton("Hide man penis", s.OnGUI_HidePenis, b => settings.OnGUI_HidePenis = b));
  2187. containers["overlay"].Add(new ToggleButton("有効", s.enableOverlay, b => settings.enableOverlay = b));
  2188. containers["overlay"].Add(new LabelSlider("太さ", s.Overlay_LineWidth, 0.0f, 2.0f, def.Overlay_LineWidth,
  2189. f => settings.Overlay_LineWidth = f));
  2190. containers["overlay"].Add(new LabelSlider("拡大", s.Overlay_LineScale, -0.5f, 0.5f, def.Overlay_LineScale,
  2191. f => settings.Overlay_LineScale = f));
  2192. containers["overlay"].Add(new LabelSlider("透明度", s.Overlay_Transparency, 0.0f, 1.0f,
  2193. def.Overlay_Transparency, f => settings.Overlay_Transparency = f));
  2194. containers["overlay"].Add(new LabelSlider("カメラ距離", s.Overlay_CameraDistance, 0.0f, 1.0f,
  2195. def.Overlay_CameraDistance, f => settings.Overlay_CameraDistance = f));
  2196. containers["overlay"].Add(new LabelSlider("Dir. Offset.", s.Overlay_DirectionalOffset, -0.1f, 0.1f,
  2197. def.Overlay_DirectionalOffset, f => settings.Overlay_DirectionalOffset = f));
  2198. containers["overlay"].Add(new LabelSlider("Overlay renderqueue", s.Overlay_RenderQueue, 1000, 5000,
  2199. def.Overlay_RenderQueue, f => settings.Overlay_RenderQueue = f, true));
  2200. containers["morpher"].Add(new ToggleButton("有効", s.enableMorpher, b => settings.enableMorpher = b));
  2201. containers["morpher"].Add(new ShapeKeyChange("前穴用キー", s.Morpher_KeyV, n => settings.Morpher_KeyV = n));
  2202. containers["morpher"].Add(new ShapeKeyChange("後穴用キー", s.Morpher_KeyA, n => settings.Morpher_KeyA = n));
  2203. containers["morpher"].Add(new LabelSlider("閾値", s.Morpher_Threshold, 0.0f, 1.0f, def.Morpher_Threshold,
  2204. f => settings.Morpher_Threshold = f));
  2205. containers["morpher"].Add(new LabelSlider("最小値", s.Morpher_Min, 0.0f, 1.0f, def.Morpher_Min,
  2206. f => settings.Morpher_Min = f));
  2207. containers["morpher"].Add(new LabelSlider("最大値", s.Morpher_Max, 0.0f, 1.0f, def.Morpher_Max,
  2208. f => settings.Morpher_Max = f));
  2209. var wf = new LabelSlider("更新フレーム", s.Morpher_Waitframe, 1, 60, def.Morpher_Waitframe,
  2210. f => settings.Morpher_Waitframe = f, true);
  2211. containers["morpher"].Add(new EnableToggle("FixBlendValues", s.Morpher_EnableFix, wf,
  2212. b => settings.Morpher_EnableFix = b));
  2213. containers["pokocam"].Add(new ToggleButton("有効", s.enablePokoCam, b => settings.enablePokoCam = b));
  2214. var st1 = new SimpleToggle("男を隠す", s.PokoCam_HideManBody, b => settings.PokoCam_HideManBody = b);
  2215. // var st2 = new SimpleToggle("背景を隠す", s.PokoCam_HideBG, b => settings.PokoCam_HideBG = b);
  2216. var st3 = new SimpleToggle("上下逆", s.PokoCam_UpsideDown, b => settings.PokoCam_UpsideDown = b);
  2217. containers["pokocam"].Add(new HorizontalGroup(st1, st3));
  2218. containers["pokocam"].Add(new LabelSlider("視野", s.PokoCam_FOV, 15, 180, def.PokoCam_FOV,
  2219. f => settings.PokoCam_FOV = f, true));
  2220. containers["pokocam"].Add(new LabelSlider("透明度", s.PokoCam_Transparency, 0.0f, 1.0f,
  2221. def.PokoCam_Transparency, f => settings.PokoCam_Transparency = f));
  2222. containers["pokocam"].Add(new Vec3Slider("オフセット", s.PokoCam_Offset, def.PokoCam_Offset, -0.2f, 0.2f,
  2223. v => settings.PokoCam_Offset = v));
  2224. containers["facecam"].Add(new ToggleButton("有効", s.enableFaceCam, b => settings.enableFaceCam = b));
  2225. containers["facecam"].Add(new LabelSlider("距離", s.FaceCam_Distance, 5.0f, 40.0f, def.FaceCam_Distance,
  2226. f => settings.FaceCam_Distance = f));
  2227. containers["facecam"].Add(new LabelSlider("視野", s.FaceCam_FOV, 15, 50, def.FaceCam_FOV,
  2228. f => settings.FaceCam_FOV = f, true));
  2229. containers["facecam"].Add(new LabelSlider("透明度", s.FaceCam_Transparency, 0.0f, 1.0f,
  2230. def.FaceCam_Transparency, f => settings.FaceCam_Transparency = f));
  2231. }
  2232. public bool showController
  2233. {
  2234. get => _show;
  2235. set
  2236. {
  2237. var mouse = Event.current.mousePosition;
  2238. winRect.Set(
  2239. Mathf.Clamp(mouse.x - 10.0f, 0.0f, Screen.width - Screen.width * 0.25f),
  2240. Mathf.Clamp(mouse.y - 10.0f, 0.0f, Screen.height - 400),
  2241. Screen.width * 0.25f,
  2242. Screen.height * 0.6f);
  2243. _show = value;
  2244. GC.Collect();
  2245. }
  2246. }
  2247. public void Draw()
  2248. {
  2249. winRect = Window(plugin.windowId, winRect, WindowFunc, "", noOptions);
  2250. }
  2251. private void WindowFunc(int id)
  2252. {
  2253. var stg = settings;
  2254. winScrollRect = BeginScrollView(winScrollRect, false, false, noOptions);
  2255. pluginEnabler.Draw();
  2256. //if (Button("設定ファイルを開く", ExpandWidth(false))) settings.OpenFile();
  2257. if (stg.enablePlugin && plugin.mediator.TargetMaid != null)
  2258. {
  2259. BeginHorizontal(noOptions);
  2260. {
  2261. Label(TargetMaid, noExpandWidth);
  2262. Box(plugin.current.isPlay ? plugin.mediator.TargetMaid.status.fullNameJpStyle : "", noOptions);
  2263. plugin.mediator.SwapTargetNPC = plugin.current.PlayMode == PlayMode.Swap
  2264. && Toggle(plugin.mediator.SwapTargetNPC, "NPC", noExpandWidth);
  2265. }
  2266. EndHorizontal();
  2267. foreach (var fA in fAData)
  2268. fA.Draw();
  2269. for (var i = 0; i < plugin.mediator.pokos.Length; i++)
  2270. {
  2271. var p = plugin.mediator.pokos[i];
  2272. if (p == null || !p.Validated)
  2273. continue;
  2274. BeginHorizontal(noOptions);
  2275. {
  2276. Box($"{i} {GetPokoTypeChar(p)} : {MuffNames[(int) p.TargetMuff]}", noOptions);
  2277. }
  2278. EndHorizontal();
  2279. }
  2280. foreach (var container in containers.Values)
  2281. container.Draw();
  2282. }
  2283. EndScrollView();
  2284. GUI.DragWindow();
  2285. }
  2286. private char GetPokoTypeChar(Poko type)
  2287. {
  2288. return type switch
  2289. {
  2290. TNP _ => PokoNames[0],
  2291. Vibe _ => PokoNames[1],
  2292. Dildo _ => PokoNames[2],
  2293. Finger _ => PokoNames[3],
  2294. Tongue _ => PokoNames[4],
  2295. _ => '_'
  2296. };
  2297. }
  2298. private class Container
  2299. {
  2300. private const string Down = "▼";
  2301. private readonly List<IDrawable> contents;
  2302. private readonly string label;
  2303. private bool visible;
  2304. public Container(string label)
  2305. {
  2306. this.label = label;
  2307. contents = new List<IDrawable>();
  2308. }
  2309. public void Add(IDrawable controllerParts)
  2310. {
  2311. contents.Add(controllerParts);
  2312. }
  2313. public void Draw()
  2314. {
  2315. BeginHorizontal(noOptions);
  2316. {
  2317. Box(label, noOptions);
  2318. if (Button(Down, noExpandWidth))
  2319. visible = !visible;
  2320. }
  2321. EndHorizontal();
  2322. if (!visible)
  2323. return;
  2324. foreach (var drawable in contents)
  2325. drawable.Draw();
  2326. }
  2327. }
  2328. private class HorizontalGroup : IDrawable
  2329. {
  2330. private readonly List<IDrawable> contents;
  2331. public HorizontalGroup(params IDrawable[] drawable)
  2332. {
  2333. contents = drawable.ToList();
  2334. }
  2335. public void Draw()
  2336. {
  2337. BeginHorizontal(noOptions);
  2338. foreach (var drawable in contents) drawable.Draw();
  2339. EndHorizontal();
  2340. }
  2341. public void Add(IDrawable drawable)
  2342. {
  2343. contents.Add(drawable);
  2344. }
  2345. }
  2346. private class FlipAnimData : IDrawable
  2347. {
  2348. private const string Reload = "再読込",
  2349. mes1 = "準備完了",
  2350. mes2 = "ex画像がありません",
  2351. mes3 = "画像がありません";
  2352. private static Color color;
  2353. private readonly FlipAnim flipAnim;
  2354. private readonly string label;
  2355. private string message;
  2356. public FlipAnimData(string label, FlipAnim flipAnim)
  2357. {
  2358. this.label = label;
  2359. this.flipAnim = flipAnim;
  2360. }
  2361. public void Draw()
  2362. {
  2363. CheckLoaded();
  2364. BeginHorizontal(noOptions);
  2365. {
  2366. width010 = Width(winRect.width * 0.10f);
  2367. width015 = Width(winRect.width * 0.15f);
  2368. width020 = Width(winRect.width * 0.20f);
  2369. Label(label, width010);
  2370. Box($"{flipAnim.CurrentFrame:D2}/{flipAnim.MaxFrame:D2}", width020);
  2371. GUI.contentColor = color;
  2372. Box($"{message}", noOptions);
  2373. GUI.contentColor = bgColor;
  2374. if (Button(Reload, width015))
  2375. flipAnim.Load();
  2376. }
  2377. EndHorizontal();
  2378. }
  2379. private void CheckLoaded()
  2380. {
  2381. if (flipAnim.TextureLoaded)
  2382. {
  2383. if (flipAnim.TextureLoadedEx)
  2384. {
  2385. color = Color.white;
  2386. message = mes1;
  2387. return;
  2388. }
  2389. color = Color.yellow;
  2390. message = mes2;
  2391. return;
  2392. }
  2393. color = Color.magenta;
  2394. message = mes3;
  2395. }
  2396. }
  2397. private class SimpleToggle : IDrawable
  2398. {
  2399. private readonly string label;
  2400. private readonly Action<bool> onChanged;
  2401. private bool recent;
  2402. private bool value;
  2403. public SimpleToggle(string label, bool value, Action<bool> onChanged)
  2404. {
  2405. this.label = label;
  2406. this.value = value;
  2407. recent = this.value;
  2408. this.onChanged = onChanged;
  2409. }
  2410. public void Draw()
  2411. {
  2412. value = Toggle(value, label, noOptions);
  2413. if (recent == value)
  2414. return;
  2415. onChanged(value);
  2416. recent = value;
  2417. }
  2418. }
  2419. private class Vec3Slider : IDrawable
  2420. {
  2421. private readonly Vector3 def;
  2422. private readonly string label;
  2423. private readonly float min, max;
  2424. private readonly Action<Vector3> onChanged;
  2425. private Vector3 value, recent;
  2426. public Vec3Slider(string label, Vector3 value, Vector3 def, float min, float max,
  2427. Action<Vector3> onChanged)
  2428. {
  2429. this.label = label;
  2430. this.value = value;
  2431. recent = this.value;
  2432. this.def = def;
  2433. this.min = min;
  2434. this.max = max;
  2435. this.onChanged = onChanged;
  2436. }
  2437. public void Draw()
  2438. {
  2439. BeginHorizontal(noOptions);
  2440. {
  2441. Label(label, noOptions);
  2442. if (Button("def", noExpandWidth))
  2443. value = def;
  2444. }
  2445. EndHorizontal();
  2446. BeginHorizontal(noOptions);
  2447. {
  2448. Label("X", noExpandWidth);
  2449. value.x = HorizontalSlider(value.x, min, max, noOptions);
  2450. Label("Y", noExpandWidth);
  2451. value.y = HorizontalSlider(value.y, min, max, noOptions);
  2452. Label("Z", noExpandWidth);
  2453. value.z = HorizontalSlider(value.z, min, max, noOptions);
  2454. }
  2455. EndHorizontal();
  2456. if (recent.Equals(value))
  2457. return;
  2458. onChanged(value);
  2459. recent = value;
  2460. }
  2461. }
  2462. private class EnableToggle : IDrawable
  2463. {
  2464. private readonly string label;
  2465. private readonly Action<bool> onChanged;
  2466. private readonly IDrawable parts;
  2467. private bool enable, recent;
  2468. public EnableToggle(string label, bool enable, IDrawable parts, Action<bool> onChanged)
  2469. {
  2470. this.label = label;
  2471. this.enable = enable;
  2472. this.parts = parts;
  2473. this.onChanged = onChanged;
  2474. }
  2475. public void Draw()
  2476. {
  2477. enable = Toggle(enable, label, noOptions);
  2478. GUI.enabled = enable;
  2479. parts.Draw();
  2480. GUI.enabled = true;
  2481. if (recent == enable)
  2482. return;
  2483. onChanged(enable);
  2484. recent = enable;
  2485. }
  2486. }
  2487. private class ShapeKeyChange : IDrawable
  2488. {
  2489. private const string Change = "変更";
  2490. private readonly string label;
  2491. private readonly Action<string> onChanged;
  2492. private bool Editable;
  2493. private string key, recent;
  2494. public ShapeKeyChange(string label, string key, Action<string> onChanged)
  2495. {
  2496. this.label = label;
  2497. this.key = key;
  2498. recent = key;
  2499. this.onChanged = onChanged;
  2500. }
  2501. public void Draw()
  2502. {
  2503. width025 = Width(winRect.width * 0.25f);
  2504. BeginHorizontal(noOptions);
  2505. Label(label, width025);
  2506. if (Editable)
  2507. try
  2508. {
  2509. key = TextArea($"{key}", noOptions).Trim();
  2510. }
  2511. catch (FormatException e)
  2512. {
  2513. Console.WriteLine(e);
  2514. key = "";
  2515. }
  2516. else
  2517. Box($"{key}", noOptions);
  2518. GUI.backgroundColor = Editable ? onColor : offColor;
  2519. if (Button(Change, noExpandWidth))
  2520. Editable = !Editable;
  2521. GUI.backgroundColor = bgColor;
  2522. EndHorizontal();
  2523. if (recent.Equals(key))
  2524. return;
  2525. onChanged(key);
  2526. recent = key;
  2527. }
  2528. }
  2529. private class ToggleButton : IDrawable
  2530. {
  2531. private readonly string label;
  2532. private readonly Action<bool> onChanged;
  2533. private bool value, recent;
  2534. public ToggleButton(string label, bool value, Action<bool> onChanged)
  2535. {
  2536. this.label = label;
  2537. this.value = value;
  2538. recent = value;
  2539. this.onChanged = onChanged;
  2540. }
  2541. public void Draw()
  2542. {
  2543. GUI.backgroundColor = value ? onColor : offColor;
  2544. if (Button(label, noOptions))
  2545. value = !value;
  2546. GUI.backgroundColor = bgColor;
  2547. if (recent == value)
  2548. return;
  2549. onChanged(value);
  2550. recent = value;
  2551. }
  2552. }
  2553. private class LabelSlider : IDrawable
  2554. {
  2555. private const string _def = "def";
  2556. private readonly bool ceil;
  2557. private readonly string label;
  2558. private readonly float min, max, def;
  2559. private readonly Action<float> onChanged;
  2560. private string str;
  2561. private float value, recent;
  2562. public LabelSlider(string label, float value, float min, float max, float def, Action<float> onChanged,
  2563. bool ceil = false)
  2564. {
  2565. this.label = label;
  2566. this.value = value;
  2567. recent = this.value;
  2568. this.min = min;
  2569. this.max = max;
  2570. this.def = def;
  2571. this.ceil = ceil;
  2572. this.onChanged = onChanged;
  2573. }
  2574. public void Draw()
  2575. {
  2576. width015 = Width(winRect.width * 0.15f);
  2577. width025 = Width(winRect.width * 0.25f);
  2578. BeginHorizontal(noOptions);
  2579. {
  2580. if (ceil)
  2581. value = Mathf.Ceil(value);
  2582. str = ceil ? $"{value}" : $"{value:F2}";
  2583. Label(label, width025);
  2584. Box(str, width015);
  2585. value = HorizontalSlider(value, min, max, noOptions);
  2586. if (Button(_def, noExpandWidth))
  2587. value = def;
  2588. }
  2589. EndHorizontal();
  2590. if (recent.Equals(value))
  2591. return;
  2592. onChanged(value);
  2593. recent = value;
  2594. }
  2595. }
  2596. private interface IDrawable
  2597. {
  2598. void Draw();
  2599. }
  2600. }
  2601. private class MessageBox
  2602. {
  2603. private readonly Rect winRect = new Rect(30, Screen.height * 0.5f, 400, 300);
  2604. private GUIContent message;
  2605. public void Draw(GUIContent content)
  2606. {
  2607. message = content;
  2608. BeginArea(winRect);
  2609. {
  2610. Box(message);
  2611. }
  2612. EndArea();
  2613. }
  2614. }
  2615. #endregion
  2616. }
  2617. public static class Util
  2618. {
  2619. public static bool IsValid(this Maid maid)
  2620. {
  2621. return maid != null && maid.isActiveAndEnabled &&
  2622. !maid.IsAllProcPropBusy && maid.Visible &&
  2623. !string.IsNullOrEmpty(maid.body0.LastAnimeFN);
  2624. }
  2625. public static IEnumerable<Maid> GetMaidCol(this CharacterMgr mgr, Func<Maid, bool> pred)
  2626. {
  2627. return Enumerable.Range(0, mgr.GetMaidCount()).Select(mgr.GetMaid).Where(pred);
  2628. }
  2629. }
  2630. #region enums
  2631. internal enum MuffNum
  2632. {
  2633. Unknown,
  2634. Double,
  2635. Triple
  2636. }
  2637. internal enum MuffType
  2638. {
  2639. Front,
  2640. Back,
  2641. Mouth,
  2642. None
  2643. }
  2644. internal enum PlayMode
  2645. {
  2646. Normal,
  2647. Multiple,
  2648. Swap,
  2649. Harem,
  2650. Self
  2651. }
  2652. internal enum sPosition
  2653. {
  2654. None,
  2655. Normal,
  2656. Dog,
  2657. Side
  2658. }
  2659. internal enum PlayState
  2660. {
  2661. None,
  2662. Insert,
  2663. Eject,
  2664. Wait,
  2665. Play,
  2666. Shot,
  2667. ShotFin
  2668. }
  2669. internal enum PokoType
  2670. {
  2671. TNP,
  2672. Vibe,
  2673. Dildo,
  2674. Finger,
  2675. Tongue
  2676. }
  2677. #endregion
  2678. }