├── Better Penetration Studio Instructions.pdf
├── Better Penetration Frequently Asked Questions.pdf
├── Core_BetterPenetration
├── Constants.cs
├── ControllerOptions.cs
├── ItemColliderInfo.cs
├── CollisionPoint.cs
├── Core_BetterPenetration.shproj
├── CollisionPoints.cs
├── DanPoint.cs
├── Core_BetterPenetration.projitems
├── DanOptions.cs
├── MathHelpers.cs
├── DanPoints.cs
├── CollisionOptions.cs
├── Tools.cs
├── TwistedPlane.cs
├── BoneNames.cs
├── Studio_BetterPenetration.cs
├── CoreGame.cs
└── CollisionAgent.cs
├── AI_BetterPenetration
└── AI_BetterPenetration.csproj
├── HS2_BetterPenetration
└── HS2_BetterPenetration.csproj
├── KKS_BetterPenetration
├── KKS_BetterPenetration.csproj
└── KKS_BetterPenetration.cs
├── KK_BetterPenetration
├── KK_BetterPenetration.csproj
└── KK_BetterPenetration.cs
├── AI_Studio_BetterPenetration
└── AI_Studio_BetterPenetration.csproj
├── HS2_Studio_BetterPenetration
└── HS2_Studio_BetterPenetration.csproj
├── KKS_Studio_BetterPenetration
└── KKS_Studio_BetterPenetration.csproj
├── KK_Studio_BetterPenetration
└── KK_Studio_BetterPenetration.csproj
├── nuget.config
├── README.md
├── Directory.Build.props
├── .gitignore
└── BetterPenetration.sln
/Better Penetration Studio Instructions.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IllusionMods/BetterPenetration/HEAD/Better Penetration Studio Instructions.pdf
--------------------------------------------------------------------------------
/Better Penetration Frequently Asked Questions.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IllusionMods/BetterPenetration/HEAD/Better Penetration Frequently Asked Questions.pdf
--------------------------------------------------------------------------------
/Core_BetterPenetration/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace Core_BetterPenetration
2 | {
3 | internal class Constants
4 | {
5 | #if KK || KKS || EC
6 | public const string PluginVersion = "4.5.5.4";
7 | #else
8 | public const string PluginVersion = "5.0.1.4";
9 | #endif
10 | }
11 | }
--------------------------------------------------------------------------------
/AI_BetterPenetration/AI_BetterPenetration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net46
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/HS2_BetterPenetration/HS2_BetterPenetration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net46
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/KKS_BetterPenetration/KKS_BetterPenetration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net46
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/KK_BetterPenetration/KK_BetterPenetration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net35
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/AI_Studio_BetterPenetration/AI_Studio_BetterPenetration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net46
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/HS2_Studio_BetterPenetration/HS2_Studio_BetterPenetration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net46
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/KKS_Studio_BetterPenetration/KKS_Studio_BetterPenetration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net46
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/KK_Studio_BetterPenetration/KK_Studio_BetterPenetration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net35
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/ControllerOptions.cs:
--------------------------------------------------------------------------------
1 | #if Studio
2 | namespace Core_BetterPenetration
3 | {
4 | class ControllerOptions
5 | {
6 | internal enum AutoTarget
7 | {
8 | Off,
9 | Vaginal,
10 | Anal,
11 | Oral
12 | }
13 |
14 | internal AutoTarget danAutoTarget;
15 |
16 | public ControllerOptions(AutoTarget danAutoTarget)
17 | {
18 | this.danAutoTarget = danAutoTarget;
19 | }
20 | }
21 | }
22 | #endif
23 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/ItemColliderInfo.cs:
--------------------------------------------------------------------------------
1 | #if AI || HS2
2 | using System.Collections.Generic;
3 |
4 | namespace Core_BetterPenetration
5 | {
6 | class ItemColliderInfo
7 | {
8 | internal List animationNames;
9 | internal List itemBones;
10 | internal DynamicBoneColliderBase.Direction direction;
11 | internal float colliderRadius;
12 | internal float colliderHeight;
13 |
14 | public ItemColliderInfo(List animationNames, List itemBones, DynamicBoneColliderBase.Direction direction, float colliderRadius, float colliderHeight)
15 | {
16 | this.animationNames = animationNames;
17 | this.itemBones = itemBones;
18 | this.direction = direction;
19 | this.colliderRadius = colliderRadius;
20 | this.colliderHeight = colliderHeight;
21 | }
22 | }
23 | }
24 | #endif
--------------------------------------------------------------------------------
/Core_BetterPenetration/CollisionPoint.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace Core_BetterPenetration
4 | {
5 | class CollisionPoint
6 | {
7 | internal Transform transform;
8 | internal CollisionPointInfo info;
9 |
10 | public CollisionPoint(Transform point, CollisionPointInfo collisionInfo)
11 | {
12 | transform = point;
13 | info = collisionInfo;
14 | }
15 |
16 | public void UpdateCollisionInfo(CollisionPointInfo collisionInfo)
17 | {
18 | info = collisionInfo;
19 | }
20 |
21 | }
22 |
23 | class CollisionPointInfo
24 | {
25 | internal string name;
26 | internal float offset;
27 | internal bool inward;
28 |
29 | public CollisionPointInfo(string transformName, float offsetValue, bool inwardDirection)
30 | {
31 | name = transformName;
32 | offset = offsetValue;
33 | inward = inwardDirection;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/Core_BetterPenetration.shproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ccd25b62-1040-4727-a0b5-78335fcf9f01
5 | 14.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/CollisionPoints.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEngine;
3 |
4 | namespace Core_BetterPenetration
5 | {
6 | class CollisionPoints
7 | {
8 | internal List frontCollisionPoints;
9 | internal List backCollisionPoints;
10 |
11 | public CollisionPoints()
12 | {
13 | frontCollisionPoints = new List();
14 | backCollisionPoints = new List();
15 | }
16 |
17 | public CollisionPoints(List frontPoints, List backPoints)
18 | {
19 | frontCollisionPoints = frontPoints;
20 | backCollisionPoints = backPoints;
21 | }
22 |
23 | public void UpdateCollisionOptions(CollisionOptions options)
24 | {
25 | for (var point = 0; point < frontCollisionPoints.Count && point < options.frontCollisionInfo.Count; point++)
26 | frontCollisionPoints[point].UpdateCollisionInfo(options.frontCollisionInfo[point]);
27 |
28 | for (var point = 0; point < frontCollisionPoints.Count && point < options.frontCollisionInfo.Count; point++)
29 | backCollisionPoints[point].UpdateCollisionInfo(options.backCollisonInfo[point]);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/DanPoint.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace Core_BetterPenetration
4 | {
5 | class DanPoint
6 | {
7 | internal Transform transform;
8 | internal Vector3 defaultLocalPosition;
9 | internal Vector3 defaultLocalScale;
10 | internal Vector3 defaultLossyScale;
11 |
12 | public DanPoint(Transform point)
13 | {
14 | this.transform = point;
15 | this.defaultLocalPosition = point.localPosition;
16 | this.defaultLocalScale = point.localScale;
17 | this.defaultLossyScale = point.lossyScale;
18 | }
19 |
20 | internal void ResetDanPoint()
21 | {
22 | if (transform == null)
23 | return;
24 |
25 | transform.localPosition = defaultLocalPosition;
26 | transform.localScale = defaultLocalScale;
27 | }
28 |
29 | internal void SetDanPointRotation(Quaternion rotation)
30 | {
31 | if (transform == null)
32 | return;
33 |
34 | transform.rotation = rotation;
35 | }
36 |
37 | internal Quaternion GetDanPointRotation()
38 | {
39 | if (transform == null)
40 | return Quaternion.identity;
41 |
42 | return transform.rotation;
43 | }
44 |
45 | internal void ScaleDanGirth(float girthScale)
46 | {
47 | if (transform == null)
48 | return;
49 |
50 | transform.localScale = new Vector3(defaultLocalScale.x * girthScale, defaultLocalScale.y * girthScale, transform.localScale.z);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/Core_BetterPenetration.projitems:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
5 | true
6 | ccd25b62-1040-4727-a0b5-78335fcf9f01
7 |
8 |
9 | Core_BetterPenetration
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BetterPenetration
2 | This plugin seeks to improve HScenes in AI Shoujo, Honey Select 2, Koikatsu, and Koikatsu Sunshine by making penetration look a bit more realistic. It also adds some additional features to overall improve the HScene experience.
3 |
4 | # Features
5 | Replaces the default "telescoping" behavior by allowing the head to move past the point of penetration.
6 | After the penis has passed the point of penetration, it will bend to avoid clipping.
7 | You can allow the penis to begin to squish after it has penetrated by a specified percentage
8 | Works for vaginal, anal, and oral penetraion.
9 | Maintain proper rotation of the penis, no more spinning shafts during certain positions.
10 | Offset options to further tweak things when using characters with abnormal body shapes.
11 | Supports multiple male and multiple female positions.
12 | Includes several male and female uncensors designed specifically for BetterPenetration, the plugin works best with those uncensors.
13 | Female uncensors will spread open when penetrated. They also include individual toe bones that can be repositioned in studio.
14 | Penis uncensors have additional bones which allows them to bend, so they can penetrate at the correct point and still not clip.
15 | Ball uncensors have additional dynamic bones which are affected by gravity and will collide with the guy and the girl, drastically improving the way they look.
16 | Adds a push/pull effect to the mouth (all games) and vagina (HS2/AIS). This effect pushes the mouth/vagina inward during insertion and pulls it outward during extraction.
17 | (HS2/AIS) Adds colliders to all characters fingers and other game objects so the vagina spreads correctly when using those objects.
18 |
19 | # Installation
20 | Requires BepInEx
21 | Copy the dll to your install directory /BepInEx/plugins
22 |
23 | # For early releases and to offer support visit:
24 | https://www.patreon.com/Animal42069
25 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/DanOptions.cs:
--------------------------------------------------------------------------------
1 | namespace Core_BetterPenetration
2 | {
3 | class DanOptions
4 | {
5 | public float danLengthSquish;
6 | public float danGirthSquish;
7 | public float squishThreshold;
8 | public float danRadiusScale;
9 | public float danLengthScale;
10 |
11 | public bool simplifyVaginal;
12 | public bool simplifyOral;
13 | public bool simplifyAnal;
14 | public bool squishOralGirth;
15 | public bool rotateTamaWithShaft;
16 |
17 | public bool limitCorrection;
18 | public float maxCorrection;
19 |
20 | public DanOptions(float danRadiusScale, float danLengthScale,
21 | float danLengthSquish, float danGirthSquish, float squishThreshold, bool squishOralGirth,
22 | bool simplifyVaginal, bool simplifyOral, bool simplifyAnal, bool rotateTamaWithShaft,
23 | bool limitCorrection, float maxCorrection)
24 | {
25 | this.danLengthSquish = danLengthSquish;
26 | this.danGirthSquish = danGirthSquish;
27 | this.squishThreshold = squishThreshold;
28 | this.simplifyVaginal = simplifyVaginal;
29 | this.simplifyOral = simplifyOral;
30 | this.simplifyAnal = simplifyAnal;
31 | this.squishOralGirth = squishOralGirth;
32 | this.rotateTamaWithShaft = rotateTamaWithShaft;
33 | this.danRadiusScale = danRadiusScale;
34 | this.danLengthScale = danLengthScale;
35 | this.limitCorrection = limitCorrection;
36 | this.maxCorrection = maxCorrection;
37 | }
38 |
39 | public DanOptions(float danRadiusScale, float danLengthScale,
40 | float danLengthSquish, float danGirthSquish, float squishThreshold,
41 | bool limitCorrection, float maxCorrection)
42 | {
43 | this.danLengthSquish = danLengthSquish;
44 | this.danGirthSquish = danGirthSquish;
45 | this.squishThreshold = squishThreshold;
46 | this.danRadiusScale = danRadiusScale;
47 | this.danLengthScale = danLengthScale;
48 | simplifyVaginal = true;
49 | simplifyOral = true;
50 | simplifyAnal = true;
51 | squishOralGirth = true;
52 | rotateTamaWithShaft = true;
53 | this.limitCorrection = limitCorrection;
54 | this.maxCorrection = maxCorrection;
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/Core_BetterPenetration/MathHelpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | namespace Core_BetterPenetration
5 | {
6 | internal static class MathHelpers
7 | {
8 | public enum Axis
9 | {
10 | X = 0,
11 | Y = 1,
12 | Z = 2
13 | }
14 |
15 | // Casts a point onto an infinite line defined by two points on the line
16 | internal static Vector3 CastToSegment(Vector3 position, Vector3 lineStart, Vector3 lineVector)
17 | {
18 | Vector3 lineEnd = lineStart + lineVector;
19 | float normDistAlongSegment = Vector3.Dot(position - lineStart, lineVector) / Vector3.Magnitude(lineVector);
20 | return Vector3.LerpUnclamped(lineStart, lineEnd, normDistAlongSegment);
21 | }
22 |
23 | // Finds the point on segment C to D that is closest to segment A to B
24 | // SEGMENT C D must be normalized
25 | internal static Vector3 CastSegmentToSegment(Vector3 projFromStart, Vector3 projFromVector, Vector3 projToStart, Vector3 projToVector)
26 | {
27 | Vector3 projFromEnd = projFromStart + projFromVector;
28 | Vector3 inPlaneStart = projFromStart - Vector3.Dot(projFromStart - projToStart, projToVector) * projToVector;
29 | Vector3 inPlaneEnd = projFromEnd - Vector3.Dot(projFromEnd - projToStart, projToVector) * projToVector;
30 | Vector3 inPlaneVector = inPlaneEnd - inPlaneStart;
31 | Vector3 inToPlaneStart = projToStart - inPlaneStart;
32 |
33 | float dotinToPlaneStartinPlaneVector = Vector3.Dot(inToPlaneStart, inPlaneVector);
34 | float inPlaneVectorMag = Vector3.Magnitude(inPlaneVector);
35 | float normDistAlongLine = dotinToPlaneStartinPlaneVector / inPlaneVectorMag;
36 |
37 | return CastToSegment(projFromStart + projFromVector * normDistAlongLine, projToStart, projToVector);
38 | }
39 |
40 | internal static double DegToRad(double degrees)
41 | {
42 | return (degrees * Math.PI / 180);
43 | }
44 |
45 | internal static double RadToDeg(double radians)
46 | {
47 | return (radians * 180 / Math.PI);
48 | }
49 |
50 | // returns the two solutions of a quadratic equation
51 | internal static bool SolveQuadratic(double quadA, double quadB, double quadC, out double solution1, out double solution2)
52 | {
53 | solution1 = solution2 = 0;
54 | if (ApproximatelyZero(quadA))
55 | {
56 | if (ApproximatelyZero(quadB))
57 | return false;
58 |
59 | solution1 = solution2 = -quadC / quadB;
60 | return true;
61 | }
62 |
63 | double quadD = (quadB * quadB) - (4 * quadA * quadC);
64 | if (quadD >= 0)
65 | {
66 | solution1 = (-quadB + Math.Sqrt(quadD)) / (2 * quadA);
67 | solution2 = (-quadB - Math.Sqrt(quadD)) / (2 * quadA);
68 | return true;
69 | }
70 |
71 | return false;
72 | }
73 |
74 | internal static bool ApproximatelyZero(double value)
75 | {
76 | return (value > -0.0001 && value < 0.0001);
77 | }
78 |
79 | internal static void SolveSSATriangle(double sideA, double sideB, double angleA, out double sideC, out double angleB, out double angleC)
80 | {
81 | sideC = 0;
82 | angleB = 0;
83 | angleC = 0;
84 |
85 | if (ApproximatelyZero(sideA) || ApproximatelyZero(sideB) || ApproximatelyZero(angleA))
86 | return;
87 |
88 | angleB = Math.Asin(Math.Sin(angleA) * sideB / sideA);
89 | angleC = Math.PI - angleA - angleB;
90 | sideC = sideA * Math.Sin(angleC) / Math.Sin(angleA);
91 | }
92 |
93 | // Return True if Vectors are close enough to each other
94 | internal static bool VectorsEqual(Vector3 firstVector, Vector3 secondVector, float threshold = 0.01f)
95 | {
96 | if (Math.Abs(firstVector.x - secondVector.x) > threshold)
97 | return false;
98 |
99 | if (Math.Abs(firstVector.y - secondVector.y) > threshold)
100 | return false;
101 |
102 | if (Math.Abs(firstVector.z - secondVector.z) > threshold)
103 | return false;
104 |
105 | return true;
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 5.0.1.5
5 |
6 |
7 | https://gitgoon.dev/IllusionMods/BetterPenetration
8 |
9 | Copyright GPL-3.0 © 2020
10 |
11 | BetterPenetration
12 |
13 | Make penetration look a bit more realistic and overall improve the HScene experience
14 |
15 | false
16 |
17 | Library
18 | true
19 |
20 | true
21 | true
22 | embedded
23 | 512
24 |
25 |
26 |
27 | true
28 | false
29 |
30 |
31 |
32 |
33 |
34 | PreserveNewest
35 |
36 |
37 | PreserveNewest
38 |
39 |
40 |
41 |
42 |
43 | $(MSBuildProjectName.Replace('-',';').Replace('_',';'))
44 |
45 | ..\bin\$(MSBuildProjectName.Substring(0, $(MSBuildProjectName.IndexOf('_'))))\
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | $(OutputPath)\..\TEMP_COPY_$(AssemblyName)
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
89 |
90 | $(IntermediateOutputPath)GeneratedConstantsFile.cs
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/DanPoints.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEngine;
3 |
4 | namespace Core_BetterPenetration
5 | {
6 | class DanPoints
7 | {
8 | internal Transform danTop;
9 | internal List danPoints;
10 | internal Transform danEnd;
11 | internal List virtualDanPoints;
12 |
13 | public DanPoints(List danTransforms, Transform top, Transform end = null, List virtualDanTransforms = null)
14 | {
15 | danTop = top;
16 | danEnd = end;
17 | virtualDanPoints = virtualDanTransforms;
18 | danPoints = new List();
19 |
20 | foreach (var transform in danTransforms)
21 | danPoints.Add(new DanPoint(transform));
22 | }
23 |
24 | internal void AimDanPoints(List newDanPositions, bool aimTop, List virtualDanPositions)
25 | {
26 | if (newDanPositions == null || danPoints == null || newDanPositions.Count == 0 || danPoints.Count == 0 || newDanPositions.Count != danPoints.Count)
27 | return;
28 |
29 | Quaternion danQuaternion = Quaternion.identity;
30 | for (int point = 0; point < danPoints.Count - 1; point++)
31 | {
32 | Vector3 forwardVector = Vector3.Normalize(newDanPositions[point + 1] - newDanPositions[point]);
33 | danQuaternion = Quaternion.LookRotation(forwardVector, Vector3.Cross(forwardVector, danTop.right));
34 | danPoints[point].transform.SetPositionAndRotation(newDanPositions[point], danQuaternion);
35 | }
36 |
37 | danPoints[danPoints.Count - 1].transform.SetPositionAndRotation(newDanPositions[danPoints.Count - 1], danQuaternion);
38 |
39 | if (danEnd != null)
40 | danEnd.transform.SetPositionAndRotation(newDanPositions[danPoints.Count - 1], danQuaternion);
41 |
42 | if (aimTop)
43 | AimDanTop();
44 |
45 | if (virtualDanPositions == null || virtualDanPoints == null || virtualDanPositions.Count == 0 || virtualDanPoints.Count == 0 || virtualDanPositions.Count != virtualDanPoints.Count)
46 | return;
47 |
48 | for (int point = 0; point < virtualDanPoints.Count - 1; point++)
49 | {
50 | Vector3 forwardVector = Vector3.Normalize(virtualDanPositions[point + 1] - virtualDanPositions[point]);
51 | danQuaternion = Quaternion.LookRotation(forwardVector, Vector3.Cross(forwardVector, danTop.right));
52 | virtualDanPoints[point].SetPositionAndRotation(virtualDanPositions[point], danQuaternion);
53 | }
54 |
55 | virtualDanPoints[virtualDanPoints.Count - 1].SetPositionAndRotation(virtualDanPositions[virtualDanPoints.Count - 1], danQuaternion);
56 | }
57 |
58 | internal void AimDanTop()
59 | {
60 | danTop.transform.rotation = danPoints[0].transform.rotation;
61 | }
62 |
63 | #if !Studio
64 | internal void SquishDanGirth(float girthScaleFactor)
65 | {
66 | float points = danPoints.Count - 1;
67 | if (points <= 0)
68 | return;
69 |
70 | float inverseScaleFactor = (girthScaleFactor - (girthScaleFactor - 1) / points) / girthScaleFactor;
71 |
72 | for (int point = 0; point < danPoints.Count; point++)
73 | {
74 | if (point == 0)
75 | danPoints[point].ScaleDanGirth(girthScaleFactor);
76 | else
77 | danPoints[point].ScaleDanGirth(inverseScaleFactor);
78 | }
79 | }
80 | #else
81 | internal void SquishDanGirth(float girthScaleFactor)
82 | {
83 | float points = danPoints.Count - 2;
84 | if (points <= 0)
85 | return;
86 |
87 | float inverseScaleFactor = (girthScaleFactor - (girthScaleFactor - 1) / points) / girthScaleFactor;
88 |
89 | for (int point = 1; point < danPoints.Count; point++)
90 | {
91 | if (point == 1)
92 | danPoints[point].ScaleDanGirth(girthScaleFactor);
93 | else
94 | danPoints[point].ScaleDanGirth(inverseScaleFactor);
95 | }
96 | }
97 | #endif
98 |
99 | internal void ResetDanPoints()
100 | {
101 | if (danPoints == null || danPoints.Count <= 0)
102 | return;
103 |
104 | foreach (var danPoint in danPoints)
105 | danPoint.ResetDanPoint();
106 |
107 | Quaternion danRotation = danPoints[0].GetDanPointRotation();
108 | for (int point = 1; point < danPoints.Count - 1; point++)
109 | danPoints[point].SetDanPointRotation(danRotation);
110 | }
111 |
112 | internal Vector3 GetDanStartPosition()
113 | {
114 | if (danPoints == null)
115 | return Vector3.zero;
116 |
117 | return danPoints[0].transform.position;
118 | }
119 |
120 | internal Vector3 GetDanEndPosition()
121 | {
122 | if (danPoints == null)
123 | return Vector3.zero;
124 |
125 | return danPoints[danPoints.Count - 1].transform.position;
126 | }
127 |
128 | internal float GetDanLossyScale()
129 | {
130 | if (danPoints == null || danPoints?[0].transform == null)
131 | return 1;
132 |
133 | return danPoints[0].transform.lossyScale.z;
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | PostBuild.ps1
2 | .vscode/
3 |
4 | ## Ignore Visual Studio temporary files, build results, and
5 | ## files generated by popular Visual Studio add-ons.
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # DNX
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # NCrunch
117 | _NCrunch_*
118 | .*crunch*.local.xml
119 | nCrunchTemp_*
120 |
121 | # MightyMoose
122 | *.mm.*
123 | AutoTest.Net/
124 |
125 | # Web workbench (sass)
126 | .sass-cache/
127 |
128 | # Installshield output folder
129 | [Ee]xpress/
130 |
131 | # DocProject is a documentation generator add-in
132 | DocProject/buildhelp/
133 | DocProject/Help/*.HxT
134 | DocProject/Help/*.HxC
135 | DocProject/Help/*.hhc
136 | DocProject/Help/*.hhk
137 | DocProject/Help/*.hhp
138 | DocProject/Help/Html2
139 | DocProject/Help/html
140 |
141 | # Click-Once directory
142 | publish/
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | #*.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.jfm
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # Since there are multiple workflows, uncomment next line to ignore bower_components
202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
203 | #bower_components/
204 |
205 | # RIA/Silverlight projects
206 | Generated_Code/
207 |
208 | # Backup & report files from converting an old project file
209 | # to a newer Visual Studio version. Backup files are not needed,
210 | # because we have git ;-)
211 | _UpgradeReport_Files/
212 | Backup*/
213 | UpgradeLog*.XML
214 | UpgradeLog*.htm
215 |
216 | # SQL Server files
217 | *.mdf
218 | *.ldf
219 |
220 | # Business Intelligence projects
221 | *.rdl.data
222 | *.bim.layout
223 | *.bim_*.settings
224 |
225 | # Microsoft Fakes
226 | FakesAssemblies/
227 |
228 | # GhostDoc plugin setting file
229 | *.GhostDoc.xml
230 |
231 | # Node.js Tools for Visual Studio
232 | .ntvs_analysis.dat
233 |
234 | # Visual Studio 6 build log
235 | *.plg
236 |
237 | # Visual Studio 6 workspace options file
238 | *.opt
239 |
240 | # Visual Studio LightSwitch build output
241 | **/*.HTMLClient/GeneratedArtifacts
242 | **/*.DesktopClient/GeneratedArtifacts
243 | **/*.DesktopClient/ModelManifest.xml
244 | **/*.Server/GeneratedArtifacts
245 | **/*.Server/ModelManifest.xml
246 | _Pvt_Extensions
247 |
248 | # Paket dependency manager
249 | #.paket/paket.exe
250 | .paket/Paket.Restore.targets
251 | paket-files/
252 |
253 | # FAKE - F# Make
254 | .fake/
255 |
256 | # JetBrains Rider
257 | .idea/
258 | *.sln.iml
259 |
260 | # CodeRush
261 | .cr/
262 |
263 | # Python Tools for Visual Studio (PTVS)
264 | __pycache__/
265 | *.pyc
266 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/CollisionOptions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEngine;
3 |
4 | namespace Core_BetterPenetration
5 | {
6 | class CollisionOptions
7 | {
8 | internal float kokanOffset = 0.0f;
9 | internal float innerKokanOffset = 0.0f;
10 | internal float mouthOffset = 0.0f;
11 | internal float innerMouthOffset = 0.0f;
12 |
13 | internal bool kokan_adjust = false;
14 | internal float kokan_adjust_position_z = 0;
15 | internal float kokan_adjust_position_y = 0;
16 | internal float kokan_adjust_rotation_x = 0;
17 | internal float clippingDepth = 0;
18 | internal bool ana_adjust = false;
19 | internal Vector3 ana_adjust_position = Vector3.zero;
20 | internal Vector3 ana_adjust_rotation = Vector3.zero;
21 | #if HS2 || AI
22 | internal bool enableKokanPush = true;
23 | #else
24 | internal bool enableKokanPush = false;
25 | #endif
26 | internal float maxKokanPush = 0.08f;
27 | internal float maxKokanPull = 0.04f;
28 | internal float kokanPullRate = 18.0f;
29 | internal float kokanReturnRate = 0.3f;
30 | internal bool enableOralPush = true;
31 | internal float maxOralPush = 0.02f;
32 | internal float maxOralPull = 0.10f;
33 | internal float oralPullRate = 18.0f;
34 | internal float oralReturnRate = 0.3f;
35 | #if HS2 || AI
36 | internal bool enableAnaPush = true;
37 | #else
38 | internal bool enableAnaPush = false;
39 | #endif
40 | internal float maxAnaPush = 0.08f;
41 | internal float maxAnaPull = 0.04f;
42 | internal float anaPullRate = 18.0f;
43 | internal float anaReturnRate = 0.3f;
44 |
45 | internal TargetType outer = TargetType.Average;
46 | internal TargetType inner = TargetType.Average;
47 |
48 | internal List frontCollisionInfo;
49 | internal List backCollisonInfo;
50 |
51 | internal bool enableBellyBulge = true;
52 | internal float bellyBulgeScale = 1.0f;
53 |
54 | public enum TargetType
55 | {
56 | Outer = 0,
57 | Average = 1,
58 | Inside = 2
59 | }
60 |
61 | public CollisionOptions(float kokanOffset, float innerKokanOffset, float mouthOffset, float innerMouthOffset,
62 | bool kokan_adjust, float kokan_adjust_position_z, float kokan_adjust_position_y, float kokan_adjust_rotation_x,
63 | bool ana_adjust, Vector3 ana_adjust_position, Vector3 ana_adjust_rotation,
64 | float clippingDepth, List frontInfo, List backInfo,
65 | bool enableKokanPush, float maxKokanPush, float maxKokanPull, float kokanPullRate, float kokanReturnRate,
66 | bool enableOralPush, float maxOralPush, float maxOralPull, float oralPullRate, float oralReturnRate,
67 | bool enableAnaPush, float maxAnaPush, float maxAnaPull, float anaPullRate, float anaReturnRate, TargetType outer = TargetType.Average, TargetType inner = TargetType.Inside,
68 | bool enableBellyBulge = true, float bellyBulgeScale = 1.0f)
69 | {
70 | this.kokanOffset = kokanOffset;
71 | this.innerKokanOffset = innerKokanOffset;
72 | this.mouthOffset = mouthOffset;
73 | this.innerMouthOffset = innerMouthOffset;
74 |
75 | this.kokan_adjust = kokan_adjust;
76 | this.kokan_adjust_position_z = kokan_adjust_position_z;
77 | this.kokan_adjust_position_y = kokan_adjust_position_y;
78 | this.kokan_adjust_rotation_x = kokan_adjust_rotation_x;
79 | this.clippingDepth = clippingDepth;
80 |
81 | this.ana_adjust = ana_adjust;
82 | this.ana_adjust_position = ana_adjust_position;
83 | this.ana_adjust_rotation = ana_adjust_rotation;
84 |
85 | #if HS2 || AI
86 | this.enableKokanPush = enableKokanPush;
87 | #else
88 | this.enableKokanPush = false;
89 | #endif
90 | this.maxKokanPush = maxKokanPush;
91 | this.maxKokanPull = maxKokanPull;
92 | this.kokanPullRate = kokanPullRate;
93 | this.kokanReturnRate = kokanReturnRate;
94 |
95 | this.enableOralPush = enableOralPush;
96 | this.maxOralPush = maxOralPush;
97 | this.maxOralPull = maxOralPull;
98 | this.oralPullRate = oralPullRate;
99 | this.oralReturnRate = oralReturnRate;
100 |
101 | this.enableAnaPush = enableAnaPush;
102 | this.maxAnaPush = maxAnaPush;
103 | this.maxAnaPull = maxAnaPull;
104 | this.anaPullRate = anaPullRate;
105 | this.anaReturnRate = anaReturnRate;
106 |
107 | frontCollisionInfo = frontInfo;
108 | backCollisonInfo = backInfo;
109 |
110 | this.outer = outer;
111 | this.inner = inner;
112 |
113 | this.enableBellyBulge = enableBellyBulge;
114 | this.bellyBulgeScale = bellyBulgeScale;
115 | }
116 |
117 | #if Studio
118 | public CollisionOptions(float maxPush, float maxPull, float pullRate, float returnRate, bool enableBellyBulge = true, float bellyBulgeScale = 1.0f)
119 | {
120 | kokanOffset = 0.0f;
121 | innerKokanOffset = 0.0f;
122 | mouthOffset = 0.0f;
123 | innerMouthOffset = 0.0f;
124 |
125 | kokan_adjust = false;
126 | kokan_adjust_position_z = 0;
127 | kokan_adjust_position_y = 0;
128 | kokan_adjust_rotation_x = 0;
129 | clippingDepth = 0;
130 | ana_adjust = false;
131 | ana_adjust_position = Vector3.zero;
132 | ana_adjust_rotation = Vector3.zero;
133 |
134 | #if HS2 || AI
135 | enableKokanPush = true;
136 | enableOralPush = true;
137 | enableAnaPush = true;
138 | #else
139 | enableKokanPush = false;
140 | enableOralPush = true;
141 | enableAnaPush = false;
142 | #endif
143 | maxKokanPush = maxPush;
144 | maxKokanPull = maxPull;
145 | kokanPullRate = pullRate;
146 | kokanReturnRate = returnRate;
147 |
148 | maxOralPush = maxPush;
149 | maxOralPull = maxPull;
150 | oralPullRate = pullRate;
151 | oralReturnRate = returnRate;
152 |
153 | maxAnaPush = maxPush;
154 | maxAnaPull = maxPull;
155 | anaPullRate = pullRate;
156 | anaReturnRate = returnRate;
157 |
158 | frontCollisionInfo = null;
159 | backCollisonInfo = null;
160 |
161 | this.enableBellyBulge = enableBellyBulge;
162 | this.bellyBulgeScale = bellyBulgeScale;
163 | }
164 | #endif
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/BetterPenetration.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32328.378
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HS2_BetterPenetration", "HS2_BetterPenetration\HS2_BetterPenetration.csproj", "{F5E096BB-2509-4431-972E-148500210D06}"
7 | ProjectSection(ProjectDependencies) = postProject
8 | {06A2BE07-7AB5-46CD-8A77-FDE1BFDE687C} = {06A2BE07-7AB5-46CD-8A77-FDE1BFDE687C}
9 | EndProjectSection
10 | EndProject
11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI_BetterPenetration", "AI_BetterPenetration\AI_BetterPenetration.csproj", "{052B343B-8793-481B-B053-0A99B09A0B52}"
12 | ProjectSection(ProjectDependencies) = postProject
13 | {7008D2E3-1C29-4786-A4F6-7CFD6D6D8AD9} = {7008D2E3-1C29-4786-A4F6-7CFD6D6D8AD9}
14 | EndProjectSection
15 | EndProject
16 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Core_BetterPenetration", "Core_BetterPenetration\Core_BetterPenetration.shproj", "{CCD25B62-1040-4727-A0B5-78335FCF9F01}"
17 | EndProject
18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KK_BetterPenetration", "KK_BetterPenetration\KK_BetterPenetration.csproj", "{13F643E0-45CA-483E-ADFA-32634A22787E}"
19 | ProjectSection(ProjectDependencies) = postProject
20 | {A68BEAE5-21B9-4C45-9624-A377BB953238} = {A68BEAE5-21B9-4C45-9624-A377BB953238}
21 | EndProjectSection
22 | EndProject
23 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HS2_Studio_BetterPenetration", "HS2_Studio_BetterPenetration\HS2_Studio_BetterPenetration.csproj", "{06A2BE07-7AB5-46CD-8A77-FDE1BFDE687C}"
24 | EndProject
25 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AI_Studio_BetterPenetration", "AI_Studio_BetterPenetration\AI_Studio_BetterPenetration.csproj", "{7008D2E3-1C29-4786-A4F6-7CFD6D6D8AD9}"
26 | EndProject
27 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KK_Studio_BetterPenetration", "KK_Studio_BetterPenetration\KK_Studio_BetterPenetration.csproj", "{A68BEAE5-21B9-4C45-9624-A377BB953238}"
28 | EndProject
29 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KKS_BetterPenetration", "KKS_BetterPenetration\KKS_BetterPenetration.csproj", "{0FF42A1B-86EB-4CEE-BD04-DA3BB249773F}"
30 | ProjectSection(ProjectDependencies) = postProject
31 | {B2F3F19C-14D5-477B-ADF7-EFBE76E85AD7} = {B2F3F19C-14D5-477B-ADF7-EFBE76E85AD7}
32 | EndProjectSection
33 | EndProject
34 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KKS_Studio_BetterPenetration", "KKS_Studio_BetterPenetration\KKS_Studio_BetterPenetration.csproj", "{B2F3F19C-14D5-477B-ADF7-EFBE76E85AD7}"
35 | EndProject
36 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Solution", "_Solution", "{58356582-991A-40E5-8DEF-704666191C72}"
37 | ProjectSection(SolutionItems) = preProject
38 | Directory.Build.props = Directory.Build.props
39 | README.md = README.md
40 | EndProjectSection
41 | EndProject
42 | Global
43 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
44 | Debug|Any CPU = Debug|Any CPU
45 | Release|Any CPU = Release|Any CPU
46 | EndGlobalSection
47 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
48 | {F5E096BB-2509-4431-972E-148500210D06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {F5E096BB-2509-4431-972E-148500210D06}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {F5E096BB-2509-4431-972E-148500210D06}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {F5E096BB-2509-4431-972E-148500210D06}.Release|Any CPU.Build.0 = Release|Any CPU
52 | {052B343B-8793-481B-B053-0A99B09A0B52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
53 | {052B343B-8793-481B-B053-0A99B09A0B52}.Debug|Any CPU.Build.0 = Debug|Any CPU
54 | {052B343B-8793-481B-B053-0A99B09A0B52}.Release|Any CPU.ActiveCfg = Release|Any CPU
55 | {052B343B-8793-481B-B053-0A99B09A0B52}.Release|Any CPU.Build.0 = Release|Any CPU
56 | {13F643E0-45CA-483E-ADFA-32634A22787E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
57 | {13F643E0-45CA-483E-ADFA-32634A22787E}.Debug|Any CPU.Build.0 = Debug|Any CPU
58 | {13F643E0-45CA-483E-ADFA-32634A22787E}.Release|Any CPU.ActiveCfg = Release|Any CPU
59 | {13F643E0-45CA-483E-ADFA-32634A22787E}.Release|Any CPU.Build.0 = Release|Any CPU
60 | {06A2BE07-7AB5-46CD-8A77-FDE1BFDE687C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
61 | {06A2BE07-7AB5-46CD-8A77-FDE1BFDE687C}.Debug|Any CPU.Build.0 = Debug|Any CPU
62 | {06A2BE07-7AB5-46CD-8A77-FDE1BFDE687C}.Release|Any CPU.ActiveCfg = Release|Any CPU
63 | {06A2BE07-7AB5-46CD-8A77-FDE1BFDE687C}.Release|Any CPU.Build.0 = Release|Any CPU
64 | {7008D2E3-1C29-4786-A4F6-7CFD6D6D8AD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
65 | {7008D2E3-1C29-4786-A4F6-7CFD6D6D8AD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
66 | {7008D2E3-1C29-4786-A4F6-7CFD6D6D8AD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
67 | {7008D2E3-1C29-4786-A4F6-7CFD6D6D8AD9}.Release|Any CPU.Build.0 = Release|Any CPU
68 | {A68BEAE5-21B9-4C45-9624-A377BB953238}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
69 | {A68BEAE5-21B9-4C45-9624-A377BB953238}.Debug|Any CPU.Build.0 = Debug|Any CPU
70 | {A68BEAE5-21B9-4C45-9624-A377BB953238}.Release|Any CPU.ActiveCfg = Release|Any CPU
71 | {A68BEAE5-21B9-4C45-9624-A377BB953238}.Release|Any CPU.Build.0 = Release|Any CPU
72 | {0FF42A1B-86EB-4CEE-BD04-DA3BB249773F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
73 | {0FF42A1B-86EB-4CEE-BD04-DA3BB249773F}.Debug|Any CPU.Build.0 = Debug|Any CPU
74 | {0FF42A1B-86EB-4CEE-BD04-DA3BB249773F}.Release|Any CPU.ActiveCfg = Release|Any CPU
75 | {0FF42A1B-86EB-4CEE-BD04-DA3BB249773F}.Release|Any CPU.Build.0 = Release|Any CPU
76 | {B2F3F19C-14D5-477B-ADF7-EFBE76E85AD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
77 | {B2F3F19C-14D5-477B-ADF7-EFBE76E85AD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
78 | {B2F3F19C-14D5-477B-ADF7-EFBE76E85AD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
79 | {B2F3F19C-14D5-477B-ADF7-EFBE76E85AD7}.Release|Any CPU.Build.0 = Release|Any CPU
80 | EndGlobalSection
81 | GlobalSection(SolutionProperties) = preSolution
82 | HideSolutionNode = FALSE
83 | EndGlobalSection
84 | GlobalSection(ExtensibilityGlobals) = postSolution
85 | SolutionGuid = {CCFA8C78-8530-4958-8678-C27D5C24C5F8}
86 | EndGlobalSection
87 | GlobalSection(SharedMSBuildProjectFiles) = preSolution
88 | Core_BetterPenetration\Core_BetterPenetration.projitems*{052b343b-8793-481b-b053-0a99b09a0b52}*SharedItemsImports = 5
89 | Core_BetterPenetration\Core_BetterPenetration.projitems*{06a2be07-7ab5-46cd-8a77-fde1bfde687c}*SharedItemsImports = 5
90 | Core_BetterPenetration\Core_BetterPenetration.projitems*{0ff42a1b-86eb-4cee-bd04-da3bb249773f}*SharedItemsImports = 5
91 | Core_BetterPenetration\Core_BetterPenetration.projitems*{13f643e0-45ca-483e-adfa-32634a22787e}*SharedItemsImports = 5
92 | Core_BetterPenetration\Core_BetterPenetration.projitems*{7008d2e3-1c29-4786-a4f6-7cfd6d6d8ad9}*SharedItemsImports = 5
93 | Core_BetterPenetration\Core_BetterPenetration.projitems*{a68beae5-21b9-4c45-9624-a377bb953238}*SharedItemsImports = 5
94 | Core_BetterPenetration\Core_BetterPenetration.projitems*{b2f3f19c-14d5-477b-adf7-efbe76e85ad7}*SharedItemsImports = 5
95 | Core_BetterPenetration\Core_BetterPenetration.projitems*{ccd25b62-1040-4727-a0b5-78335fcf9f01}*SharedItemsImports = 13
96 | Core_BetterPenetration\Core_BetterPenetration.projitems*{f5e096bb-2509-4431-972e-148500210d06}*SharedItemsImports = 5
97 | EndGlobalSection
98 | EndGlobal
99 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/Tools.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using UnityEngine;
5 | using System.Linq;
6 | #if AI || HS2
7 | using AIChara;
8 | #endif
9 |
10 | namespace Core_BetterPenetration
11 | {
12 | static class Tools
13 | {
14 | internal struct MemberKey
15 | {
16 | public readonly Type type;
17 | public readonly string name;
18 | internal readonly int _hashCode;
19 |
20 | public MemberKey(Type inType, string inName)
21 | {
22 | this.type = inType;
23 | this.name = inName;
24 | this._hashCode = this.type.GetHashCode() ^ this.name.GetHashCode();
25 | }
26 |
27 | public override int GetHashCode()
28 | {
29 | return this._hashCode;
30 | }
31 | }
32 |
33 | internal static readonly Dictionary _propertyCache = new Dictionary();
34 |
35 | internal static object GetPrivateProperty(this object self, string name)
36 | {
37 | MemberKey key = new MemberKey(self.GetType(), name);
38 | if (_propertyCache.TryGetValue(key, out PropertyInfo info) == false)
39 | {
40 | info = key.type.GetProperty(key.name, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
41 | _propertyCache.Add(key, info);
42 | }
43 | return info.GetValue(self, null);
44 | }
45 |
46 | public static Transform GetTransformOfChaControl(ChaControl chaControl, string transformName)
47 | {
48 | Transform transform = null;
49 | if (chaControl == null)
50 | return transform;
51 |
52 | var transforms = chaControl.GetComponentsInChildren().Where(x => x.name != null && x.name.Equals(transformName));
53 | if (transforms.Count() == 0)
54 | return transform;
55 |
56 | for (int transformIndex = transforms.Count() - 1; transformIndex >= 0; transformIndex--)
57 | {
58 | transform = transforms.ElementAt(transformIndex);
59 | if (transform == null || chaControl != transform.GetComponentInParent())
60 | continue;
61 |
62 | return transform;
63 | }
64 |
65 | return transform;
66 | }
67 |
68 | public static DynamicBone GetDynamicBoneOfChaControl(ChaControl chaControl, string dynamicBoneName)
69 | {
70 | DynamicBone dynamicBone = null;
71 | if (chaControl == null)
72 | return dynamicBone;
73 |
74 | var dynamicBones = chaControl.GetComponentsInChildren().Where(x => x.name != null && x.name.Equals(dynamicBoneName));
75 | if (dynamicBones.Count() == 0)
76 | return dynamicBone;
77 |
78 | for (int boneIndex = dynamicBones.Count() - 1; boneIndex >= 0; boneIndex--)
79 | {
80 | dynamicBone = dynamicBones.ElementAt(boneIndex);
81 | if (dynamicBone != null && chaControl == dynamicBone.GetComponentInParent())
82 | return dynamicBone;
83 | }
84 |
85 | return dynamicBone;
86 | }
87 |
88 | public static List GetCollidersOfChaControl(ChaControl chaControl, string colliderName)
89 | {
90 | List colliderList = new List();
91 | if (chaControl == null)
92 | return colliderList;
93 |
94 | var colliders = chaControl.GetComponentsInChildren().Where(x => x.name != null && x.name.Contains(colliderName));
95 | if (colliders.Count() == 0)
96 | return colliderList;
97 |
98 | foreach (var collider in colliders)
99 | {
100 | if (chaControl != collider.GetComponentInParent())
101 | continue;
102 |
103 | colliderList.Add(collider);
104 | }
105 |
106 | return colliderList;
107 | }
108 |
109 | public static List GetCollidersOfChaControl(ChaControl chaControl, List colliderNames)
110 | {
111 | List colliderList = new List();
112 | if (chaControl == null)
113 | return colliderList;
114 |
115 | var colliders = chaControl.GetComponentsInChildren().Where(x => x.name != null && colliderNames.Contains(x.name));
116 | if (colliders.Count() == 0)
117 | return colliderList;
118 |
119 | foreach (var collider in colliders)
120 | {
121 | if (chaControl != collider.GetComponentInParent())
122 | continue;
123 |
124 | colliderList.Add(collider);
125 | }
126 |
127 | return colliderList;
128 | }
129 |
130 | internal static DynamicBoneCollider InitializeCollider(Transform parent, float radius, float length, Vector3 centerOffset,
131 | DynamicBoneCollider.Direction direction = DynamicBoneCollider.Direction.X,
132 | DynamicBoneCollider.Bound bound = DynamicBoneCollider.Bound.Outside)
133 | {
134 | if (parent == null)
135 | return null;
136 |
137 | DynamicBoneCollider collider = parent.GetComponent();
138 |
139 | if (collider == null)
140 | collider = parent.gameObject.AddComponent(typeof(DynamicBoneCollider)) as DynamicBoneCollider;
141 |
142 | collider.m_Direction = direction;
143 | collider.m_Center = centerOffset;
144 | collider.m_Bound = bound;
145 | collider.m_Radius = radius;
146 | collider.m_Height = length;
147 |
148 | return collider;
149 | }
150 |
151 | internal static float ComputeRadiusScale(Transform transform, DynamicBoneCollider.Direction direction)
152 | {
153 | if (direction == DynamicBoneCollider.Direction.X)
154 | return (transform.lossyScale.y + transform.lossyScale.z) / 2;
155 |
156 | if (direction == DynamicBoneCollider.Direction.Y)
157 | return (transform.lossyScale.x + transform.lossyScale.z) / 2;
158 |
159 | return (transform.lossyScale.x + transform.lossyScale.y) / 2;
160 | }
161 |
162 | internal static float ComputeHeightScale(Transform transform, DynamicBoneCollider.Direction direction)
163 | {
164 | if (direction == DynamicBoneCollider.Direction.X)
165 | return transform.lossyScale.x;
166 |
167 | if (direction == DynamicBoneCollider.Direction.Y)
168 | return transform.lossyScale.y;
169 |
170 | return transform.lossyScale.z;
171 | }
172 |
173 | internal static void RemoveCollidersFromCoordinate(ChaControl character)
174 | {
175 | var dynamicBones = character.GetComponentsInChildren(true);
176 |
177 | if (dynamicBones == null)
178 | return;
179 |
180 | foreach (var dynamicBone in dynamicBones)
181 | {
182 | if (!dynamicBone)
183 | continue;
184 |
185 | var dbName = dynamicBone.name;
186 | var dbColliders = dynamicBone.m_Colliders;
187 |
188 | if (dbName == null || dbColliders == null || dbColliders.Count <= 0)
189 | continue;
190 |
191 | bool bpBone = dbName.Contains("Vagina") || dbName.Contains("Belly") || dbName.Contains("Ana");
192 | int last = 0;
193 |
194 | for (int collider = 0; collider < dbColliders.Count; ++collider)
195 | {
196 | if (dbColliders[collider])
197 | {
198 | var colliderName = dbColliders[collider].name;
199 |
200 | if (colliderName != null)
201 | {
202 | bool bpCollider = colliderName.Contains("cm_J_vdan") || colliderName.Contains("cm_J_dan");
203 |
204 | if (bpBone != bpCollider)
205 | continue; //remove collider
206 | }
207 | }
208 |
209 | //keep collider
210 | if (last != collider)
211 | dbColliders[last] = dbColliders[collider];
212 | ++last;
213 | }
214 |
215 | dbColliders.RemoveRange(last, dbColliders.Count - last);
216 | }
217 | }
218 | }
219 | }
--------------------------------------------------------------------------------
/Core_BetterPenetration/TwistedPlane.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | namespace Core_BetterPenetration
5 | {
6 | // Creates a Plane defined by two non-parallel lines
7 | class TwistedPlane
8 | {
9 | internal Vector3 firstOrigin;
10 | internal Vector3 firstVector;
11 | internal Vector3 secondOrigin;
12 | internal Vector3 secondVector;
13 | internal Vector3 forwardVector;
14 | internal Vector3 twistVector;
15 |
16 | public TwistedPlane(Vector3 firstOrig, Vector3 firstVec, Vector3 secondOrig, Vector3 secondVec)
17 | {
18 | firstOrigin = firstOrig;
19 | firstVector = firstVec;
20 | secondOrigin = secondOrig;
21 | secondVector = secondVec;
22 | forwardVector = secondOrig - firstOrig;
23 | twistVector = secondVec - firstVec;
24 | }
25 |
26 | internal bool FindIntersectValues(Vector3 lineVector, Vector3 offsetVector, Vector3 FVxLV, Vector3 TWxLV, Vector3 OFxLV, Vector3 LVxFW, double u, out double v, out double t)
27 | {
28 | double Cu = 0;
29 | v = 0;
30 | t = 0;
31 |
32 | for (MathHelpers.Axis axis = MathHelpers.Axis.X; axis <= MathHelpers.Axis.Z; axis++)
33 | {
34 | if (axis == MathHelpers.Axis.X)
35 | {
36 | Cu = FVxLV.x + TWxLV.x * u;
37 | if (!MathHelpers.ApproximatelyZero(Cu))
38 | {
39 | v = (OFxLV.x + LVxFW.x * u) / Cu;
40 | break;
41 | }
42 | }
43 | else if (axis == MathHelpers.Axis.Y)
44 | {
45 | Cu = FVxLV.y + TWxLV.y * u;
46 | if (!MathHelpers.ApproximatelyZero(Cu))
47 | {
48 | v = (OFxLV.y + LVxFW.y * u) / Cu;
49 | break;
50 | }
51 | }
52 | else
53 | {
54 | Cu = FVxLV.z + TWxLV.z * u;
55 | if (!MathHelpers.ApproximatelyZero(Cu))
56 | {
57 | v = (OFxLV.z + LVxFW.z * u) / Cu;
58 | break;
59 | }
60 | }
61 | }
62 |
63 | if (MathHelpers.ApproximatelyZero(Cu))
64 | return false;
65 |
66 | if (!MathHelpers.ApproximatelyZero(lineVector.x))
67 | t = (-offsetVector.x + firstVector.x * v + (forwardVector.x + twistVector.x * v) * u) / lineVector.x;
68 | else if (!MathHelpers.ApproximatelyZero(lineVector.y))
69 | t = (-offsetVector.y + firstVector.y * v + (forwardVector.y + twistVector.y * v) * u) / lineVector.y;
70 | else if (!MathHelpers.ApproximatelyZero(lineVector.z))
71 | t = (-offsetVector.z + firstVector.z * v + (forwardVector.z + twistVector.z * v) * u) / lineVector.z;
72 | else
73 | return false;
74 |
75 | return true;
76 | }
77 |
78 | // return true if they interstect
79 | internal bool IntersectLineOnTwistedPlane(Vector3 lineStart, Vector3 lineEnd, bool bExtendPlaneBeyondFirstVector, bool bExtendPlaneBeyoneSecondVector, out Vector3 intersectionPoint, out Vector3 intersectForwardVector, out float distanceToSecondVector)
80 | {
81 | distanceToSecondVector = 0;
82 | intersectForwardVector = forwardVector;
83 | intersectionPoint = lineEnd;
84 |
85 | Vector3 lineVector = lineEnd - lineStart;
86 | Vector3 offsetVector = lineStart - firstOrigin;
87 | Vector3 TVxFW = Vector3.Cross(twistVector, forwardVector);
88 | Vector3 FVxFW = Vector3.Cross(firstVector, forwardVector);
89 | Vector3 OFxTW = Vector3.Cross(offsetVector, twistVector);
90 | Vector3 OFxFV = Vector3.Cross(offsetVector, firstVector);
91 |
92 | double quadraticA = lineVector.x * TVxFW.x + lineVector.y * TVxFW.y + lineVector.z * TVxFW.z;
93 | double quadraticB = lineVector.x * (FVxFW.x + OFxTW.x) + lineVector.y * (FVxFW.y + OFxTW.y) + lineVector.z * (FVxFW.z + OFxTW.z);
94 | double quadraticC = lineVector.x * OFxFV.x + lineVector.y * OFxFV.y + lineVector.z * OFxFV.z;
95 | if (MathHelpers.SolveQuadratic(quadraticA, quadraticB, quadraticC, out double u1, out double u2) == false)
96 | return false;
97 |
98 | double t1 = 0, t2 = 0;
99 | Vector3 FVxLV = Vector3.Cross(firstVector, lineVector);
100 | Vector3 TWxLV = Vector3.Cross(twistVector, lineVector);
101 | Vector3 OFxLV = Vector3.Cross(offsetVector, lineVector);
102 | Vector3 LVxFW = Vector3.Cross(lineVector, forwardVector);
103 |
104 | bool bIntersect1Found = false;
105 | if ((u1 < 4) && (u1 > -4) && (u1 >= 0 || bExtendPlaneBeyondFirstVector) && (u1 <= 1 || bExtendPlaneBeyoneSecondVector))
106 | {
107 | bIntersect1Found = this.FindIntersectValues(lineVector, offsetVector, FVxLV, TWxLV, OFxLV, LVxFW, u1, out _, out t1);
108 | if (bIntersect1Found && t1 < 0 || t1 > 1)
109 | bIntersect1Found = false;
110 |
111 | }
112 |
113 | bool bIntersect2Found = false;
114 | if ((u2 < 4) && (u2 > -4) && (u2 >= 0 || bExtendPlaneBeyondFirstVector) && (u2 <= 1 || bExtendPlaneBeyoneSecondVector))
115 | {
116 | bIntersect2Found = this.FindIntersectValues(lineVector, offsetVector, FVxLV, TWxLV, OFxLV, LVxFW, u2, out _, out t2);
117 | if (bIntersect2Found && t2 < 0 || t2 > 1)
118 | bIntersect2Found = false;
119 | }
120 |
121 | if (!bIntersect1Found && !bIntersect2Found)
122 | return false;
123 |
124 | float t = 0;
125 | if (bIntersect1Found)
126 | t = (float)t1;
127 |
128 | if (bIntersect2Found && (!bIntersect1Found || (bIntersect1Found && t2 < t1)))
129 | t = (float)t2;
130 |
131 | intersectionPoint = lineStart + lineVector * t;
132 | Vector3 intersectFirst = MathHelpers.CastSegmentToSegment(lineStart, lineVector, firstOrigin, firstVector);
133 | Vector3 intersectSecond = MathHelpers.CastSegmentToSegment(lineStart, lineVector, secondOrigin, secondVector);
134 |
135 | intersectForwardVector = Vector3.Normalize(intersectSecond - intersectFirst);
136 | distanceToSecondVector = Vector3.Distance(intersectSecond, intersectionPoint);
137 |
138 | return true;
139 | }
140 |
141 | internal Vector3 ConstrainLineToTwistedPlane(Vector3 lineStart, Vector3 lineEnd, float lineLength, ref bool bExtendPlaneBeyondStart, bool bExtendPlaneBeyondEnd, out bool bHitPointFound)
142 | {
143 | Vector3 newLineEnd;
144 | Vector3 lineVector = Vector3.Normalize(lineEnd - lineStart);
145 | bHitPointFound = false;
146 |
147 | // create a normal plane approximation to determine side, not the most accurate but close enough
148 | Vector3 planeRightVector = Vector3.Normalize(firstVector + secondVector);
149 | Vector3 planeUpVector = Vector3.Normalize(Vector3.Cross(planeRightVector, forwardVector));
150 | Plane upPlane = new Plane(planeUpVector, firstOrigin + forwardVector / 2);
151 | bool bAbovePlane = upPlane.GetSide(lineEnd);
152 | if (!bAbovePlane)
153 | {
154 | bExtendPlaneBeyondStart = false;
155 | return lineEnd;
156 | }
157 |
158 | bool bIntersectFound = this.IntersectLineOnTwistedPlane(lineStart, lineEnd, bExtendPlaneBeyondStart, bExtendPlaneBeyondEnd, out Vector3 hitPoint, out Vector3 lineForwardVector, out float distanceToEdgeOfPlane);
159 |
160 | if (!bIntersectFound)
161 | {
162 | bExtendPlaneBeyondStart = false;
163 | return lineEnd;
164 | }
165 |
166 | double hitDistance = Vector3.Distance(hitPoint, lineStart);
167 | if (hitDistance > lineLength)
168 | {
169 | bExtendPlaneBeyondStart = false;
170 | return lineEnd;
171 | }
172 |
173 | double angleLineToPlane = (double)MathHelpers.DegToRad(Vector3.Angle(lineVector, -lineForwardVector));
174 | MathHelpers.SolveSSATriangle(lineLength, hitDistance, angleLineToPlane, out double distanceAlongPlane, out _, out _);
175 |
176 | if (!bExtendPlaneBeyondEnd)
177 | {
178 | if (distanceAlongPlane > distanceToEdgeOfPlane)
179 | {
180 | newLineEnd = hitPoint + distanceToEdgeOfPlane * lineForwardVector;
181 | newLineEnd = lineStart + Vector3.Normalize(newLineEnd - lineStart) * lineLength;
182 | bExtendPlaneBeyondStart = true;
183 | return newLineEnd;
184 | }
185 | }
186 |
187 | newLineEnd = hitPoint + (float)distanceAlongPlane * lineForwardVector;
188 | bHitPointFound = true;
189 | bExtendPlaneBeyondStart = false;
190 | return newLineEnd;
191 | }
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/BoneNames.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Core_BetterPenetration
4 | {
5 | #if HS2 || AI
6 | static class LookTargets
7 | {
8 | internal const string HeadTarget = "k_f_head_00";
9 | internal const string KokanTarget = "k_f_kokan_00";
10 | internal const string BPKokanTarget = "cf_J_Vagina_root";
11 | internal const string BPAnaTarget = "cf_J_Ana_Root";
12 | internal const string AnaTarget = "k_f_ana_00";
13 | internal const string InnerTarget = "cf_J_Kosi01";
14 | internal const string InnerHeadTarget = "cf_J_FaceBase";
15 | }
16 |
17 | static class BoneNames
18 | {
19 |
20 | internal const string KokanBone = "cf_J_Kokan";
21 | internal const string TamaTop = "cm_J_dan_f_top";
22 | internal const string BPBone = "cf_J_Vagina";
23 | internal const string BellyBone = "cf_J_Belly";
24 | internal const string BPDanBone = "cm_J_dan";
25 | internal const string virtualBPDanBone = "cm_J_vdan";
26 | internal const string BPDanEnd = "cm_J_dan119_00";
27 | internal const string MouthPullBone = "cf_J_MouthMove";
28 | internal const string ButtBoneL = "cf_J_Siri_s_L";
29 | internal const string ButtBoneR = "cf_J_Siri_s_R";
30 |
31 | internal const string BPKokanTarget = "cf_J_Vagina_root";
32 | internal const string AnaTarget = "cf_J_Ana";
33 | internal const string InnerTarget = "cf_J_Kosi01";
34 | internal const string HeadTarget = "cf_J_MouthLow";
35 | internal const string InnerHeadTarget = "cf_J_FaceBase";
36 | internal const string BPDanEntryTarget = "k_f_dan_entry";
37 | internal const string BPDanEndTarget = "k_f_dan_end";
38 |
39 | internal static readonly List KokanPullBones = new List { "cf_J_Vagina_s_F", "cf_J_Vagina_s_F_L", "cf_J_Vagina_s_F_R", "cf_J_Vagina_s_M_F_L", "cf_J_Vagina_s_M_F_R", "cf_J_Vagina_s_M_L", "cf_J_Vagina_s_M_R", "cf_J_Vagina_s_M_B_L", "cf_J_Vagina_s_M_B_R", "cf_J_Vagina_s_B_L", "cf_J_Vagina_s_B_R", "cf_J_Vagina_s_B",
40 | "cf_J_Vagina_Outer_s_F", "cf_J_Vagina_Inner_s_F", "cf_J_Vagina_Inner_s_F_L", "cf_J_Vagina_Inner_s_F_R", "cf_J_Vagina_Inner_s_L", "cf_J_Vagina_Inner_s_R", "cf_J_Vagina_Inner_s_B_L", "cf_J_Vagina_Inner_s_B_R", "cf_J_Vagina_Inner_s_B"};
41 | internal static readonly List KokanPullWeights = new List { 0.2f, 0.3f, 0.3f, 0.4f, 0.4f, 0.4f, 0.4f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
42 | 0.7f, 0.8f, 0.9f, 0.9f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
43 |
44 | /* internal static readonly List KokanPullBones = new List { "cf_J_Vagina_s_F", "cf_J_Vagina_s_F_L", "cf_J_Vagina_s_F_R", "cf_J_Vagina_s_M_F_L", "cf_J_Vagina_s_M_F_R", "cf_J_Vagina_s_M_L", "cf_J_Vagina_s_M_R", "cf_J_Vagina_s_M_B_L", "cf_J_Vagina_s_M_B_R", "cf_J_Vagina_s_B_L", "cf_J_Vagina_s_B_R", "cf_J_Vagina_s_B",
45 | "cf_J_Vagina_Outer_s_F", "cf_J_Vagina_Inner_s_F", "cf_J_Vagina_Inner_s_F_L", "cf_J_Vagina_Inner_s_F_R", "cf_J_Vagina_Inner_s_M_F_L", "cf_J_Vagina_Inner_s_M_F_R", "cf_J_Vagina_Inner_s_M_L", "cf_J_Vagina_Inner_s_M_R", "cf_J_Vagina_Inner_s_B_L", "cf_J_Vagina_Inner_s_M_B_R", "cf_J_Vagina_Inner_s_M_B_L", "cf_J_Vagina_Inner_s_B_R", "cf_J_Vagina_Inner_s_B"};
46 | internal static readonly List KokanPullWeights = new List { 0.2f, 0.3f, 0.3f, 0.4f, 0.4f, 0.4f, 0.4f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
47 | 0.7f, 0.8f, 0.9f, 0.9f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
48 | */
49 | internal static readonly List AnaPullBones = new List { "cf_J_Ana_s_F", "cf_J_Ana_s_B", "cf_J_Ana_s_L", "cf_J_Ana_s_R", "cf_J_Ana_s_F_L", "cf_J_Ana_s_F_R", "cf_J_Ana_s_B_L", "cf_J_Ana_s_B_R" };
50 | internal static readonly List AnaPullWeights = new List { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
51 | internal static readonly List DanBones = new List { "cm_J_dan101_00", "cm_J_dan102_00", "cm_J_dan103_00", "cm_J_dan104_00", "cm_J_dan105_00", "cm_J_dan106_00", "cm_J_dan107_00", "cm_J_dan108_00", "cm_J_dan109_00" };
52 | internal static readonly List VirtualDanBones = new List { "cm_J_vdan102_00", "cm_J_vdan104_00", "cm_J_vdan106_00", "cm_J_vdan108_00"};
53 | internal static readonly List TamaBones = new List { "cm_J_dan_Pivot_f_top", "cm_J_dan_Pivot_f_L", "cm_J_dan_Pivot_f_R"};
54 | internal static readonly List FingerColliders = new List { "cf_J_Hand_Index02_R", "cf_J_Hand_Index03_R", "cf_J_Hand_Middle02_R", "cf_J_Hand_Middle03_R", "cf_J_Hand_Ring02_R", "cf_J_Hand_Ring03_R" };
55 | internal static readonly List MidSectionColliders = new List { "cf_hit_Kosi02_s", "cf_hit_LegUp01_s_L", "cf_hit_LegUp01_s_R"};
56 | internal static readonly List BodyColliders = new List { "cf_hit_Kosi02_s", "cf_hit_LegLow02_s_L", "cf_hit_LegLow02_s_R", "cf_hit_LegUp01_s_L", "cf_hit_LegUp01_s_R",
57 | "cf_J_Spine01_s", "cf_J_Spine02_s", "cf_J_Spine03_s", "cf_hit_Mune02_s_L", "cf_hit_Mune02_s_R",
58 | "ColFace01", "ColFace02", "cf_J_Neck_s", "cf_J_ArmUp02_s_L", "cf_J_ArmUp02_s_R" };
59 | internal static readonly List frontCollisionList = new List { LookTargets.KokanTarget, "N_Waist_f"};
60 | internal static readonly List backCollisionList = new List { LookTargets.AnaTarget, "N_Waist_b"};
61 | internal static readonly List animationAdjustmentList = new List { "ais_f_00", "ais_f_01", "ais_f_12", "ais_f_19", "ais_f_20" };
62 | internal static readonly List anaPullExceptionList = new List { "ais_f_13", "ais_f_31" };
63 |
64 | internal static readonly List vibeBones = new List { "J_vibe_00", "J_vibe_01", "J_vibe_02", "J_vibe_03", "J_vibe_04", "J_vibe_05"};
65 | internal static readonly List vibe2Bones = new List { "j_ai_hi_hitem02_02", "j_ai_hi_hitem02_03", "j_ai_hi_hitem02_04", "j_ai_hi_hitem02_05", "j_ai_hi_hitem02_06", "j_ai_hi_hitem02_07" };
66 | internal static readonly List dildoBones = new List { "J_dildo_00", "J_dildo_01", "J_dildo_02", "J_dildo_03", "J_dildo_04", "J_dildo_05" };
67 | internal static readonly List tentacleBones = new List { "j_S_kokan_01", "j_S_kokan_02", "j_S_kokan_03", "j_S_kokan_04", "j_S_kokan_05" };
68 | internal static readonly List anaVibeBones = new List { "J_analvibe_ball_03", "J_analvibe_ball_04", "J_analvibe_ball_05", "J_analvibe_ball_06", "J_analvibe_ball_07", "J_analvibe_ball_08", "J_analvibe_ball_09", "J_analvibe_ball_10" };
69 | internal static readonly List anaTentacleBones = new List { "j_S_ana_01", "j_S_ana_02", "j_S_ana_03", "j_S_ana_04", "j_S_ana_05" };
70 |
71 | internal static readonly List vibeAnimationNames = new List { "ait_f_14", "aia_f_15", "aia_f_16", "aia_f_20" };
72 | internal static readonly List vibe2AnimationNames = new List {"ait_f_13" };
73 | internal static readonly List dildoAnimationNames = new List {"ait_f_02" };
74 | internal static readonly List tentacleAnimationNames = new List {"h2t_f_09", "h2t_f_10" };
75 | internal static readonly List anaVibeAnimationNames = new List { "ait_f_13", "ait_f_14", "aia_f_09", "aia_f_16" };
76 |
77 | internal static readonly List maleFingerAnimationNames = new List { "aia_f_03", "aia_f_05", "aia_f_14", "aia_f_21", "h2a_f_00", "h2a_f_01", "h2_mf2_f1_02", "h2_mf2_f2_05" };
78 | internal static readonly List femaleSelfFingerAnimationNames = new List { "aia_f_07", "ait_f_01", "ait_f_03", "ait_f_04", "ait_f_05", "ait_f_06", "ait_f_08", "ait_f_09"};
79 | internal static readonly List lesbianFingerAnimationNames = new List { "ail_f1_01", "ail_f2_01" };
80 | }
81 | #endif
82 |
83 | #if KK || KKS
84 | static class LookTargets
85 | {
86 | internal const string HeadTarget = "k_f_head_00";
87 | internal const string KokanTarget = "k_f_kokan_00";
88 | internal const string BPKokanTarget = "cf_J_Vagina_root";
89 | internal const string BPAnaTarget = "cf_J_Ana_Root";
90 | internal const string AnaTarget = "k_f_ana_00";
91 | internal const string InnerTarget = "cf_j_waist01";
92 | internal const string InnerHeadTarget = "cf_J_FaceBase";
93 | }
94 |
95 | static class BoneNames
96 | {
97 | internal const string KokanBone = "cf_j_kokan";
98 | internal const string TamaTop = "cm_J_dan_f_top";
99 | internal const string BPBone = "cf_J_Vagina";
100 | internal const string BellyBone = "cf_J_Belly";
101 | internal const string BPDanBone = "cm_J_dan";
102 | internal const string virtualBPDanBone = "cm_J_vdan";
103 | internal const string BPDanEnd = "cm_J_dan119_00";
104 | internal const string MouthPullBone = "cf_J_MouthMove";
105 | internal const string ButtBoneL = "cf_J_Siri_s_L";
106 | internal const string ButtBoneR = "cf_J_Siri_s_R";
107 |
108 | internal const string BPKokanTarget = "cf_J_Vagina_root";
109 | internal const string AnaTarget = "cf_j_ana";
110 | internal const string InnerTarget = "cf_j_waist01";
111 | internal const string HeadTarget = "cf_J_MouthLow";
112 | internal const string InnerHeadTarget = "cf_J_FaceBase";
113 | internal const string BPDanEntryTarget = "k_f_dan_entry";
114 | internal const string BPDanEndTarget = "k_f_dan_end";
115 |
116 | internal static readonly List KokanPullBones = new List { "cf_J_Vagina_L.011", "cf_J_Vagina_R.011", "cf_J_Vagina_L.012", "cf_J_Vagina_R.012", "cf_J_Vagina_L.013", "cf_J_Vagina_R.013",
117 | "cf_J_Vagina_L.014", "cf_J_Vagina_L.015", "cf_J_Vagina_R.014", "cf_J_Vagina_R.015", "cf_J_Vagina_B.010" };
118 | internal static readonly List KokanPullWeights = new List { 0.1f, 0.25f, 0.25f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,
119 | 0.4f, 0.7f, 0.7f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
120 |
121 | internal static readonly List AnaPullBones = new List { "cf_J_Ana_s_F", "cf_J_Ana_s_B", "cf_J_Ana_s_L", "cf_J_Ana_s_R", "cf_J_Ana_s_F_L", "cf_J_Ana_s_F_R", "cf_J_Ana_s_B_L", "cf_J_Ana_s_B_R" };
122 | internal static readonly List AnaPullWeights = new List { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
123 | internal static readonly List AnaBones = new List { "cf_J_Ana_Pivot", "cf_J_Vagina_Pivot_B", "cf_J_Vagina_Pivot_L.005", "cf_J_Vagina_Pivot_R.005" };
124 | internal static readonly List DanBones = new List { "cm_J_dan101_00", "cm_J_dan102_00", "cm_J_dan103_00", "cm_J_dan104_00", "cm_J_dan105_00", "cm_J_dan106_00", "cm_J_dan107_00", "cm_J_dan108_00", "cm_J_dan109_00" };
125 | internal static readonly List VirtualDanBones = new List { "cm_J_vdan102_00", "cm_J_vdan104_00", "cm_J_vdan106_00", "cm_J_vdan108_00"};
126 | internal static readonly List TamaBones = new List { "cm_J_dan_Pivot_f_L", "cm_J_dan_Pivot_f_R" };
127 | internal static readonly List FingerColliders = new List { "cf_j_index02_R", "cf_j_index03_R", "cf_j_middle02_R", "cf_j_middle03_R", "cf_j_ring02_R", "cf_j_ring03_R" };
128 | internal static readonly List MidSectionColliders = new List { "cm_J_dan101_00", "cm_J_dan103_00", "cf_hit_waist02", "cf_hit_LegLow02_s_L", "cf_hit_LegLow02_s_R" };
129 | internal static readonly List BodyColliders = new List { "cf_hit_thigh01_L", "cf_hit_thigh01_R", "cf_hit_thigh02_L", "cf_hit_thigh02_R",
130 | "cf_hit_waist_L", "cf_hit_berry", "cf_hit_waist01", "cf_hit_waist02",
131 | "cf_hit_spine01", "cf_hit_spine02", "cf_hit_spine03", "cf_hit_spine03_2",
132 | "cf_hit_bust00", "cf_hit_bust02_L", "cf_hit_bust02_R",
133 | "cf_hit_neck", "cf_hit_head",
134 | "cf_hit_arm_L", "cf_hit_arm_R", "cf_hit_shoulder_L", "cf_hit_shoulder_R" };
135 |
136 | internal static readonly List frontCollisionList = new List { LookTargets.KokanTarget, "a_n_waist_f", "a_n_bust_f" };
137 | internal static readonly List backCollisionList = new List { LookTargets.AnaTarget, "a_n_waist_b", "a_n_back" };
138 | internal static readonly List frontAnaCollisionList = new List { LookTargets.KokanTarget, "a_n_waist_f", "a_n_bust_f" };
139 | internal static readonly List animationAdjustmentList = new List { "ais_f_00", "ais_f_01", "ais_f_12", "ais_f_19", "ais_f_20" };
140 | internal static readonly List anaPullExceptionList = new List { "ais_f_13", "ais_f_31" };
141 |
142 | internal static readonly List maleFingerAnimationNames = new List { "aia_f_03", "aia_f_05", "aia_f_14", "aia_f_21", "h2a_f_00", "h2_mf2_f1_02", "h2_mf2_f2_05" };
143 | internal static readonly List femaleSelfFingerAnimationNames = new List { "ait_f_01", "ait_f_03", "ait_f_04", "ait_f_05", "ait_f_06", "ait_f_08", "ait_f_09"};
144 | internal static readonly List lesbianFingerAnimationNames = new List { "ail_f1_01", "ail_f2_01" };
145 | }
146 | #endif
147 | }
148 |
--------------------------------------------------------------------------------
/Core_BetterPenetration/Studio_BetterPenetration.cs:
--------------------------------------------------------------------------------
1 | #if Studio
2 | using BepInEx;
3 | using BepInEx.Bootstrap;
4 | using HarmonyLib;
5 | using UnityEngine;
6 | using KKAPI.Studio;
7 | using KKAPI.Studio.UI;
8 | using KKAPI.Chara;
9 | using UniRx;
10 | using System;
11 | using System.Linq;
12 | using System.Reflection;
13 | #if AI || HS2
14 | using AIChara;
15 | #endif
16 |
17 | namespace Core_BetterPenetration
18 | {
19 | [BepInPlugin(GUID, PluginName, VERSION)]
20 | [BepInDependency("com.deathweasel.bepinex.uncensorselector", "3.10")]
21 | [BepInDependency("com.rclcircuit.bepinex.modboneimplantor", "1.1.1")]
22 | [BepInDependency("com.joan6694.illusionplugins.nodesconstraints")]
23 | [BepInProcess(KKAPI.KoikatuAPI.StudioProcessName)]
24 | public class Studio_BetterPenetration : BaseUnityPlugin
25 | {
26 | public const string GUID = "com.animal42069.studiobetterpenetration";
27 | internal const string PluginName = "Studio Better Penetration";
28 | public const string VERSION = Constants.PluginVersion;
29 | internal const string BEHAVIOR = "BetterPenetrationController";
30 | internal const string StudioCategoryName = "Better Penetration";
31 | internal static Harmony harmony;
32 | internal static BaseUnityPlugin nodeConstraintPlugin;
33 | internal static bool reloadConstraints = false;
34 | internal static int updateCount = 0;
35 | internal static int resetDelay = 0;
36 |
37 | internal void Main()
38 | {
39 | CharacterApi.RegisterExtraBehaviour(BEHAVIOR);
40 |
41 | harmony = new Harmony("Studio_BetterPenetration");
42 | harmony.PatchAll(GetType());
43 |
44 | Chainloader.PluginInfos.TryGetValue("com.deathweasel.bepinex.uncensorselector", out PluginInfo pluginInfo);
45 | if (pluginInfo == null || pluginInfo.Instance == null)
46 | return;
47 |
48 | Type nestedType = pluginInfo.Instance.GetType().GetNestedType("UncensorSelectorController", AccessTools.all);
49 | if (nestedType == null)
50 | return;
51 |
52 | MethodInfo methodInfo = AccessTools.Method(nestedType, "ReloadCharacterBody", null, null);
53 | if (methodInfo == null)
54 | return;
55 |
56 | harmony.Patch(methodInfo, prefix: new HarmonyMethod(GetType(), "BeforeCharacterReload"));
57 | UnityEngine.Debug.Log("Studio_BetterPenetration: patched UncensorSelector::ReloadCharacterBody correctly");
58 |
59 | methodInfo = AccessTools.Method(nestedType, "ReloadCharacterBalls", null, null);
60 | if (methodInfo == null)
61 | return;
62 |
63 | harmony.Patch(methodInfo, postfix: new HarmonyMethod(GetType(), "AfterTamaCharacterReload"));
64 | UnityEngine.Debug.Log("Studio_BetterPenetration: patched UncensorSelectorController::ReloadCharacterBalls correctly");
65 |
66 | Chainloader.PluginInfos.TryGetValue("com.joan6694.illusionplugins.nodesconstraints", out pluginInfo);
67 | if (pluginInfo == null || pluginInfo.Instance == null)
68 | return;
69 |
70 | nodeConstraintPlugin = pluginInfo.Instance;
71 | Type nodeConstraintType = nodeConstraintPlugin.GetType();
72 | if (nodeConstraintType == null)
73 | return;
74 |
75 | // Find the most specific AddConstraint method since it's the one that always runs
76 | methodInfo = AccessTools.GetDeclaredMethods(nodeConstraintType).Where(x => x.Name == "AddConstraint").OrderByDescending(x => x.GetParameters().Length).FirstOrDefault();
77 | if (methodInfo == null)
78 | return;
79 |
80 | harmony.Patch(methodInfo, postfix: new HarmonyMethod(GetType(), nameof(AfterAddConstraint)));
81 | UnityEngine.Debug.Log("Studio_BetterPenetration: patched NodeConstraints::AddConstraint correctly");
82 |
83 | methodInfo = AccessTools.Method(nodeConstraintType, "ApplyNodesConstraints", null, null);
84 | if (methodInfo == null)
85 | return;
86 |
87 | harmony.Patch(methodInfo, postfix: new HarmonyMethod(GetType(), nameof(AfterApplyNodesConstraints)));
88 | UnityEngine.Debug.Log("Studio_BetterPenetration: patched NodeConstraints::ApplyNodesConstraints correctly");
89 |
90 | methodInfo = AccessTools.Method(nodeConstraintType, "ApplyConstraints", null, null);
91 | if (methodInfo == null)
92 | return;
93 |
94 | harmony.Patch(methodInfo, postfix: new HarmonyMethod(GetType(), nameof(AfterApplyConstraints)));
95 | UnityEngine.Debug.Log("Studio_BetterPenetration: patched NodeConstraints::ApplyConstraints correctly");
96 |
97 | RegisterStudioControllerBasic();
98 | }
99 |
100 | public static void RegisterStudioControllerBasic()
101 | {
102 | if (!StudioAPI.InsideStudio)
103 | return;
104 |
105 | var bpEnable = new CurrentStateCategorySwitch("Enable BP Controller", c => StudioAPI.GetSelectedControllers().First().enabled);
106 | bpEnable.Value.Subscribe(value =>
107 | {
108 | foreach (var controller in StudioAPI.GetSelectedControllers())
109 | {
110 | if (value == false)
111 | {
112 | controller.ClearDanAgent();
113 | controller.enabled = false;
114 | }
115 | else
116 | {
117 | controller.enabled = true;
118 | controller.InitializeDanAgent();
119 | controller.AddDanConstraints(nodeConstraintPlugin);
120 | }
121 | }
122 | });
123 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(bpEnable);
124 |
125 | var colliderRadiusScale = new CurrentStateCategorySlider("Collilder Radius Scale", c => StudioAPI.GetSelectedControllers().First().DanColliderRadiusScale, 0.5f, 1.5f);
126 | colliderRadiusScale.Value.Subscribe(value =>
127 | {
128 | foreach (var controller in StudioAPI.GetSelectedControllers())
129 | controller.DanColliderRadiusScale = value;
130 | });
131 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(colliderRadiusScale);
132 |
133 | var colliderLengthScale = new CurrentStateCategorySlider("Collilder Length Scale", c => StudioAPI.GetSelectedControllers().First().DanColliderLengthScale, 0.5f, 1.5f);
134 | colliderLengthScale.Value.Subscribe(value =>
135 | {
136 | foreach (var controller in StudioAPI.GetSelectedControllers())
137 | controller.DanColliderLengthScale = value;
138 | });
139 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(colliderLengthScale);
140 |
141 | var lengthSlider = new CurrentStateCategorySlider("Length Squish", c => StudioAPI.GetSelectedControllers().First().DanLengthSquish, 0f, 1f);
142 | lengthSlider.Value.Subscribe(value =>
143 | {
144 | foreach (var controller in StudioAPI.GetSelectedControllers())
145 | controller.DanLengthSquish = value;
146 | });
147 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(lengthSlider);
148 |
149 | var girthSlider = new CurrentStateCategorySlider("Girth Squish", c => StudioAPI.GetSelectedControllers().First().DanGirthSquish, 0f, 2f);
150 | girthSlider.Value.Subscribe(value =>
151 | {
152 | foreach (var controller in StudioAPI.GetSelectedControllers())
153 | controller.DanGirthSquish = value;
154 | });
155 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(girthSlider);
156 |
157 | var thresholdSlider = new CurrentStateCategorySlider("Squish Threshold", c => StudioAPI.GetSelectedControllers().First().DanSquishThreshold, 0f, 1f);
158 | thresholdSlider.Value.Subscribe(value =>
159 | {
160 | foreach (var controller in StudioAPI.GetSelectedControllers())
161 | controller.DanSquishThreshold = value;
162 | });
163 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(thresholdSlider);
164 |
165 | var autoTargeter = new CurrentStateCategoryDropdown("Auto-Target", new string[] { "Off", "Vaginal", "Anal", "Oral" }, c => StudioAPI.GetSelectedControllers().First().DanAutoTarget);
166 | autoTargeter.Value.Subscribe(value =>
167 | {
168 | foreach (var controller in StudioAPI.GetSelectedControllers())
169 | controller.DanAutoTarget = value;
170 | });
171 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(autoTargeter);
172 |
173 | var maxPush = new CurrentStateCategorySlider("Max Push", c => StudioAPI.GetSelectedControllers().First().MaxPush, 0f, 0.3f);
174 | maxPush.Value.Subscribe(value =>
175 | {
176 | foreach (var controller in StudioAPI.GetSelectedControllers())
177 | controller.MaxPush = value;
178 | });
179 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(maxPush);
180 |
181 | var maxPull = new CurrentStateCategorySlider("Max Pull", c => StudioAPI.GetSelectedControllers().First().MaxPull, 0f, 0.3f);
182 | maxPull.Value.Subscribe(value =>
183 | {
184 | foreach (var controller in StudioAPI.GetSelectedControllers())
185 | controller.MaxPull = value;
186 | });
187 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(maxPull);
188 |
189 | var pullRate = new CurrentStateCategorySlider("Pull Rate", c => StudioAPI.GetSelectedControllers().First().PullRate, 0f, 50f);
190 | pullRate.Value.Subscribe(value =>
191 | {
192 | foreach (var controller in StudioAPI.GetSelectedControllers())
193 | controller.PullRate = value;
194 | });
195 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(pullRate);
196 |
197 | var returnRate = new CurrentStateCategorySlider("Return Rate", c => StudioAPI.GetSelectedControllers().First().ReturnRate, 0f, 1f);
198 | returnRate.Value.Subscribe(value =>
199 | {
200 | foreach (var controller in StudioAPI.GetSelectedControllers())
201 | controller.ReturnRate = value;
202 | });
203 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(returnRate);
204 |
205 | #if AI || HS2
206 | var bellyBulgeEnable = new CurrentStateCategorySwitch("Enable Belly Bulge", c => StudioAPI.GetSelectedControllers().First().EnableBellyBulge);
207 | bellyBulgeEnable.Value.Subscribe(value =>
208 | {
209 | foreach (var controller in StudioAPI.GetSelectedControllers())
210 | controller.EnableBellyBulge = value;
211 | });
212 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(bellyBulgeEnable);
213 |
214 | var bellyBulgeScale = new CurrentStateCategorySlider("Belly Bulge Scale", c => StudioAPI.GetSelectedControllers().First().BellyBulgeScale, 0.0f, 3.0f);
215 | bellyBulgeScale.Value.Subscribe(value =>
216 | {
217 | foreach (var controller in StudioAPI.GetSelectedControllers())
218 | controller.BellyBulgeScale = value;
219 | });
220 | StudioAPI.GetOrCreateCurrentStateCategory(StudioCategoryName).AddControl(bellyBulgeScale);
221 | #endif
222 | }
223 |
224 | public static void RegisterStudioControls()
225 | {
226 | if (!StudioAPI.InsideStudio)
227 | return;
228 | }
229 |
230 | [HarmonyPostfix, HarmonyPatch(typeof(ChaControl), "UpdateAccessoryMoveFromInfo")]
231 | internal static void ChaControl_UpdateAccessoryMoveFromInfo(ChaControl __instance)
232 | {
233 | Tools.RemoveCollidersFromCoordinate(__instance);
234 | }
235 |
236 | [HarmonyPostfix, HarmonyPatch(typeof(ChaControl), "UpdateSiru")]
237 | internal static void ChaControl_UpdateSiru(ChaControl __instance, bool forceChange)
238 | {
239 |
240 | if (!forceChange)
241 | return;
242 |
243 | Tools.RemoveCollidersFromCoordinate(__instance);
244 | }
245 |
246 | internal static void BeforeCharacterReload()
247 | {
248 | foreach (var controller in BetterPenetrationController.controllers)
249 | {
250 | if (controller == null)
251 | continue;
252 |
253 | controller.ClearDanAgent();
254 | }
255 | }
256 |
257 | internal static void AfterTamaCharacterReload()
258 | {
259 | reloadConstraints = true;
260 | }
261 |
262 | internal static void AfterAddConstraint(bool enabled, Transform parentTransform, Transform childTransform,
263 | bool linkPosition, Vector3 positionOffset, bool linkRotation, Quaternion rotationOffset, bool linkScale,
264 | Vector3 scaleOffset, string alias)
265 | {
266 | if (childTransform.name != BoneNames.BPDanEntryTarget && childTransform.name != BoneNames.BPDanEndTarget)
267 | return;
268 |
269 | var controller = childTransform.GetComponentInParent();
270 | if (controller == null)
271 | return;
272 |
273 | var constrainParams = new object[] { enabled, parentTransform.name, childTransform, linkPosition, positionOffset,
274 | linkRotation, rotationOffset, linkScale, scaleOffset, alias};
275 |
276 | controller.SaveConstraintParams(childTransform.name == BoneNames.BPDanEntryTarget, constrainParams);
277 |
278 | if (childTransform.name != BoneNames.BPDanEntryTarget)
279 | return;
280 |
281 | var targetChaControl = parentTransform.GetComponentInParent();
282 | if (targetChaControl == null)
283 | return;
284 |
285 | controller.SetCollisionAgent(targetChaControl, parentTransform.name == BoneNames.BPKokanTarget, parentTransform.name == BoneNames.AnaTarget, parentTransform.name == BoneNames.HeadTarget);
286 | }
287 |
288 | internal static void AfterApplyConstraints()
289 | {
290 | if (!reloadConstraints)
291 | return;
292 |
293 | resetDelay = 60;
294 | reloadConstraints = false;
295 | }
296 |
297 | internal static void AfterApplyNodesConstraints()
298 | {
299 | if (!reloadConstraints)
300 | return;
301 |
302 | resetDelay = 60;
303 | reloadConstraints = false;
304 | }
305 |
306 | internal static void ReinitializeControllers()
307 | {
308 | if (nodeConstraintPlugin == null)
309 | return;
310 |
311 | foreach (var controller in BetterPenetrationController.controllers)
312 | {
313 | if (controller == null)
314 | continue;
315 |
316 | controller.InitializeDanAgent();
317 | controller.AddDanConstraints(nodeConstraintPlugin);
318 | }
319 | }
320 |
321 | internal void Update()
322 | {
323 | if (nodeConstraintPlugin == null)
324 | return;
325 |
326 | if (resetDelay > 0 && --resetDelay <= 0)
327 | ReinitializeControllers();
328 |
329 | if (++updateCount < 60)
330 | return;
331 |
332 | updateCount = 0;
333 |
334 | foreach (var controller in BetterPenetrationController.controllers)
335 | {
336 | if (controller == null)
337 | continue;
338 |
339 | controller.CheckAutoTarget(nodeConstraintPlugin);
340 | }
341 | }
342 | }
343 | }
344 | #endif
--------------------------------------------------------------------------------
/Core_BetterPenetration/CoreGame.cs:
--------------------------------------------------------------------------------
1 | #if !Studio
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using System;
5 | using System.Linq;
6 |
7 | #if HS2 || AI
8 | using AIChara;
9 | #endif
10 |
11 | namespace Core_BetterPenetration
12 | {
13 | class CoreGame
14 | {
15 | internal static List danAgents;
16 | internal static List collisionAgents;
17 | internal static List danHasNewTarget;
18 | #if HS2 || AI
19 | internal static List itemColliderInfo;
20 | internal static List anaItemColliderInfo;
21 | internal static List m_itemColliders = new List();
22 | internal static List m_anaItemColliders = new List();
23 | #endif
24 |
25 | public static void InitializeAgents(List danCharacterList, List collisionCharacterList, List danOptions, List collisionOptions)
26 | {
27 | InitializeDanAgents(danCharacterList, danOptions);
28 | InitializeCollisionAgents(collisionCharacterList, collisionOptions);
29 | #if HS2 || AI
30 | InitializeItemColliderInfo();
31 | #endif
32 | }
33 |
34 | public static void InitializeDanAgents(List danCharacterList, List danOptions)
35 | {
36 | danAgents = new List();
37 | danHasNewTarget = new List();
38 |
39 | int characterNum = 0;
40 | foreach (var character in danCharacterList)
41 | {
42 | if (character == null)
43 | continue;
44 |
45 | danAgents.Add(new DanAgent(character, danOptions[characterNum]));
46 | danHasNewTarget.Add(false);
47 | characterNum++;
48 | }
49 | }
50 |
51 | public static void ClearDanAgents()
52 | {
53 | if (danAgents == null)
54 | return;
55 |
56 | foreach (var agent in danAgents)
57 | agent.ClearDanAgent();
58 | }
59 |
60 | internal static void ClearCollisionAgents()
61 | {
62 | if (collisionAgents == null)
63 | return;
64 |
65 | foreach (var collisionAgent in collisionAgents)
66 | collisionAgent.ClearColliders();
67 | }
68 |
69 | public static void InitializeCollisionAgents(List collisionCharacterList, List collisionOptions)
70 | {
71 | collisionAgents = new List();
72 |
73 | int characterNum = 0;
74 | foreach (var character in collisionCharacterList)
75 | {
76 | if (character == null)
77 | continue;
78 |
79 | collisionAgents.Add(new CollisionAgent(character, collisionOptions[characterNum++]));
80 | }
81 | }
82 |
83 | public static void LookAtDanUpdate(Transform lookAtTransform, string currentMotion, bool topStick, bool changingAnimation, int maleNum, int femaleNum, bool twoDans, bool isInScene)
84 | {
85 | if (maleNum >= danAgents.Count || femaleNum >= collisionAgents.Count)
86 | return;
87 |
88 | if (!changingAnimation)
89 | {
90 | collisionAgents[femaleNum].AdjustMissionaryAnimation();
91 |
92 | if (topStick && lookAtTransform != null && (lookAtTransform.name == LookTargets.AnaTarget || lookAtTransform.name == LookTargets.BPAnaTarget))
93 | collisionAgents[femaleNum].AdjustAnalAnimation();
94 | }
95 |
96 | if (danHasNewTarget[maleNum] && !changingAnimation)
97 | LookAtDanSetup(lookAtTransform, currentMotion, topStick, maleNum, femaleNum, twoDans, isInScene);
98 |
99 | danAgents[maleNum].SetDanTarget(collisionAgents[femaleNum], twoDans);
100 | }
101 |
102 | public static void LookAtDanSetup(Transform lookAtTransform, string currentMotion, bool topStick, int maleNum, int femaleNum, bool twoDans, bool isInScene)
103 | {
104 | if (maleNum >= danAgents.Count || femaleNum >= collisionAgents.Count)
105 | return;
106 |
107 | if (!twoDans && danAgents.Count > 1 && danAgents[1] != null)
108 | {
109 | danAgents[1].RemoveDanColliders(collisionAgents[femaleNum]);
110 | #if HS2 || AI
111 | danAgents[1].RemoveMidsectionColliders(collisionAgents[femaleNum].m_collisionCharacter);
112 | danAgents[1].RemoveDanCollidersFromDB2(collisionAgents[femaleNum].m_collisionCharacter);
113 | #endif
114 | }
115 |
116 | if (maleNum == 1 && !twoDans)
117 | return;
118 |
119 | CollisionAgent firstAgent = collisionAgents[femaleNum];
120 | CollisionAgent secondAgent = null;
121 |
122 | var secondFemaleNum = femaleNum == 0 ? 1 : 0;
123 | if (collisionAgents.Count > secondFemaleNum && collisionAgents[secondFemaleNum].m_collisionCharacter.visibleAll && collisionAgents[secondFemaleNum].m_collisionCharacter.objTop != null)
124 | secondAgent = collisionAgents[secondFemaleNum];
125 |
126 | danAgents[maleNum].SetupNewDanTarget(lookAtTransform, currentMotion, topStick, isInScene, firstAgent, secondAgent, twoDans);
127 | danHasNewTarget[maleNum] = false;
128 | }
129 |
130 | public static void ClearKokanBones()
131 | {
132 | if (collisionAgents == null || collisionAgents.Count == 0)
133 | return;
134 |
135 | foreach (var agent in collisionAgents)
136 | {
137 | if (agent == null)
138 | continue;
139 |
140 | agent.ClearKokanDynamicBones();
141 | }
142 | }
143 |
144 | public static void LookAtDanRelease(int maleNum, int femaleNum, bool twoDans)
145 | {
146 | if (maleNum >= danAgents.Count || femaleNum >= collisionAgents.Count)
147 | return;
148 |
149 | if (!twoDans && danAgents.Count > 1 && danAgents[1] != null)
150 | {
151 | danAgents[1].RemoveDanColliders(collisionAgents[femaleNum]);
152 | #if HS2 || AI
153 | danAgents[1].RemoveMidsectionColliders(collisionAgents[femaleNum].m_collisionCharacter);
154 | danAgents[1].RemoveDanCollidersFromDB2(collisionAgents[femaleNum].m_collisionCharacter);
155 | #endif
156 | }
157 |
158 | if (maleNum == 1 && !twoDans)
159 | return;
160 |
161 | if (collisionAgents.Count > 1 && collisionAgents[1].m_collisionCharacter.visibleAll && collisionAgents[1].m_collisionCharacter.objTop != null)
162 | {
163 | var secondTarget = 1 - femaleNum;
164 | if (secondTarget < 0)
165 | secondTarget = 0;
166 |
167 | danAgents[maleNum].ClearDanTarget(collisionAgents[femaleNum], collisionAgents[secondTarget]);
168 | }
169 | else
170 | {
171 | danAgents[maleNum].ClearDanTarget(collisionAgents[femaleNum]);
172 | }
173 | }
174 |
175 | public static void OnChangeAnimation(string newAnimationFile)
176 | {
177 | foreach (var socketAgent in collisionAgents)
178 | socketAgent.adjustFAnimation = false;
179 |
180 | SetDansHaveNewTarget(true);
181 |
182 | if (collisionAgents == null || collisionAgents[0] == null)
183 | return;
184 |
185 | collisionAgents[0].CheckForAdjustment(newAnimationFile);
186 | }
187 |
188 | public static void ResetParticles()
189 | {
190 | foreach (var agent in danAgents)
191 | agent.ResetParticles();
192 |
193 | foreach (var agent in collisionAgents)
194 | agent.ResetParticles();
195 | }
196 |
197 | public static void EnableParticles(bool enable)
198 | {
199 | foreach (var agent in collisionAgents)
200 | agent.EnableParticles(enable);
201 | }
202 |
203 | public static void SetDansHaveNewTarget(bool set)
204 | {
205 | for (int index = 0; index < danHasNewTarget.Count; index++)
206 | danHasNewTarget[index] = set;
207 | }
208 |
209 | public static void UpdateDanCollider(int maleNum, float danRadiusScale, float danLengthScale)
210 | {
211 | if (maleNum >= danAgents.Count || danAgents[maleNum] == null)
212 | return;
213 |
214 | danAgents[maleNum].UpdateDanColliders(danRadiusScale, danLengthScale);
215 | }
216 |
217 | public static void UpdateDanOptions(int maleNum, float danLengthSquish, float danGirthSquish, float squishThreshold, bool squishOralGirth, bool simplifyVaginal, bool simplifyOral, bool rotateTamaWithShaft, bool limitCorrection, float maxCorrection)
218 | {
219 | if (maleNum >= danAgents.Count || danAgents[maleNum] == null)
220 | return;
221 |
222 | danAgents[maleNum].UpdateDanOptions(danLengthSquish, danGirthSquish, squishThreshold, squishOralGirth, simplifyVaginal, simplifyOral, rotateTamaWithShaft, limitCorrection, maxCorrection);
223 | }
224 |
225 | public static void UpdateCollisionOptions(int femaleNum, CollisionOptions options)
226 | {
227 | if (femaleNum >= collisionAgents.Count || collisionAgents[femaleNum] == null)
228 | return;
229 |
230 | collisionAgents[femaleNum].UpdateCollisionOptions(options);
231 | }
232 |
233 | public static void OnEndScene()
234 | {
235 | ClearDanAgents();
236 | ClearCollisionAgents();
237 | danAgents = null;
238 | collisionAgents = null;
239 | danHasNewTarget = null;
240 | }
241 |
242 | internal static void SetAgentsBPBoneWeights(float weight)
243 | {
244 | SetDanAgentsBPBoneWeights(weight);
245 | SetCollisionAgentsBPBoneWeights(weight);
246 | }
247 |
248 | internal static void SetDanAgentsBPBoneWeights(float weight)
249 | {
250 | if (danAgents == null)
251 | return;
252 |
253 | foreach (var agent in danAgents)
254 | {
255 | if (agent?.m_danCharacter == null)
256 | continue;
257 |
258 | SetBPBoneWeights(agent.m_danCharacter, weight);
259 | }
260 | }
261 |
262 | internal static void SetCollisionAgentsBPBoneWeights(float weight)
263 | {
264 | if (collisionAgents == null)
265 | return;
266 |
267 | foreach (var agent in collisionAgents)
268 | {
269 | if (agent?.m_collisionCharacter == null)
270 | continue;
271 |
272 | SetBPBoneWeights(agent.m_collisionCharacter, weight);
273 | }
274 | }
275 |
276 | internal static void SetBPBoneWeights(ChaControl character, float weight)
277 | {
278 | var dynamicBones = character.GetComponentsInChildren(true);
279 |
280 | if (dynamicBones == null)
281 | return;
282 |
283 | foreach (var dynamicBone in dynamicBones)
284 | {
285 | if (dynamicBone == null ||
286 | dynamicBone.m_Root == null ||
287 | dynamicBone.name == null ||
288 | character != dynamicBone.GetComponentInParent())
289 | continue;
290 |
291 | if (dynamicBone.name.Contains(BoneNames.BPBone) || dynamicBone.name.Contains(BoneNames.BellyBone))
292 | dynamicBone.SetWeight(weight);
293 | }
294 | }
295 |
296 | internal static void SetupFingerColliders(string animation)
297 | {
298 | DanAgent danAgent = null;
299 |
300 | if (danAgents != null && danAgents.Count > 0)
301 | danAgent = danAgents[0];
302 |
303 | CollisionAgent firstAgent = collisionAgents[0];
304 | CollisionAgent secondAgent = null;
305 | if (collisionAgents.Count > 1 && collisionAgents[1].m_collisionCharacter.visibleAll && collisionAgents[1].m_collisionCharacter.objTop != null)
306 | secondAgent = collisionAgents[1];
307 |
308 | ClearFingerColliders(danAgent, firstAgent, secondAgent);
309 | AddFingerColliders(animation, danAgent, firstAgent, secondAgent);
310 | }
311 |
312 | internal static void ClearFingerColliders()
313 | {
314 | DanAgent danAgent = null;
315 |
316 | if (danAgents != null && danAgents.Count > 0)
317 | danAgent = danAgents[0];
318 |
319 | CollisionAgent firstAgent = collisionAgents[0];
320 | CollisionAgent secondAgent = null;
321 | if (collisionAgents.Count > 1)
322 | secondAgent = collisionAgents[1];
323 |
324 | ClearFingerColliders(danAgent, firstAgent, secondAgent);
325 | }
326 |
327 | internal static void ClearFingerColliders(DanAgent danAgent, CollisionAgent firstAgent, CollisionAgent secondAgent = null)
328 | {
329 | if (firstAgent == null)
330 | return;
331 |
332 | firstAgent.RemoveFingerColliders(firstAgent);
333 |
334 | if (danAgent != null)
335 | danAgent.RemoveFingerColliders(firstAgent);
336 |
337 | if (secondAgent == null)
338 | return;
339 |
340 | firstAgent.RemoveFingerColliders(secondAgent);
341 | secondAgent.RemoveFingerColliders(firstAgent);
342 |
343 | if (danAgent != null)
344 | danAgent.RemoveFingerColliders(secondAgent);
345 | }
346 |
347 | internal static void AddFingerColliders(string animation, DanAgent danAgent, CollisionAgent firstAgent, CollisionAgent secondAgent = null)
348 | {
349 | if (animation == null || firstAgent == null)
350 | return;
351 |
352 | if (danAgent != null && BoneNames.maleFingerAnimationNames.Contains(animation))
353 | {
354 | danAgent.AddFingerColliders(firstAgent);
355 |
356 | if (secondAgent != null)
357 | danAgent.AddFingerColliders(secondAgent);
358 |
359 | return;
360 | }
361 |
362 | if (BoneNames.femaleSelfFingerAnimationNames.Contains(animation))
363 | {
364 | firstAgent.AddFingerColliders(firstAgent);
365 | return;
366 | }
367 |
368 | if (secondAgent == null)
369 | return;
370 |
371 | if (BoneNames.lesbianFingerAnimationNames.Contains(animation))
372 | {
373 | firstAgent.AddFingerColliders(secondAgent);
374 | secondAgent.AddFingerColliders(firstAgent);
375 | return;
376 | }
377 | }
378 |
379 | #if HS2 || AI
380 |
381 | internal static void SetupItemColliders(string animation)
382 | {
383 | ClearItemColliders();
384 | AddItemColliders(animation);
385 | }
386 |
387 | internal static void AddItemColliders(string animation)
388 | {
389 | if (danAgents == null || danAgents.Count <= 0 || danAgents[0] == null || collisionAgents == null || collisionAgents[0] == null)
390 | return;
391 |
392 | m_itemColliders = new List();
393 | m_itemColliders.AddRange(GetCharacterItemColliders(danAgents[0].m_danCharacter, animation));
394 | m_itemColliders.AddRange(GetCharacterItemColliders(collisionAgents[0].m_collisionCharacter, animation));
395 |
396 | m_anaItemColliders = new List();
397 | m_anaItemColliders.AddRange(GetCharacterAnaItemColliders(danAgents[0].m_danCharacter, animation));
398 | m_anaItemColliders.AddRange(GetCharacterAnaItemColliders(collisionAgents[0].m_collisionCharacter, animation));
399 |
400 | collisionAgents[0].AddCollidersToKokan(m_itemColliders);
401 | collisionAgents[0].AddCollidersToAna(m_anaItemColliders);
402 | }
403 |
404 | internal static List GetCharacterItemColliders(ChaControl character, string animation)
405 | {
406 | var itemList = new List();
407 |
408 | if (character == null)
409 | return itemList;
410 |
411 | foreach (var boneInfo in itemColliderInfo)
412 | {
413 | if (!boneInfo.animationNames.Contains(animation))
414 | continue;
415 |
416 | foreach (var boneName in boneInfo.itemBones)
417 | {
418 | var bones = character.GetComponentsInChildren().Where(bone => bone.name.Equals(boneName));
419 | if (bones == null || bones.Count() == 0)
420 | break;
421 |
422 | foreach (var bone in bones)
423 | {
424 | float radiusScale = Tools.ComputeRadiusScale(bone, boneInfo.direction);
425 | float heightScale = Tools.ComputeHeightScale(bone, boneInfo.direction);
426 |
427 | var collider = Tools.InitializeCollider(bone, boneInfo.colliderRadius * radiusScale, boneInfo.colliderHeight * heightScale, Vector3.zero, boneInfo.direction);
428 | itemList.Add(collider);
429 | }
430 | }
431 | }
432 |
433 | return itemList;
434 | }
435 |
436 | internal static List GetCharacterAnaItemColliders(ChaControl character, string animation)
437 | {
438 | var itemList = new List();
439 |
440 | if (character == null || anaItemColliderInfo == null)
441 | return itemList;
442 |
443 | foreach (var boneInfo in anaItemColliderInfo)
444 | {
445 | if (!boneInfo.animationNames.Contains(animation))
446 | continue;
447 |
448 | foreach (var boneName in boneInfo.itemBones)
449 | {
450 | var bones = character.GetComponentsInChildren().Where(bone => bone.name.Equals(boneName));
451 | if (bones == null || bones.Count() == 0)
452 | break;
453 |
454 | foreach (var bone in bones)
455 | {
456 | float radiusScale = Tools.ComputeRadiusScale(bone, boneInfo.direction);
457 | float heightScale = Tools.ComputeHeightScale(bone, boneInfo.direction);
458 |
459 | var collider = Tools.InitializeCollider(bone, boneInfo.colliderRadius * radiusScale, boneInfo.colliderHeight * heightScale, Vector3.zero, boneInfo.direction);
460 | itemList.Add(collider);
461 | }
462 | }
463 | }
464 |
465 | return itemList;
466 | }
467 |
468 | internal static void ClearItemColliders()
469 | {
470 | if (collisionAgents == null || collisionAgents[0] == null)
471 | return;
472 |
473 | collisionAgents[0].RemoveCollidersFromKokan(m_itemColliders);
474 | collisionAgents[0].RemoveCollidersFromAna(m_anaItemColliders);
475 | }
476 |
477 | internal static void InitializeItemColliderInfo()
478 | {
479 | InitializeKokanItemColliderInfo();
480 | InitializeItemAnaColliderInfo();
481 | }
482 |
483 | internal static void InitializeKokanItemColliderInfo()
484 | {
485 | itemColliderInfo = new List
486 | {
487 | #if HS2
488 | new ItemColliderInfo(BoneNames.vibeAnimationNames, BoneNames.vibeBones, DynamicBoneColliderBase.Direction.Y, 0.15f, 0.56f),
489 | new ItemColliderInfo(BoneNames.vibe2AnimationNames, BoneNames.vibe2Bones, DynamicBoneColliderBase.Direction.Y, 0.15f, 0.56f),
490 | new ItemColliderInfo(BoneNames.dildoAnimationNames, BoneNames.dildoBones, DynamicBoneColliderBase.Direction.Y, 0.172f, 0.576f),
491 | new ItemColliderInfo(BoneNames.tentacleAnimationNames, BoneNames.tentacleBones, DynamicBoneColliderBase.Direction.X, 0.164f, 0.656f)
492 | #else
493 | new ItemColliderInfo(BoneNames.vibeAnimationNames, BoneNames.vibeBones, DynamicBoneColliderBase.Direction.Y, 0.1f, 0.5f),
494 | new ItemColliderInfo(BoneNames.vibe2AnimationNames, BoneNames.vibe2Bones, DynamicBoneColliderBase.Direction.Y, 0.1f, 0.5f),
495 | new ItemColliderInfo(BoneNames.dildoAnimationNames, BoneNames.dildoBones, DynamicBoneColliderBase.Direction.Y, 0.115f, 0.5f),
496 | new ItemColliderInfo(BoneNames.tentacleAnimationNames, BoneNames.tentacleBones, DynamicBoneColliderBase.Direction.X, 0.115f, 0.625f),
497 | #endif
498 | };
499 | }
500 |
501 | internal static void InitializeItemAnaColliderInfo()
502 | {
503 | anaItemColliderInfo = new List
504 | {
505 | #if HS2
506 | new ItemColliderInfo(BoneNames.anaVibeAnimationNames, BoneNames.anaVibeBones, DynamicBoneColliderBase.Direction.Y, 0.125f, 0.4f),
507 | new ItemColliderInfo(BoneNames.tentacleAnimationNames, BoneNames.anaTentacleBones, DynamicBoneColliderBase.Direction.X, 0.164f, 0.656f)
508 | #else
509 | new ItemColliderInfo(BoneNames.anaVibeAnimationNames, BoneNames.anaVibeBones, DynamicBoneColliderBase.Direction.Y, 0.09f, 0.36f),
510 | new ItemColliderInfo(BoneNames.tentacleAnimationNames, BoneNames.tentacleBones, DynamicBoneColliderBase.Direction.X, 0.115f, 0.625f)
511 | #endif
512 | };
513 | }
514 |
515 | internal static void ToggleMaleColliders()
516 | {
517 | if (danAgents == null)
518 | return;
519 |
520 | foreach (var agent in danAgents)
521 | agent.ToggleMaleColliders();
522 | }
523 |
524 | #endif
525 | }
526 | }
527 | #endif
--------------------------------------------------------------------------------
/Core_BetterPenetration/CollisionAgent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using UnityEngine;
5 | #if HS2 || AI
6 | using AIChara;
7 | #endif
8 |
9 | namespace Core_BetterPenetration
10 | {
11 | class CollisionAgent
12 | {
13 | internal ChaControl m_collisionCharacter;
14 | internal CollisionPoints m_collisionPoints;
15 | internal CollisionOptions m_collisionOptions;
16 | internal bool m_collisionPointsFound = false;
17 |
18 | internal Transform m_bpKokanTarget;
19 | internal Transform m_bpAnaTarget;
20 | internal Transform m_innerTarget;
21 | internal Transform m_innerHeadTarget;
22 | internal Transform m_kokanBone;
23 | internal Transform m_siriBoneL;
24 | internal Transform m_siriBoneR;
25 | internal Transform m_oralPullBone;
26 | internal List m_kokanDynamicBones = new List();
27 | internal DynamicBone m_anaDynamicBones;
28 | internal DynamicBone m_bellyDynamicBone;
29 | internal List m_fingerColliders = new List();
30 | internal List m_kokanPullBones = new List();
31 | internal List m_anaPullBones = new List();
32 | internal Transform m_innerKokan;
33 |
34 | internal float currentKokanPull = 0f;
35 | internal float currentOralPull = 0f;
36 | internal float currentAnaPull = 0f;
37 | internal Vector3 currentKokanDanDirection = Vector3.up;
38 | internal Vector3 currentOralDanDirection = Vector3.Normalize(Vector3.up + Vector3.back);
39 | internal Vector3 currentAnaDanDirection = Vector3.up;
40 | internal bool adjustFAnimation = false;
41 | internal bool anaPullException = false;
42 | internal float m_bellyColliderRadius;
43 |
44 | public CollisionAgent(ChaControl character, CollisionOptions options)
45 | {
46 | Initialize(character, options);
47 | }
48 |
49 | internal void Initialize(ChaControl character, CollisionOptions options)
50 | {
51 | m_collisionOptions = options;
52 | currentKokanPull = 0f;
53 | currentOralPull = 0f;
54 | currentAnaPull = 0f;
55 | currentKokanDanDirection = Vector3.up;
56 | currentOralDanDirection = Vector3.Normalize(Vector3.up + Vector3.back);
57 | currentAnaDanDirection = Vector3.up;
58 |
59 | List frontCollisionPoints = new List();
60 | List backCollisionPoints = new List();
61 | m_collisionPointsFound = false;
62 |
63 | if (character == null)
64 | return;
65 |
66 | m_collisionCharacter = character;
67 |
68 | m_kokanBone = Tools.GetTransformOfChaControl(m_collisionCharacter, BoneNames.KokanBone);
69 | if (m_kokanBone == null)
70 | return;
71 |
72 | m_bpKokanTarget = Tools.GetTransformOfChaControl(m_collisionCharacter, LookTargets.BPKokanTarget);
73 | m_bpAnaTarget = Tools.GetTransformOfChaControl(m_collisionCharacter, LookTargets.BPAnaTarget);
74 | m_innerTarget = Tools.GetTransformOfChaControl(m_collisionCharacter, LookTargets.InnerTarget);
75 | m_innerHeadTarget = Tools.GetTransformOfChaControl(m_collisionCharacter, LookTargets.InnerHeadTarget);
76 | m_siriBoneL = Tools.GetTransformOfChaControl(m_collisionCharacter, BoneNames.ButtBoneL);
77 | m_siriBoneR = Tools.GetTransformOfChaControl(m_collisionCharacter, BoneNames.ButtBoneR);
78 | m_innerKokan = Tools.GetTransformOfChaControl(m_collisionCharacter, "cf_J_Vagina_Inner");
79 |
80 | #if !Studio
81 | for (int index = 0; index < options.frontCollisionInfo.Count; index++)
82 | {
83 | Transform frontCollisionPoint = Tools.GetTransformOfChaControl(m_collisionCharacter, options.frontCollisionInfo[index].name);
84 | frontCollisionPoints.Add(new CollisionPoint(frontCollisionPoint, options.frontCollisionInfo[index]));
85 | }
86 | for (int index = 0; index < options.backCollisonInfo.Count; index++)
87 | {
88 | Transform backCollisionPoint = Tools.GetTransformOfChaControl(m_collisionCharacter, options.backCollisonInfo[index].name);
89 | backCollisionPoints.Add(new CollisionPoint(backCollisionPoint, options.backCollisonInfo[index]));
90 | }
91 |
92 | if (frontCollisionPoints.Count == options.frontCollisionInfo.Count &&
93 | backCollisionPoints.Count == options.backCollisonInfo.Count &&
94 | m_innerTarget != null && m_innerHeadTarget != null)
95 | {
96 | m_collisionPointsFound = true;
97 | m_collisionPoints = new CollisionPoints(frontCollisionPoints, backCollisionPoints);
98 | }
99 | #else
100 | m_collisionPoints = null;
101 | #endif
102 | UnityEngine.Debug.Log($"constrainPointsFound {m_collisionPointsFound}");
103 |
104 | m_kokanDynamicBones = new List();
105 | foreach (DynamicBone dynamicBone in m_collisionCharacter.GetComponentsInChildren())
106 | {
107 | if (dynamicBone == null ||
108 | dynamicBone.m_Root == null ||
109 | dynamicBone.name == null ||
110 | m_collisionCharacter != dynamicBone.GetComponentInParent())
111 | continue;
112 |
113 | if (dynamicBone.name.Contains(BoneNames.BPBone))
114 | {
115 | dynamicBone.m_Colliders.Clear();
116 | m_kokanDynamicBones.Add(dynamicBone);
117 | }
118 | else if (dynamicBone.name.Contains(BoneNames.BellyBone))
119 | {
120 | dynamicBone.m_Colliders.Clear();
121 | m_bellyDynamicBone = dynamicBone;
122 | m_bellyColliderRadius = dynamicBone.m_Radius;
123 | UpdateBellyBones(options.bellyBulgeScale);
124 | }
125 | else if (dynamicBone.name.Contains(BoneNames.AnaTarget))
126 | {
127 | dynamicBone.m_Colliders.Clear();
128 | m_anaDynamicBones = dynamicBone;
129 | }
130 | }
131 |
132 | m_kokanPullBones = new List();
133 | foreach (var boneName in BoneNames.KokanPullBones)
134 | {
135 | var kokanTransform = Tools.GetTransformOfChaControl(m_collisionCharacter, boneName);
136 | if (kokanTransform == null)
137 | continue;
138 |
139 | m_kokanPullBones.Add(kokanTransform);
140 | }
141 |
142 | m_oralPullBone = Tools.GetTransformOfChaControl(m_collisionCharacter, BoneNames.MouthPullBone);
143 |
144 | foreach (var boneName in BoneNames.AnaPullBones)
145 | {
146 | var anaTransform = Tools.GetTransformOfChaControl(m_collisionCharacter, boneName);
147 | if (anaTransform == null)
148 | continue;
149 |
150 | m_anaPullBones.Add(anaTransform);
151 | }
152 |
153 | #if !Studio
154 | #if AI || HS2
155 | InitializeFingerColliders(0.055f, 0.18f);
156 | #else
157 | InitializeFingerColliders(0.0055f, 0.018f);
158 | #endif
159 | #endif
160 | }
161 |
162 | internal void CheckForAdjustment(string animationFile)
163 | {
164 | adjustFAnimation = false;
165 | anaPullException = false;
166 | if (m_kokanBone != null && BoneNames.animationAdjustmentList.Contains(animationFile))
167 | adjustFAnimation = true;
168 | if (m_bpAnaTarget != null && BoneNames.anaPullExceptionList.Contains(animationFile))
169 | anaPullException = true;
170 | }
171 |
172 | internal void AdjustMissionaryAnimation()
173 | {
174 | if (!m_collisionOptions.kokan_adjust || !adjustFAnimation || m_kokanBone == null)
175 | return;
176 |
177 | m_kokanBone.localPosition += new Vector3(0, m_collisionOptions.kokan_adjust_position_y, m_collisionOptions.kokan_adjust_position_z);
178 | m_kokanBone.localEulerAngles += new Vector3(m_collisionOptions.kokan_adjust_rotation_x, 0, 0);
179 | }
180 |
181 | internal void AdjustAnalAnimation()
182 | {
183 | if (!m_collisionOptions.ana_adjust || m_siriBoneL == null || m_siriBoneR == null)
184 | return;
185 |
186 | m_siriBoneR.localPosition += m_collisionOptions.ana_adjust_position;
187 | m_siriBoneR.localEulerAngles += m_collisionOptions.ana_adjust_rotation;
188 |
189 | m_siriBoneL.localPosition += new Vector3(-m_collisionOptions.ana_adjust_position.x, m_collisionOptions.ana_adjust_position.y, m_collisionOptions.ana_adjust_position.z);
190 | m_siriBoneL.localEulerAngles += new Vector3(m_collisionOptions.ana_adjust_rotation.x, -m_collisionOptions.ana_adjust_rotation.y, -m_collisionOptions.ana_adjust_rotation.z);
191 | }
192 |
193 | internal void UpdateCollisionOptions(CollisionOptions options)
194 | {
195 | m_collisionOptions = options;
196 |
197 | if (m_collisionPoints == null)
198 | return;
199 |
200 | m_collisionPoints.UpdateCollisionOptions(options);
201 | UpdateBellyBones(options.bellyBulgeScale);
202 | }
203 |
204 | internal void UpdateBellyBones(float radiusScale)
205 | {
206 | if (m_bellyDynamicBone == null)
207 | return;
208 |
209 | m_bellyDynamicBone.m_Radius = m_bellyColliderRadius * radiusScale;
210 | #if HS2 || AIS
211 | m_bellyDynamicBone.UpdateParameters();
212 | #endif
213 | }
214 |
215 | internal void ClearColliders()
216 | {
217 | foreach (DynamicBone dynamicBone in m_collisionCharacter.GetComponentsInChildren())
218 | {
219 | if ((dynamicBone.name.Contains(BoneNames.BPBone) || dynamicBone.name.Contains(BoneNames.BellyBone)) &&
220 | m_collisionCharacter == dynamicBone.GetComponentInParent())
221 | dynamicBone.m_Colliders.Clear();
222 | }
223 | }
224 |
225 | internal void ResetParticles()
226 | {
227 | ResetKokanParticles();
228 | ResetAnaParticles();
229 | ResetBellyParticles();
230 | }
231 |
232 | internal void EnableParticles(bool enable)
233 | {
234 | EnableKokanParticles(enable);
235 | EnableAnaParticles(enable);
236 | EnableBellyParticles(enable);
237 | }
238 |
239 | internal void ResetKokanParticles()
240 | {
241 | foreach (var kokanBone in m_kokanDynamicBones)
242 | {
243 | if (kokanBone == null)
244 | continue;
245 |
246 | kokanBone.ResetParticlesPosition();
247 | }
248 | }
249 |
250 | internal void EnableKokanParticles(bool enable)
251 | {
252 | foreach (var kokanBone in m_kokanDynamicBones)
253 | {
254 | if (kokanBone == null)
255 | continue;
256 |
257 | kokanBone.enabled = enable;
258 | }
259 | }
260 |
261 | internal void ResetAnaParticles()
262 | {
263 | if (m_anaDynamicBones == null)
264 | return;
265 |
266 | m_anaDynamicBones.ResetParticlesPosition();
267 | }
268 |
269 | internal void EnableAnaParticles(bool enable)
270 | {
271 | if (m_anaDynamicBones == null)
272 | return;
273 |
274 | m_anaDynamicBones.enabled = enable;
275 | }
276 |
277 | internal void ResetBellyParticles()
278 | {
279 | if (m_bellyDynamicBone == null)
280 | return;
281 |
282 | m_bellyDynamicBone.ResetParticlesPosition();
283 | }
284 |
285 | internal void EnableBellyParticles(bool enable)
286 | {
287 | if (m_bellyDynamicBone == null)
288 | return;
289 |
290 | m_bellyDynamicBone.enabled = enable;
291 | }
292 |
293 | internal void PullKokanBones(float pullAmount, Vector3 outerDirection, Vector3 insideDirection)
294 | {
295 | if (!m_collisionOptions.enableKokanPush || m_kokanPullBones == null)
296 | {
297 | ReturnKokanBones();
298 | return;
299 | }
300 |
301 | Vector3 averageDirection = Vector3.Normalize(outerDirection + insideDirection);
302 |
303 | Vector3 outer = insideDirection;
304 | Vector3 inner = insideDirection;
305 |
306 | if (m_collisionOptions.outer == CollisionOptions.TargetType.Average)
307 | outer = averageDirection;
308 | else if (m_collisionOptions.outer == CollisionOptions.TargetType.Outer)
309 | outer = outerDirection;
310 |
311 | if (m_collisionOptions.inner == CollisionOptions.TargetType.Average)
312 | inner = averageDirection;
313 | else if (m_collisionOptions.inner == CollisionOptions.TargetType.Outer)
314 | inner = outerDirection;
315 |
316 | if (m_innerKokan != null)
317 | {
318 | Vector3 innerPosition = m_bpKokanTarget.position + inner;
319 | Vector3 upVector = Vector3.Normalize(innerPosition - m_bpKokanTarget.position);
320 | Quaternion innerQuaternion = Quaternion.LookRotation(m_innerKokan.transform.forward, upVector);
321 | m_innerKokan.transform.rotation = innerQuaternion;
322 | }
323 |
324 | currentKokanDanDirection = outer;
325 | currentKokanPull += pullAmount * m_collisionOptions.kokanPullRate * Time.deltaTime;
326 | if (currentKokanPull > m_collisionOptions.maxKokanPush)
327 | currentKokanPull = m_collisionOptions.maxKokanPush;
328 | if (currentKokanPull < -m_collisionOptions.maxKokanPull)
329 | currentKokanPull = -m_collisionOptions.maxKokanPull;
330 |
331 | for (var kokanBone = 0; kokanBone < m_kokanPullBones.Count; kokanBone++)
332 | {
333 | m_kokanPullBones[kokanBone].localPosition = BoneNames.KokanPullWeights[kokanBone] * currentKokanPull * m_kokanPullBones[kokanBone].InverseTransformDirection(currentKokanDanDirection);
334 | }
335 | }
336 |
337 | internal void ReturnKokanBones()
338 | {
339 | if (m_innerKokan != null)
340 | m_innerKokan.localRotation = Quaternion.identity;
341 |
342 | if (MathHelpers.ApproximatelyZero(currentKokanPull) || m_kokanPullBones == null)
343 | return;
344 |
345 | var returnRate = m_collisionOptions.kokanReturnRate * Time.deltaTime;
346 |
347 | if (currentKokanPull > returnRate)
348 | currentKokanPull -= returnRate;
349 | else if (currentKokanPull < -returnRate)
350 | currentKokanPull += returnRate;
351 | else
352 | currentKokanPull = 0;
353 |
354 | for (var kokanBone = 0; kokanBone < m_kokanPullBones.Count; kokanBone++)
355 | m_kokanPullBones[kokanBone].localPosition = BoneNames.KokanPullWeights[kokanBone] * currentKokanPull * Vector3.up;
356 | }
357 |
358 | internal void PullOralBone(float pullAmount, Vector3 danDirection)
359 | {
360 | if (!m_collisionOptions.enableOralPush || m_oralPullBone == null)
361 | {
362 | ReturnOralBones();
363 | return;
364 | }
365 |
366 | currentOralPull += pullAmount * m_collisionOptions.oralPullRate * Time.deltaTime;
367 | if (currentOralPull > m_collisionOptions.maxOralPush)
368 | currentOralPull = m_collisionOptions.maxOralPush;
369 | if (currentOralPull < -m_collisionOptions.maxOralPull)
370 | currentOralPull = -m_collisionOptions.maxOralPull;
371 |
372 | currentOralDanDirection = danDirection;
373 | m_oralPullBone.localPosition = currentOralPull * m_oralPullBone.InverseTransformDirection(currentOralDanDirection);
374 | }
375 |
376 | internal void ReturnOralBones()
377 | {
378 | if (MathHelpers.ApproximatelyZero(currentOralPull) || m_oralPullBone == null)
379 | return;
380 |
381 | var returnRate = m_collisionOptions.oralReturnRate * Time.deltaTime;
382 |
383 | if (currentOralPull > returnRate)
384 | currentOralPull -= returnRate;
385 | else if (currentOralPull < -returnRate)
386 | currentOralPull += returnRate;
387 | else
388 | currentOralPull = 0;
389 |
390 | m_oralPullBone.localPosition = currentOralPull * m_oralPullBone.InverseTransformDirection(currentOralDanDirection);
391 | }
392 |
393 | internal void PullAnaBone(float pullAmount, Vector3 outerDirection, Vector3 insideDirection)
394 | {
395 | if (!m_collisionOptions.enableAnaPush || m_anaPullBones == null)
396 | {
397 | ReturnAnaBones();
398 | return;
399 | }
400 |
401 | Vector3 averageDirection = Vector3.Normalize(outerDirection + insideDirection);
402 |
403 | Vector3 outer = insideDirection;
404 | Vector3 inner = insideDirection;
405 |
406 | if (m_collisionOptions.outer == CollisionOptions.TargetType.Average)
407 | outer = averageDirection;
408 | else if (m_collisionOptions.outer == CollisionOptions.TargetType.Outer)
409 | outer = outerDirection;
410 |
411 | if (m_collisionOptions.inner == CollisionOptions.TargetType.Average)
412 | inner = averageDirection;
413 | else if (m_collisionOptions.inner == CollisionOptions.TargetType.Outer)
414 | inner = outerDirection;
415 |
416 | if (m_bpAnaTarget != null)
417 | {
418 | Vector3 innerPosition = m_bpAnaTarget.position + inner;
419 | Vector3 upVector = Vector3.Normalize(innerPosition - m_bpAnaTarget.position);
420 | Quaternion innerQuaternion = Quaternion.LookRotation(m_bpAnaTarget.transform.forward, upVector);
421 | m_bpAnaTarget.transform.rotation = innerQuaternion;
422 | }
423 |
424 | currentAnaDanDirection = outer;
425 | currentAnaPull += pullAmount * m_collisionOptions.anaPullRate * Time.deltaTime;
426 | if (currentAnaPull > m_collisionOptions.maxAnaPush)
427 | currentAnaPull = m_collisionOptions.maxAnaPush;
428 | if (currentAnaPull < -m_collisionOptions.maxAnaPull)
429 | currentAnaPull = -m_collisionOptions.maxAnaPull;
430 |
431 | for (var anaBone = 0; anaBone < m_anaPullBones.Count; anaBone++)
432 | {
433 | m_anaPullBones[anaBone].localPosition = BoneNames.AnaPullWeights[anaBone] * currentAnaPull * m_anaPullBones[anaBone].InverseTransformDirection(currentAnaDanDirection);
434 | }
435 | }
436 |
437 | internal void ReturnAnaBones()
438 | {
439 | if (m_bpAnaTarget != null)
440 | m_bpAnaTarget.localRotation = Quaternion.identity;
441 |
442 | if (MathHelpers.ApproximatelyZero(currentAnaPull) || m_anaPullBones == null)
443 | return;
444 |
445 | var returnRate = m_collisionOptions.anaReturnRate * Time.deltaTime;
446 |
447 | if (currentAnaPull > returnRate)
448 | currentAnaPull -= returnRate;
449 | else if (currentAnaPull < -returnRate)
450 | currentAnaPull += returnRate;
451 | else
452 | currentAnaPull = 0;
453 |
454 | for (var anaBone = 0; anaBone < m_anaPullBones.Count; anaBone++)
455 | {
456 | m_anaPullBones[anaBone].localPosition = BoneNames.AnaPullWeights[anaBone] * currentAnaPull * Vector3.up;
457 | }
458 | }
459 |
460 | internal void InitializeFingerColliders(float fingerRadius, float fingerLength)
461 | {
462 | m_fingerColliders = new List();
463 | foreach (var bone in BoneNames.FingerColliders)
464 | {
465 | var fingerTransform = Tools.GetTransformOfChaControl(m_collisionCharacter, bone);
466 | if (fingerTransform == null)
467 | continue;
468 |
469 | var fingerCollider = Tools.InitializeCollider(fingerTransform, fingerRadius * (fingerTransform.lossyScale.y + fingerTransform.lossyScale.z) / 2, fingerLength * fingerTransform.lossyScale.x, Vector3.zero);
470 |
471 | m_fingerColliders.Add(fingerCollider);
472 | }
473 | }
474 |
475 | internal void AddFingerColliders(CollisionAgent target)
476 | {
477 | if (m_fingerColliders == null || m_fingerColliders.Count == 0)
478 | return;
479 |
480 | foreach (DynamicBone dynamicBone in target.m_kokanDynamicBones)
481 | {
482 | foreach (var collider in m_fingerColliders)
483 | {
484 | if (collider != null && !dynamicBone.m_Colliders.Contains(collider))
485 | dynamicBone.m_Colliders.Add(collider);
486 | }
487 | }
488 | }
489 |
490 | internal void RemoveFingerColliders(CollisionAgent target)
491 | {
492 | if (m_fingerColliders == null || m_fingerColliders.Count == 0)
493 | return;
494 |
495 | foreach (DynamicBone dynamicBone in target.m_kokanDynamicBones)
496 | {
497 | foreach (var collider in m_fingerColliders)
498 | {
499 | if (collider != null)
500 | dynamicBone.m_Colliders.Remove(collider);
501 | }
502 | }
503 | }
504 |
505 | internal void AddCollidersToKokan(List colliders)
506 | {
507 | if (colliders == null || colliders.Count == 0)
508 | return;
509 |
510 | foreach (var collider in colliders)
511 | {
512 | if (collider == null)
513 | continue;
514 |
515 | foreach (DynamicBone dynamicBone in m_kokanDynamicBones)
516 | {
517 | if (!dynamicBone.m_Colliders.Contains(collider))
518 | dynamicBone.m_Colliders.Add(collider);
519 | }
520 |
521 | if (m_bellyDynamicBone == null)
522 | continue;
523 |
524 | m_bellyDynamicBone.m_Colliders.Add(collider);
525 | }
526 | }
527 |
528 | internal void RemoveCollidersFromKokan(List colliders)
529 | {
530 | if (colliders == null || colliders.Count == 0)
531 | return;
532 |
533 | foreach (var collider in colliders)
534 | {
535 | if (collider == null)
536 | continue;
537 |
538 | foreach (DynamicBone dynamicBone in m_kokanDynamicBones)
539 | dynamicBone.m_Colliders.Remove(collider);
540 |
541 | if (!m_collisionOptions.enableBellyBulge || m_bellyDynamicBone == null)
542 | continue;
543 |
544 | m_bellyDynamicBone.m_Colliders.Remove(collider);
545 | }
546 | }
547 |
548 | internal void AddCollidersToAna(List colliders)
549 | {
550 | if (colliders == null || colliders.Count == 0 || m_anaDynamicBones == null)
551 | return;
552 |
553 | foreach (var collider in colliders)
554 | {
555 | if (collider == null)
556 | continue;
557 |
558 | if (!m_anaDynamicBones.m_Colliders.Contains(collider))
559 | m_anaDynamicBones.m_Colliders.Add(collider);
560 | }
561 | }
562 |
563 | internal void RemoveCollidersFromAna(List colliders)
564 | {
565 | if (colliders == null || colliders.Count == 0 || m_anaDynamicBones == null)
566 | return;
567 |
568 | foreach (var collider in colliders)
569 | {
570 | if (collider == null)
571 | continue;
572 |
573 | m_anaDynamicBones.m_Colliders.Remove(collider);
574 | }
575 | }
576 |
577 | internal void ClearKokanDynamicBones()
578 | {
579 | if (m_kokanDynamicBones == null || m_kokanDynamicBones.Count == 0)
580 | return;
581 |
582 | foreach (var kokanBone in m_kokanDynamicBones)
583 | {
584 | if (kokanBone == null)
585 | continue;
586 |
587 | kokanBone.m_Colliders.Clear();
588 | }
589 |
590 | if (m_bellyDynamicBone == null)
591 | return;
592 |
593 | m_bellyDynamicBone.m_Colliders.Clear();
594 | }
595 |
596 | internal void ClearAnaDynamicBones()
597 | {
598 | if (m_anaDynamicBones == null)
599 | return;
600 |
601 | m_anaDynamicBones.m_Colliders.Clear();
602 | }
603 | }
604 | }
605 | //#endif
--------------------------------------------------------------------------------
/KKS_BetterPenetration/KKS_BetterPenetration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Collections.Generic;
4 | using BepInEx;
5 | using BepInEx.Bootstrap;
6 | using BepInEx.Configuration;
7 | using HarmonyLib;
8 | using Core_BetterPenetration;
9 | using UnityEngine;
10 |
11 | namespace KKS_BetterPenetration
12 | {
13 | [BepInPlugin(GUID, "KKS Better Penetration", VERSION)]
14 | [BepInDependency("com.deathweasel.bepinex.uncensorselector", "3.11.1")]
15 | [BepInDependency("com.rclcircuit.bepinex.modboneimplantor", "1.1.1")]
16 | [BepInProcess(KKAPI.KoikatuAPI.GameProcessName)]
17 | [BepInProcess(KKAPI.KoikatuAPI.VRProcessName)]
18 | public class KKS_BetterPenetration : BaseUnityPlugin
19 | {
20 | public static KKS_BetterPenetration instance;
21 |
22 | public const string GUID = "animal42069.KKSbetterpenetration";
23 | public const string VERSION = Constants.Version;
24 | internal const int MaleLimit = 2;
25 | internal const int FemaleLimit = 2;
26 |
27 | internal static readonly List frontOffsets = new List { -0.04f, 0.04f, 0.06f };
28 | internal static readonly List backOffsets = new List { -0.04f, 0.02f, 0f };
29 | internal static readonly List frontPointsInward = new List { false, false, false, };
30 | internal static readonly List backPointsInward = new List { false, true, true };
31 |
32 | internal static readonly ConfigEntry[] _danColliderLengthScale = new ConfigEntry[MaleLimit];
33 | internal static readonly ConfigEntry[] _danColliderRadiusScale = new ConfigEntry[MaleLimit];
34 | internal static readonly ConfigEntry[] _danLengthSquishFactor = new ConfigEntry[MaleLimit];
35 | internal static readonly ConfigEntry[] _danGirthSquishFactor = new ConfigEntry[MaleLimit];
36 | internal static readonly ConfigEntry[] _danSquishThreshold = new ConfigEntry[MaleLimit];
37 | internal static readonly ConfigEntry[] _danSquishOralGirth = new ConfigEntry[MaleLimit];
38 | internal static readonly ConfigEntry[] _simplifyVaginal = new ConfigEntry[MaleLimit];
39 | internal static readonly ConfigEntry[] _simplifyOral = new ConfigEntry[MaleLimit];
40 | internal static readonly ConfigEntry[] _simplifyAnal = new ConfigEntry[MaleLimit];
41 | internal static readonly ConfigEntry[] _rotateTamaWithShaft = new ConfigEntry[MaleLimit];
42 | internal static readonly ConfigEntry[] _maxCorrection = new ConfigEntry[MaleLimit];
43 | internal static readonly ConfigEntry[] _limitCorrection = new ConfigEntry[MaleLimit];
44 |
45 | internal static ConfigEntry