mirror of
https://github.com/hykilpikonna/AquaDX.git
synced 2026-08-26 03:05:01 -05:00
[+] ScreenPositionAdjust supports virtual touch & ExteraMouseInput supports 2P
This commit is contained in:
@@ -15,6 +15,7 @@ public class ConfigMigrationManager : IConfigMigrationManager
|
||||
new ConfigMigration_V1_0_V2_0(),
|
||||
new ConfigMigration_V2_0_V2_1(),
|
||||
new ConfigMigration_V2_1_V2_2(),
|
||||
new ConfigMigration_V2_2_V2_3(),
|
||||
}.ToDictionary(m => m.FromVersion);
|
||||
|
||||
public string LatestVersion { get; }
|
||||
|
||||
30
AquaMai.Config/Migration/ConfigMigration_V2_2_V2_3.cs
Normal file
30
AquaMai.Config/Migration/ConfigMigration_V2_2_V2_3.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using AquaMai.Config.Interfaces;
|
||||
using Tomlet.Models;
|
||||
|
||||
namespace AquaMai.Config.Migration;
|
||||
|
||||
public class ConfigMigration_V2_2_V2_3 : IConfigMigration
|
||||
{
|
||||
public string FromVersion => "2.2";
|
||||
public string ToVersion => "2.3";
|
||||
|
||||
public ConfigView Migrate(ConfigView src)
|
||||
{
|
||||
var dst = (ConfigView)src.Clone();
|
||||
dst.SetValue("Version", ToVersion);
|
||||
|
||||
if (src.TryGetValue<float>("GameSystem.SinglePlayer.Radius", out var Radius))
|
||||
{
|
||||
dst.SetValue("GameSystem.ExteraMouseInput.Radius", Radius);
|
||||
dst.Remove("GameSystem.SinglePlayer.Radius");
|
||||
}
|
||||
|
||||
if (src.TryGetValue<bool>("GameSystem.SinglePlayer.DisplayArea", out var DisplayArea))
|
||||
{
|
||||
dst.SetValue("GameSystem.ExteraMouseInput.DisplayArea", DisplayArea);
|
||||
dst.Remove("GameSystem.SinglePlayer.DisplayArea");
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,18 @@ using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AquaMai.Mods.GameSystem;
|
||||
|
||||
public partial class SinglePlayer
|
||||
[ConfigSection(
|
||||
defaultOn: true,
|
||||
en: "Enable touch input with radius for a more realistic touchscreen experience.",
|
||||
zh: "启用触摸输入和半径,以获得更真实的触摸屏体验")]
|
||||
public partial class ExteraMouseInput
|
||||
{
|
||||
[ConfigEntry(
|
||||
en: "Touch area radius size. Adjust according to the size of your finger, you can test in Test Mode.",
|
||||
@@ -21,32 +26,26 @@ public partial class SinglePlayer
|
||||
zh: "显示触摸点(仅限触屏输入)")]
|
||||
public readonly static bool displayArea = false;
|
||||
|
||||
static RectTransform rectTransform;
|
||||
static Canvas leftCanvas;
|
||||
static RectTransform[] rectTransform = new RectTransform[2];
|
||||
static List<CustomCircleGraphic> circleGraphics = new List<CustomCircleGraphic>();
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MouseTouchPanel), "Start")]
|
||||
public static void MouseTouchPanelStart(MouseTouchPanel __instance)
|
||||
{
|
||||
if (!__instance.transform.parent.parent.name.Equals("LeftMonitor"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
MelonLoader.MelonLogger.Msg("ExteraMouseInput: Start");
|
||||
leftCanvas = __instance.transform.parent.GetComponent<Canvas>();
|
||||
var player = __instance.transform.parent.parent.name.Equals("LeftMonitor") ? 0 : 1;
|
||||
UnityEngine.Object.Destroy(__instance.transform.parent.GetComponent<GraphicRaycaster>());
|
||||
MeshButtonRaycaster radiusRaycaster = __instance.transform.parent.gameObject.AddComponent<MeshButtonRaycaster>();
|
||||
rectTransform = __instance.GetComponent<RectTransform>();
|
||||
__instance.transform.parent.gameObject.AddComponent<MeshButtonRaycaster>();
|
||||
rectTransform[player] = __instance.GetComponent<RectTransform>();
|
||||
|
||||
if (displayArea)
|
||||
if (displayArea && player == 0)
|
||||
{
|
||||
__instance.StartCoroutine(UpdateInputDisplay());
|
||||
circleGraphics = new List<CustomCircleGraphic>(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
GameObject go = new GameObject("CircleGraphic" + i);
|
||||
go.transform.SetParent(rectTransform);
|
||||
go.transform.SetParent(rectTransform[0]);
|
||||
go.transform.localPosition = Vector3.zero;
|
||||
go.transform.localRotation = Quaternion.identity;
|
||||
go.transform.localScale = Vector3.one;
|
||||
@@ -68,9 +67,9 @@ public partial class SinglePlayer
|
||||
for (int i = 0; i < customGraphic.vertex.Count; i++)
|
||||
{
|
||||
var localPos3 = new Vector3(customGraphic.vertex[i].x, customGraphic.vertex[i].y, 0f);
|
||||
var rotatedPos3 = __instance.transform.localRotation * localPos3;//ApplyRot
|
||||
var rotatedPos3 = __instance.transform.localRotation * localPos3; //ApplyRot
|
||||
var scaledPos3 = Vector3.Scale(rotatedPos3, __instance.transform.localScale); // ApplyScale
|
||||
var finalPos3 = __instance.transform.position + scaledPos3;//ApplyPos
|
||||
var finalPos3 = __instance.transform.position + scaledPos3; //ApplyPos
|
||||
|
||||
___vertexArray[i] = RectTransformUtility.WorldToScreenPoint(
|
||||
Camera.main,
|
||||
@@ -97,7 +96,7 @@ public partial class SinglePlayer
|
||||
Vector2 localPoint;
|
||||
|
||||
// 将屏幕点转换为本地空间
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, touchPoint, Camera.main, out localPoint);
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform[0], touchPoint, Camera.main, out localPoint);
|
||||
circleGraphics[i].rectTransform.anchoredPosition = localPoint;
|
||||
// 缩放半径
|
||||
circleGraphics[i].radius = radius;
|
||||
@@ -117,13 +116,24 @@ public partial class SinglePlayer
|
||||
[HarmonyPatch(typeof(MeshButton), "IsPointInPolygon", new Type[] { typeof(Vector2[]), typeof(Vector2) })]
|
||||
public static bool IsPointInPolygon(MeshButton __instance, Vector2[] polygon, Vector2 point, ref bool __result)
|
||||
{
|
||||
var player = __instance.transform.parent.parent.parent.name.Equals("LeftMonitor") ? 0 : 1;
|
||||
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||
rectTransform,
|
||||
rectTransform[player],
|
||||
point,
|
||||
Camera.main,
|
||||
out var localInputPoint
|
||||
);
|
||||
|
||||
// 防止触发另外半边的
|
||||
if (localInputPoint.x * 2 is > 1080 or < -1080)
|
||||
{
|
||||
__result = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
MelonLogger.Msg($"IsPointInPolygon, {localInputPoint}");
|
||||
|
||||
bool isInsidePolygon = false;
|
||||
//检查是否在多边形顶点内
|
||||
isInsidePolygon = IsVertDistance(polygon, localInputPoint, radius);
|
||||
@@ -154,6 +164,7 @@ public partial class SinglePlayer
|
||||
}
|
||||
|
||||
#region 计算
|
||||
|
||||
/// <summary>
|
||||
/// 检查点是否在多边形的顶点内
|
||||
/// </summary>
|
||||
@@ -245,11 +256,14 @@ public partial class SinglePlayer
|
||||
Vector2 projection = segmentStart + t * segment;
|
||||
return Vector2.Distance(point, projection);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ⚪
|
||||
|
||||
public class CustomCircleGraphic : Graphic
|
||||
{
|
||||
public float radius = 50f; // 圆的半径
|
||||
public float radius = 50f; // 圆的半径
|
||||
public int segmentCount = 64; // 圆的细分段数
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
@@ -279,8 +293,8 @@ public partial class SinglePlayer
|
||||
if (i > 0)
|
||||
{
|
||||
// 形成三角形的索引
|
||||
indices.Add(0); // 圆心
|
||||
indices.Add(i); // 当前点
|
||||
indices.Add(0); // 圆心
|
||||
indices.Add(i); // 当前点
|
||||
indices.Add(i - 1); // 上一个点
|
||||
}
|
||||
}
|
||||
@@ -290,7 +304,6 @@ public partial class SinglePlayer
|
||||
}
|
||||
public class MeshButtonRaycaster : BaseRaycaster
|
||||
{
|
||||
|
||||
public override Camera eventCamera => Camera.main;
|
||||
|
||||
MeshButton[] meshButtons = new MeshButton[0];
|
||||
@@ -313,5 +326,6 @@ public partial class SinglePlayer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,9 @@ public class ScreenPositionAdjust
|
||||
private static Transform[] images = new Transform[4];
|
||||
private static Camera[] cameras = new Camera[4];
|
||||
private static RenderTexture[] renderTextures = new RenderTexture[4];
|
||||
private static Transform[] mouseTouchPanels = new Transform[2];
|
||||
|
||||
private static readonly Vector3 mouseTouchPanelsDelta = new Vector3(0, (1920 - 1080) / 2f, 0);
|
||||
|
||||
/// <summary>
|
||||
/// 避免一帧延迟
|
||||
@@ -127,6 +130,8 @@ public class ScreenPositionAdjust
|
||||
PlayerPrefs.SetFloat($"AquaMaiScreenPositionAdjust-y:{i}", offsetY[i]);
|
||||
}
|
||||
PlayerPrefs.Save();
|
||||
mouseTouchPanels[0].position = images[0].position + mouseTouchPanelsDelta;
|
||||
mouseTouchPanels[1].position = images[2].position + mouseTouchPanelsDelta;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -162,69 +167,83 @@ public class ScreenPositionAdjust
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<MethodBase> TargetMethods()
|
||||
[HarmonyPatch]
|
||||
public class Init
|
||||
{
|
||||
var lateInitialize = AccessTools.Method(typeof(Main.GameMain), "LateInitialize", [typeof(MonoBehaviour), typeof(Transform), typeof(Transform)]);
|
||||
if (lateInitialize is not null) return [lateInitialize];
|
||||
return [AccessTools.Method(typeof(Main.GameMain), "Initialize", [typeof(MonoBehaviour), typeof(Transform), typeof(Transform)])];
|
||||
public static IEnumerable<MethodBase> TargetMethods()
|
||||
{
|
||||
return SinglePlayer.WhateverInitialize.TargetMethods();
|
||||
}
|
||||
|
||||
public static void Prefix(Transform left, Transform right)
|
||||
{
|
||||
root = new GameObject("[AquaMai] ScreenPositionAdjust Display", [typeof(Canvas)]);
|
||||
root.transform.position = new Vector3(11451, 19198, 0);
|
||||
var canvas = root.GetComponent<Canvas>();
|
||||
canvas.GetComponent<RectTransform>().sizeDelta = new Vector2(2160, 1920);
|
||||
canvas.renderMode = RenderMode.WorldSpace;
|
||||
root.AddComponent<CanvasScaler>();
|
||||
root.AddComponent<GraphicRaycaster>();
|
||||
root.AddComponent<DynamicRenderTextureResizer>();
|
||||
root.AddComponent<AdjustController>();
|
||||
Camera.main.gameObject.AddComponent<CameraUpdater>();
|
||||
Camera.main.transform.position = new Vector3(ConfigLoader.Config.GetSectionState(typeof(SinglePlayer)).Enabled ? 11451 - 540 : 11451, 19198, -800);
|
||||
|
||||
var compactDelta = 0;
|
||||
if (compactMode)
|
||||
{
|
||||
Camera.main.orthographicSize = 540 + 225;
|
||||
// 960 - 540 - 225 = 195
|
||||
compactDelta = 195;
|
||||
}
|
||||
|
||||
// init camera
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var player = i < 2 ? "1P" : "2P";
|
||||
var sub = i % 2 == 0 ? "Main" : "Sub";
|
||||
var texture = new RenderTexture((int)(1080 * GetSizeFactor()), (int)((sub == "Main" ? 1080 : 450) * GetSizeFactor()), 24, RenderTextureFormat.RGB111110Float)
|
||||
{
|
||||
useMipMap = false,
|
||||
autoGenerateMips = false,
|
||||
depth = 0,
|
||||
antiAliasing = 1,
|
||||
};
|
||||
|
||||
var camera = new GameObject($"[AquaMai] ScreenPositionAdjust Camera {sub} {player}").AddComponent<Camera>();
|
||||
camera.transform.parent = player == "1P" ? left : right;
|
||||
camera.enabled = false;
|
||||
camera.targetTexture = texture;
|
||||
camera.cullingMask = Camera.main.cullingMask;
|
||||
camera.backgroundColor = Color.black;
|
||||
camera.orthographic = true;
|
||||
camera.orthographicSize = sub == "Main" ? 540 : 225;
|
||||
camera.transform.localPosition = new Vector3(0, sub == "Main" ? -420 : 735, -800);
|
||||
cameras[i] = camera;
|
||||
|
||||
var image = new GameObject($"[AquaMai] ScreenPositionAdjust Image {sub} {player}").AddComponent<UnityEngine.UI.RawImage>();
|
||||
image.transform.parent = root.transform;
|
||||
image.texture = texture;
|
||||
image.rectTransform.sizeDelta = new Vector2(1080, sub == "Main" ? 1080 : 450);
|
||||
image.transform.localPosition = new Vector3(player == "1P" ? -540 : 540, sub == "Main" ? -420 + compactDelta : 735 - compactDelta, 0);
|
||||
images[i] = image.transform;
|
||||
|
||||
offsetX[i] = PlayerPrefs.GetFloat($"AquaMaiScreenPositionAdjust-x:{i}", 0);
|
||||
offsetY[i] = PlayerPrefs.GetFloat($"AquaMaiScreenPositionAdjust-y:{i}", 0);
|
||||
images[i].localPosition += new Vector3(offsetX[i], offsetY[i], 0);
|
||||
}
|
||||
|
||||
mouseTouchPanels[0] = left.Find("MouseTouchPanel");
|
||||
mouseTouchPanels[1] = right.Find("MouseTouchPanel");
|
||||
mouseTouchPanels[0].position = images[0].position + mouseTouchPanelsDelta;
|
||||
mouseTouchPanels[1].position = images[2].position + mouseTouchPanelsDelta;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Prefix(Transform left, Transform right)
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(MouseTouchPanel), "Start")]
|
||||
public static void FixTouchPanelPlayer(ref int ___PlayerID, MouseTouchPanel __instance)
|
||||
{
|
||||
root = new GameObject("[AquaMai] ScreenPositionAdjust Display", [typeof(Canvas)]);
|
||||
root.transform.position = new Vector3(11451, 19198, 0);
|
||||
var canvas = root.GetComponent<Canvas>();
|
||||
canvas.GetComponent<RectTransform>().sizeDelta = new Vector2(2160, 1920);
|
||||
canvas.renderMode = RenderMode.WorldSpace;
|
||||
root.AddComponent<CanvasScaler>();
|
||||
root.AddComponent<GraphicRaycaster>();
|
||||
root.AddComponent<DynamicRenderTextureResizer>();
|
||||
root.AddComponent<AdjustController>();
|
||||
Camera.main.gameObject.AddComponent<CameraUpdater>();
|
||||
Camera.main.transform.position = new Vector3(ConfigLoader.Config.GetSectionState(typeof(SinglePlayer)).Enabled ? 11451 - 540 : 11451, 19198, -800);
|
||||
|
||||
var compactDelta = 0;
|
||||
if (compactMode)
|
||||
{
|
||||
Camera.main.orthographicSize = 540 + 225;
|
||||
// 960 - 540 - 225 = 195
|
||||
compactDelta = 195;
|
||||
}
|
||||
|
||||
// init camera
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var player = i < 2 ? "1P" : "2P";
|
||||
var sub = i % 2 == 0 ? "Main" : "Sub";
|
||||
var texture = new RenderTexture((int)(1080 * GetSizeFactor()), (int)((sub == "Main" ? 1080 : 450) * GetSizeFactor()), 24, RenderTextureFormat.RGB111110Float)
|
||||
{
|
||||
useMipMap = false,
|
||||
autoGenerateMips = false,
|
||||
depth = 0,
|
||||
antiAliasing = 1,
|
||||
};
|
||||
|
||||
var camera = new GameObject($"[AquaMai] ScreenPositionAdjust Camera {sub} {player}").AddComponent<Camera>();
|
||||
camera.transform.parent = player == "1P" ? left : right;
|
||||
camera.enabled = false;
|
||||
camera.targetTexture = texture;
|
||||
camera.cullingMask = Camera.main.cullingMask;
|
||||
camera.backgroundColor = Color.black;
|
||||
camera.orthographic = true;
|
||||
camera.orthographicSize = sub == "Main" ? 540 : 225;
|
||||
camera.transform.localPosition = new Vector3(0, sub == "Main" ? -420 : 735, -800);
|
||||
cameras[i] = camera;
|
||||
|
||||
var image = new GameObject($"[AquaMai] ScreenPositionAdjust Image {sub} {player}").AddComponent<UnityEngine.UI.RawImage>();
|
||||
image.transform.parent = root.transform;
|
||||
image.texture = texture;
|
||||
image.rectTransform.sizeDelta = new Vector2(1080, sub == "Main" ? 1080 : 450);
|
||||
image.transform.localPosition = new Vector3(player == "1P" ? -540 : 540, sub == "Main" ? -420 + compactDelta : 735 - compactDelta, 0);
|
||||
images[i] = image.transform;
|
||||
|
||||
offsetX[i] = PlayerPrefs.GetFloat($"AquaMaiScreenPositionAdjust-x:{i}", 0);
|
||||
offsetY[i] = PlayerPrefs.GetFloat($"AquaMaiScreenPositionAdjust-y:{i}", 0);
|
||||
images[i].localPosition += new Vector3(offsetX[i], offsetY[i], 0);
|
||||
}
|
||||
___PlayerID = __instance.transform.parent.parent.name.Equals("LeftMonitor") ? 0 : 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user