cheat UI
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using BrewMonster.Network;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using EditorAttributes;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
@@ -11,9 +13,19 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
[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;
|
||||
|
||||
@@ -25,11 +37,20 @@ namespace BrewMonster.Scripts
|
||||
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);
|
||||
//_btnClose?.onClick.AddListener(OnBtnCloseClicked);
|
||||
_btnNoCooldown?.onClick.AddListener(OnBtnNoCooldownClicked);
|
||||
_btnToggleAutoWrath?.onClick.AddListener(OnBtnToggleAutoWrathClicked);
|
||||
|
||||
@@ -38,6 +59,7 @@ namespace BrewMonster.Scripts
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
CancelAllLoopCommands();
|
||||
// Stop coroutine if running when object is destroyed
|
||||
// 对象销毁时如果协程正在运行则停止它
|
||||
if (_autoAddWrathCoroutine != null)
|
||||
@@ -50,28 +72,36 @@ namespace BrewMonster.Scripts
|
||||
#region button events
|
||||
private void OnBtnSendClicked()
|
||||
{
|
||||
string input = _consoleInput.text;
|
||||
if (string.IsNullOrEmpty(input))
|
||||
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;
|
||||
}
|
||||
|
||||
if (!input.StartsWith("d "))
|
||||
return;
|
||||
|
||||
input = input.Substring(2);
|
||||
string[] cmdParams = input.Split(' ');
|
||||
|
||||
// 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()
|
||||
{
|
||||
_panelConsole.SetActive(true);
|
||||
isOpen = !isOpen;
|
||||
_panelConsole.SetActive(isOpen);
|
||||
}
|
||||
private void OnBtnCloseClicked()
|
||||
/* private void OnBtnCloseClicked()
|
||||
{
|
||||
_panelConsole.SetActive(false);
|
||||
}
|
||||
}*/
|
||||
public void OnBtnNoCooldownClicked()
|
||||
{
|
||||
UnityGameSession.c2s_CmdDebug(8903, 73125);
|
||||
@@ -122,6 +152,288 @@ namespace BrewMonster.Scripts
|
||||
}
|
||||
_autoAddWrathCoroutine = null;
|
||||
}
|
||||
|
||||
private void SendCmdDebug(int header, int param, bool hasParam)
|
||||
{
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user