Skip to content

Commit

Permalink
1.31.0 fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
rcelyte committed Jul 4, 2023
1 parent bd272c3 commit ca394e5
Show file tree
Hide file tree
Showing 38 changed files with 887 additions and 481 deletions.
2 changes: 1 addition & 1 deletion BeatUpClient/BeatUpClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<LocalRefsDir Condition="Exists('..\Refs')">..\Refs</LocalRefsDir>
<BeatSaberDir>$(LocalRefsDir)</BeatSaberDir>
<DebugType>full</DebugType>
<ModVersion>0.5.3</ModVersion>
<ModVersion>0.6.0</ModVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Cecil">
Expand Down
4 changes: 3 additions & 1 deletion BeatUpClient/MakeThingsPublic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"MultiplayerController::GetSongStartSyncTime",
"MultiplayerLevelLoader::_getBeatmapCancellationTokenSource",
"MultiplayerLevelLoader::_loaderState",
// "MultiplayerLevelLoader/MultiplayerBeatmapLoaderState",
"MultiplayerLocalActivePlayerFacade::_gameSongController",
"MultiplayerLocalActivePlayerInGameMenuViewController::_levelBar",
"MultiplayerLocalActivePlayerInGameMenuViewController::_localPlayerInGameMenuInitData",
Expand Down Expand Up @@ -178,12 +179,13 @@
("Libs", "MonoMod.RuntimeDetour.dll", null),
("Libs", "MonoMod.Utils.dll", null),
("Libs", "Newtonsoft.Json.dll", null),
("Libs", "System.IO.Compression.dll", null),
("Plugins", "SongCore.dll", null),
(managed, "BeatmapCore.dll", null),
(managed, "Colors.dll", null),
(managed, "GameplayCore.dll", null),
(managed, "Ignorance.dll", null),
(managed, "IPA.Loader.dll", null),
(managed, "System.IO.Compression.dll", null),
(managed, "System.Net.Http.dll", null),
(managed, "Unity.ResourceManager.dll", new[] {
"MonoBehaviourCallbackHooks",
Expand Down
23 changes: 0 additions & 23 deletions BeatUpClient/cs/MpCore/Patches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,6 @@ public static bool MpEntitlementChecker_HandleGetIsEntitledToLevel(MultiplayerCo
return false;
}

/*public static async System.Threading.Tasks.Task<EntitlementsStatus> MpShareWrapper(System.Threading.Tasks.Task<EntitlementsStatus> status, string levelId, NetworkPlayerEntitlementChecker checker) {
switch(await status) {
case EntitlementsStatus.Ok: return await ShareTask(levelId);
case EntitlementsStatus.NotOwned: return await checker._additionalContentModel.GetLevelEntitlementStatusAsync(levelId, System.Threading.CancellationToken.None) switch {
AdditionalContentModel.EntitlementStatus.Owned => await ShareTask(levelId),
AdditionalContentModel.EntitlementStatus.NotOwned => EntitlementsStatus.NotOwned,
_ => EntitlementsStatus.Unknown,
};
default: return status.Result;
};
}
[Patch(PatchType.Postfix, typeof(MultiplayerCore.Objects.MpEntitlementChecker), nameof(MultiplayerCore.Objects.MpEntitlementChecker.GetEntitlementStatus))]
public static void MpEntitlementChecker_GetEntitlementStatus(MultiplayerCore.Objects.MpEntitlementChecker __instance, ref System.Threading.Tasks.Task<EntitlementsStatus> __result, string levelId) {
Log.Debug($"MpEntitlementChecker_GetEntitlementStatus(levelId=\"{levelId}\")");
__result = MpShareWrapper(__result, levelId, __instance);
}*/

static System.Diagnostics.Stopwatch rateLimit = System.Diagnostics.Stopwatch.StartNew();
[Patch(PatchType.Postfix, typeof(MultiplayerCore.Objects.MpLevelLoader), nameof(MultiplayerCore.Objects.MpLevelLoader.Report))]
static void MpLevelLoader_Report(double value) {
Expand All @@ -36,11 +18,6 @@ static void MpLevelLoader_Report(double value) {
Net.SetLocalProgressUnreliable(new LoadProgress(LoadState.Downloading, (ushort)(value * 65535)));
}

[Patch.Overload(PatchType.Postfix, typeof(MultiplayerCore.Patchers.NetworkConfigPatcher), "UseMasterServer", true, new[] {typeof(DnsEndPoint), typeof(string), typeof(System.Nullable<int>)})]
[Patch.Overload(PatchType.Postfix, typeof(MultiplayerCore.Patchers.NetworkConfigPatcher), "UseMasterServer", true, new[] {typeof(DnsEndPoint), typeof(string), typeof(System.Nullable<int>), typeof(string)})]
static void NetworkConfigPatcher_UseMasterServer(DnsEndPoint endPoint, string statusUrl) =>
UpdateNetworkConfig(endPoint.ToString(), statusUrl);

[Patch(PatchType.Postfix, typeof(MultiplayerCore.Patchers.NetworkConfigPatcher), nameof(MultiplayerCore.Patchers.NetworkConfigPatcher.UseCustomApiServer), true)]
static void NetworkConfigPatcher_UseCustomApiServer(string graphUrl, string statusUrl, int? maxPartySize, string? quickPlaySetupUrl) =>
UpdateNetworkConfig(graphUrl, statusUrl); // TODO: respect `maxPartySize`, `quickPlaySetupUrl`
Expand Down
30 changes: 20 additions & 10 deletions BeatUpClient/cs/Net.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public enum MessageType : byte {
DataFragmentRequest,
DataFragment,
LoadProgress,
ServerConnectInfo,
}

const byte beatUpMessageType = 101;
Expand Down Expand Up @@ -67,7 +68,7 @@ static void HandleBeatUpPacket(LiteNetLib.Utils.NetDataReader reader, int length
int end = reader.Position + length;
try {
MessageType type = (MessageType)reader.GetByte();
if(type != MessageType.ConnectInfo && !beatUpPlayers.Keys.Contains(player))
if(type != MessageType.ConnectInfo && type != MessageType.ServerConnectInfo && !beatUpPlayers.Keys.Contains(player))
return;
switch(type) {
case MessageType.ConnectInfo: HandleConnectInfo(new ConnectInfo(reader), player); break;
Expand All @@ -76,6 +77,16 @@ static void HandleBeatUpPacket(LiteNetLib.Utils.NetDataReader reader, int length
case MessageType.DataFragmentRequest: ShareProvider.OnDataFragmentRequest(new DataFragmentRequest(reader), player); break;
case MessageType.DataFragment: onDataFragment?.Invoke(new DataFragment(reader, end), player); break;
case MessageType.LoadProgress: playerData.UpdateLoadProgress(new LoadProgress(reader), player); break;
case MessageType.ServerConnectInfo: {
if((player as ConnectedPlayerManager.ConnectedPlayer)?.remoteConnectionId != 0)
break;
Log.Debug("Late ServerConnectInfo received");
connectInfo = new ServerConnectInfo(reader);
infoText?.SetActive(true);
RefreshModifiersHeader();
HandleConnectInfo(connectInfo.@base, player);
break;
}
default: break;
}
} catch(System.Exception ex) {
Expand Down Expand Up @@ -103,17 +114,16 @@ static void HandleMpPacket(LiteNetLib.Utils.NetDataReader reader, int length, IC
reader.SkipBytes(end - reader.Position);
}

internal static void Setup(IMenuRpcManager rpcManager) {
internal static void Setup(IMenuRpcManager rpcManager, MultiplayerSessionManager? multiplayerSessionManager) {
rpcManager.setIsEntitledToLevelEvent += (userId, levelId, status) =>
playerData.UpdateLoadProgress(new LoadProgress(status), GetPlayer(userId), true);
MultiplayerSessionManager? multiplayerSessionManager = Resolve<MultiplayerSessionManager>();
if(multiplayerSessionManager != null) {
multiplayerSessionManager._packetSerializer._typeRegistry[typeof(BeatUpPacket)] = beatUpMessageType;
multiplayerSessionManager._packetSerializer._typeRegistry[typeof(MpBeatmapPacket)] = mpCoreMessageType;
multiplayerSessionManager._packetSerializer._messsageHandlers[beatUpMessageType] = HandleBeatUpPacket;
if(!haveMpCore)
multiplayerSessionManager._packetSerializer._messsageHandlers[mpCoreMessageType] = HandleMpPacket;
}
if(multiplayerSessionManager == null)
return;
multiplayerSessionManager._packetSerializer._typeRegistry[typeof(BeatUpPacket)] = beatUpMessageType;
multiplayerSessionManager._packetSerializer._typeRegistry[typeof(MpBeatmapPacket)] = mpCoreMessageType;
multiplayerSessionManager._packetSerializer._messsageHandlers[beatUpMessageType] = HandleBeatUpPacket;
if(!haveMpCore)
multiplayerSessionManager._packetSerializer._messsageHandlers[mpCoreMessageType] = HandleMpPacket;
}
}

Expand Down
4 changes: 2 additions & 2 deletions BeatUpClient/cs/Packets/1_RecommendPreview.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public RecommendPreview(CustomPreviewBeatmapLevel preview) : this((IPreviewBeatm
return;
Newtonsoft.Json.Linq.JObject info = Newtonsoft.Json.Linq.JObject.Parse(System.IO.File.ReadAllText(path));
Newtonsoft.Json.Linq.IJEnumerable<Newtonsoft.Json.Linq.JToken> customData = Newtonsoft.Json.Linq.Extensions.Children(info["_difficultyBeatmapSets"]?.Children()["_difficultyBeatmaps"] ?? new Newtonsoft.Json.Linq.JArray())["_customData"];
requirements = Newtonsoft.Json.Linq.Extensions.Values<string>(customData["_requirements"]).ToHashSet().ToArray();
suggestions = Newtonsoft.Json.Linq.Extensions.Values<string>(customData["_suggestions"]).ToHashSet().ToArray();
requirements = Newtonsoft.Json.Linq.Extensions.Values<string>(customData["_requirements"]).ToHashSet().ToArray()!;
suggestions = Newtonsoft.Json.Linq.Extensions.Values<string>(customData["_suggestions"]).ToHashSet().ToArray()!;
}
}
}
23 changes: 13 additions & 10 deletions BeatUpClient/cs/Packets/PreviewBeatmapLevel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
static partial class BeatUpClient {
static string? HashForLevelID([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? levelId) {
static string? HashForLevelID(string? levelId) {
string[] parts = (levelId ?? string.Empty).Split(new[] {'_', ' '});
if(parts.Length < 3 || parts[2].Length != 40)
return null;
Expand All @@ -23,18 +23,19 @@ internal abstract class PreviewBeatmapLevel : BeatUpPacket, IPreviewBeatmapLevel
public System.Collections.Generic.IReadOnlyList<PreviewDifficultyBeatmapSet>? previewDifficultyBeatmapSets {get; protected set;} = null;
public EnvironmentInfoSO? environmentInfo {get;} = null;
public EnvironmentInfoSO? allDirectionsEnvironmentInfo {get;} = null;
public EnvironmentInfoSO[] environmentInfos => System.Array.Empty<EnvironmentInfoSO>();
public readonly ByteArrayNetSerializable cover = new ByteArrayNetSerializable("cover", 0, 8192);
UnityEngine.Sprite? localSprite = null;
public async System.Threading.Tasks.Task<UnityEngine.Sprite> GetCoverImageAsync(System.Threading.CancellationToken cancellationToken) {
Log.Debug("PreviewBeatmapLevel.GetCoverImageAsync()");
localSprite ??= await new MemorySpriteLoader(cover.data).LoadSpriteAsync("", cancellationToken);
localSprite ??= await new MemorySpriteLoader(cover.GetData()).LoadSpriteAsync("", cancellationToken);
localSprite ??= defaultPackCover;
return localSprite;
}
public void SetCover(UnityEngine.Sprite? fullSprite) {
localSprite = fullSprite;
if(fullSprite == null) {
cover.data = new byte[0];
cover.SetData(new byte[0]);
return;
}
UnityEngine.RenderTexture target = new UnityEngine.RenderTexture(128, 128, 0);
Expand All @@ -50,10 +51,10 @@ public void SetCover(UnityEngine.Sprite? fullSprite) {
byte[] data = UnityEngine.ImageConversion.EncodeToJPG(pixels, quality);
if(data.Length > 8192)
continue;
cover.data = data;
cover.SetData(data);
return;
}
cover.data = new byte[0];
cover.SetData(new byte[0]);
}
public override void Serialize(LiteNetLib.Utils.NetDataWriter writer) {
writer.Put((string?)(mpCore ? HashForLevelID(levelID) : levelID));
Expand Down Expand Up @@ -83,8 +84,10 @@ public override void Serialize(LiteNetLib.Utils.NetDataWriter writer) {
}
cover.Serialize(writer);
}
PreviewBeatmapLevel(bool mpCore) =>
(this.mpCore, cover.data) = (mpCore, new byte[0]);
PreviewBeatmapLevel(bool mpCore) {
this.mpCore = mpCore;
cover.SetData(new byte[0]);
}
protected PreviewBeatmapLevel(LiteNetLib.Utils.NetDataReader reader, bool mpCore) : this(mpCore) {
(levelID, songName, songSubName, songAuthorName, levelAuthorName) =
(reader.GetString(), reader.GetString(), reader.GetString(), reader.GetString(), reader.GetString());
Expand Down Expand Up @@ -114,14 +117,14 @@ protected PreviewBeatmapLevel(IPreviewBeatmapLevel? prv, bool mpCore) : this(mpC
(levelID, songName, songSubName, songAuthorName, levelAuthorName, beatsPerMinute, songTimeOffset, shuffle, shufflePeriod, previewStartTime, previewDuration, songDuration) =
(prv.levelID, prv.songName, prv.songSubName, prv.songAuthorName, prv.levelAuthorName, prv.beatsPerMinute, prv.songTimeOffset, prv.shuffle, prv.shufflePeriod, prv.previewStartTime, prv.previewDuration, prv.songDuration);
previewDifficultyBeatmapSets = prv.previewDifficultyBeatmapSets;
cover.data = new byte[0];
cover.SetData(new byte[0]);
if(prv is PreviewBeatmapLevel preview) {
cover.data = preview.cover.data;
cover.SetData(preview.cover.GetData());
} else if(!mpCore) {
System.Threading.Tasks.Task<UnityEngine.Sprite?> spriteTask = prv.GetCoverImageAsync(System.Threading.CancellationToken.None);
if(spriteTask.IsCompleted) { // `Wait()`ing on an async method will deadlock
SetCover(spriteTask.Result);
Log.Debug($" Cover size: {cover.data.Length} bytes");
Log.Debug($" Cover size: {cover.length} bytes");
} else {
Log.Debug($" Cover not encoded; operation would block");
}
Expand Down
2 changes: 1 addition & 1 deletion BeatUpClient/cs/PatchAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class Patch : System.Attribute, IPatch {
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple = true)]
public class Overload : Patch {
public Overload(PatchType patchType, System.Type type, string fn, bool optional, params System.Type[] args) =>
(this.patchType, this.optional, method) = (patchType, optional, HarmonyLib.AccessTools.DeclaredMethod(type, fn, args));
(this.patchType, this.optional, method) = (patchType, optional, fn == ".ctor" ? HarmonyLib.AccessTools.DeclaredConstructor(type, args) : HarmonyLib.AccessTools.DeclaredMethod(type, fn, args));
}
[System.AttributeUsage(System.AttributeTargets.Method, AllowMultiple = true)]
public class Generic : Patch {
Expand Down
9 changes: 6 additions & 3 deletions BeatUpClient/cs/Patches/1_MainSystemInit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,20 @@ static partial class BeatUpClient {
}
}

// TODO: this should run later (i.e. @ AudioClipAsyncLoader..ctor)
[Patch(PatchType.Postfix, typeof(MainSystemInit), nameof(MainSystemInit.InstallBindings))]
static void MainSystemInit_InstallBindings_post(MainSystemInit __instance, Zenject.DiContainer container) {
customServerHostName = __instance._mainSettingsModel.customServerHostName;
NetworkConfigSetup(__instance._networkConfig);
Injected<BeatmapCharacteristicCollectionSO>.Resolve(container);
Injected<BeatmapCharacteristicCollection>.Resolve(container);
Injected<BeatmapLevelsModel>.Resolve(container);
Injected<CustomLevelLoader>.Resolve(container);
Injected<CustomNetworkConfig>.Resolve<INetworkConfig>(container);
Injected<IMultiplayerStatusModel>.Resolve(container);
Injected<IQuickPlaySetupModel>.Resolve(container);
Injected<MultiplayerSessionManager>.Resolve<IMultiplayerSessionManager>(container)?.SetLocalPlayerState("modded", true);
Net.Setup(Injected<IMenuRpcManager>.Resolve(container)!);
MultiplayerSessionManager? multiplayerSessionManager = Injected<MultiplayerSessionManager>.Resolve<IMultiplayerSessionManager>(container);
IMenuRpcManager menuRpcManager = Injected<IMenuRpcManager>.Resolve(container)!;
multiplayerSessionManager?.SetLocalPlayerState("modded", true);
Net.Setup(menuRpcManager, multiplayerSessionManager);
}
}
23 changes: 8 additions & 15 deletions BeatUpClient/cs/Patches/2_ModeSelection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ static void MultiplayerModeSelectionFlowCoordinator_PresentMasterServerUnavailab
}

static UnityEngine.GameObject[]? BeatUpServerUI = null;
static (UnityEngine.Sprite normal, UnityEngine.Sprite highlight, UnityEngine.Sprite pressed, UnityEngine.Sprite disabled) altCreateButtonSprites;
static bool createButtonSpriteState = false;
static (UnityEngine.Sprite normal, UnityEngine.Sprite highlight, UnityEngine.Sprite pressed, UnityEngine.Sprite disabled) createButtonSprites, heartButtonSprites;
static HMUI.ButtonSpriteSwap? spriteSwap = null;
[Detour(typeof(MultiplayerModeSelectionViewController), nameof(MultiplayerModeSelectionViewController.SetData))]
static void MultiplayerModeSelectionViewController_SetData(MultiplayerModeSelectionViewController self, MultiplayerStatusData? multiplayerStatusData) {
ShowLoading(null);
Expand All @@ -74,19 +74,12 @@ static void MultiplayerModeSelectionViewController_SetData(MultiplayerModeSelect
if(BeatUpServerUI != null)
foreach(UnityEngine.GameObject element in BeatUpServerUI)
element.SetActive(isBeatUp);
UnityEngine.Transform? buttons = self.transform.Find("Buttons");
if(buttons != null) {
if(createButtonSpriteState != isBeatUp) {
HMUI.ButtonSpriteSwap? sprites = buttons.Find("CreateServerButton")?.GetComponent<HMUI.ButtonSpriteSwap>();
if(sprites != null) {
(sprites._normalStateSprite, altCreateButtonSprites.normal) = (altCreateButtonSprites.normal, sprites._normalStateSprite);
(sprites._highlightStateSprite, altCreateButtonSprites.highlight) = (altCreateButtonSprites.highlight, sprites._highlightStateSprite);
(sprites._pressedStateSprite, altCreateButtonSprites.pressed) = (altCreateButtonSprites.pressed, sprites._pressedStateSprite);
(sprites._disabledStateSprite, altCreateButtonSprites.disabled) = (altCreateButtonSprites.disabled, sprites._disabledStateSprite);
createButtonSpriteState = isBeatUp;
}
}
buttons.gameObject.SetActive(true);
UnityEngine.Transform? createButton = self.transform.Find("Buttons/CreateServerButton");
if(createButton != null) {
if(spriteSwap != null)
(spriteSwap._normalStateSprite, spriteSwap._highlightStateSprite, spriteSwap._pressedStateSprite, spriteSwap._disabledStateSprite) =
isBeatUp ? heartButtonSprites : createButtonSprites;
createButton.parent.gameObject.SetActive(true);
}
Base(self, multiplayerStatusData);
}
Expand Down
27 changes: 14 additions & 13 deletions BeatUpClient/cs/Patches/4_Handshake.cs
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
static partial class BeatUpClient {
static ServerConnectInfo connectInfo = ServerConnectInfo.Default;
static void RefreshModifiersHeader() {
Polyglot.LocalizedTextMeshProUGUI? SuggestedModifiers = UnityEngine.Resources.FindObjectsOfTypeAll<GameServerPlayersTableView>()[0].transform.Find("ServerPlayersTableHeader/Labels/SuggestedModifiers")?.GetComponent<Polyglot.LocalizedTextMeshProUGUI>();
if(SuggestedModifiers != null)
SuggestedModifiers.Key = connectInfo.perPlayerModifiers ? "BEATUP_SELECTED_MODIFIERS" : "SUGGESTED_MODIFIERS";
}

[Detour(typeof(LiteNetLibConnectionManager), nameof(LiteNetLibConnectionManager.GetConnectionMessage))]
static LiteNetLib.Utils.NetDataWriter LiteNetLibConnectionManager_GetConnectionMessage(LiteNetLibConnectionManager self) {
Log.Debug("LiteNetLibConnectionManager_GetConnectionMessage()");
LiteNetLib.Utils.NetDataWriter writer = (LiteNetLib.Utils.NetDataWriter)Base(self);
[Detour(typeof(GameLiftClientConnectionRequestHandler), nameof(GameLiftClientConnectionRequestHandler.GetConnectionMessage))]
static void GameLiftClientConnectionRequestHandler_GetConnectionMessage(GameLiftClientConnectionRequestHandler self, LiteNetLib.Utils.NetDataWriter writer, string userId, string userName, bool isConnectionOwner) {
Log.Debug("GameLiftClientConnectionRequestHandler_GetConnectionMessage()");
Base(self, writer, userId, userName, isConnectionOwner);
LiteNetLib.Utils.NetDataWriter sub = new LiteNetLib.Utils.NetDataWriter(false, (int)ServerConnectInfo.Size);
new ServerConnectInfo(LocalBlockSize, BeatUpClient_Config.Instance).Serialize(sub);
writer.PutVarUInt((uint)sub.Length);
writer.Put("BeatUpClient beta1");
writer.Put(sub.CopyData());
Log.Debug("LiteNetLibConnectionManager_GetConnectionMessage() end");
return writer;
Log.Debug("GameLiftClientConnectionRequestHandler_GetConnectionMessage() end");
}

// `windowSize` MUST be set before LiteNetLib constructs any `ReliableChannel`s
[Detour(typeof(LiteNetLib.NetConnectAcceptPacket), nameof(LiteNetLib.NetConnectAcceptPacket.FromData))]
static LiteNetLib.NetConnectAcceptPacket NetConnectAcceptPacket_FromData(LiteNetLib.NetPacket packet) {
if(packet.Size == LiteNetLib.NetConnectAcceptPacket.Size + ServerConnectInfo.Size) {
packet.Size = LiteNetLib.NetConnectAcceptPacket.Size;
ServerConnectInfo info = new ServerConnectInfo(new LiteNetLib.Utils.NetDataReader(packet.RawData, packet.Size));
connectInfo = info;
connectInfo = new ServerConnectInfo(new LiteNetLib.Utils.NetDataReader(packet.RawData, packet.Size));
infoText?.SetActive(true);
if(info.windowSize != 0)
Log.Info($"Overriding window size - {info.windowSize}");
if(connectInfo.windowSize != 0)
Log.Info($"Overriding window size - {connectInfo.windowSize}");
} else if(packet.Size != LiteNetLib.NetConnectAcceptPacket.Size) {
Log.Error($"Bad NetConnectAcceptPacket length: {packet.Size} != {LiteNetLib.NetConnectAcceptPacket.Size}");
}
Polyglot.LocalizedTextMeshProUGUI? SuggestedModifiers = UnityEngine.Resources.FindObjectsOfTypeAll<GameServerPlayersTableView>()[0].transform.Find("ServerPlayersTableHeader/Labels/SuggestedModifiers")?.GetComponent<Polyglot.LocalizedTextMeshProUGUI>();
if(SuggestedModifiers != null)
SuggestedModifiers.Key = connectInfo.perPlayerModifiers ? "BEATUP_SELECTED_MODIFIERS" : "SUGGESTED_MODIFIERS";
RefreshModifiersHeader();
return (LiteNetLib.NetConnectAcceptPacket)Base(packet);
}

Expand Down
Loading

0 comments on commit ca394e5

Please sign in to comment.