Fixed inability to connect via port
Added Scrollbar to choose Relic with more than 4 players Added custom player name feature, Now host will synchronize client names
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.Core.Multiplayer.Game;
|
||||
using MegaCrit.Sts2.Core.Nodes.Screens.CharacterSelect;
|
||||
using MegaCrit.Sts2.Core.Platform;
|
||||
using SlayTheSpire2.LAN.Multiplayer.Helpers;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens
|
||||
{
|
||||
[HarmonyPatch]
|
||||
internal class NCharacterSelectScreenInitializeMultiplayerPatchs
|
||||
{
|
||||
private static IEnumerable<MethodInfo> TargetMethods()
|
||||
{
|
||||
yield return typeof(NCharacterSelectScreen).GetMethod("InitializeMultiplayerAsClient",
|
||||
BindingFlags.Instance | BindingFlags.Public)!;
|
||||
yield return typeof(NCharacterSelectScreen).GetMethod("InitializeMultiplayerAsHost",
|
||||
BindingFlags.Instance | BindingFlags.Public)!;
|
||||
}
|
||||
|
||||
private static void Prefix(NCharacterSelectScreen __instance, INetGameService gameService)
|
||||
{
|
||||
if (gameService.Platform == PlatformType.None)
|
||||
{
|
||||
LanPlayerNameHelper.CharacterSelectScreen = __instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using Godot;
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.addons.mega_text;
|
||||
using MegaCrit.Sts2.Core.Helpers;
|
||||
using MegaCrit.Sts2.Core.Localization;
|
||||
using MegaCrit.Sts2.Core.Multiplayer.Connection;
|
||||
using MegaCrit.Sts2.Core.Nodes.GodotExtensions;
|
||||
using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu;
|
||||
using SlayTheSpire2.LAN.Multiplayer.Components;
|
||||
using SlayTheSpire2.LAN.Multiplayer.Helpers;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens
|
||||
{
|
||||
[HarmonyPatch(typeof(NJoinFriendScreen), "_Ready")]
|
||||
internal class NJoinFriendScreenReadyPatch
|
||||
{
|
||||
private static void Prefix(NJoinFriendScreen __instance)
|
||||
{
|
||||
var lanPanel = new NinePatchRect { Name = "LANPanel" };
|
||||
|
||||
__instance.AddChild(lanPanel);
|
||||
|
||||
lanPanel.PatchMarginTop = 12;
|
||||
lanPanel.PatchMarginBottom = 12;
|
||||
lanPanel.PatchMarginLeft = 12;
|
||||
lanPanel.PatchMarginRight = 12;
|
||||
|
||||
lanPanel.SetAnchorsPreset(Control.LayoutPreset.Center);
|
||||
lanPanel.OffsetLeft = 450;
|
||||
lanPanel.OffsetTop = -338;
|
||||
lanPanel.OffsetRight = 790;
|
||||
lanPanel.OffsetBottom = 338;
|
||||
|
||||
if (__instance.GetNode("Panel") is NinePatchRect panel)
|
||||
{
|
||||
lanPanel.Texture = panel.Texture;
|
||||
lanPanel.SelfModulate = panel.SelfModulate;
|
||||
}
|
||||
|
||||
var vBoxContainer = new VBoxContainer();
|
||||
|
||||
lanPanel.AddChild(vBoxContainer);
|
||||
|
||||
vBoxContainer.Alignment = BoxContainer.AlignmentMode.Center;
|
||||
vBoxContainer.SetAnchorsAndOffsetsPreset(Control.LayoutPreset.FullRect);
|
||||
vBoxContainer.AddThemeConstantOverride("separation", 24);
|
||||
|
||||
if (__instance.GetNode("TitleLabel").Duplicate() is MegaLabel ipAddressLabel)
|
||||
{
|
||||
lanPanel.AddChild(ipAddressLabel);
|
||||
|
||||
ipAddressLabel.SetTextAutoSize("LAN IP:");
|
||||
ipAddressLabel.CustomMinimumSize = new Vector2(300, 0);
|
||||
ipAddressLabel.SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter;
|
||||
}
|
||||
|
||||
var addressLineEdit = new AddressLineEdit { Name = "AddressInput" };
|
||||
|
||||
vBoxContainer.AddChild(addressLineEdit);
|
||||
|
||||
addressLineEdit.Text = SettingsHelper.Instance.SettingsModel.IPAddress;
|
||||
addressLineEdit.Alignment = HorizontalAlignment.Center;
|
||||
addressLineEdit.CustomMinimumSize = new Vector2(300, 50);
|
||||
addressLineEdit.SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter;
|
||||
|
||||
if (__instance.GetNode<NJoinFriendRefreshButton>("RefreshButton").Duplicate() is NJoinFriendRefreshButton
|
||||
joinButton)
|
||||
{
|
||||
joinButton.Name = "JointButton";
|
||||
|
||||
vBoxContainer.AddChild(joinButton);
|
||||
|
||||
joinButton.CustomMinimumSize = new Vector2(150, 50);
|
||||
joinButton.SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter;
|
||||
|
||||
joinButton.Connect(NClickableControl.SignalName.Released, Callable.From<NClickableControl>(_ =>
|
||||
{
|
||||
var addressInfo = addressLineEdit.GetAddressInfo();
|
||||
|
||||
if (!addressInfo.IsValid)
|
||||
return;
|
||||
|
||||
SettingsHelper.Instance.SettingsModel.IPAddress = addressLineEdit.Text;
|
||||
SettingsHelper.Instance.WriteSettings();
|
||||
|
||||
ushort port = 33771;
|
||||
|
||||
if (addressInfo.Port.HasValue)
|
||||
{
|
||||
port = addressInfo.Port.Value;
|
||||
}
|
||||
|
||||
DisplayServer.WindowSetTitle("Slay The Spire 2 (Client)");
|
||||
if (addressInfo.Address != null)
|
||||
{
|
||||
TaskHelper.RunSafely(
|
||||
__instance.JoinGameAsync(new ENetClientConnectionInitializer(
|
||||
SettingsHelper.Instance.SettingsModel.NetId, addressInfo.Address, port)));
|
||||
}
|
||||
}));
|
||||
|
||||
joinButton.Material = joinButton.Material.Duplicate() as Material;
|
||||
Traverse.Create(joinButton).Field("_hsv").SetValue(joinButton.Material);
|
||||
|
||||
var joinButtonLabel = joinButton.GetNode<MegaLabel>("Label");
|
||||
|
||||
joinButtonLabel.SetTextAutoSize(new LocString("main_menu_ui", "JOIN.title").GetFormattedText());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Godot;
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.Core.Entities.Players;
|
||||
using MegaCrit.Sts2.Core.Nodes.Screens.Map;
|
||||
using SlayTheSpire2.LAN.Multiplayer.Helpers;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens
|
||||
{
|
||||
[HarmonyPatch(typeof(NMapDrawings), "CreateLineForPlayer")]
|
||||
internal class NMapDrawingsCreateLineForPlayerPatch
|
||||
{
|
||||
private static void Postfix(Player player, Line2D __result)
|
||||
{
|
||||
if (LanMapDrawingsHelper.DisableDrawingHashSet.Contains(player.NetId))
|
||||
{
|
||||
__result.Visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.Core.Multiplayer.Game;
|
||||
using MegaCrit.Sts2.Core.Nodes.Screens.CharacterSelect;
|
||||
using MegaCrit.Sts2.Core.Platform;
|
||||
using SlayTheSpire2.LAN.Multiplayer.Helpers;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens
|
||||
{
|
||||
[HarmonyPatch]
|
||||
internal class NMultiplayerLoadGameScreenInitializePatchs
|
||||
{
|
||||
private static IEnumerable<MethodInfo> TargetMethods()
|
||||
{
|
||||
yield return typeof(NMultiplayerLoadGameScreen).GetMethod("InitializeAsHost",
|
||||
BindingFlags.Instance | BindingFlags.Public)!;
|
||||
yield return typeof(NMultiplayerLoadGameScreen).GetMethod("InitializeAsClient",
|
||||
BindingFlags.Instance | BindingFlags.Public)!;
|
||||
}
|
||||
|
||||
private static void Prefix(NMultiplayerLoadGameScreen __instance, INetGameService gameService)
|
||||
{
|
||||
if (gameService.Platform == PlatformType.None)
|
||||
{
|
||||
LanPlayerNameHelper.MultiplayerLoadGameScreen = __instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using Godot;
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.Core.Assets;
|
||||
using MegaCrit.Sts2.Core.Entities.Players;
|
||||
using MegaCrit.Sts2.Core.Helpers;
|
||||
using MegaCrit.Sts2.Core.Nodes.Multiplayer;
|
||||
using MegaCrit.Sts2.Core.Nodes.Screens.CardLibrary;
|
||||
using MegaCrit.Sts2.Core.Nodes.Screens.Map;
|
||||
using MegaCrit.Sts2.Core.Runs;
|
||||
using SlayTheSpire2.LAN.Multiplayer.Helpers;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens
|
||||
{
|
||||
[HarmonyPatch(typeof(NMultiplayerPlayerExpandedState), "_Ready")]
|
||||
internal class NMultiplayerPlayerExpandedStateReadyPatch
|
||||
{
|
||||
private static void Prefix(NMultiplayerPlayerExpandedState __instance, Player ____player)
|
||||
{
|
||||
if (____player.NetId != RunManager.Instance.NetService.NetId)
|
||||
{
|
||||
var lanPanel = new HBoxContainer { Name = "LANPanel" };
|
||||
__instance.AddChild(lanPanel);
|
||||
|
||||
lanPanel.AnchorLeft = 0.5f;
|
||||
lanPanel.AnchorTop = 0;
|
||||
lanPanel.AnchorRight = 0.5f;
|
||||
lanPanel.AnchorBottom = 0;
|
||||
|
||||
lanPanel.OffsetLeft = -162;
|
||||
lanPanel.OffsetTop = 100;
|
||||
lanPanel.OffsetRight = 162;
|
||||
lanPanel.OffsetBottom = 100;
|
||||
|
||||
var disableDrawing = PreloadManager.Cache
|
||||
.GetScene(SceneHelper.GetScenePath("screens/card_library/card_library_tickbox"))
|
||||
.Instantiate<Control>();
|
||||
|
||||
if (disableDrawing is NLibraryStatTickbox cardLibraryTickBox)
|
||||
{
|
||||
disableDrawing.Name = "DisableDrawing";
|
||||
|
||||
lanPanel.AddChild(cardLibraryTickBox);
|
||||
|
||||
cardLibraryTickBox.SetLabel("Disable drawing");
|
||||
|
||||
cardLibraryTickBox.IsTicked = LanMapDrawingsHelper.DisableDrawingHashSet.Contains(____player.NetId);
|
||||
|
||||
cardLibraryTickBox.Toggled += tickBox =>
|
||||
{
|
||||
var drawingState = Traverse.Create(NMapScreen.Instance?.Drawings)
|
||||
.Method("GetDrawingStateForPlayer", ____player.NetId).GetValue();
|
||||
var drawViewport = Traverse.Create(drawingState).Field("drawViewport").GetValue<SubViewport>();
|
||||
|
||||
if (tickBox.IsTicked)
|
||||
{
|
||||
if (drawViewport != null)
|
||||
{
|
||||
foreach (var line2D in drawViewport.GetChildren().OfType<Line2D>())
|
||||
{
|
||||
line2D.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
LanMapDrawingsHelper.DisableDrawingHashSet.Add(____player.NetId);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (drawViewport != null)
|
||||
{
|
||||
foreach (var line2D in drawViewport.GetChildren().OfType<Line2D>())
|
||||
{
|
||||
line2D.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
LanMapDrawingsHelper.DisableDrawingHashSet.Remove(____player.NetId);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
using Godot;
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.addons.mega_text;
|
||||
using MegaCrit.Sts2.Core.Helpers;
|
||||
using MegaCrit.Sts2.Core.Nodes.GodotExtensions;
|
||||
using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu;
|
||||
using MegaCrit.Sts2.Core.Runs;
|
||||
using SlayTheSpire2.LAN.Multiplayer.Helpers;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens
|
||||
{
|
||||
[HarmonyPatch(typeof(NMultiplayerSubmenu), "_Ready")]
|
||||
internal class NMultiplayerSubmenuReadyPatch
|
||||
{
|
||||
private static void Prefix(NMultiplayerSubmenu __instance)
|
||||
{
|
||||
var buttonContainerNode = __instance.GetNode("ButtonContainer");
|
||||
|
||||
if (buttonContainerNode.GetNode("HostButton").Duplicate() is not NSubmenuButton lanHostButton)
|
||||
return;
|
||||
|
||||
buttonContainerNode.AddChild(lanHostButton);
|
||||
buttonContainerNode.MoveChild(lanHostButton, 1);
|
||||
|
||||
lanHostButton.Connect(NClickableControl.SignalName.Released,
|
||||
Callable.From<NButton>(_ =>
|
||||
{
|
||||
var traverse = Traverse.Create(__instance);
|
||||
|
||||
var settingsModel = SettingsHelper.Instance.SettingsModel;
|
||||
|
||||
LanHostHelper.StartHost(GameMode.Standard, traverse.Field("_loadingOverlay").GetValue<Control>(),
|
||||
traverse.Field("_stack").GetValue<NSubmenuStack>(),
|
||||
settingsModel.HostPort, settingsModel.HostMaxPlayers);
|
||||
}));
|
||||
lanHostButton.SetIconAndLocalization("HOST");
|
||||
var lanHostTitle = Traverse.Create(lanHostButton).Field("_title").GetValue<MegaLabel>();
|
||||
lanHostTitle.Text = $"LAN {lanHostTitle.Text}";
|
||||
|
||||
NSubmenuButtonDuplicateMaterial(lanHostButton);
|
||||
|
||||
NMultiplayerSubmenuButtonHelpers.LanHostButton = lanHostButton;
|
||||
|
||||
if (buttonContainerNode.GetNode("LoadButton").Duplicate() is not NSubmenuButton lanLoadButton)
|
||||
return;
|
||||
|
||||
buttonContainerNode.AddChild(lanLoadButton);
|
||||
buttonContainerNode.MoveChild(lanLoadButton, 2);
|
||||
|
||||
lanLoadButton.Connect(NClickableControl.SignalName.Released,
|
||||
Callable.From<NButton>(_ =>
|
||||
{
|
||||
var traverse = Traverse.Create(__instance);
|
||||
|
||||
var settingsModel = SettingsHelper.Instance.SettingsModel;
|
||||
|
||||
LanHostHelper.StartLoad(lanLoadButton, traverse.Field("_loadingOverlay").GetValue<Control>(),
|
||||
traverse.Field("_stack").GetValue<NSubmenuStack>(),
|
||||
settingsModel.HostPort, settingsModel.HostMaxPlayers);
|
||||
}));
|
||||
lanLoadButton.SetIconAndLocalization("MP_LOAD");
|
||||
var lanLoadButtonTitle = Traverse.Create(lanLoadButton).Field("_title").GetValue<MegaLabel>();
|
||||
lanLoadButtonTitle.Text = $"LAN {lanLoadButtonTitle.Text}";
|
||||
|
||||
NSubmenuButtonDuplicateMaterial(lanLoadButton);
|
||||
|
||||
NMultiplayerSubmenuButtonHelpers.LanLoadButton = lanLoadButton;
|
||||
|
||||
if (buttonContainerNode.GetNode("AbandonButton").Duplicate() is not NSubmenuButton lanAbandonButton)
|
||||
return;
|
||||
|
||||
buttonContainerNode.AddChild(lanAbandonButton);
|
||||
buttonContainerNode.MoveChild(lanAbandonButton, 3);
|
||||
|
||||
lanAbandonButton.Connect(NClickableControl.SignalName.Released,
|
||||
Callable.From<NButton>(_ =>
|
||||
{
|
||||
var traverse = Traverse.Create(__instance);
|
||||
|
||||
TaskHelper.RunSafely(
|
||||
LanHostHelper.TryAbandonMultiplayerRun(() => traverse.Method("UpdateButtons").GetValue()));
|
||||
}));
|
||||
lanAbandonButton.SetIconAndLocalization("MP_ABANDON");
|
||||
var lanAbandonButtonTitle = Traverse.Create(lanAbandonButton).Field("_title").GetValue<MegaLabel>();
|
||||
lanAbandonButtonTitle.Text = $"LAN {lanAbandonButtonTitle.Text}";
|
||||
|
||||
NSubmenuButtonDuplicateMaterial(lanAbandonButton);
|
||||
|
||||
NMultiplayerSubmenuButtonHelpers.LanAbandonButton = lanAbandonButton;
|
||||
}
|
||||
|
||||
private static void NSubmenuButtonDuplicateMaterial(NSubmenuButton nSubmenuButton)
|
||||
{
|
||||
var traverse = Traverse.Create(nSubmenuButton);
|
||||
|
||||
var bgPanel = traverse.Field("_bgPanel").GetValue<Control>();
|
||||
bgPanel.Material = bgPanel.Material.Duplicate() as Material;
|
||||
|
||||
traverse.Field("_hsv").SetValue(bgPanel.Material);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(NMultiplayerSubmenu), "UpdateButtons")]
|
||||
internal class NMultiplayerSubmenuUpdateButtonsPatch
|
||||
{
|
||||
private static void Postfix()
|
||||
{
|
||||
if (NMultiplayerSubmenuButtonHelpers.LanHostButton != null)
|
||||
{
|
||||
NMultiplayerSubmenuButtonHelpers.LanHostButton.Visible = !LanRunSaveManagerHelper.HasMultiplayerRunSave;
|
||||
}
|
||||
|
||||
if (NMultiplayerSubmenuButtonHelpers.LanLoadButton != null)
|
||||
{
|
||||
NMultiplayerSubmenuButtonHelpers.LanLoadButton.Visible = LanRunSaveManagerHelper.HasMultiplayerRunSave;
|
||||
}
|
||||
|
||||
if (NMultiplayerSubmenuButtonHelpers.LanAbandonButton != null)
|
||||
{
|
||||
NMultiplayerSubmenuButtonHelpers.LanAbandonButton.Visible =
|
||||
LanRunSaveManagerHelper.HasMultiplayerRunSave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using Godot;
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.Core.Nodes.Rooms;
|
||||
using MegaCrit.Sts2.Core.Runs;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens
|
||||
{
|
||||
[HarmonyPatch(typeof(NRestSiteRoom), "_Ready")]
|
||||
internal class NRestSiteRoomReadyPatch
|
||||
{
|
||||
private static void Prefix(NRestSiteRoom __instance, IRunState ____runState,
|
||||
List<Control> ____characterContainers)
|
||||
{
|
||||
if (____runState.Players.Count > 4)
|
||||
{
|
||||
var bgContainer = __instance.GetNode("BgContainer");
|
||||
|
||||
var lastLeftCharacterUp = bgContainer.GetNode("Character_3");
|
||||
var lastLeftCharacterDown = bgContainer.GetNode("Character_1");
|
||||
|
||||
var lastRightCharacterUp = bgContainer.GetNode("Character_4");
|
||||
var lastRightCharacterDown = bgContainer.GetNode("Character_2");
|
||||
|
||||
for (var i = 4; i < ____runState.Players.Count; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
if (i % 4 == 0)
|
||||
{
|
||||
AddCharacter(bgContainer, ref lastLeftCharacterUp, ____characterContainers, i, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCharacter(bgContainer, ref lastLeftCharacterDown, ____characterContainers, i, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i % 4 == 1)
|
||||
{
|
||||
AddCharacter(bgContainer, ref lastRightCharacterUp, ____characterContainers, i, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddCharacter(bgContainer, ref lastRightCharacterDown, ____characterContainers, i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Postfix(NRestSiteRoom __instance, IRunState ____runState)
|
||||
{
|
||||
if (____runState.Players.Count > 4)
|
||||
{
|
||||
var bgContainer = __instance.GetNode("BgContainer");
|
||||
var restSiteBackground = bgContainer.GetChild(0);
|
||||
|
||||
var lastLeftRestSite = restSiteBackground.GetNode("RestSiteLLog");
|
||||
var lastRightRestSite = restSiteBackground.GetNode("RestSiteRLog");
|
||||
|
||||
for (var i = 4; i < ____runState.Players.Count; i++)
|
||||
{
|
||||
if (i % 2 == 0 && i % 4 == 0)
|
||||
{
|
||||
AddRestSite(restSiteBackground, ref lastLeftRestSite, true);
|
||||
}
|
||||
else if (i % 4 == 1)
|
||||
{
|
||||
AddRestSite(restSiteBackground, ref lastRightRestSite, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddRestSite(Node restSiteBackground, ref Node restSite, bool isLeft)
|
||||
{
|
||||
var nextRestSiteIndex = restSite.GetIndex() + 1;
|
||||
restSite = restSite.Duplicate();
|
||||
restSiteBackground.AddChild(restSite);
|
||||
restSite.MoveChild(restSite, nextRestSiteIndex);
|
||||
|
||||
if (restSite is Control control)
|
||||
{
|
||||
control.Position = new Vector2(isLeft ? control.Position.X - 200 : control.Position.X + 200,
|
||||
control.Position.Y - 50);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddCharacter(Node bgContainer, ref Node character, List<Control> characterContainers,
|
||||
int index, bool isLeft)
|
||||
{
|
||||
var nextCharacterIndex = character.GetIndex() + 1;
|
||||
character = character.Duplicate();
|
||||
bgContainer.AddChild(character);
|
||||
bgContainer.MoveChild(character, nextCharacterIndex);
|
||||
|
||||
if (character is Control control)
|
||||
{
|
||||
control.Name = $"Character_{index + 1}";
|
||||
control.Position = new Vector2(isLeft ? control.Position.X - 200 : control.Position.X + 200,
|
||||
control.Position.Y - 50);
|
||||
|
||||
characterContainers.Add(control);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
using Godot;
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.Core.Nodes.Screens.Settings;
|
||||
using SlayTheSpire2.LAN.Multiplayer.Components;
|
||||
using SlayTheSpire2.LAN.Multiplayer.Helpers;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens
|
||||
{
|
||||
[HarmonyPatch(typeof(NSettingsScreen), "_Ready")]
|
||||
internal class NSettingsScreenReadyPatch
|
||||
{
|
||||
private static void Prefix(NSettingsScreen __instance)
|
||||
{
|
||||
var moddingNode = __instance.GetNode("%Modding");
|
||||
|
||||
var vBoxContainerNode = moddingNode.GetParent();
|
||||
var generalSettings = vBoxContainerNode.GetParent();
|
||||
|
||||
if (__instance.GetNode("%ModdingDivider").Duplicate() is ColorRect hostPortDivider &&
|
||||
moddingNode.Duplicate() is MarginContainer hostPort &&
|
||||
hostPort.GetNode("Label") is RichTextLabel hostPortLabel)
|
||||
{
|
||||
hostPortDivider.Name = "HostPortDivider";
|
||||
|
||||
vBoxContainerNode.AddChild(hostPortDivider);
|
||||
vBoxContainerNode.MoveChild(hostPortDivider, moddingNode.GetIndex() + 1);
|
||||
|
||||
hostPortDivider.Show();
|
||||
|
||||
hostPort.Name = "HostPort";
|
||||
|
||||
hostPort.RemoveChild(hostPort.GetNode("ModdingButton"));
|
||||
|
||||
vBoxContainerNode.AddChild(hostPort);
|
||||
vBoxContainerNode.MoveChild(hostPort, hostPortDivider.GetIndex() + 1);
|
||||
|
||||
hostPort.Show();
|
||||
|
||||
var hostPortLineEdit = new SpinBox { Name = "HostPortInput" };
|
||||
|
||||
hostPort.AddChild(hostPortLineEdit);
|
||||
|
||||
hostPortLineEdit.CustomMinimumSize = new Vector2(324, 64);
|
||||
hostPortLineEdit.SizeFlagsHorizontal = Control.SizeFlags.ShrinkEnd;
|
||||
hostPortLineEdit.GetLineEdit().Alignment = HorizontalAlignment.Center;
|
||||
|
||||
hostPortLineEdit.Step = 1;
|
||||
hostPortLineEdit.MinValue = 0;
|
||||
hostPortLineEdit.MaxValue = 65535;
|
||||
hostPortLineEdit.Value = SettingsHelper.Instance.SettingsModel.HostPort;
|
||||
hostPortLineEdit.ValueChanged += value =>
|
||||
{
|
||||
SettingsHelper.Instance.SettingsModel.HostPort = (ushort)value;
|
||||
SettingsHelper.Instance.WriteSettings();
|
||||
};
|
||||
|
||||
hostPortLabel.Text = "Host Port";
|
||||
}
|
||||
|
||||
if (__instance.GetNode("%ModdingDivider").Duplicate() is ColorRect hostMaxPlayersDivider &&
|
||||
moddingNode.Duplicate() is MarginContainer hostMaxPlayers &&
|
||||
hostMaxPlayers.GetNode("Label") is RichTextLabel hostMaxPlayersLabel)
|
||||
{
|
||||
hostMaxPlayersDivider.Name = "HostMaxPlayersDivider";
|
||||
|
||||
vBoxContainerNode.AddChild(hostMaxPlayersDivider);
|
||||
vBoxContainerNode.MoveChild(hostMaxPlayersDivider, moddingNode.GetIndex() + 1);
|
||||
|
||||
hostMaxPlayersDivider.Show();
|
||||
|
||||
hostMaxPlayers.Name = "HostMaxPlayers";
|
||||
|
||||
hostMaxPlayers.RemoveChild(hostMaxPlayers.GetNode("ModdingButton"));
|
||||
|
||||
vBoxContainerNode.AddChild(hostMaxPlayers);
|
||||
vBoxContainerNode.MoveChild(hostMaxPlayers, hostMaxPlayersDivider.GetIndex() + 1);
|
||||
|
||||
hostMaxPlayers.Show();
|
||||
|
||||
var hostMaxPlayersInput = new SpinBox { Name = "HostMaxPlayersInput" };
|
||||
|
||||
hostMaxPlayers.AddChild(hostMaxPlayersInput);
|
||||
|
||||
hostMaxPlayersInput.CustomMinimumSize = new Vector2(324, 64);
|
||||
hostMaxPlayersInput.SizeFlagsHorizontal = Control.SizeFlags.ShrinkEnd;
|
||||
hostMaxPlayersInput.GetLineEdit().Alignment = HorizontalAlignment.Center;
|
||||
|
||||
hostMaxPlayersInput.Step = 1;
|
||||
hostMaxPlayersInput.MinValue = 2;
|
||||
hostMaxPlayersInput.Value = SettingsHelper.Instance.SettingsModel.HostMaxPlayers;
|
||||
hostMaxPlayersInput.ValueChanged += value =>
|
||||
{
|
||||
SettingsHelper.Instance.SettingsModel.HostMaxPlayers = (int)value;
|
||||
SettingsHelper.Instance.WriteSettings();
|
||||
};
|
||||
|
||||
hostMaxPlayersLabel.Text = "Host Max Players";
|
||||
}
|
||||
|
||||
if (__instance.GetNode("%ModdingDivider").Duplicate() is ColorRect playerNameDivider &&
|
||||
moddingNode.Duplicate() is MarginContainer playerName &&
|
||||
playerName.GetNode("Label") is RichTextLabel playerNameLabel)
|
||||
{
|
||||
playerNameDivider.Name = "PlayerNameDivider";
|
||||
|
||||
vBoxContainerNode.AddChild(playerNameDivider);
|
||||
vBoxContainerNode.MoveChild(playerNameDivider, moddingNode.GetIndex() + 1);
|
||||
|
||||
playerNameDivider.Show();
|
||||
|
||||
playerName.Name = "PlayerName";
|
||||
|
||||
playerName.RemoveChild(playerName.GetNode("ModdingButton"));
|
||||
|
||||
vBoxContainerNode.AddChild(playerName);
|
||||
vBoxContainerNode.MoveChild(playerName, playerNameDivider.GetIndex() + 1);
|
||||
|
||||
playerName.Show();
|
||||
|
||||
var playerNameInput = new PlayerNameLineEdit { Name = "PlayerNameInput" };
|
||||
|
||||
playerName.AddChild(playerNameInput);
|
||||
|
||||
playerNameInput.CustomMinimumSize = new Vector2(324, 64);
|
||||
playerNameInput.SizeFlagsHorizontal = Control.SizeFlags.ShrinkEnd;
|
||||
playerNameInput.Alignment = HorizontalAlignment.Center;
|
||||
|
||||
playerNameInput.MaxLength = 16;
|
||||
playerNameInput.Text = SettingsHelper.Instance.SettingsModel.PlayerName;
|
||||
playerNameInput.TextChanged += value =>
|
||||
{
|
||||
if (playerNameInput.IsEmpty || !playerNameInput.IsInvalid)
|
||||
{
|
||||
SettingsHelper.Instance.SettingsModel.PlayerName = value;
|
||||
LanPlayerNameHelper.SetHostPlayerName();
|
||||
SettingsHelper.Instance.WriteSettings();
|
||||
}
|
||||
};
|
||||
|
||||
playerNameLabel.Text = "Player Name";
|
||||
}
|
||||
|
||||
if (__instance.GetNode("%ModdingDivider").Duplicate() is ColorRect netIdDivider &&
|
||||
moddingNode.Duplicate() is MarginContainer netId &&
|
||||
netId.GetNode("Label") is RichTextLabel netIdLabel)
|
||||
{
|
||||
netIdDivider.Name = "NetIDDivider";
|
||||
|
||||
vBoxContainerNode.AddChild(netIdDivider);
|
||||
vBoxContainerNode.MoveChild(netIdDivider, moddingNode.GetIndex() + 1);
|
||||
|
||||
netIdDivider.Show();
|
||||
|
||||
netId.Name = "NetID";
|
||||
|
||||
netId.RemoveChild(netId.GetNode("ModdingButton"));
|
||||
|
||||
vBoxContainerNode.AddChild(netId);
|
||||
vBoxContainerNode.MoveChild(netId, netIdDivider.GetIndex() + 1);
|
||||
|
||||
netId.Show();
|
||||
|
||||
var netIdInput = new SpinBox { Name = "NetIDInput" };
|
||||
|
||||
netId.AddChild(netIdInput);
|
||||
|
||||
netIdInput.CustomMinimumSize = new Vector2(324, 64);
|
||||
netIdInput.SizeFlagsHorizontal = Control.SizeFlags.ShrinkEnd;
|
||||
netIdInput.GetLineEdit().Alignment = HorizontalAlignment.Center;
|
||||
|
||||
netIdInput.Step = 1;
|
||||
netIdInput.MinValue = 2;
|
||||
netIdInput.MaxValue = ulong.MaxValue;
|
||||
netIdInput.Value = SettingsHelper.Instance.SettingsModel.NetId;
|
||||
netIdInput.ValueChanged += value =>
|
||||
{
|
||||
SettingsHelper.Instance.SettingsModel.NetId = (ulong)value;
|
||||
SettingsHelper.Instance.WriteSettings();
|
||||
};
|
||||
|
||||
netIdLabel.Text = "NetID";
|
||||
}
|
||||
|
||||
if (generalSettings is NSettingsPanel nSettingsPanel)
|
||||
{
|
||||
Traverse.Create(nSettingsPanel).Method("RefreshSize").GetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using Godot;
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.Core.Assets;
|
||||
using MegaCrit.Sts2.Core.Helpers;
|
||||
using MegaCrit.Sts2.Core.Nodes.GodotExtensions;
|
||||
using MegaCrit.Sts2.Core.Nodes.Screens.TreasureRoomRelic;
|
||||
using MegaCrit.Sts2.Core.Runs;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens
|
||||
{
|
||||
[HarmonyPatch(typeof(NTreasureRoomRelicCollection), "_Ready")]
|
||||
internal class NTreasureRoomRelicCollectionReadyPatch
|
||||
{
|
||||
private static void Prefix(NTreasureRoomRelicCollection __instance)
|
||||
{
|
||||
var runState = Traverse.Create(RunManager.Instance).Property("State").GetValue<RunState?>();
|
||||
|
||||
if (runState is { Players.Count: > 4 })
|
||||
{
|
||||
var container = __instance.GetNode("Container");
|
||||
var multiplayerRelicHolder = container.GetNode("MultiplayerRelicHolder4");
|
||||
|
||||
for (var i = 4; i < runState.Players.Count; i++)
|
||||
{
|
||||
var newMultiplayerRelicHolder = multiplayerRelicHolder.Duplicate();
|
||||
container.AddChild(newMultiplayerRelicHolder);
|
||||
|
||||
if (newMultiplayerRelicHolder is NTreasureRoomRelicHolder nTreasureRoomRelicHolder)
|
||||
{
|
||||
nTreasureRoomRelicHolder.Name = $"MultiplayerRelicHolder{i + 1}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Postfix(NTreasureRoomRelicCollection __instance,
|
||||
List<NTreasureRoomRelicHolder> ____multiplayerHolders)
|
||||
{
|
||||
if (____multiplayerHolders.Count > 4)
|
||||
{
|
||||
var container = __instance.GetNode("Container");
|
||||
|
||||
var scrollContainer = new NScrollableContainer { Name = "ScrollableContainer" };
|
||||
|
||||
var mask = new TextureRect { Name = "Mask" };
|
||||
scrollContainer.AddChild(mask);
|
||||
|
||||
mask.ClipContents = true;
|
||||
|
||||
var viewport = new Control { Name = "Viewport" };
|
||||
mask.AddChild(viewport);
|
||||
|
||||
var gridContainer = new GridContainer { Name = "RelicContainer" };
|
||||
viewport.AddChild(gridContainer);
|
||||
|
||||
var scrollbar = PreloadManager.Cache.GetScene(SceneHelper.GetScenePath("ui/scrollbar"))
|
||||
.Instantiate<NScrollbar>();
|
||||
scrollContainer.AddChild(scrollbar);
|
||||
|
||||
container.AddChild(scrollContainer);
|
||||
|
||||
scrollContainer.SetAnchorsPreset(Control.LayoutPreset.FullRect);
|
||||
scrollContainer.OffsetLeft = -510;
|
||||
scrollContainer.OffsetTop = -250;
|
||||
scrollContainer.OffsetRight = 510;
|
||||
scrollContainer.OffsetBottom = 250;
|
||||
|
||||
mask.SetAnchorsPreset(Control.LayoutPreset.CenterTop);
|
||||
mask.OffsetLeft = -450;
|
||||
mask.OffsetTop = 250;
|
||||
mask.OffsetRight = 450;
|
||||
mask.OffsetBottom = 830;
|
||||
|
||||
viewport.SetAnchorsPreset(Control.LayoutPreset.TopWide);
|
||||
viewport.OffsetLeft = 110;
|
||||
viewport.OffsetTop = 110;
|
||||
viewport.OffsetRight = -120;
|
||||
viewport.OffsetBottom = 580;
|
||||
|
||||
scrollbar.AnchorLeft = 0.794f;
|
||||
scrollbar.AnchorTop = 0.187f;
|
||||
scrollbar.AnchorRight = 0.818f;
|
||||
scrollbar.AnchorBottom = 0.947f;
|
||||
scrollbar.OffsetLeft = -200;
|
||||
scrollbar.OffsetTop = 158;
|
||||
scrollbar.OffsetRight = -199;
|
||||
scrollbar.OffsetBottom = -163;
|
||||
|
||||
gridContainer.SetAnchorsAndOffsetsPreset(Control.LayoutPreset.TopWide);
|
||||
|
||||
gridContainer.Columns = 4;
|
||||
gridContainer.CustomMinimumSize = new Vector2(0, 469);
|
||||
|
||||
gridContainer.AddThemeConstantOverride("h_separation", 42);
|
||||
gridContainer.AddThemeConstantOverride("v_separation", 42);
|
||||
|
||||
scrollContainer.SetContent(gridContainer, 20, 30);
|
||||
|
||||
//The animation will change MultiplayerHolder position. Manually fix the position.
|
||||
|
||||
var position = new Vector2(0, 110);
|
||||
|
||||
for (var i = 0; i < ____multiplayerHolders.Count; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
position = i % 4 == 0
|
||||
? new Vector2(0, position.Y + 178)
|
||||
: new Vector2(position.X + 178, position.Y);
|
||||
}
|
||||
|
||||
var multiplayerHolder = ____multiplayerHolders[i];
|
||||
multiplayerHolder.Position = position;
|
||||
multiplayerHolder.Reparent(gridContainer, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user