Internals rewritten. PHoton config can now be fetched from the server, and if it fails, fallback to the local configuration.

This commit is contained in:
2025-08-16 21:04:26 -04:00
parent 8ca37170e4
commit 087d9a900e
20 changed files with 393 additions and 234 deletions

View File

@@ -0,0 +1,51 @@
using UnityEngine;
using System.Collections.Generic;
using System.Collections.Concurrent;
using Mapster;
using System;
using System.Linq;
using BestHTTP;
namespace undead_universal_patch_il2cpp.Core.Content.CustomRecNet.CustomEmotes;
public class EmoteConfigDTO
{
public string UniqueName { get; set; }
public string NewText { get; set; }
public string RoomChatText { get; set; }
public string FacialExpression { get; set; }
public bool ForceEmoteBubble { get; set; }
public bool OnlyBroadcastToTeam { get; set; }
}
public class CustomEmotes : MonoBehaviour
{
public void Start()
{
RecNetInteractions.postLocalAccountActions.Add(DownloadCustomEmotes);
}
void Patch(HTTPResponse _res, List<EmoteConfigDTO> emotes)
{
UniversalPatchPlugin.Log.LogInfo("Setting new emotes");
var internalEmotes = RecRoom.AGUI.Expresso.ContextualEmotesSettings.ConfigAsset.Emotes.ToList();
foreach (var emote in emotes)
{
var internalEmote = internalEmotes.Find(match => match.emoteUniqueName == emote.UniqueName);
if (internalEmote != null)
{
emote.Adapt(internalEmote);
}
}
Util.ConditionalDebug($"{emotes.Count} new emote configurations");
}
void DownloadCustomEmotes()
{
RecNetInteractions.SendRequest<List<EmoteConfigDTO>>(HTTPMethods.Get, RecNet.Service.API, "/api/undead/v1/emotes", Patch);
}
}

View File

@@ -0,0 +1,67 @@
using System;
using BestHTTP;
using Il2CppInterop.Runtime;
using undead_universal_patch_il2cpp.Core.Config;
using undead_universal_patch_il2cpp.Patches.Photon;
using UnityEngine;
namespace undead_universal_patch_il2cpp.Core.Content.CustomRecNet.CustomPhoton;
public class PhotonConfigDTO
{
public bool Logging { get; set; }
public string AppID { get; set; }
public string VoiceAppID { get; set; }
public bool SelfHosted { get; set; }
public string ServerAddress { get; set; }
public int ServerPort { get; set; }
public byte ConnectionProtocol { get; set; }
}
public class CustomPhoton : MonoBehaviour
{
public static bool ServerConfigFailed { get; set; } = false;
public void Start()
{
RecNetInteractions.postLocalAccountActions.Add(DownloadServerConfig);
}
void OnServerConfigFailed(HTTPResponse res)
{
ServerConfigFailed = true;
if (PhotonConfig.PatchPhotonIds.Value)
{
UniversalPatchPlugin.Log.LogInfo("Attempting Photon patch from local configuration");
PhotonPatch.Patch(new PhotonConfigDTO
{
Logging = PhotonConfig.PunLogging.Value,
AppID = PhotonConfig.AppID.Value,
VoiceAppID = PhotonConfig.VoiceAppID.Value,
SelfHosted = PhotonConfig.SelfHosted.Value,
ServerAddress = PhotonConfig.ServerAddress.Value,
ServerPort = PhotonConfig.ServerPort.Value,
ConnectionProtocol = PhotonConfig.ConnectionProtocol.Value
});
}
}
void ApplyPhotonConfig(HTTPResponse res, PhotonConfigDTO photonConfig)
{
if (!ServerPatchesConfig.CustomPhoton.Value) return;
try
{
UniversalPatchPlugin.Log.LogInfo("Attempting Photon patch from server configuration");
PhotonPatch.Patch(photonConfig);
}
catch (Exception err)
{
UniversalPatchPlugin.Log.LogError($"Failed to apply Photon configuration from server: {err}");
OnServerConfigFailed(res);
}
}
void DownloadServerConfig()
{
RecNetInteractions.SendRequest<PhotonConfigDTO>(HTTPMethods.Get, RecNet.Service.API, "/api/undead/v1/photon", ApplyPhotonConfig, OnServerConfigFailed);
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using BestHTTP;
using Il2CppInterop.Runtime;
using RecNet;
namespace undead_universal_patch_il2cpp.Core.Content.CustomRecNet;
public class RecNetInteractions
{
public static int AccountId { get; set; }
public static string AccessToken { get; set; }
public static List<Action> postNameServerActions = [];
public static List<Action> postAuthenticationActions = [];
public static List<Action> postLocalAccountActions = [];
public static Il2CppSystem.Uri CreateServiceUri(Service service, string pathAndQuery)
{
Il2CppSystem.Uri uri = RecNet.Core.GetServiceUri(service) ?? throw new Exception("Service is not available");
var newUri = new Il2CppSystem.Uri(uri, pathAndQuery);
return newUri;
}
public static bool HasNameserverConnected()
{
return RecNet.Core.ServiceUris.Count > 1;
}
public static void SendRequest<T>(HTTPMethods method, Service service, string requestUri, Action<HTTPResponse, T> reqFinished, Action<HTTPResponse>? reqFailed = null)
{
var res = RecNet.Core.SendRequest(method, service, requestUri);
res.Then(DelegateSupport.ConvertDelegate<Il2CppSystem.Action<HTTPResponse>>((HTTPResponse res) =>
{
try
{
var data = JsonSerializer.Deserialize<T>(res.DataAsText);
reqFinished(res, data);
}
catch (Exception ex)
{
UniversalPatchPlugin.Log.LogError($"'{requestUri}' failed\n{ex}");
if (reqFailed != null) reqFailed(res);
}
}));
}
}

View File

@@ -0,0 +1,155 @@
using System.Collections.Generic;
using RecRoom.Tools;
namespace undead_universal_patch_il2cpp.Core.Content.UndeadGameManager;
public class AutoHealSettingsDTO
{
public float Delay { get; set; }
public float Duration{ get; set; }
}
public class GameStartRequirementDTO
{
public int MinPlayerCount { get; set; }
public int MinTeamCount { get; set; }
public int MinTeamSize { get; set; }
}
public class DownButNotOutSettingsDTO
{
public float MaxDepletionDuration { get; set; }
public float InvincibilityDuration { get; set; }
}
public struct EnemyCombatUISettingsDTO
{
public bool OpponentUISupported { get; set; }
public bool TeammateUISupported { get; set; }
}
public struct FriendlyFireSettingsDTO
{
public bool PlayerOnPlayerFriendlyFireSupported { get; set; }
public bool PlayerOnEnemyFriendlyFireSupported { get; set; }
public bool EnemyOnPlayerFriendlyFireSupported { get; set; }
public bool EnemyOnEnemyFriendlyFireSupported { get; set; }
public bool GrenadesCanDamageTeammates { get; set; }
}
public struct PlayerCombatUISettingsDTO
{
public bool LocalPlayerUISupported { get; set; }
public bool OpponentUISupported { get; set; }
public bool TeammateUISupported { get; set; }
public bool TeammateUIAlwaysVisible { get; set; }
public bool OpponentUIAlwaysVisible { get; set; }
}
public class TeamConfigurationDTO
{
public int MaxTeamSize { get; set; }
}
public class PlayerVisualSettingsDTO
{
public bool UseTeamNameInsteadOfPlayerNameInNotifications { get; set; }
public bool UseTeamColorInFeedback { get; set; }
public TeamPlayerColorMode TeamColorMode { get; set; }
public bool TeamOutfitsSupported { get; set; }
public PlayerBeaconMode TeammateBeaconMode { get; set; }
public PlayerBeaconMode OpponentBeaconMode { get; set; }
}
public class TeamRadioSettingsDTO
{
public float RadioVolume { get; set; }
public float EnterRadioDistance { get; set; }
public float ExitRadioDistance { get; set; }
}
public struct StatConfigurationDTO
{
public string Name { get; set; }
public bool HideInUI { get; set; }
public bool HideInHUD { get; set; }
public GameUIDataModelStatFormat Format { get; set; }
}
public struct RespawnSettingsDTO
{
public float AutoRespawnDelay { get; set; }
public bool RestoreHealthOnRespawn { get; set; }
public float RespawnInvincibilityDuration { get; set; }
}
public struct ReviveSettingsDTO
{
public float RequiredDelay { get; set; }
public float MaxReviveHealthNormalized { get; set; }
public float MinReviveHealthNormalized { get; set; }
public float MultiplierPerReviveHealthNormalized { get; set; }
public bool PickupToolsOnRevive { get; set; }
public float ReviverInvincibilityDuration { get; set; }
public float ReviveeInvincibilityDuration { get; set; }
public float HandshakeHoldDuration { get; set; }
}
public class GameConfigurationAssetDTO
{
public string Name { get; set; }
public int LoadPriority { get; set; }
public GameStartRequirementDTO ManualGameStartRequirement { get; set; }
public bool AutomaticGameStartSupported { get; set; }
public GameStartRequirementDTO AutomaticGameStartRequirement { get; set; }
public bool PreGameVoiceOverSupported { get; set; }
public bool ResultsVoiceOverSupported { get; set; }
public bool CountdownVoiceOverSupported { get; set; }
public bool GameModeNotificationsSupported { get; set; }
public bool InGamePlayerNotificationsSupported { get; set; }
public float GameStartDelay { get; set; }
public float EndGameResultsDuration { get; set; }
public bool RespawnOnGameStartSupported { get; set; }
public bool RespawnOnGameEndSupported { get; set; }
public bool JoinInProgressSupported { get; set; }
public List<TeamConfigurationDTO> TeamConfigurations { get; set; }
public TeamSelectionMethod TeamSelectionMethod { get; set; }
public bool EndGameIfStartRequirementsNotMet { get; set; }
public bool ExplicitTeamSelectionSupported { get; set; }
public bool GameRunningTeamChangeSupported { get; set; }
public bool RespawnOnGameRunningTeamChangeSupported { get; set; }
public bool SpectatingSupported { get; set; }
public bool ShowOpenSlotsOnScoreboard { get; set; }
public bool ClearTeamsAfterGame { get; set; }
public PlayerVisualSettingsDTO TeamPlayerVisualSettings { get; set; }
public bool TeamRadioSupported { get; set; }
public TeamRadioSettingsDTO TeamRadioSettings { get; set; }
public List<StatConfigurationDTO> StatConfigurations { get; set; }
public bool PersistStatsOnGameStart { get; set; }
public int MaxHealth { get; set; }
public int MaxShield { get; set; }
public bool SuppressWeaponDamage { get; set; }
public bool AutoHealSupported { get; set; }
public AutoHealSettingsDTO AutoHealSettings { get; set; }
public bool DownButNotOutSupported { get; set; }
public DownButNotOutSettingsDTO DownButNotOutSettings { get; set; }
public bool AutoRespawnSupported { get; set; }
public RespawnSettingsDTO RespawnSettings { get; set; }
public GameCombatManager.PlayerReviveMode ReviveMode { get; set; }
public ReviveSettingsDTO ReviveSettings { get; set; }
public bool HUDSupported { get; set; }
public FriendlyFireSettingsDTO FriendlyFireSettings { get; set; }
public PlayerCombatUISettingsDTO PlayerCombatUISettings { get; set; }
public EnemyCombatUISettingsDTO EnemyCombatUISettings { get; set; }
public bool DeadMonochromeEffectSupported { get; set; }
public bool DownButNotOutMonochromeEffectSupported { get; set; }
public bool DamageRedFlashEffectSupported { get; set; }
public bool DefaultHitFeedbackSupported { get; set; }
public bool DefaultReviveFeedbackSupported { get; set; }
public bool DefaultDownedOpponentFeedbackSupported { get; set; }
public bool DefaultDownedLocalPlayerFeedbackSupported { get; set; }
public bool DefaultDownedTeammateFeedbackSupported { get; set; }
public bool DeadPersistentNotificationSupported { get; set; }
public GameSpawnPointSelectionMethod SpawnPointSelectionMethod { get; set; }
public SpawnableToolType MainHandTool { get; set; }
public SpawnableToolType OffHandTool { get; set; }
public bool ResetToolsOnGameStartSupported { get; set; }
public ToolEntity.BrokenBehavior BrokenToolBehavior { get; set; }
public bool EquipmentBeaconsSupported { get; set; }
public bool WeaponInfiniteAmmoSupported { get; set; }
public bool TeleportBufferDistanceRetricted { get; set; }
public bool OutOfBoundsSupported { get; set; }
public bool OutOfBoundsSpectatorsSupported { get; set; }
public bool DownOutOfBoundsPlayers { get; set; }
public float OutOfBoundsGracePeriod { get; set; }
public float OutOfBoundsMaxDuration { get; set; }
}

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace undead_universal_patch_il2cpp.Core.Content.UndeadGameManager;
public static class GameConfigurator
{
static readonly string name = "GameConfigurations";
public static DediConfig<Dictionary<string, GameConfigurationAssetDTO>> config = new(name, "{}", null);
}

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace undead_universal_patch_il2cpp.Core.Content.UndeadGameManager;
public static class GameFreeSpawns
{
static readonly string name = "GameFreeSpawns";
public static DediConfig<List<string>> config = new(name, "[]", null);
}