442 lines
15 KiB
C#
442 lines
15 KiB
C#
using BrewMonster.Network;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using EditorAttributes;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using UnityEngine.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;
|
|
|
|
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);
|
|
|
|
DontDestroyOnLoad(this);
|
|
}
|
|
|
|
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
|