Загрузка данных


using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using UnityEngine;
using UnityEngine.SceneManagement;

[BepInPlugin("my.cheatmenu", "CheatMenu", "1.7")]
public class Plugin : BasePlugin
{
    public static ManualLogSource L;
    public override void Load()
    {
        L = Log;
        ClassInjector.RegisterTypeInIl2Cpp<MenuBehaviour>();
        AddComponent<MenuBehaviour>();
        Log.LogInfo("CheatMenu loaded, press Insert");
    }
}

public class MenuBehaviour : MonoBehaviour
{
    public MenuBehaviour(IntPtr ptr) : base(ptr) { }

    bool open, fly, stamina;
    float flySpeed = 15f;
    Transform player;
    CharacterController cc;
    Rigidbody rb;
    int scenePage = 0;
    float nextApply;

    // режим шахеда
    bool drone, exploding;
    float droneSpeed = 30f, crashSpeed = 20f, spinSpeed = 360f;
    float droneStartTime, respawnAt, explodeTime = -100f;
    Vector3 startPos;
    GameObject flash;
    AudioClip boomClip, buzzClip, musicClip;
    AudioSource buzzSrc, musicSrc, remoteBuzz, remoteMusic;
    string lastHit = "-";
    string soundStatus = "звуки не загружены";
    string statsStatus = "";

    // размеры, выбор, грабители
    Transform sel;
    string selInfo = "Выбрано: ничего";
    float selfScale = 1f, selScale = 1f, robberScale = 1f;
    string robberKey = "robber";
    string lastRobberKey = null;
    bool aiOff;
    int robbersFound = 0;
    float nextRobber;

    // список объектов
    string filter = "";
    string lastFilter = null;
    bool rootOnly = true;
    bool lastRootOnly = true;
    int listOffset = 0;
    int listRows = 18;
    Rect listRect = new Rect(0, 0, 0, 0);
    string spawnStatus = "";

    // свой ввод текста: 0 нет, 1 поиск, 2 имя грабителя, 3 IP друга
    int focus = 0;

    static readonly List<GameObject> found = new List<GameObject>();
    static readonly List<string> foundLabels = new List<string>();
    static readonly Dictionary<int, Vector3> origScale = new Dictionary<int, Vector3>();
    static readonly List<Behaviour> disabledAI = new List<Behaviour>();
    static readonly HashSet<string> guiErrors = new HashSet<string>();

    // сеть
    static UdpClient udp;
    static Thread thr;
    static volatile bool netOn;
    static string friendIp = "";
    static int netPort = 27777;
    static string netStatus = "выключена";
    static readonly ConcurrentQueue<string> inbox = new ConcurrentQueue<string>();

    // стамина
    static Assembly gameAsm;
    static readonly Dictionary<string, Type> typeCache = new Dictionary<string, Type>();
    static readonly Dictionary<string, double> best = new Dictionary<string, double>();
    static readonly HashSet<string> loggedSet = new HashSet<string>();
    static readonly string[] StaminaWords = { "stamina", "energy" };
    static readonly string[] BadWords = { "regen", "rate", "damage", "cost", "drain", "speed", "time", "delay", "max", "min", "percent", "ratio", "fov", "view", "camera", "zoom", "field", "bar", "text", "ui", "image", "slider" };

    // ---------- звук ----------

    bool ClipOk(AudioClip c)
    {
        if (c == null) return false;
        try { return c.length > 0f; } catch { return false; }
    }

    void EnsureSounds()
    {
        if (!ClipOk(boomClip)) boomClip = LoadWav("boom.wav");
        if (!ClipOk(boomClip)) { boomClip = MakeBoom(); }
        if (!ClipOk(buzzClip)) buzzClip = LoadWav("buzz.wav");
        if (!ClipOk(musicClip)) musicClip = LoadWav("music.wav");
        soundStatus = "boom:" + (ClipOk(boomClip) ? "ok" : "нет")
                    + " buzz:" + (ClipOk(buzzClip) ? "ok" : "нет")
                    + " music:" + (ClipOk(musicClip) ? "ok" : "нет");
    }

    AudioClip MakeClip(string name, float[] d, int ch, int rate)
    {
        var clip = AudioClip.Create(name, d.Length / ch, ch, rate, false);
        clip.SetData((Il2CppStructArray<float>)d, 0);
        clip.hideFlags = HideFlags.HideAndDontSave;
        return clip;
    }

    AudioClip MakeBoom()
    {
        try
        {
            int rate = 22050, n = rate * 2;
            var d = new float[n];
            var r = new System.Random(1);
            for (int i = 0; i < n; i++)
            {
                float t = (float)i / rate;
                d[i] = ((float)r.NextDouble() * 2f - 1f) * Mathf.Exp(-t * 3f) * 0.9f;
            }
            return MakeClip("boom_gen", d, 1, rate);
        }
        catch (Exception e) { Plugin.L.LogInfo("MakeBoom error: " + e.Message); return null; }
    }

    AudioClip LoadWav(string name)
    {
        try
        {
            using (var s = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
            {
                if (s == null) { Plugin.L.LogInfo("No embedded sound: " + name); return null; }
                var ms = new MemoryStream();
                s.CopyTo(ms);
                byte[] b = ms.ToArray();
                int pos = 12, ch = 1, rate = 44100, bits = 16, fmt = 1, dataPos = -1, dataLen = 0;
                while (pos + 8 <= b.Length)
                {
                    string id = Encoding.ASCII.GetString(b, pos, 4);
                    int size = BitConverter.ToInt32(b, pos + 4);
                    if (id == "fmt ")
                    {
                        fmt = BitConverter.ToInt16(b, pos + 8);
                        ch = BitConverter.ToInt16(b, pos + 10);
                        rate = BitConverter.ToInt32(b, pos + 12);
                        bits = BitConverter.ToInt16(b, pos + 22);
                    }
                    else if (id == "data") { dataPos = pos + 8; dataLen = Math.Min(size, b.Length - dataPos); break; }
                    pos += 8 + size + (size % 2);
                }
                if (dataPos < 0) { Plugin.L.LogInfo(name + ": no data chunk"); return null; }
                if (fmt != 1 && fmt != 65534) { Plugin.L.LogInfo(name + ": unsupported format " + fmt + " (need PCM)"); return null; }
                if (bits != 16) { Plugin.L.LogInfo(name + ": need 16-bit, got " + bits); return null; }
                int samples = dataLen / 2;
                var f = new float[samples];
                for (int i = 0; i < samples; i++) f[i] = BitConverter.ToInt16(b, dataPos + i * 2) / 32768f;
                var clip = MakeClip(name, f, ch, rate);
                Plugin.L.LogInfo("Loaded sound: " + name + " (" + ch + "ch, " + rate + "Hz, " + samples + " samples)");
                return clip;
            }
        }
        catch (Exception e) { Plugin.L.LogInfo("LoadWav error (" + name + "): " + e.Message); return null; }
    }

    AudioSource MakeLoopSource(string name, AudioClip clip, float volume)
    {
        var g = new GameObject(name);
        UnityEngine.Object.DontDestroyOnLoad(g);
        var src = g.AddComponent<AudioSource>();
        src.clip = clip;
        src.loop = true;
        src.spatialBlend = 0f;
        src.volume = volume;
        src.ignoreListenerPause = true;
        src.Play();
        return src;
    }

    void KillSource(ref AudioSource src)
    {
        if (src == null) return;
        try { src.Stop(); UnityEngine.Object.Destroy(src.gameObject); } catch { }
        src = null;
    }

    void StopDroneSounds()
    {
        KillSource(ref buzzSrc);
        KillSource(ref musicSrc);
    }

    void PlayMusic()
    {
        EnsureSounds();
        StopDroneSounds();
        if (ClipOk(buzzClip)) buzzSrc = MakeLoopSource("DroneBuzz", buzzClip, 1f);
        if (ClipOk(musicClip)) musicSrc =