-
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #36 from Ardub92/main
Cybergrind Synchronization
- Loading branch information
Showing
5 changed files
with
230 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
namespace Jaket.HarmonyPatches; | ||
|
||
using HarmonyLib; | ||
using UnityEngine; | ||
using UnityEngine.UI; | ||
|
||
using Jaket.Net; | ||
using Jaket.World; | ||
|
||
#pragma warning disable IDE0051 // Remove unused private members | ||
#pragma warning disable RCS1213 // Remove unused member declaration. | ||
|
||
[HarmonyPatch(typeof(EndlessGrid), "LoadPattern")] | ||
public class EndlessGridLoadPatternPatch | ||
{ | ||
static void Prefix(ref ArenaPattern pattern) | ||
{ | ||
// load current pattern in client | ||
if (LobbyController.Lobby != null) | ||
{ | ||
// send pattern if the player is the owner of the lobby | ||
if (LobbyController.IsOwner) CyberGrind.Instance.SendPattern(pattern); | ||
// replacing client pattern with server pattern on client | ||
else pattern = CyberGrind.Instance.CurrentPattern; | ||
} | ||
} | ||
} | ||
|
||
[HarmonyPatch(typeof(EndlessGrid), "Start")] | ||
public class EndlessGridStartPatch | ||
{ | ||
static bool Prefix() | ||
{ | ||
// getting cybergrind grid deathzone to change it later | ||
foreach (var deathZone in Resources.FindObjectsOfTypeAll<DeathZone>()) if (deathZone.name == "Cube") CyberGrind.Instance.GridDeathZoneInstance = deathZone; | ||
|
||
// don't skip original method | ||
return true; | ||
} | ||
|
||
// use postfix to wait object to initialize | ||
static void Postfix() | ||
{ | ||
var cg = CyberGrind.Instance; | ||
// check when the player in a lobby | ||
if (LobbyController.Lobby != null || LobbyController.IsOwner) | ||
{ | ||
// sets as first time | ||
cg.LoadTimes = 0; | ||
// check if current pattern is loaded and the player is the client | ||
if (cg.CurrentPattern != null && !LobbyController.IsOwner) | ||
// loads current pattern from the server | ||
cg.LoadCurrentPattern(); | ||
// send empty pattern when game starts and the player is the owner to prevent load previous cybergrind pattern | ||
else cg.SendPattern(new ArenaPattern()); | ||
} | ||
else | ||
{ | ||
// resetting values if the player is not in a lobby. | ||
cg.LoadTimes = 0; | ||
cg.CurrentWave = 0; | ||
cg.CurrentPattern = null; | ||
} | ||
} | ||
} | ||
|
||
[HarmonyPatch(typeof(EndlessGrid), "OnTriggerEnter")] | ||
public class EndlessGridOnTriggerEnterPatch | ||
{ | ||
// dont allow to launch CyberGrind to client | ||
static bool Prefix(ref Text ___waveNumberText) | ||
{ | ||
// for some reason, the wave number text is not shown on the client | ||
___waveNumberText.transform.parent.parent.gameObject.SetActive(value: true); | ||
// don't activate trigger if the player is not the owner of the lobby | ||
if (LobbyController.Lobby != null && !LobbyController.IsOwner) return false; | ||
return true; | ||
} | ||
} | ||
|
||
[HarmonyPatch(typeof(EndlessGrid), "Update")] | ||
public class EndlessGridUpdatePatch | ||
{ | ||
static bool Prefix(ref ActivateNextWave ___anw, EndlessGrid __instance) | ||
{ | ||
// check if the player is not the owner of the lobby (client) | ||
if (LobbyController.Lobby != null && !LobbyController.IsOwner) | ||
{ | ||
// set the current wave on the client to original cybergrind singleton to sync with the server | ||
__instance.currentWave = CyberGrind.Instance.CurrentWave; | ||
// set death enemies to prevent start new wave on the client to sync it | ||
___anw.deadEnemies = -999; | ||
} | ||
return true; | ||
} | ||
|
||
// use postfix to change object after original object is changed | ||
static void Postfix(ref Text ___enemiesLeftText) | ||
{ | ||
// check if the player is not the owner of the lobby (client) | ||
if (LobbyController.Lobby != null && !LobbyController.IsOwner) | ||
{ | ||
// we broke original death enemies count, so we need to create new counter based on EnemyTracker | ||
var enemies = EnemyTracker.Instance.enemies; | ||
// remove dead enemies or null enemies from the list | ||
enemies.RemoveAll(e => e.dead || e is null); | ||
// set enemies left text on the client, replacing original | ||
___enemiesLeftText.text = EnemyTracker.Instance.enemies.Count.ToString(); | ||
} | ||
// change y position of cybergrind grid deathzone when lobby created or not to prevent enemies randomly dying | ||
var dz = CyberGrind.Instance.GridDeathZoneInstance; | ||
if (dz != null) dz.transform.position = dz.transform.position with { y = LobbyController.Lobby != null ? -10 : 0.5f }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
namespace Jaket.World; | ||
|
||
using HarmonyLib; | ||
using Jaket.Content; | ||
using Jaket.IO; | ||
using Jaket.Net; | ||
using Jaket.UI; | ||
using UnityEngine.UI; | ||
|
||
/// <summary> Class responsible for Cybergrind synchronization </summary> | ||
public class CyberGrind : MonoSingleton<CyberGrind> | ||
{ | ||
/// <summary> UI Text, used for displaying current wave number. </summary> | ||
public Text WaveNumberTextInstance; | ||
/// <summary> UI Text, used for displaying current enemies left. </summary> | ||
public Text EnemiesLeftTextInstance; | ||
public DeathZone GridDeathZoneInstance; | ||
|
||
/// <summary> Current wave count used for sync. </summary> | ||
public int CurrentWave; | ||
/// <summary> How many times pattern is loaded. Can't be bigger that 1. </summary> | ||
public int LoadTimes; | ||
|
||
/// <summary> Current pattern used for sync. </summary> | ||
public ArenaPattern CurrentPattern; | ||
public int LoadCount; | ||
|
||
/// <summary> Sends the current arena pattern to all clients. </summary> | ||
/// <param name="pattern"> Pattern to send to clients. </param> | ||
public void SendPattern(ArenaPattern pattern) | ||
{ | ||
// serialize pattern to send to clients | ||
var data = SerializePattern(pattern); | ||
// sending to clients | ||
Networking.Redirect(Writer.Write(w => | ||
{ | ||
// wave number | ||
w.Int(EndlessGrid.Instance.currentWave); | ||
// pattern | ||
w.String(data); | ||
}), PacketType.CybergrindAction); | ||
} | ||
|
||
/// <summary> Load pattern serialized pattern and wave from server. </summary> | ||
/// <param name="data"> String type represented in <see cref="SerializePattern(ArenaPattern)"/> </param> | ||
public void LoadPattern(int currentWave, string data) | ||
{ | ||
// sets current pattern to give it to LoadPattern method of original class | ||
CurrentPattern = DeserializePattern(data); | ||
// set current wave to synced one | ||
CurrentWave = currentWave; | ||
LoadPattern(CurrentPattern); | ||
} | ||
|
||
/// <summary> Loads pattern and invoking next wave. </summary> | ||
/// <param name="pattern"> <see cref="ArenaPattern"/> to load. </param> | ||
public void LoadPattern(ArenaPattern pattern) | ||
{ | ||
// sets current pattern to give it to LoadPattern method of original class | ||
CurrentPattern = pattern; | ||
// start a new wave with server pattern | ||
AccessTools.Method(typeof(EndlessGrid), "NextWave").Invoke(EndlessGrid.Instance, new object[] { }); | ||
|
||
// Do not make new wave if it is the first time | ||
if (LoadTimes < 1) | ||
{ | ||
LoadTimes++; | ||
return; | ||
} | ||
|
||
// Resetting weapon charges (for example, railgun will be charged and etc.) | ||
WeaponCharges.Instance.MaxCharges(); | ||
|
||
// play cheering sound effect | ||
var cr = CrowdReactions.Instance; | ||
cr.React(cr.cheerLong); | ||
|
||
// resetting values after each wave | ||
var nmov = NewMovement.Instance; | ||
if (nmov.hp > 0) | ||
{ | ||
nmov.ResetHardDamage(); | ||
nmov.exploded = false; | ||
nmov.GetHealth(999, silent: true); | ||
nmov.FullStamina(); | ||
} | ||
} | ||
|
||
/// <summary> Loads current pattern. </summary> | ||
public void LoadCurrentPattern() => LoadPattern(CurrentPattern); | ||
|
||
/// <summary> Deserialize pattern to load it to client. </summary> | ||
/// <param name="data"> String to deserialize to <see cref="ArenaPattern"/>. </param> | ||
public ArenaPattern DeserializePattern(string data) | ||
{ | ||
// split a pattern into heights and prefabs. | ||
string[] parts = data.Split('|'); | ||
return new ArenaPattern { heights = parts[0], prefabs = parts[1] }; | ||
} | ||
|
||
/// <summary> Serializes pattern to string to send it to clients. </summary> | ||
/// <param name="arena"> <see cref="ArenaPattern"/> to serialize to string. </param> | ||
public string SerializePattern(ArenaPattern arena) => $"{arena.heights}|{arena.prefabs}"; | ||
|
||
public static void Load() | ||
{ | ||
// initialize the singleton | ||
UI.Object("CyberGrind").AddComponent<CyberGrind>(); | ||
} | ||
} |