Sauceke / LoveMachine

Support for interactive sex toys in over 30 different Hentai games, including Koikatsu, Honey Select 2, COM3D2, Insult Order, and more.
https://sauceke.github.io/LoveMachine/
GNU General Public License v3.0
172 stars 11 forks source link

The com3d2 mod seems not work with version 1.55-, maybe consider work out two version of the plugin? #92

Closed RPKU closed 2 years ago

RPKU commented 2 years ago

When I play animation the game always show me the error:

[Error :LoveMachine] Coroutine failed with exception: System.NullReferenceException: Object reference not set to an instance of an object at LoveMachine.COM3D2.Com3d2ButtplugController.GetFemaleBones (Int32 girlIndex) [0x00000] in :0 at LoveMachine.Core.AnimationAnalyzer+d__16.MoveNext () [0x00000] in :0 at LoveMachine.Core.CoroutineHandler.TryNext (IEnumerator coroutine, Boolean suppressExceptions) [0x00000] in :0

my game version is 1.551 Because COM3D2 works different with the version under 1.555 and above 2.0.0, maybe considered work out two version of the game?

Sauceke commented 2 years ago

1.551 seems to be an older version rolled out in 2018 back when the game was still called Custom Maid 3D2. Since it is a severely outdated version of the game, it is not expected to work with the plugin. Given that I only own the latest version of the game, I am unable to make the plugin backwards compatible. Please consider upgrading to the latest version if possible. Thank you for your understanding.

Sauceke commented 2 years ago

I will leave this issue open just in case another developer wants to have a go at it.

RPKU commented 2 years ago

I fixed it by refer to some mod, this may work fine with 1.55 `using System; using System.Collections; using System.Collections.Generic; using System.Linq; using LoveMachine.Core; using UnityEngine;

namespace LoveMachine.COM3D2 { internal abstract class Com3d2ButtplugController : ButtplugController { private const string SpineF = "Bip01/Bip01 Spine/Bip01 Spine0a/" + "Bip01 Spine1/Bip01 Spine1a"; private const string PelvisF = "Bip01/Bip01 Pelvis";

    private readonly string[] idlePoseNames = { "taiki", "nade", "shaseigo" };

    // TODO 3some, groups
    protected override int HeroineCount => 1;

    // TOOD animation name numbering is not consistent, need to make some sense out of it
    protected override bool IsHardSex => GetPose(0).Contains('2');

    protected override bool IsHSceneInterrupted => false;

    protected override int AnimationLayer => throw new NotImplementedException();

    protected override Animator GetFemaleAnimator(int girlIndex) =>
        throw new NotImplementedException();

    private float lastPartialTime = 0f;
    private int totalTime = 0;

    protected override void GetAnimState(int girlIndex, out float normalizedTime,
        out float length, out float speed)
    {
        var state = GetActiveState();
        float partialTime = state.normalizedTime;
        // Yes, this is horrible. So is COM3D2's code, so I don't care.
        if (partialTime < lastPartialTime)
        {
            totalTime += Mathf.CeilToInt(lastPartialTime - partialTime);
        }
        normalizedTime = partialTime + totalTime;
        length = state.length;
        speed = state.speed;
        lastPartialTime = partialTime;
        return;
    }

    private AnimationState GetActiveState()
    {
        var animations = FindObjectsOfType<Animation>()
            .Where(animation => animation.name == "_BO_mbody");
        foreach (var animation in animations)
        {
            foreach (AnimationState state in animation)
            {
                if (animation.IsPlaying(state.name))
                {
                    return state;
                }
            }
        }
        return null;
    }

    protected override Dictionary<Bone, Transform> GetFemaleBones(int girlIndex)
        => new Dictionary<Bone, Transform>
        {
            { Bone.Vagina, FindComponentObject("Maid[", PelvisF + "/_IK_vagina").transform },
            {
                Bone.RightHand,
                FindComponentObject("Maid[", SpineF + "/Bip01 R Clavicle/Bip01 R UpperArm/" +
                    "Bip01 R Forearm/Bip01 R Hand/_IK_handR").transform
            },
            {
                Bone.Mouth,
                FindComponentObject("Maid[", SpineF + "/Bip01 Neck/Bip01 Head/Bone_Face/MouthUp").transform
            },
            { Bone.LeftBreast, FindComponentObject("Maid[", SpineF + "/Mune_L/_IK_muneL").transform },
            { Bone.RightBreast, FindComponentObject("Maid[", SpineF + "/Mune_R/_IK_muneR").transform },
            {
                Bone.RightFoot,
                FindComponentObject("Maid[", PelvisF + "/Bip01 L Thigh_SCL_/Bip01 L Calf/_IK_calfL").transform
            },
            {
                Bone.LeftFoot,
                FindComponentObject("Maid[", PelvisF + "/Bip01 R Thigh_SCL_/Bip01 R Calf/_IK_calfR").transform
            }
        };

    protected override Transform GetMaleBone() =>
        FindComponentObject("Man[", "ManBip/ManBip Pelvis/chinkoCenter/chinko1/chinko2/chinko_nub")
            .transform;

    protected List<GameObject> FindCharaObject(string pattern) {
        GameObject characterRootObject = GameObject.Find("__GameMain__/Character/Active/AllOffset");
        List<GameObject> list = new List<GameObject>();
        if (characterRootObject != null)
        {
            int childCount = characterRootObject.transform.childCount;
            for (int i = 0; i < childCount; i++)
            {
                Transform child = characterRootObject.transform.GetChild(i);
                if (child != null && child.gameObject != null && child.gameObject.name.StartsWith(pattern))
                {
                    GameObject gameObject = child.gameObject;
                    if (gameObject != null)
                    {
                        Transform transform = gameObject.transform.Find("Offset");
                        if (transform != null && transform.childCount > 0)
                        {
                            GameObject gameObject2 = transform.GetChild(0).gameObject;
                            if (gameObject2 != null && gameObject2.gameObject != null)
                            {
                                //CoreConfig.Logger.LogInfo(GetAllChilds(gameObject2.transform, "", 0));
                                list.Add(gameObject2);
                            }
                        }
                    }
                }
            }
        }
        return list;
    }

    protected Transform FindComponentObject(string pattern, string path)
    {
        CoreConfig.Logger.LogInfo("Try to find object: " + pattern + " " + path);
        List<GameObject> list = FindCharaObject(pattern);
        Transform trans = null;
        foreach (GameObject rootObject in list)
        {
            trans = rootObject.transform.Find(path);
            if (trans != null)
            {
                break;
            }
        }
        if (trans == null)
        {
            foreach (GameObject rootObject in list)
            {
                string[] paths = path.Split('/');
                CoreConfig.Logger.LogInfo("Path is invaild, try to find " + paths[paths.Length - 1]);
                trans = FindChild(rootObject.transform, paths[paths.Length - 1].Trim());
                if (trans != null)
                {
                    CoreConfig.Logger.LogInfo("Find unnamed object: " + GetGameObjectPath(trans.gameObject));
                    break;
                }
            }
            if (trans == null)
                CoreConfig.Logger.LogWarning("the object is null");
        }
        return trans;
    }

    public static string GetGameObjectPath(GameObject obj)
    {
        string path = "/" + obj.name;
        while (obj.transform.parent != null)
        {
            obj = obj.transform.parent.gameObject;
            path = "/" + obj.name + path;
        }
        return path;
    }

    public static Transform FindChild(Transform _t, string name)
    {
        Transform target = null;
        foreach (Transform t in _t)
        {
            if (t.name.Trim().Equals(name))
                target = t;
            if (t.childCount > 0)
                target = FindChild(t, name);
            if (target != null)
                break;
        }

        return target;
    }

    protected override string GetPose(int girlIndex) => GetActiveState()?.name;

    protected override bool IsIdle(int girlIndex)
    {
        string pose = GetPose(girlIndex);
        return idlePoseNames.Any(pose.Contains);
    }

    protected override IEnumerator UntilReady()
    {
        yield return new WaitForSecondsRealtime(5f);
    }
}

internal class Com3d2ButtplugVibeController : Com3d2ButtplugController
{
    protected override IEnumerator Run(int girlIndex, Bone bone) =>
        RunVibratorLoop(girlIndex, bone);
}

internal class Com3d2ButtplugStrokerController : Com3d2ButtplugController
{
    protected override IEnumerator Run(int girlIndex, Bone bone) =>
        RunStrokerLoop(girlIndex, bone);
}

}`

ghost commented 2 years ago

I'm on 2.14.0 and got the same error messages. It turns out that using Maid Fiddler to unlock yotogi poses can cause the issue (amongst many other unrelated ones), as it worked swimmingly on an untampered save. To produce the log file attached below, I queued up a 'first time insertion' missionary pose and an illegal 騎乗位 pose with a virgin maid and then started yotogi. Interestingly, even though the first pose was legal, it still threw these errors. I'll try cheating again with a bit more reservation to see if there are any further issues. LogOutput.log

RPKU commented 2 years ago

Now I think this may cause by different types of body mod in COM3D2.

Sauceke commented 2 years ago

@RPKU Rebuilt with your proposed changes, please check it against your version. LoveMachine_for_Custom_Order_Maid_3D_2.zip chinko_nub is not a suitable male bone, it needs to be further towards the base of the penis (this is why I usually choose the scrotum).

RPKU commented 2 years ago

This version works fine for me. In my opinion, COM3D2 has many different type of body, it is better to use recursion to find gameobject of the body.

Sauceke commented 2 years ago

@RPKU The stroke syncing is out of phase in several animations, including tekoki (handjob) and seijyoui (missionary). Did you encounter the same issues in your version?

Sauceke commented 2 years ago

@YuriseXYZ I'd be interested in your input on the above change as well. Please try to keep it to vanilla gameplay though. Supporting just the base game has proved to be enough of a hassle in itself for this game.

RPKU commented 2 years ago

Yes, in the missionary the speed of the stroke is not stable and out of syncing.

Sauceke commented 2 years ago

@RPKU Please open a pull request with your changes, and I will make the further changes necessary to fix the issue. Just paste the changed file here, click "Propose changes", and make sure the "Allow edits by maintainers" box is checked.

ghost commented 2 years ago

@Sauceke At slow speeds, it's like there's high latency (see paizuri below), while at faster speeds, it looks like it's moving opposite to what's on screen. Tested with the Keon and OSR2 (TCode 3.0 or whatever in the logs). Kijoui (cowgirl): the stroker moves upwards when the heroine moves downwards and vice versa. Not sure if it's perfectly reciprocating though. Same goes for grinding variants, Footjob: in addition to the general out of phase behavior, for every 3 - 5 strokes, there's a random short stroke that occurs in the top half of the stroker (i.e. the stroker goes from 100% to ~95-70% and then back to 100% quickly for no justifiable reason). Doggy: stroking pauses for ~1-2 seconds after a certain number of strokes, where generally the faster the stroke, the more strokes there are before a pause. Paizuri: At the slowest speed, the stroker moves down when the breasts do, but the breasts move up before the stroker does. At faster speeds, we can observe that reciprocal movement as with the other cases. Furthermore, I feel obligated to report that the maid who volunteered had a flat chest. It was great. Onahokoki: similar case to paizuri. Face sitting: similar to cowgirl.

LogOutput.log The earlier exceptions thrown in the log file came from clicking the 'Test Slow' button whilst in the maid admin menu or something like that, if you were wondering. It didn't kick me out of the game, so no big deal.

I hope that helps, and I'm down for some more testing if you need it. 頑張れ!

Sauceke commented 2 years ago

@YuriseXYZ But most importantly, you're no longer getting errors about bones not being found. Most of the out of sync behavior you've documented here can be chalked up to RP's patch using the tip of the penis instead of the base as LoveMachine.Core expects, which of course turned most things upside down. The pauses and jumps are probably artifacts of COM3D2 rewinding the animation every few seconds (which makes absolutely no sense and gave me a lot of headache). I think I've already done what I can about that. For now, I'll just wait for @RPKU to upload the above patch in a pull request (or entrust me to do it). Then I can fix all the out of sync problems, simplify the code, merge and call it a day. Thanks for all the tests, both of you, and will definitely ask you to do a final verification before rolling out 2.9.

RPKU commented 2 years ago

I have complete the pull request. I keeps the path of the components this time.

Sauceke commented 2 years ago

@RPKU I don't see any open pull requests. Did you click both "Propose changes" and "Create pull request" after uploading the file?

Sauceke commented 2 years ago

Never mind, I found your branch and opened a PR from it. This will preserve authorship information.

Sauceke commented 2 years ago

Did some refactoring and added threesome support. You can switch between first and second maid in Plugin Settings. Also made the optimization suggested by @RPKU. Should still work in older versions, please check. LoveMachine_for_Custom_Order_Maid_3D_2.zip

ghost commented 2 years ago

@Sauceke @RPKU Good work guys. Here's what I've got after testing on version 2.14.0:

asikoki_1_m and asikoki_3_m don't move the stroker at all. (Follow up tests show something different later in the report) asikoki_2_m is out of phase (it's as if the tip was taken as the male bone).

[Info   :LoveMachine] Calibration for pose asikoki_1_m.anm.girl0.Auto completed. 722 frames inspected. Leading bone: RightFoot, result: {"Phase":0.9074326,"Frequency":1,"Crest":0.340313,"Trough":0.2500773}.
[Info   :LoveMachine] Calibration for pose asikoki_2_m.anm.girl0.Auto completed. 360 frames inspected. Leading bone: RightFoot, result: {"Phase":0.2210693,"Frequency":9,"Crest":0.295624,"Trough":0.2048035}.
[Info   :LoveMachine] Calibration for pose asikoki_3_m.anm.girl0.Auto completed. 720 frames inspected. Leading bone: LeftFoot, result: {"Phase":0.8891449,"Frequency":1,"Crest":0.288371,"Trough":0.2381198}.

The idle poses are being analyzed if you stay idle long enough. I'm not sure what's going on with IsIdle().

[Info   :LoveMachine] Calibration for pose asikoki_taiki_m.anm.girl0.Auto completed. 121 frames inspected. Leading bone: RightFoot, result: {"Phase":0.6090393,"Frequency":1,"Crest":0.2911353,"Trough":0.2880665}.
[Info   :LoveMachine] Calibration for pose om_tekoki_taiki_m.anm.girl0.Auto completed. 120 frames inspected. Leading bone: RightHand, result: {"Phase":0.05284119,"Frequency":1,"Crest":0.7861813,"Trough":0.2309004}.
[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_shaseigo_naka_m.anm - Queued Clone.girl0.Auto completed. 121 frames inspected. Leading bone: Vagina, result: {"Phase":0.2955933,"Frequency":1,"Crest":0.07061899,"Trough":0.06351763}.

[Warning:LoveMachine] Pose sixnine_uiui_shasei_kuti_m_once_.anm.girl0.Auto interrupted; canceling calibration.
[Warning:LoveMachine] Pose sixnine_uiui_shaseigo_kuti_m.anm - Queued Clone.girl0.Auto interrupted; canceling calibration.

For these three cowgirl-while-kissing poses, the stroker appears to alternate between two speeds, with one of om_taimenkijyoui_kiss_1* generating no movement at all.

[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_kiss_3_m.anm.girl0.Auto completed. 29 frames inspected. Leading bone: Vagina, result: {"Phase":0.3831787,"Frequency":1,"Crest":0.08547366,"Trough":0.03329957}.
[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_kiss_3a01_m.anm.girl0.Auto completed. 509 frames inspected. Leading bone: Vagina, result: {"Phase":0.07659912,"Frequency":9,"Crest":0.08339725,"Trough":0.03097988}.

[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_kiss_1_m.anm.girl0.Auto completed. 110 frames inspected. Leading bone: Vagina, result: {"Phase":0.9929199,"Frequency":1,"Crest":0.09089218,"Trough":0.06246616}.
[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_kiss_1a01_m.anm.girl0.Auto completed. 680 frames inspected. Leading bone: Vagina, result: {"Phase":0.998291,"Frequency":6,"Crest":0.09092207,"Trough":0.06246004}.

[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_kiss_2_m.anm.girl0.Auto completed. 61 frames inspected. Leading bone: Vagina, result: {"Phase":0.3422852,"Frequency":1,"Crest":0.1082027,"Trough":0.06193208}.
[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_kiss_2a01_m.anm.girl0.Auto completed. 532 frames inspected. Leading bone: Vagina, result: {"Phase":0.3711548,"Frequency":9,"Crest":0.1086724,"Trough":0.06134932}.

The cowgirl 'estrus' (the bottom-most pose button that disappears when you click it) pose at speed 3 creates stroker movement that is too slow compared to the actual speed of the pose on screen.

The second instance tested was slower than the first.

[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_hatu_3_m.anm.girl0.Auto completed. 679 frames inspected. Leading bone: Vagina, result: {"Phase":0.2330322,"Frequency":9,"Crest":0.1440688,"Trough":0.081284}.

[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_hatu_3_m.anm.girl0.Auto completed. 686 frames inspected. Leading bone: Vagina, result: {"Phase":0.2886963,"Frequency":2,"Crest":0.1429554,"Trough":0.07397966}.

asikoki_1_m (the same one discussed initially) was tested again. It showed extremely slow stroker output, instead of the lack of movement observed earlier.

[Info   :LoveMachine] Calibration for pose asikoki_1_m.anm.girl0.Auto completed. 205 frames inspected. Leading bone: LeftFoot, result: {"Phase":0.2676392,"Frequency":2,"Crest":0.2748908,"Trough":0.2191452}.

After a third asikoki_1_m run, the stroker moved at a reasonable speed, but out of phase as with asikoki_2_m discussed at the start.

[Info   :LoveMachine] Calibration for pose asikoki_1_m.anm.girl0.Auto completed. 702 frames inspected. Leading bone: LeftFoot, result: {"Phase":0.2668457,"Frequency":7,"Crest":0.3283614,"Trough":0.2495268}.

asikoki_tati_fumi_m produces stroker output that's too slow for what's on screen.

[Info   :LoveMachine] Calibration for pose asikoki_tati_fumi_m.anm.girl0.Auto completed. 105 frames inspected. Leading bone: RightFoot, result: {"Phase":0.1394653,"Frequency":1,"Crest":0.5126659,"Trough":0.237364}

The error below has occurred in several instances. I wasn't sure about the first instance, but for the second instance, it happened whilst changing yotogi poses (e.g. when you change from a cowgirl to footjob). The third occurred after changing from asikoki_1_m to asikoki_2_m. It happened sporadically, and may not have an effect on normal operation.

[Error  :LoveMachine] Coroutine failed with exception: System.ArgumentException: Value does not fall within the expected range.
  at LoveMachine.COM3D2.Com3d2ButtplugController.IsIdle (Int32 girlIndex) [0x00000] in <filename unknown>:0
  at LoveMachine.Core.ButtplugController+<RunStrokerLoop>d__19.MoveNext () [0x00000] in <filename unknown>:0
  at LoveMachine.Core.CoroutineHandler.TryNext (IEnumerator coroutine, Boolean suppressExceptions) [0x00000] in <filename unknown>:0
[Error  : Unity Log] ArgumentException: Value does not fall within the expected range.
Stack trace:
LoveMachine.COM3D2.Com3d2ButtplugController.IsIdle (Int32 girlIndex)
LoveMachine.Core.ButtplugController+<RunStrokerLoop>d__19.MoveNext ()
LoveMachine.Core.CoroutineHandler.TryNext (IEnumerator coroutine, Boolean suppressExceptions)

om_fera_1_name_m is out of phase, mainly because RightBreast is being used instead of mouth.

[Info   :LoveMachine] Calibration for pose om_fera_1_name_m.anm.girl0.Auto completed. 121 frames inspected. Leading bone: RightBreast, result: {"Phase":0.3342285,"Frequency":1,"Crest":0.2155319,"Trough":0.1548602}.

sixnine_2a01_m also does the random pausing after several in-sync strokes. Probably alternating between a speed that's too slow and the normal one.

[Warning:LoveMachine] Pose .girl0.Auto interrupted; canceling calibration.
[Warning:LoveMachine] Pose sixnine_taiki_m.anm.girl0.Auto interrupted; canceling calibration.
[Info   :LoveMachine] Calibration for pose sixnine_2_m.anm.girl0.Auto completed. 61 frames inspected. Leading bone: Mouth, result: {"Phase":0.4283447,"Frequency":1,"Crest":0.2289904,"Trough":0.1526965}.
[Info   :LoveMachine] Starting monitoring loop in controller Com3d2ButtplugVibeController for girl index 0 and bone Auto.
[Info   :LoveMachine] Starting monitoring loop in controller Com3d2ButtplugVibeController for girl index 0 and bone Vagina.
.
.
.
[Info   :LoveMachine] Starting monitoring loop in controller Com3d2ButtplugStrokerController for girl index 0 and bone LeftFoot.
[Info   :LoveMachine] Calibration for pose sixnine_2a01_m.anm.girl0.Auto completed. 536 frames inspected. Leading bone: Mouth, result: {"Phase":0.1584473,"Frequency":9,"Crest":0.2315671,"Trough":0.1520775}.

Same goes for these. Not sure why there were interruptions.

[Warning:LoveMachine] Pose sixnine_1_m.anm.girl0.Auto interrupted; canceling calibration.
[Warning:LoveMachine] Pose sixnine_1a01_m.anm.girl0.Auto interrupted; canceling calibration.
[Info   :LoveMachine] Calibration for pose sixnine_1_m.anm.girl0.Auto completed. 121 frames inspected. Leading bone: Mouth, result: {"Phase":0.3479004,"Frequency":1,"Crest":0.2271008,"Trough":0.1636668}.
[Info   :LoveMachine] Calibration for pose sixnine_1a01_m.anm.girl0.Auto completed. 715 frames inspected. Leading bone: Mouth, result: {"Phase":0.223877,"Frequency":6,"Crest":0.2307767,"Trough":0.1634868}.

[Info   :LoveMachine] Calibration for pose sixnine_3_m.anm.girl0.Auto completed. 26 frames inspected. Leading bone: Mouth, result: {"Phase":0.4000244,"Frequency":1,"Crest":0.2275862,"Trough":0.1344993}.
[Info   :LoveMachine] Calibration for pose sixnine_3a01_m.anm.girl0.Auto completed. 538 frames inspected. Leading bone: Mouth, result: {"Phase":0.6895752,"Frequency":1,"Crest":0.2292207,"Trough":0.1337158}.

om_kakae_seijyoui* is out of phase like the other cases. We can also see more inconsistent naming of the animations.

[Info   :LoveMachine] Calibration for pose om_kakae_seijyoui_2_m.anm.girl0.Auto completed. 57 frames inspected. Leading bone: Vagina, result: {"Phase":0.2077637,"Frequency":1,"Crest":0.1602166,"Trough":0.02190329}.
[Info   :LoveMachine] Calibration for pose om_kakae_seijyoui_1_m.anm.girl0.Auto completed. 115 frames inspected. Leading bone: Vagina, result: {"Phase":0.1899414,"Frequency":1,"Crest":0.1387072,"Trough":0.03183372}.
[Info   :LoveMachine] Calibration for pose om_kakae_seijyouia_momi_2_m.anm.girl0.Auto completed. 57 frames inspected. Leading bone: Vagina, result: {"Phase":0.1101074,"Frequency":1,"Crest":0.1789427,"Trough":0.05336113}.

[Info   :LoveMachine] Calibration for pose om_kakae_seijyoui_3_m.anm.girl0.Auto completed. 26 frames inspected. Leading bone: Vagina, result: {"Phase":0.2216797,"Frequency":1,"Crest":0.144603,"Trough":0.05076979}.

Unrelated, but if you left click in the BepInEx console (which freezes the game, expected behavior), the strokers still move, but connecting a new device (vibe or stroker) causes a disconnection from Intiface. The Intiface server also needs to be restarted to be able to reconnect, as clicking the connect button in the Plugin settings menu without doing so doesn't work, despite printing [Info :LoveMachine] Connecting to Intiface server at ws://localhost:12345/ in console. Doesn't matter too much.

Can't be bothered organizing these reports. I haven't tested much else, but handjobs seems to work fine. We can probably solve that animation rewinding problem @Sauceke cited by taking the good animation out of the *_1* and *_1a01* pairs and ignoring the dud, whichever one that is. Unless it was related to something else. I'm not sure if the issue is limited to COM3D2, but we do see the wrong leading bone being picked in some of the footjob and blowjob cases. There are also a bunch of unexplained issues like with asikoki_tati_fumi_m having the correct leading bone, but not matching up to the motion.

In other news, 3P cowgirl works as expected. Haven't tested the other 3P poses.

I haven't tested on CM3D2, but the version of my copy is higher than 1.55 anyway if that matters. I'll leave testing on that for @RPKU.

This is absolutely bonkers. Good luck, and ping me if you've got something to test.

Sauceke commented 2 years ago

@YuriseXYZ Thanks for the extensive testing! This time I made sure to always use the shortest (in time) animation state as clock. I also added a longer waiting time before starting the analysis, to wait through the blending between animations. LoveMachine_for_Custom_Order_Maid_3D_2.zip Hopefully this will solve the majority of the bugs you mentioned. If it doesn't, please let me know.

ghost commented 2 years ago

@Sauceke おつ!

The fix you made for the rewinding animation issues has a bug where it still pauses the animation, and also doesn't seem to affect the rewinding problem in some cases, where we instead see behavior similar to the last patch. More details below. I still logged matters of incorrect leading bones, but I'm pretty sure you haven't worked on that yet, so no biggie.

There appears to be multiple calibrations occurring sequentially for a single pose's idle animation. I haven't seen this occur for non-idle poses so far.

[Info   :LoveMachine] Calibration for pose paizuri_taiki_m.anm.girl0.Auto completed. 114 frames inspected. Leading bone: Mouth, result: {"Phase":0.9039307,"Frequency":1,"Crest":0.3752364,"Trough":0.3693}.
[Info   :LoveMachine] Calibration for pose paizuri_taiki_m.anm.girl0.Auto completed. 114 frames inspected. Leading bone: Mouth, result: {"Phase":0.9039307,"Frequency":1,"Crest":0.3752365,"Trough":0.3693}.
[Info   :LoveMachine] Calibration for pose paizuri_taiki_m.anm.girl0.Auto completed. 114 frames inspected. Leading bone: Mouth, result: {"Phase":0.9039307,"Frequency":1,"Crest":0.3752365,"Trough":0.3693}.

om_fera_1_name_m and om_fera_1_name_ura_m are out of phase due to incorrect leading bone detection.

[Info   :LoveMachine] Calibration for pose om_fera_1_name_m.anm.girl0.Auto completed. 48 frames inspected. Leading bone: RightBreast, result: {"Phase":0.3392029,"Frequency":1,"Crest":0.1873513,"Trough":0.133907}.

[Info   :LoveMachine] Calibration for pose om_fera_1_name_ura_m.anm.girl0.Auto completed. 50 frames inspected. Leading bone: LeftBreast, result: {"Phase":0.4978333,"Frequency":1,"Crest":0.2454941,"Trough":0.1034414}.

sixnine_1* is in phase when it moves, but it doesn't start right away when starting the pose, and the stroker still alternates between stroking and not moving, spending more time paused compared to moving in every interval.

[Warning:LoveMachine] Pose sixnine_1_m.anm.girl0.Auto interrupted; canceling calibration.
[Warning:LoveMachine] Pose sixnine_1a01_m.anm.girl0.Auto interrupted; canceling calibration.
[Info   :LoveMachine] Calibration for pose sixnine_1_m.anm.girl0.Auto completed. 120 frames inspected. Leading bone: Mouth, result: {"Phase":0.3500242,"Frequency":1,"Crest":0.2272081,"Trough":0.1642148}.
[Warning:LoveMachine] Pose sixnine_1a01_m.anm.girl0.Auto interrupted; canceling calibration.
[Warning:LoveMachine] Pose sixnine_1a01_m.anm.girl0.Auto interrupted; canceling calibration.
.
.
.
[Warning:LoveMachine] Pose sixnine_1a01_m.anm.girl0.Auto interrupted; canceling calibration.
[Warning:LoveMachine] Pose sixnine_1a01_m.anm.girl0.Auto interrupted; canceling calibration.

sixnine_2* shows start and stop behavior similar to that of the previous patch, the pauses are shorter in length here compared to sixnine_1*. We don't observe the calibration cancels here.

[Info   :LoveMachine] Calibration for pose sixnine_2_m.anm.girl0.Auto completed. 58 frames inspected. Leading bone: Mouth, result: {"Phase":0.4227905,"Frequency":1,"Crest":0.2278362,"Trough":0.1516959}.
[Info   :LoveMachine] Calibration for pose sixnine_2a01_m.anm.girl0.Auto completed. 531 frames inspected. Leading bone: Mouth, result: {"Phase":0.1585464,"Frequency":9,"Crest":0.2302949,"Trough":0.1510706}.

Same thing for sixnine_3*, except it's alternating between a super slow speed and the correct in phase speed. In this case, it started off with the super slow speed first.

[Info   :LoveMachine] Calibration for pose sixnine_3_m.anm.girl0.Auto completed. 31 frames inspected. Leading bone: Mouth, result: {"Phase":0.4122162,"Frequency":1,"Crest":0.2247633,"Trough":0.1327693}.
[Info   :LoveMachine] Calibration for pose sixnine_3a01_m.anm.girl0.Auto completed. 530 frames inspected. Leading bone: Mouth, result: {"Phase":0.6898193,"Frequency":1,"Crest":0.2272615,"Trough":0.1321541}.

In this instance, it started off correct, then super slow. This shows that the order in which is moves or stops when the animation starts doesn't matter.

[Info   :LoveMachine] Calibration for pose sixnine_3_m.anm.girl0.Auto completed. 31 frames inspected. Leading bone: Mouth, result: {"Phase":0.4122162,"Frequency":1,"Crest":0.2247633,"Trough":0.1327693}.
[Info   :LoveMachine] Calibration for pose sixnine_3a01_m.anm.girl0.Auto completed. 530 frames inspected. Leading bone: Mouth, result: {"Phase":0.6898193,"Frequency":1,"Crest":0.2272615,"Trough":0.1321541}.

asikoki_2_m is still out of phase, despite the correct leading bone being used.

[Info   :LoveMachine] Calibration for pose asikoki_2_m.anm.girl0.Auto completed. 357 frames inspected. Leading bone: RightFoot, result: {"Phase":0.2210083,"Frequency":9,"Crest":0.3257839,"Trough":0.2331068}.
[Info   :LoveMachine] Calibration for pose asikoki_2_m.anm.girl0.Auto completed. 357 frames inspected. Leading bone: RightFoot, result: {"Phase":0.2210083,"Frequency":9,"Crest":0.3257839,"Trough":0.2331068}.

asikoki_1_m is out of phase, the LeftFoot doesn't move all the time in the animation, the right foot does. Not sure if we can do much about this.

[Info   :LoveMachine] Calibration for pose asikoki_1_m.anm.girl0.Auto completed. 719 frames inspected. Leading bone: LeftFoot, result: {"Phase":0.2670593,"Frequency":7,"Crest":0.3283624,"Trough":0.2495214}.

asikoki_3_m was so slow that I thought that the stroker wasn't moving.

[Info   :LoveMachine] Calibration for pose asikoki_3_m.anm.girl0.Auto completed. 717 frames inspected. Leading bone: LeftFoot, result: {"Phase":0.8886414,"Frequency":1,"Crest":0.326615,"Trough":0.2712492}.

om_taimenkijyoui_hatu_3_m is still super slow. The non _hatu_ version worked perfectly though. (As a reminder, hatu animations are the ones available for some poses in estrus mode.)

[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_3_m.anm.girl0.Auto completed. 30 frames inspected. Leading bone: Vagina, result: {"Phase":0.3721619,"Frequency":1,"Crest":0.1434728,"Trough":0.07302219}.

[Info   :LoveMachine] Calibration for pose om_taimenkijyoui_hatu_3_m.anm.girl0.Auto completed. 705 frames inspected. Leading bone: Vagina, result: {"Phase":0.1774292,"Frequency":1,"Crest":0.1429431,"Trough":0.07392883}.

There does not appear to be a trend for whether we have pausing due to cancelling or super slow movement as observed in the previous patch.

om_kouhaii_momi_1* is some hugging doggy whilst rubbing breasts.

[Warning:LoveMachine] Pose om_kouhaii_momi_1_m.anm.girl0.Auto interrupted; canceling calibration.
[Warning:LoveMachine] Pose om_kouhaii_momi_1a01_m.anm.girl0.Auto interrupted; canceling calibration.
[Info   :LoveMachine] Calibration for pose om_kouhaii_momi_1_m.anm.girl0.Auto completed. 101 frames inspected. Leading bone: Vagina, result: {"Phase":0.2523193,"Frequency":1,"Crest":0.1412193,"Trough":0.049845}.
[Warning:LoveMachine] Pose om_kouhaii_momi_1a01_m.anm.girl0.Auto interrupted; canceling calibration.
[Warning:LoveMachine] Pose om_kouhaii_momi_1a01_m.anm.girl0.Auto interrupted; canceling calibration.
.
.
.
[Warning:LoveMachine] Pose om_kouhaii_momi_1a01_m.anm.girl0.Auto interrupted; canceling calibration.
[Warning:LoveMachine] Pose om_kouhaii_momi_1a01_m.anm.girl1.Auto interrupted; canceling calibration.

The issues seen in the previous patch still persist. I still don't know why animations such as om_taimenkijyoui_hatu_3_m have such a long frame inspection time that produces slow output compared to the actual action on screen.

Feel free to ping me if you need some more testing / logging.

Sauceke commented 2 years ago

@YuriseXYZ Thank you!

As for asikoki_2_m, I reassigned the foot bones from the calves to the toes, so this should take care of that (though the first few seconds are still out of sync for god knows what reason): LoveMachine_for_Custom_Order_Maid_3D_2.zip

asikoki_3_m being slow is not surprising, this is what its plot looks like: soffice bin_XeJvdaps33

Now, LoveMachine does a basic Fourier analysis on these graphs to figure out how many strokes there are in a cycle, but that does sweet FA to a graph that looks like this. Even finding the exact number of strokes won't help with this one, because the strokes aren't evenly timed. I'm not saying it's impossible to reenact movements like this, in fact I've already done some groundwork in this direction, but it is WAY out of scope for this PR. Thanks for digging it up anyway, because now I have one more reason to add more granular stroke syncing. The same goes for asikoki_1_m by the way. Haven't looked at om_taimenkijyoui_hatu_3_m yet, but I'm pretty sure it's also something similar. Or is it not?

I can confirm the behavior with 69, and it's fascinating. The calibration always gets interrupted, so there should be no movement at all. What the actual fuck. Well, on the bright side, if the player uses the plugin in its intended way (VR), he will never find out that the strokes don't match up. For this reason, I think we can ignore this one for now.

For any positions where the wrong leading bone is being picked, the easiest workaround is just to select the correct bone manually in Plugin Settings. Ideally the plugin should select the correct leading bone most of the time, but it's not infallible, and probably never can be.

Multiple calibrations should NEVER occur on the same animation on the same girl. I'll open a separate issue for this since it's not critical, but definitely needs to be looked into.

All in all, it seems to me most of the positions are synced correctly with these fixes. @RPKU , @YuriseXYZ, if you still don't see any hard errors in your own version, I'm inclined to call this PR done and dusted. As before, I'd appreciate any feedback.

ghost commented 2 years ago

@Sauceke I'll do another once over in the next couple of days. I'm pretty sure om_taimenkijyoui_hatu_3_m is something similar, so it should be fine. I completely forgot about setting the bone manually, thanks for that.

ghost commented 2 years ago

@Sauceke Just tested it on my usual version. Indeed, the positions that I've tested are synced nicely except for the ones with issues that we've already discussed. Either way, the missing bone problem is solved on my version. Nice work.

Sauceke commented 2 years ago

@RPKU I'm assuming this build works fine in 1.55 too? I changed two gameobject paths, I don't think it should break anything but who knows.

Sauceke commented 2 years ago

@RPKU Thank you very much for your contribution. Please reopen this if issues with 1.55 arise again. @YuriseXYZ Thank you for the thorough testing.