Skip to content

Initial checkin of olmod integration with tracker for challenge mode #303

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions GameMod/CMTracker/Menu.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using HarmonyLib;
using Overload;
using System.Collections.Generic;
using System.Reflection.Emit;
using UnityEngine;

namespace GameMod.CMTracker
{
class CMTracker
{
public static bool mms_cm_runs_visible_in_tracker = false;
}

[HarmonyPatch(typeof(UIElement), "DrawChallengeLevelSelectMenu")]
class CMTracker_Menu_UIElement_DrawChallengeLevelSelectMenu
{

private static void PatchMenu(UIElement uie, Vector2 position)
{
uie.SelectAndDrawCheckboxItem("SUBMIT RESULTS TO PUBLIC TRACKER", position, 7, CMTracker.mms_cm_runs_visible_in_tracker, false, 1f, -1);
}

private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> codes)
{
// Skip from float num = 137f; to end of method, not applicable to olmod
bool skip = false;
foreach (var code in codes)
{
if (code.opcode == OpCodes.Ldc_R4 && (float)code.operand == 137f)
skip = true;

if (skip)
continue;

yield return code;
}

yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Ldloc_0);
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(CMTracker_Menu_UIElement_DrawChallengeLevelSelectMenu), "PatchMenu"));
yield return new CodeInstruction(OpCodes.Ret);
}
}

[HarmonyPatch(typeof(MenuManager), "ChallengeLevelSelectUpdate")]
internal class CMTracker_Menu_MenuManager_ChallengeLevelSelectUpdate
{
private static int PatchMenu()
{
if (UIManager.m_menu_selection == 7)
{
CMTracker.mms_cm_runs_visible_in_tracker = !CMTracker.mms_cm_runs_visible_in_tracker;
MenuManager.PlaySelectSound();
return UIManager.m_menu_selection;
}

// ilcode represented differently in Harmony than dnSpy, we need to return something other than UIManager.m_menu_selection to hit CreateNewGame branch
return 99;
}

private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> codes)
{
foreach (var code in codes)
{
if (code.opcode == OpCodes.Ldc_I4_S && (sbyte)code.operand == 97)
{
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(CMTracker_Menu_MenuManager_ChallengeLevelSelectUpdate), "PatchMenu"));
continue;
}
yield return code;
}
}
}
}
11 changes: 11 additions & 0 deletions GameMod/CMTracker/Models/LeaderboardEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace GameMod.CMTracker.Models
{
public class LeaderboardEntry
{
public int FavoriteWeaponId { get; set; }
public float AliveTime { get; set; }
public int RobotsDestroyed { get; set; }
public string PilotName { get; set; }
public int Score { get; set; }
}
}
27 changes: 27 additions & 0 deletions GameMod/CMTracker/Models/Run.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Collections.Generic;

namespace GameMod.CMTracker.Models
{
public class Run
{
public string PlayerId { get; set; }
public string PilotName { get; set; }
public bool DisplayOnTracker { get; set; }
public string LevelName { get; set; }
public string LevelHash { get; set; }
public int KillerId { get; set; }
public int FavoriteWeaponId { get; set; }
public int DifficultyLevelId { get; set; }
public int ModeId { get; set; }
public int RobotsDestroyed { get; set; }
public float AliveTime { get; set; }
public int Score { get; set; }
public float SmashDamage { get; set; }
public int SmashKills { get; set; }
public float AutoOpDamage { get; set; }
public int AutoOpKills { get; set; }
public float SelfDamage { get; set; }
public List<Models.StatRobot> StatsRobot { get; set; }
public List<Models.StatPlayer> StatsPlayer { get; set; }
}
}
10 changes: 10 additions & 0 deletions GameMod/CMTracker/Models/StatPlayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace GameMod.CMTracker.Models
{
public class StatPlayer
{
public int WeaponTypeId { get; set; }
public bool IsPrimary { get; set; }
public float DamageDealt { get; set; }
public int NumKilled { get; set; }
}
}
11 changes: 11 additions & 0 deletions GameMod/CMTracker/Models/StatRobot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace GameMod.CMTracker.Models
{
public class StatRobot
{
public int EnemyTypeId { get; set; }
public bool IsSuper { get; set; }
public float DamageReceived { get; set; }
public float DamageDealt { get; set; }
public int NumKilled { get; set; }
}
}
174 changes: 174 additions & 0 deletions GameMod/CMTracker/Platform.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
using HarmonyLib;
using Newtonsoft.Json;
using Overload;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;

namespace GameMod.CMTracker
{
[HarmonyPatch(typeof(Platform), "Init")]
internal class CMTracker_Platform_Init
{
static void Postfix()
{
AccessTools.Field(typeof(Platform), "CloudProvider").SetValue(null, 4);
}
}

[HarmonyPatch(typeof(Platform), "UserName", MethodType.Getter)]
internal class CMTracker_Platform_UserName
{
static void Postfix(ref string __result)
{
__result = PilotManager.PilotName;
}
}

[HarmonyPatch(typeof(Platform), "PlatformName", MethodType.Getter)]
internal class CMTracker_Platform_PlatformName
{
public static void Postfix(ref string __result)
{
__result = "OLMOD";
}
}

[HarmonyPatch(typeof(Platform), "StatsAvailable", MethodType.Getter)]
internal class CMTracker_Platform_PlatformStatsAvailable
{
public static void Postfix(ref bool __result)
{
__result = true;
}
}

[HarmonyPatch(typeof(Platform), "OnlineErrorMessage", MethodType.Getter)]
internal class CMTracker_Platform_OnlineErrorMessage
{
public static void Postfix(ref string __result)
{
__result = null;
}
}

[HarmonyPatch(typeof(Platform), "GetLeaderboardData")]
internal class CMTracker_Platform_GetLeaderboardData
{
public static void Postfix(ref LeaderboardEntry[] __result, out int leaderboard_length, out int user_index, out Platform.LeaderboardDataState result)
{
user_index = -1;
leaderboard_length = 0;

if (m_download_state == DownloadState.NoLeaderboard)
{
result = Platform.LeaderboardDataState.NoLeaderboard;
__result = null;
return;
}
if (m_download_state == DownloadState.RetryFromStart)
{
m_request_start = 1;
try
{
Platform.RequestChallengeLeaderboardData(MenuManager.ChallengeMission.DisplayName, MenuManager.m_leaderboard_challenge_countdown, MenuManager.m_leaderboard_difficulty, 1, m_request_num_entries - 1, false);
m_download_state = DownloadState.WaitingForData;
result = Platform.LeaderboardDataState.Waiting;
}
catch (Exception ex)
{
Debug.Log($"Error requesting olmod leaderboard entries: {ex.Message}");
m_download_state = DownloadState.NoLeaderboard;
result = Platform.LeaderboardDataState.NoLeaderboard;
}
__result = null;
return;
}
if (m_download_state != DownloadState.HaveData)
{
result = Platform.LeaderboardDataState.Waiting;
__result = null;
return;
}

LeaderboardEntry[] array = new LeaderboardEntry[m_entries.Length];
for (int i = 0; i < m_entries.Length; i++)
{
if (m_entries[i].m_name == null)
{
m_entries[i].m_name = "m_name here";
m_entries[i].m_rank = i + 1;
}
array[i] = m_entries[i];
}
leaderboard_length = m_entries.Length;
result = Platform.LeaderboardDataState.HaveData;
__result = array;
}

public static DownloadState m_download_state = DownloadState.RetryFromStart;
public static int m_request_start;
public static int m_request_num_entries = 0;
public static int m_leaderboard_length = 0;
public static LeaderboardEntry[] m_entries;

public enum DownloadState
{
WaitingForData,
NoLeaderboard,
RetryFromStart,
HaveData
}
}

[HarmonyPatch(typeof(Platform), "RequestChallengeLeaderboardData")]
internal static class CMRequestChallengeLeaderboardData
{
public static CloudDataYield Postfix(CloudDataYield __result, string level_name, bool submode, int difficulty_level, int range_start, int num_entries, bool friends)
{
var levelHash = MenuManager.ChallengeMission.IsLevelAnAddon(MenuManager.m_leaderboard_level_num)
? MenuManager.ChallengeMission.GetAddOnLevelIdStringHash(MenuManager.m_leaderboard_level_num)
: MenuManager.ChallengeMission.GetLevelFileName(MenuManager.m_leaderboard_level_num) + ":STOCK";
CMTracker_Platform_GetLeaderboardData.m_download_state = CMTracker_Platform_GetLeaderboardData.DownloadState.WaitingForData;
GameManager.m_gm.StartCoroutine(DownloadLeaderboard(level_name, levelHash, Convert.ToInt32(submode), difficulty_level));
CloudDataYield cdy = new CloudDataYield(() => CMTracker_Platform_GetLeaderboardData.m_download_state != CMTracker_Platform_GetLeaderboardData.DownloadState.HaveData &&
CMTracker_Platform_GetLeaderboardData.m_download_state != CMTracker_Platform_GetLeaderboardData.DownloadState.NoLeaderboard);

__result = cdy;
return null;
}

static IEnumerator DownloadLeaderboard(string levelName, string levelHash, int modeId, int difficultyLevelId)
{
var url = $"{Config.Settings.Value<string>("trackerBaseUrl")}/api/challengemodeleaderboard?levelHash={levelHash}&difficultyLevelId={difficultyLevelId}&modeId={modeId}";

UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.SendWebRequest();

if (www.isNetworkError || www.isHttpError)
{
Debug.Log($"DownloadLeaderboard Error: {www.error}");
}
else
{
List<Models.LeaderboardEntry> results = JsonConvert.DeserializeObject<List<Models.LeaderboardEntry>>(www.downloadHandler.text);

CMTracker_Platform_GetLeaderboardData.m_entries = results.Select(x => new LeaderboardEntry
{
m_data_is_valid = true,
m_favorite_weapon = x.FavoriteWeaponId,
m_game_time = (int)Math.Round(x.AliveTime),
m_kills = x.RobotsDestroyed,
m_name = x.PilotName,
m_rank = 1,
m_score = x.Score,
m_time_stamp = DateTime.Now
}).ToArray();
CMTracker_Platform_GetLeaderboardData.m_download_state = CMTracker_Platform_GetLeaderboardData.DownloadState.HaveData;
}
}
}
}
Loading