Files
test/Assets/PerfectWorld/Scripts/DebugCommandMenu/DlgConsole.cs
T
2026-04-16 17:04:44 +07:00

453 lines
16 KiB
C#

using BrewMonster.Network;
using System;
using System.Collections;
using System.Collections.Generic;
using EditorAttributes;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using BrewMonster.Scripts.UI;
namespace BrewMonster.Scripts
{
public class DlgConsole : MonoBehaviour
{
[SerializeField] GameObject _panelConsole;
[Header("Debug Cmd Input (new UI)")]
[SerializeField] TMP_InputField _inputHeader;
[SerializeField] TMP_InputField _inputParam;
[SerializeField] TMP_InputField _inputTime;
[SerializeField] Toggle _toggleLoop;
[SerializeField] TMP_InputField _inputDescribe;
[Space(6)]
[Header("Legacy Console Input")]
[SerializeField] TMP_InputField _consoleInput;
//send button
[SerializeField] Button _btnSend;
[SerializeField] Button _btnCancelAllLoops;
[SerializeField] Button _btnOpen;
[SerializeField] Button _btnClose;
[Space(10)]
[Header("Command Buttons")]
[SerializeField] Button _btnNoCooldown;
[SerializeField] Button _btnToggleAutoWrath;
[SerializeField] Button _btnToggleTaskNpcTeleport;
private bool _isAutoAddWrathEnabled = false;
private Coroutine _autoAddWrathCoroutine;
private readonly Dictionary<LoopCmdKey, LoopCmdInfo> _loopCmds = new Dictionary<LoopCmdKey, LoopCmdInfo>();
public event Action LoopCommandsChanged;
public event Action HistoryChanged;
private List<DebugCmdHistoryStore.Entry> _history;
private void Awake()
{
_history = DebugCmdHistoryStore.Load();
_btnSend?.onClick.AddListener(OnBtnSendClicked);
_btnCancelAllLoops?.onClick.AddListener(CancelAllLoopCommands);
_btnOpen?.onClick.AddListener(OnBtnOpenClicked);
//_btnClose?.onClick.AddListener(OnBtnCloseClicked);
_btnNoCooldown?.onClick.AddListener(OnBtnNoCooldownClicked);
_btnToggleAutoWrath?.onClick.AddListener(OnBtnToggleAutoWrathClicked);
_btnToggleTaskNpcTeleport?.onClick.AddListener(OnBtnToggleTaskNpcTeleportClicked);
DontDestroyOnLoad(this);
}
public void OnBtnToggleTaskNpcTeleportClicked()
{
bool next = !CECUIHelper.DebugInstantTeleportToTaskNpc;
CECUIHelper.SetDebugInstantTeleportToTaskNpc(next);
Debug.Log($"[DlgConsole] Task NPC teleport cheat: {(next ? "ON" : "OFF")}");
}
private void OnDestroy()
{
CancelAllLoopCommands();
// Stop coroutine if running when object is destroyed
// 对象销毁时如果协程正在运行则停止它
if (_autoAddWrathCoroutine != null)
{
StopCoroutine(_autoAddWrathCoroutine);
_autoAddWrathCoroutine = null;
}
}
#region button events
private void OnBtnSendClicked()
{
if (TryReadCmdFromNewInputs(out int header, out int param, out bool hasParam, out float intervalSeconds, out bool loopEnabled))
{
UpsertHistoryFromInputs(header, param, hasParam);
SendCmdDebug(header, param, hasParam);
if (loopEnabled)
{
string describe = _inputDescribe != null ? _inputDescribe.text : string.Empty;
StartOrRestartLoopCommand(header, param, hasParam, intervalSeconds, describe);
}
return;
}
// Fallback: legacy console style: "d <header> [param]"
if (TryReadCmdFromLegacyConsole(out header, out param, out hasParam))
{
UpsertHistory(header, param, hasParam, string.Empty);
SendCmdDebug(header, param, hasParam);
}
}
bool isOpen = false;
private void OnBtnOpenClicked()
{
isOpen = !isOpen;
_panelConsole.SetActive(isOpen);
}
/* private void OnBtnCloseClicked()
{
_panelConsole.SetActive(false);
}*/
public void OnBtnNoCooldownClicked()
{
UnityGameSession.c2s_CmdDebug(8903, 73125);
}
/// 8903 73125
private void OnBtnAddWrathClicked()
{
UnityGameSession.c2s_CmdDebug(1992);
}
//1992
#endregion
[ContextMenu("Toggle Auto-Add Wrath")]
public void OnBtnToggleAutoWrathClicked()
{
ToggleAutoAddWrath();
}
public void ToggleAutoAddWrath()
{
_isAutoAddWrathEnabled = !_isAutoAddWrathEnabled;
if (_isAutoAddWrathEnabled)
{
// Start the coroutine if not already running
// 如果尚未运行,则启动协程
if (_autoAddWrathCoroutine == null)
{
_autoAddWrathCoroutine = StartCoroutine(AutoAddWrathCoroutine());
}
}
else
{
if (_autoAddWrathCoroutine != null)
{
StopCoroutine(_autoAddWrathCoroutine);
_autoAddWrathCoroutine = null;
}
}
}
private IEnumerator AutoAddWrathCoroutine()
{
while (_isAutoAddWrathEnabled)
{
OnBtnAddWrathClicked();
yield return new WaitForSeconds(3.0f);
}
_autoAddWrathCoroutine = null;
}
private void SendCmdDebug(int header, int param, bool hasParam)
{
//BMLogger.LogError($"[DlgConsole] Sending Debug Cmd: {(hasParam ? $"{header} {param}" : $"{header}")}");
if (hasParam)
UnityGameSession.c2s_CmdDebug((ushort)header, param);
else
UnityGameSession.c2s_CmdDebug((ushort)header);
}
private void UpsertHistoryFromInputs(int header, int param, bool hasParam)
{
string describe = _inputDescribe != null ? _inputDescribe.text : string.Empty;
UpsertHistory(header, param, hasParam, describe);
}
private void UpsertHistory(int header, int param, bool hasParam, string describe)
{
_history ??= new List<DebugCmdHistoryStore.Entry>();
bool changed = DebugCmdHistoryStore.Upsert(_history, header, param, hasParam, describe);
if (changed)
{
DebugCmdHistoryStore.Save(_history);
HistoryChanged?.Invoke();
}
else
{
// Still persist last-used ordering (Upsert may have moved it) even if describe unchanged.
DebugCmdHistoryStore.Save(_history);
HistoryChanged?.Invoke();
}
}
public IReadOnlyList<DebugCmdHistoryStore.Entry> GetHistory()
{
_history ??= DebugCmdHistoryStore.Load();
return _history;
}
public void ClearHistory()
{
DebugCmdHistoryStore.Clear();
_history = new List<DebugCmdHistoryStore.Entry>();
HistoryChanged?.Invoke();
}
public void RemoveHistoryItem(int header, int param, bool hasParam)
{
_history ??= DebugCmdHistoryStore.Load();
bool removed = DebugCmdHistoryStore.Remove(_history, header, param, hasParam);
if (!removed)
return;
DebugCmdHistoryStore.Save(_history);
HistoryChanged?.Invoke();
}
public void ApplyHistoryItemToInputs(int header, int param, bool hasParam, string describe)
{
if (_inputHeader != null) _inputHeader.text = header.ToString();
if (_inputParam != null) _inputParam.text = hasParam ? param.ToString() : string.Empty;
if (_inputDescribe != null) _inputDescribe.text = describe ?? string.Empty;
}
private bool TryReadCmdFromNewInputs(out int header, out int param, out bool hasParam, out float intervalSeconds, out bool loopEnabled)
{
header = 0;
param = 0;
hasParam = false;
intervalSeconds = 1f;
loopEnabled = _toggleLoop != null && _toggleLoop.isOn;
// If these inputs aren't wired up in inspector, bail to legacy mode.
if (_inputHeader == null && _inputParam == null && _inputTime == null && _toggleLoop == null && _inputDescribe == null)
return false;
var headerText = _inputHeader != null ? _inputHeader.text : string.Empty;
var paramText = _inputParam != null ? _inputParam.text : string.Empty;
var timeText = _inputTime != null ? _inputTime.text : string.Empty;
if (string.IsNullOrWhiteSpace(headerText))
return false;
if (!int.TryParse(headerText.Trim(), out header))
return false;
if (!string.IsNullOrWhiteSpace(paramText) && int.TryParse(paramText.Trim(), out param))
hasParam = true;
if (!string.IsNullOrWhiteSpace(timeText) && float.TryParse(timeText.Trim(), out float parsed))
intervalSeconds = Mathf.Max(0.05f, parsed);
return true;
}
private bool TryReadCmdFromLegacyConsole(out int header, out int param, out bool hasParam)
{
header = 0;
param = 0;
hasParam = false;
if (_consoleInput == null)
return false;
string input = _consoleInput.text;
if (string.IsNullOrWhiteSpace(input))
return false;
input = input.Trim();
if (!input.StartsWith("d ", StringComparison.OrdinalIgnoreCase))
return false;
input = input.Substring(2).Trim();
if (string.IsNullOrWhiteSpace(input))
return false;
string[] cmdParams = input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (cmdParams.Length < 1)
return false;
if (!int.TryParse(cmdParams[0], out header))
return false;
if (cmdParams.Length >= 2 && int.TryParse(cmdParams[1], out param))
hasParam = true;
return true;
}
private void StartOrRestartLoopCommand(int header, int param, bool hasParam, float intervalSeconds, string describe)
{
var key = new LoopCmdKey(header, param, hasParam);
if (_loopCmds.TryGetValue(key, out var existing) && existing.Coroutine != null)
{
StopCoroutine(existing.Coroutine);
_loopCmds.Remove(key);
}
var co = StartCoroutine(LoopSendCoroutine(key, intervalSeconds));
_loopCmds[key] = new LoopCmdInfo(co, intervalSeconds, describe);
Debug.Log($"[DlgConsole] Loop ON: {key} every {intervalSeconds:0.###}s");
LoopCommandsChanged?.Invoke();
}
public void CancelLoopCommand(int header, int param, bool hasParam)
{
var key = new LoopCmdKey(header, param, hasParam);
if (_loopCmds.TryGetValue(key, out var info) && info.Coroutine != null)
{
StopCoroutine(info.Coroutine);
_loopCmds.Remove(key);
Debug.Log($"[DlgConsole] Loop OFF: {key}");
LoopCommandsChanged?.Invoke();
}
}
public void CancelAllLoopCommands()
{
if (_loopCmds.Count == 0)
return;
foreach (var kv in _loopCmds)
{
if (kv.Value.Coroutine != null)
StopCoroutine(kv.Value.Coroutine);
}
_loopCmds.Clear();
Debug.Log("[DlgConsole] Loop OFF: ALL");
LoopCommandsChanged?.Invoke();
}
public string GetActiveLoopCommandsDebugString()
{
if (_loopCmds.Count == 0)
return "(none)";
var parts = new List<string>(_loopCmds.Count);
foreach (var key in _loopCmds.Keys)
parts.Add(key.ToString());
return string.Join(", ", parts);
}
public IReadOnlyList<ActiveLoopCommand> GetActiveLoopCommands()
{
if (_loopCmds.Count == 0)
return Array.Empty<ActiveLoopCommand>();
var list = new List<ActiveLoopCommand>(_loopCmds.Count);
foreach (var kv in _loopCmds)
{
list.Add(new ActiveLoopCommand(
kv.Key.Header,
kv.Key.Param,
kv.Key.HasParam,
kv.Value.IntervalSeconds,
kv.Value.Describe
));
}
return list;
}
private IEnumerator LoopSendCoroutine(LoopCmdKey key, float intervalSeconds)
{
// Send immediately already happened in OnBtnSendClicked; wait interval then keep sending.
var wait = new WaitForSeconds(intervalSeconds);
while (true)
{
yield return wait;
SendCmdDebug(key.Header, key.Param, key.HasParam);
}
}
private readonly struct LoopCmdInfo
{
public readonly Coroutine Coroutine;
public readonly float IntervalSeconds;
public readonly string Describe;
public LoopCmdInfo(Coroutine coroutine, float intervalSeconds, string describe)
{
Coroutine = coroutine;
IntervalSeconds = intervalSeconds;
Describe = describe ?? string.Empty;
}
}
public readonly struct ActiveLoopCommand
{
public readonly int Header;
public readonly int Param;
public readonly bool HasParam;
public readonly float IntervalSeconds;
public readonly string Describe;
public ActiveLoopCommand(int header, int param, bool hasParam, float intervalSeconds, string describe)
{
Header = header;
Param = param;
HasParam = hasParam;
IntervalSeconds = intervalSeconds;
Describe = describe ?? string.Empty;
}
public override string ToString()
{
var cmd = HasParam ? $"{Header} {Param}" : $"{Header}";
if (!string.IsNullOrWhiteSpace(Describe))
return $"{Describe} ({cmd}) @ {IntervalSeconds:0.###}s";
return $"{cmd} @ {IntervalSeconds:0.###}s";
}
}
private readonly struct LoopCmdKey : IEquatable<LoopCmdKey>
{
public readonly int Header;
public readonly int Param;
public readonly bool HasParam;
public LoopCmdKey(int header, int param, bool hasParam)
{
Header = header;
Param = param;
HasParam = hasParam;
}
public bool Equals(LoopCmdKey other) => Header == other.Header && Param == other.Param && HasParam == other.HasParam;
public override bool Equals(object obj) => obj is LoopCmdKey other && Equals(other);
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = (hash * 31) + Header;
hash = (hash * 31) + Param;
hash = (hash * 31) + (HasParam ? 1 : 0);
return hash;
}
}
public override string ToString() => HasParam ? $"{Header} {Param}" : $"{Header}";
}
}
}
/// d 2000 la kn
/// d 1988 + so tien