using Unity.BossRoom.ConnectionManagement; using Unity.BossRoom.Gameplay.GameplayObjects; using Unity.BossRoom.Gameplay.GameplayObjects.Character; using Unity.BossRoom.Gameplay.Messages; using Unity.BossRoom.Infrastructure; using Unity.Multiplayer.Samples.BossRoom; using Unity.Multiplayer.Samples.Utilities; using Unity.Netcode; using UnityEngine; using VContainer; namespace Unity.BossRoom.DebugCheats { /// /// Handles debug cheat events, applies them on the server and logs them on all clients. This class is only /// available in the editor or for development builds /// public class DebugCheatsManager : NetworkBehaviour { [SerializeField] GameObject m_DebugCheatsPanel; #if UNITY_EDITOR || DEVELOPMENT_BUILD [SerializeField] [Tooltip("Enemy to spawn. Make sure this is included in the NetworkManager's list of prefabs!")] NetworkObject m_EnemyPrefab; [SerializeField] [Tooltip("Boss to spawn. Make sure this is included in the NetworkManager's list of prefabs!")] NetworkObject m_BossPrefab; [SerializeField] KeyCode m_OpenWindowKeyCode = KeyCode.Slash; SwitchedDoor m_SwitchedDoor; SwitchedDoor SwitchedDoor { get { if (m_SwitchedDoor == null) { m_SwitchedDoor = FindObjectOfType(); } return m_SwitchedDoor; } } const int k_NbTouchesToOpenWindow = 4; bool m_DestroyPortalsOnNextToggle = true; [Inject] IPublisher m_CheatUsedMessagePublisher; void Update() { if (Input.touchCount == k_NbTouchesToOpenWindow && AnyTouchDown() || m_OpenWindowKeyCode != KeyCode.None && Input.GetKeyDown(m_OpenWindowKeyCode)) { m_DebugCheatsPanel.SetActive(!m_DebugCheatsPanel.activeSelf); } } static bool AnyTouchDown() { foreach (var touch in Input.touches) { if (touch.phase == TouchPhase.Began) { return true; } } return false; } public void SpawnEnemy() { ServerSpawnEnemyRpc(); } public void SpawnBoss() { ServerSpawnBossRpc(); } public void KillTarget() { ServerKillTargetRpc(); } public void KillAllEnemies() { ServerKillAllEnemiesRpc(); } public void ToggleGodMode() { ServerToggleGodModeRpc(); } public void HealPlayer() { ServerHealPlayerRpc(); } public void ToggleSuperSpeed() { ServerToggleSuperSpeedRpc(); } public void ToggleTeleportMode() { ServerToggleTeleportModeRpc(); } public void ToggleDoor() { ServerToggleDoorRpc(); } public void TogglePortals() { ServerTogglePortalsRpc(); } public void GoToPostGame() { GoToPostGameServerRpc(); } [Rpc(SendTo.Server, RequireOwnership = false)] void ServerSpawnEnemyRpc(RpcParams serverRpcParams = default) { var newEnemy = Instantiate(m_EnemyPrefab); newEnemy.SpawnWithOwnership(NetworkManager.Singleton.LocalClientId, true); PublishCheatUsedMessage(serverRpcParams.Receive.SenderClientId, "SpawnEnemy"); } [Rpc(SendTo.Server, RequireOwnership = false)] void ServerSpawnBossRpc(RpcParams serverRpcParams = default) { var newEnemy = Instantiate(m_BossPrefab); newEnemy.SpawnWithOwnership(NetworkManager.Singleton.LocalClientId, true); PublishCheatUsedMessage(serverRpcParams.Receive.SenderClientId, "SpawnBoss"); } [Rpc(SendTo.Server, RequireOwnership = false)] void ServerKillTargetRpc(RpcParams serverRpcParams = default) { ulong clientId = serverRpcParams.Receive.SenderClientId; var playerServerCharacter = PlayerServerCharacter.GetPlayerServerCharacter(clientId); if (playerServerCharacter != null) { var targetId = playerServerCharacter.TargetId.Value; if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(targetId, out NetworkObject obj)) { var damageable = obj.GetComponent(); if (damageable != null && damageable.IsDamageable()) { damageable.ReceiveHP(playerServerCharacter, int.MinValue); PublishCheatUsedMessage(serverRpcParams.Receive.SenderClientId, "KillTarget"); } else { UnityEngine.Debug.Log($"Target {targetId} has no IDamageable component or cannot be damaged."); } } } } [Rpc(SendTo.Server, RequireOwnership = false)] void ServerKillAllEnemiesRpc(RpcParams serverRpcParams = default) { foreach (var serverCharacter in FindObjectsOfType()) { if (serverCharacter.IsNpc && serverCharacter.LifeState == LifeState.Alive) { if (serverCharacter.gameObject.TryGetComponent(out IDamageable damageable)) { damageable.ReceiveHP(null, -serverCharacter.HitPoints); } } } PublishCheatUsedMessage(serverRpcParams.Receive.SenderClientId, "KillAllEnemies"); } [Rpc(SendTo.Server, RequireOwnership = false)] void ServerToggleGodModeRpc(RpcParams serverRpcParams = default) { var clientId = serverRpcParams.Receive.SenderClientId; var playerServerCharacter = PlayerServerCharacter.GetPlayerServerCharacter(clientId); if (playerServerCharacter != null) { playerServerCharacter.NetLifeState.IsGodMode.Value = !playerServerCharacter.NetLifeState.IsGodMode.Value; PublishCheatUsedMessage(clientId, "ToggleGodMode"); } } [Rpc(SendTo.Server, RequireOwnership = false)] void ServerHealPlayerRpc(RpcParams serverRpcParams = default) { var clientId = serverRpcParams.Receive.SenderClientId; var playerServerCharacter = PlayerServerCharacter.GetPlayerServerCharacter(clientId); if (playerServerCharacter != null) { var baseHp = playerServerCharacter.CharacterClass.BaseHP.Value; if (playerServerCharacter.LifeState == LifeState.Fainted) { playerServerCharacter.Revive(null, baseHp); } else { if (playerServerCharacter.gameObject.TryGetComponent(out IDamageable damageable)) { damageable.ReceiveHP(null, baseHp); } } PublishCheatUsedMessage(serverRpcParams.Receive.SenderClientId, "HealPlayer"); } } [Rpc(SendTo.Server, RequireOwnership = false)] void ServerToggleSuperSpeedRpc(RpcParams serverRpcParams = default) { var clientId = serverRpcParams.Receive.SenderClientId; foreach (var playerServerCharacter in PlayerServerCharacter.GetPlayerServerCharacters()) { if (playerServerCharacter.OwnerClientId == clientId) { playerServerCharacter.Movement.SpeedCheatActivated = !playerServerCharacter.Movement.SpeedCheatActivated; break; } } PublishCheatUsedMessage(clientId, "ToggleSuperSpeed"); } [Rpc(SendTo.Server, RequireOwnership = false)] void ServerToggleTeleportModeRpc(RpcParams serverRpcParams = default) { var clientId = serverRpcParams.Receive.SenderClientId; foreach (var playerServerCharacter in PlayerServerCharacter.GetPlayerServerCharacters()) { if (playerServerCharacter.OwnerClientId == clientId) { playerServerCharacter.Movement.TeleportModeActivated = !playerServerCharacter.Movement.TeleportModeActivated; break; } } PublishCheatUsedMessage(serverRpcParams.Receive.SenderClientId, "ToggleTeleportMode"); } [Rpc(SendTo.Server, RequireOwnership = false)] void ServerToggleDoorRpc(RpcParams serverRpcParams = default) { if (SwitchedDoor != null) { SwitchedDoor.ForceOpen = !SwitchedDoor.ForceOpen; PublishCheatUsedMessage(serverRpcParams.Receive.SenderClientId, "ToggleDoor"); } else { UnityEngine.Debug.Log("Could not activate ToggleDoor cheat. Door not found."); } } [Rpc(SendTo.Server, RequireOwnership = false)] void ServerTogglePortalsRpc(RpcParams serverRpcParams = default) { foreach (var portal in FindObjectsOfType()) { if (m_DestroyPortalsOnNextToggle) { // This will only affect portals that are currently active in a scene and are currently loaded. // Portals that are already destroyed will not be affected by this, and won't have their cooldown // reinitialized. portal.ForceDestroy(); } else { portal.ForceRestart(); } } m_DestroyPortalsOnNextToggle = !m_DestroyPortalsOnNextToggle; PublishCheatUsedMessage(serverRpcParams.Receive.SenderClientId, "TogglePortals"); } [Rpc(SendTo.Server, RequireOwnership = false)] void GoToPostGameServerRpc(RpcParams serverRpcParams = default) { SceneLoaderWrapper.Instance.LoadScene("PostGame", useNetworkSceneManager: true); PublishCheatUsedMessage(serverRpcParams.Receive.SenderClientId, "GoToPostGame"); } void PublishCheatUsedMessage(ulong clientId, string cheatUsed) { var playerData = SessionManager.Instance.GetPlayerData(clientId); if (playerData.HasValue) { m_CheatUsedMessagePublisher.Publish(new CheatUsedMessage(cheatUsed, playerData.Value.PlayerName)); } } static void LogCheatNotImplemented(string cheat) { UnityEngine.Debug.Log($"Cheat {cheat} not implemented"); } #else void Awake() { m_DebugCheatsPanel.SetActive(false); } #endif } }