Skip to content

JudgeControl.decompiled.cs ​

源文件:code/JudgeControl.decompiled.cs

csharp
// =============================================================================
// JudgeControl(块命中部分)—— 由 APK libil2cpp.so(ARM64) 反汇编还原的等价 C#
// VA 见各方法注释。字段偏移(dump.cs):
//   0x40 nowTime | 0x90 previewElementUpdateControl | 0x70 chartNoteSortByTime
//   0xA0 blockedTouchPositions(List<Vector4>) | 0xA8 wasTouchingAnyBlock | 0xAC minDeltaTime
// =============================================================================

using System.Collections.Generic;
using UnityEngine;

public class JudgeControl
{
    public float nowTime;                                                    // 0x40
    private PreviewElementUpdateControl previewElementUpdateControl;         // 0x90
    private readonly List<Vector4> blockedTouchPositions;                    // 0xA0
    private bool wasTouchingAnyBlock;                                        // 0xA8

    // ---- VA 0x1D22560 -------------------------------------------------------
    // 命中测试:**无 inset**,恒半边长 0.5 的局部 AABB;lossyScale 退化(≤1e-4)直接失败。
    private static bool IsPositionInsideBlock(PreviewBlockControl block, Vector2 worldPosition)
    {
        if (block == null) return false;                       // Unity null 检查(implicit bool)
        Vector3 s = block.transform.lossyScale;
        const float kEps = 1e-4f;                              // .rodata 0xC26070
        if (Mathf.Abs(s.x) <= kEps) return false;
        if (Mathf.Abs(s.y) <= kEps) return false;
        Vector3 local = block.transform.InverseTransformPoint(
            new Vector3(worldPosition.x, worldPosition.y, 0f));
        return Mathf.Abs(local.x) <= 0.5f && Mathf.Abs(local.y) <= 0.5f;
    }

    // ---- VA 0x1D22010 -------------------------------------------------------
    // 遍历 Blocks,取 IsActive(nowTime) 且命中 IsPositionInsideBlock 的块;
    // 普通/减块分别记录首个命中,减块计数。返回:
    //   (减块命中数&1) != (普通块命中!=null) 时有命中;优先返回普通块。
    private bool TryGetBlockingBlock(Vector2 worldPosition, out PreviewBlockControl blockingBlock)
    {
        blockingBlock = null;
        var blocks = previewElementUpdateControl.Blocks;      // 0x90 → 0x58
        PreviewBlockControl normal = null;
        PreviewBlockControl subtract = null;
        int subtractHits = 0;

        foreach (var b in blocks)
        {
            if (b == null) continue;
            if (!b.IsActive(nowTime)) continue;               // 0x1D71C40
            if (!IsPositionInsideBlock(b, worldPosition)) continue;
            if (!b.blockInfo.isSubtract) { if (normal == null) normal = b; }
            else                         { if (subtract == null) subtract = b; subtractHits++; }
        }

        bool subtracted = (subtractHits & 1) != 0;
        if (subtracted == (normal != null)) return false;     // 抵消或未命中
        blockingBlock = (normal != null) ? normal : subtract;
        return true;
    }
}