Skip to content
Merged
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
122 changes: 122 additions & 0 deletions src/RegionFileGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Nodes;
using UnityEngine;

namespace RegionInstaller
{
public static class RegionFileGenerator
{
public static void RegenerateRegionFile(string regionFilePath, ConfigData configData)
{
try
{
bool needsRewrite = true;
JsonNode? rootNode = null;

if (File.Exists(regionFilePath) && new FileInfo(regionFilePath).Length > 0)
{
string content = File.ReadAllText(regionFilePath);
rootNode = JsonNode.Parse(content);
if (rootNode?["Regions"] is JsonArray existingRegions)
{
if (AreRegionsMatching(existingRegions, configData.Regions, configData.KeepInnerslothRegions))
{
needsRewrite = false;
}
}
}

if (needsRewrite)
{
if (File.Exists(regionFilePath))
{
File.Delete(regionFilePath);
}

Debug.Log("[RegionInstaller] Rewriting regionInfo.json...");
rootNode = CreateEmptyRegionStructure();
var regionsArray = rootNode["Regions"]!.AsArray();

foreach (var reg in configData.Regions)
{
if (!reg.IsValid) continue;
regionsArray.Add(BuildRegionNode(reg.Name, reg.FullUrl, reg.SelectedPort, reg.Dtls));
}

var options = new JsonSerializerOptions { WriteIndented = true };
File.WriteAllText(regionFilePath, rootNode.ToJsonString(options));
Debug.Log("Region file reloaded!");
}
}
catch (Exception ex)
{
Debug.LogError($"[RegionInstaller] Error processing regionInfo.json: {ex.Message}");
}
}

private static bool AreRegionsMatching(JsonArray existingRegions, List<ParsedRegion> parsedRegions, bool keepInnersloth)
{
var validCfgRegions = parsedRegions.FindAll(r => r.IsValid);

int totalExpected = validCfgRegions.Count;
int totalExisting = 0;

foreach (var node in existingRegions)
{
if (node == null) continue;
bool isOfficial = InnerslothRegions.IsOfficialInnersloth(node.ToJsonString());
if (!isOfficial || keepInnersloth)
{
totalExisting++;
}
}

if (totalExisting != totalExpected) return false;

foreach (var reg in validCfgRegions)
{
bool found = false;
foreach (var node in existingRegions)
{
if (node != null && node.ToJsonString().Contains(reg.FullUrl, StringComparison.OrdinalIgnoreCase))
{
found = true;
break;
}
}
if (!found) return false;
}

return true;
}

private static JsonNode CreateEmptyRegionStructure() => new JsonObject { ["CurrentRegionIdx"] = 0, ["Regions"] = new JsonArray() };

private static JsonNode BuildRegionNode(string name, string host, ushort port, bool dtls)
{
return new JsonObject
{
["$type"] = "StaticHttpRegionInfo, Assembly-CSharp",
["Name"] = name,
["PingServer"] = host,
["Servers"] = new JsonArray
{
new JsonObject
{
["Name"] = "Http-1",
["Ip"] = host,
["Port"] = port,
["UseDtls"] = dtls,
["Players"] = 0,
["ConnectionFailures"] = 0
}
},
["TargetServer"] = null,
["TranslateName"] = 1003
};
}
}
}
109 changes: 1 addition & 108 deletions src/RegionInstaller.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Nodes;
using BepInEx;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
Expand Down Expand Up @@ -41,7 +39,7 @@ public override void Load()
}

string regionJsonPath = Path.Combine(Application.persistentDataPath, "regionInfo.json");
ProcessAndCleanRegionJson(regionJsonPath, configData);
RegionFileGenerator.RegenerateRegionFile(regionJsonPath, configData);

Harmony.PatchAll();

Expand All @@ -55,111 +53,6 @@ public override void Load()
}));
}

private void ProcessAndCleanRegionJson(string regionFilePath, ConfigData configData)
{
try
{
bool needsRewrite = true;
JsonNode? rootNode = null;

if (File.Exists(regionFilePath) && new FileInfo(regionFilePath).Length > 0)
{
string content = File.ReadAllText(regionFilePath);
rootNode = JsonNode.Parse(content);
if (rootNode?["Regions"] is JsonArray existingRegions)
{
if (AreRegionsMatching(existingRegions, configData.Regions, configData.KeepInnerslothRegions))
{
needsRewrite = false;
}
}
}

if (needsRewrite)
{
Log.LogInfo("[RegionInstaller] Rewriting regionInfo.json...");
rootNode = CreateEmptyRegionStructure();
var regionsArray = rootNode["Regions"]!.AsArray();

foreach (var reg in configData.Regions)
{
if (!reg.IsValid) continue;
regionsArray.Add(BuildRegionNode(reg.Name, reg.FullUrl, reg.SelectedPort, reg.Dtls));
}

var options = new JsonSerializerOptions { WriteIndented = true };
File.WriteAllText(regionFilePath, rootNode.ToJsonString(options));
Log.LogInfo("[RegionInstaller] regionInfo.json successfully updated!");
}
}
catch (Exception ex)
{
Log.LogError($"[RegionInstaller] Error processing regionInfo.json: {ex.Message}");
}
}

private bool AreRegionsMatching(JsonArray existingRegions, List<ParsedRegion> parsedRegions, bool keepInnersloth)
{
var validCfgRegions = parsedRegions.FindAll(r => r.IsValid);

int totalExpected = validCfgRegions.Count;
int totalExisting = 0;

foreach (var node in existingRegions)
{
if (node == null) continue;
bool isOfficial = InnerslothRegions.IsOfficialInnersloth(node.ToJsonString());
if (!isOfficial || keepInnersloth)
{
totalExisting++;
}
}

if (totalExisting != totalExpected) return false;

foreach (var reg in validCfgRegions)
{
bool found = false;
foreach (var node in existingRegions)
{
if (node != null && node.ToJsonString().Contains(reg.FullUrl, StringComparison.OrdinalIgnoreCase))
{
found = true;
break;
}
}
if (!found) return false;
}

return true;
}

private static JsonNode CreateEmptyRegionStructure() => new JsonObject { ["CurrentRegionIdx"] = 0, ["Regions"] = new JsonArray() };

private static JsonNode BuildRegionNode(string name, string host, ushort port, bool dtls)
{
return new JsonObject
{
["$type"] = "StaticHttpRegionInfo, Assembly-CSharp",
["Name"] = name,
["PingServer"] = host,
["Servers"] = new JsonArray
{
new JsonObject
{
["Name"] = "Http-1",
["Ip"] = host,
["Port"] = port,
["UseDtls"] = dtls,
["Players"] = 0,
["ConnectionFailures"] = 0
}
},
["TargetServer"] = null,
["TranslateName"] = 1003
};
}

private void InjectRegions(List<ParsedRegion> parsedRegions)
{
ServerManager serverMngr = DestroyableSingleton<ServerManager>.Instance;
Expand Down
95 changes: 95 additions & 0 deletions src/ReloadButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System;
using System.IO;
using HarmonyLib;
using TMPro;
using UnityEngine;
using Object = UnityEngine.Object;

namespace RegionInstaller
{
[HarmonyPatch(typeof(MainMenuManager), nameof(MainMenuManager.Start))]
public static class ReloadButtonPatch
{
private static PassiveButton refreshButton;

Check warning on line 13 in src/ReloadButton.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field 'refreshButton' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 13 in src/ReloadButton.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field 'refreshButton' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

public static void Postfix(MainMenuManager __instance)
{
if (__instance == null) return;

if (refreshButton == null)
{
refreshButton = CreateOrangeRefreshButton(__instance);
}
}

private static PassiveButton CreateOrangeRefreshButton(MainMenuManager menu)
{
var parent = menu.transform.Find("MainUI/AspectScaler/LeftPanel/Main Buttons");
if (parent == null) return null;

Check warning on line 28 in src/ReloadButton.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference return.

Check warning on line 28 in src/ReloadButton.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference return.

var button = Object.Instantiate(menu.quitButton, parent);
button.name = "RefreshRegionsButton";

button.transform.localPosition = new Vector3(2f, 4.05f, 1f);
button.transform.localScale = new Vector3(0.8f, 1f, 1f);

var aspect = button.GetComponent<AspectPosition>();
if (aspect != null)
{
aspect.enabled = false;
}

button.OnClick = new();
button.OnClick.AddListener((Action)(() =>
{
ConfigData configData = ConfigFile.LoadOrCreate(RegionInstallerPlugin.ConfigPath);

if (configData.GlitchedLobbiesRegion)
{
configData.KeepInnerslothRegions = true;
GlitchedLobbies.AddGlitchedLobbiesRegion(configData.Regions);
}

if (configData.KeepInnerslothRegions)
{
InnerslothRegions.AddInnerslothRegions(configData.Regions);
}

string regionJsonPath = Path.Combine(Application.persistentDataPath, "regionInfo.json");
RegionFileGenerator.RegenerateRegionFile(regionJsonPath, configData);

if (ServerManager.Instance != null)
{
ServerManager.Instance.LoadServers();
}

Object.FindObjectOfType<RegionTextMonitor>()?.Start();
if (Object.FindObjectOfType<RegionMenu>() is { } regionMenu)
{
regionMenu.OnDisable();
regionMenu.OnEnable();
}
}));

var buttonText = button.transform.Find("FontPlacer/Text_TMP").GetComponent<TMP_Text>();

if (buttonText.TryGetComponent<TextTranslatorTMP>(out var translator))
{
Object.Destroy(translator);
}

buttonText.text = "Refresh";
buttonText.fontSize = buttonText.fontSizeMax = buttonText.fontSizeMin = 3.5f;
buttonText.enableWordWrapping = false;
buttonText.horizontalAlignment = HorizontalAlignmentOptions.Center;

var normalSprite = button.inactiveSprites.GetComponent<SpriteRenderer>();
var hoverSprite = button.activeSprites.GetComponent<SpriteRenderer>();
normalSprite.color = new Color32(255, 140, 0, byte.MaxValue);
hoverSprite.color = new Color32(255, 165, 50, byte.MaxValue);

button.gameObject.SetActive(true);
return button;
}
}
}
Loading