Compare commits

...

21 Commits

Author SHA1 Message Date
8b9c19186b fix: Update button container paths for consistency and improve fallback handling 2025-12-15 16:49:21 +01:00
99398b5479 fix: Improve logging for menu transitions and resolve top-level canvas references in ServerBrowser 2025-12-15 10:39:38 +01:00
270a92c617 fix: Update button template resolution and improve error logging for missing components 2025-12-15 09:56:55 +01:00
4d8279719c fix: Update button container path to reflect correct hierarchy and improve logging 2025-12-15 09:51:02 +01:00
3d5a53f0e2 fix: Enhance button container pathfinding and add null checks for ServerBrowser references 2025-12-15 09:49:37 +01:00
25f5af0b4d fix: Add null checks for MainMenuUI_T and TopLevelUICanvas in ServerBrowser to prevent instantiation errors 2025-12-15 09:40:11 +01:00
2ad605138e fix: Implement lazy initialization for Constants to prevent null reference errors 2025-12-15 09:36:27 +01:00
ca517be369 refactor: Remove BuildingRemoveHook to streamline building removal process 2025-12-15 09:35:39 +01:00
df1def69e4 fix: Restore correct namespace reference for packetId in BuildingRemovePacket 2025-12-15 09:32:00 +01:00
db850885f6 fix: Correct packetId reference in BuildingRemovePacket to use the appropriate Enums 2025-12-15 09:30:25 +01:00
71e1e09c75 feat: Enhance building removal logic to ensure correct player job list modifications and add fallback for Remove method 2025-12-15 09:27:05 +01:00
46ebeb1f80 feat: Enhance BuildingRemove logic to correctly manage Player.inst during building removal 2025-12-15 09:22:50 +01:00
7d06145a34 feat: Implement BuildingRemoveHook to manage building removal and prevent infinite loops
fix: Enhance SaveTransferPacket handling for out-of-order delivery and reset transfer state
2025-12-15 09:19:46 +01:00
fcf1ffac76 feat: Add BuildingRemovePacket to handle building removal requests in-game 2025-12-15 09:19:42 +01:00
40369ffe4b fix: Improve player retrieval logic and handle non-existent clients in PlayerEntryScript 2025-12-15 09:15:31 +01:00
fc089afcc0 fix: Enhance logging for save transfer process and completion checks in SaveTransferPacket 2025-12-15 00:06:36 +01:00
cb82d3706f fix: Add missing using directive for Riptide.Demos.Steam.PlayerHosted in SaveTransferPacket 2025-12-14 23:58:51 +01:00
12a207989e fix: Reset save transfer state and streamline loading logic in SaveTransferPacket and StartGame 2025-12-14 23:56:41 +01:00
4afcaccf75 fix: Reset save transfer state and update progress bar calculations 2025-12-14 23:54:49 +01:00
8f13282e04 fix: Improve job type initialization and handle game state during loading 2025-12-14 23:45:12 +01:00
0d7d989f76 fix: Change log warning to info for invalid seed handling in world generation 2025-12-14 23:24:57 +01:00
10 changed files with 361 additions and 158 deletions

View File

@@ -15,19 +15,20 @@ namespace KCM
/// </summary>
public static class Constants
{
public static readonly MainMenuMode MainMenuMode = GameState.inst.mainMenuMode;
public static readonly PlayingMode PlayingMode = GameState.inst.playingMode;
public static readonly World World = GameState.inst.world;
// Use lazy initialization to avoid null reference when GameState isn't ready yet
public static MainMenuMode MainMenuMode => GameState.inst?.mainMenuMode;
public static PlayingMode PlayingMode => GameState.inst?.playingMode;
public static World World => GameState.inst?.world;
#region "UI"
public static readonly Transform MainMenuUI_T = MainMenuMode.mainMenuUI.transform;
public static readonly GameObject MainMenuUI_O = MainMenuMode.mainMenuUI;
public static Transform MainMenuUI_T => MainMenuMode?.mainMenuUI?.transform;
public static GameObject MainMenuUI_O => MainMenuMode?.mainMenuUI;
/* public static readonly Transform TopLevelUI_T = MainMenuUI_T.parent;
public static readonly GameObject TopLevelUI_O = MainMenuUI_T.parent.gameObject;*/
public static readonly Transform ChooseModeUI_T = MainMenuMode.chooseModeUI.transform;
public static readonly GameObject ChooseModeUI_O = MainMenuMode.chooseModeUI;
public static Transform ChooseModeUI_T => MainMenuMode?.chooseModeUI?.transform;
public static GameObject ChooseModeUI_O => MainMenuMode?.chooseModeUI;
#endregion
}

View File

@@ -18,11 +18,8 @@ namespace KCM.Enums
KingdomName = 32,
StartGame = 33,
WorldSeed = 34,
Building = 50,
BuildingOnPlacement = 51,
World = 70,
WorldPlace = 71,
FellTree = 72,
@@ -44,6 +41,7 @@ namespace KCM.Enums
AddVillager = 88,
SetupInitialWorkers = 89,
VillagerTeleportTo = 90,
PlaceKeepRandomly = 91
PlaceKeepRandomly = 91,
BuildingRemove = 92
}
}

131
Main.cs
View File

@@ -57,7 +57,21 @@ namespace KCM
public static KCPlayer GetPlayerByClientID(ushort clientId)
{
return kCPlayers[clientSteamIds[clientId]];
if (TryGetPlayerByClientID(clientId, out KCPlayer player))
{
return player;
}
return null;
}
public static bool TryGetPlayerByClientID(ushort clientId, out KCPlayer player)
{
player = null;
if (clientSteamIds.TryGetValue(clientId, out string steamId))
{
return kCPlayers.TryGetValue(steamId, out player);
}
return false;
}
public static Player GetPlayerByTeamID(int teamId) // Need to replace building / production types so that the correct player is used. IResourceStorage and IResourceProvider, and jobs
@@ -166,11 +180,6 @@ namespace KCM
lobbyManager = new GameObject("LobbyManager").AddComponent<LobbyManager>();
DontDestroyOnLoad(lobbyManager);
//SteamFriends.InviteUserToGame(new CSteamID(76561198036307537), "test");
//SteamMatchmaking.lobby
//Main.helper.Log($"Timer duration for hazardpay {Player.inst.hazardPayWarmup.Duration}");
try
{
@@ -180,24 +189,62 @@ namespace KCM
Main.helper.Log(JsonConvert.SerializeObject(World.inst.mapSizeDefs, Formatting.Indented));
KaC_Button serverBrowser = new KaC_Button(Constants.MainMenuUI_T.Find("TopLevelUICanvas/TopLevel/Body/ButtonContainer/New").parent)
// Check if MainMenuUI_T is available
if (Constants.MainMenuUI_T == null)
{
Main.helper.Log("MainMenuUI_T is null, cannot create Multiplayer button");
return;
}
// Debug: Log the UI structure to find the correct path
Main.helper.Log($"MainMenuUI_T name: {Constants.MainMenuUI_T.name}");
Main.helper.Log($"MainMenuUI_T children count: {Constants.MainMenuUI_T.childCount}");
for (int i = 0; i < Constants.MainMenuUI_T.childCount; i++)
{
var child = Constants.MainMenuUI_T.GetChild(i);
Main.helper.Log($" Child {i}: {child.name}");
for (int j = 0; j < child.childCount; j++)
{
Main.helper.Log($" SubChild {j}: {child.GetChild(j).name}");
}
}
// Correct path based on debug output: MainMenuUI -> TopLevelUICanvas -> TopLevel -> Body -> ButtonContainer -> New
var buttonContainer = Constants.MainMenuUI_T.Find("TopLevelUICanvas/TopLevel/Body/ButtonContainer/New");
if (buttonContainer == null)
{
Main.helper.Log("Button container not found at TopLevelUICanvas/TopLevel/Body/ButtonContainer/New");
return;
}
Main.helper.Log($"Found button container at: {buttonContainer.name}");
var templateButton = buttonContainer.GetComponent<Button>();
if (templateButton == null)
{
Main.helper.Log("Template button on container is missing Button component.");
return;
}
KaC_Button serverBrowser = new KaC_Button(templateButton, buttonContainer.parent)
{
Name = "Multiplayer",
Text = "Multiplayer",
FirstSibling = true,
OnClick = () =>
{
//Constants.MainMenuUI_T.Find("TopLevelUICanvas/TopLevel").gameObject.SetActive(false);
Main.helper?.Log("Multiplayer button clicked");
SfxSystem.PlayUiSelect();
//ServerBrowser.serverBrowserRef.SetActive(true);
TransitionTo(MenuState.ServerBrowser);
}
};
serverBrowser.Transform.SetSiblingIndex(2);
Destroy(Constants.MainMenuUI_T.Find("TopLevelUICanvas/TopLevel/Body/ButtonContainer/Kingdom Share").gameObject);
var kingdomShare = Constants.MainMenuUI_T.Find("TopLevelUICanvas/TopLevel/Body/ButtonContainer/Kingdom Share")
?? Constants.MainMenuUI_T.Find("MainMenu/TopLevel/Body/ButtonContainer/Kingdom Share");
if (kingdomShare != null)
{
Destroy(kingdomShare.gameObject);
}
}
catch (Exception ex)
{
@@ -264,11 +311,22 @@ namespace KCM
{
try
{
ServerBrowser.serverBrowserRef.SetActive(state == MenuState.ServerBrowser);
ServerBrowser.serverLobbyRef.SetActive(state == MenuState.ServerLobby);
// Null checks for ServerBrowser references
if (ServerBrowser.serverBrowserRef != null)
ServerBrowser.serverBrowserRef.SetActive(state == MenuState.ServerBrowser);
ServerBrowser.KCMUICanvas.gameObject.SetActive((int)state > 21);
helper.Log(((int)state > 21).ToString());
if (ServerBrowser.serverLobbyRef != null)
ServerBrowser.serverLobbyRef.SetActive(state == MenuState.ServerLobby);
if (ServerBrowser.KCMUICanvas != null)
{
ServerBrowser.KCMUICanvas.gameObject.SetActive((int)state > 21);
if (state == MenuState.ServerBrowser)
{
Main.helper?.Log($"TransitionTo ServerBrowser: browserRef={(ServerBrowser.serverBrowserRef != null ? "ready" : "null")}, canvas={(ServerBrowser.KCMUICanvas != null ? "ready" : "null")}");
}
helper.Log(((int)state > 21).ToString());
}
GameState.inst.mainMenuMode.TransitionTo((MainMenuMode.State)state);
}
@@ -298,9 +356,6 @@ namespace KCM
helper.Log("Preload start in main");
try
{
//MainMenuPatches.Patch();
Main.helper = helper;
helper.Log(helper.modPath);
@@ -1294,14 +1349,35 @@ namespace KCM
{
Main.helper.Log("Attempting to load save from server");
using (MemoryStream ms = new MemoryStream(saveBytes))
try
{
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new MultiplayerSaveDeserializationBinder();
saveContainer = (MultiplayerSaveContainer)bf.Deserialize(ms);
using (MemoryStream ms = new MemoryStream(saveBytes))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new MultiplayerSaveDeserializationBinder();
saveContainer = (MultiplayerSaveContainer)bf.Deserialize(ms);
}
Main.helper.Log("Deserialize complete, calling Unpack...");
saveContainer.Unpack(null);
Main.helper.Log("Unpack complete!");
}
catch (Exception e)
{
Main.helper.Log("Error loading save from server");
Main.helper.Log(e.Message);
Main.helper.Log(e.StackTrace);
if (e.InnerException != null)
{
Main.helper.Log("Inner exception: " + e.InnerException.Message);
Main.helper.Log(e.InnerException.StackTrace);
}
}
finally
{
memoryStreamHook = false;
}
memoryStreamHook = false;
return false;
}
@@ -1660,9 +1736,10 @@ namespace KCM
__instance.JobCustomMaxEnabledFlag = new bool[World.inst.NumLandMasses][];
for (int lm = 0; lm < World.inst.NumLandMasses; lm++)
{
__instance.JobFilledAvailable[lm] = new int[38];
__instance.JobCustomMaxEnabledFlag[lm] = new bool[38];
for (int n = 0; n < 38; n++)
int numJobTypes = p.JobFilledAvailable.data[lm].GetLength(0);
__instance.JobFilledAvailable[lm] = new int[numJobTypes];
__instance.JobCustomMaxEnabledFlag[lm] = new bool[numJobTypes];
for (int n = 0; n < numJobTypes; n++)
{
__instance.JobFilledAvailable[lm][n] = p.JobFilledAvailable.data[lm][n, 1];
}

View File

@@ -0,0 +1,91 @@
using System;
using System.Reflection;
using UnityEngine;
namespace KCM.Packets.Game.GameBuilding
{
public class BuildingRemovePacket : Packet
{
public override ushort packetId => (ushort)KCM.Enums.Packets.BuildingRemove;
// Flag to prevent infinite loop when removing buildings from packet
public static bool isProcessingPacket = false;
public Guid guid { get; set; }
public override void HandlePacketClient()
{
if (clientId == KCClient.client.Id) return;
Main.helper.Log($"Received building remove packet for guid {guid} from {player.name}");
// Try to find the building in the player who owns it
Building building = player.inst.GetBuilding(guid);
if (building == null)
{
// Try to find it in any player's buildings
foreach (var kcp in Main.kCPlayers.Values)
{
building = kcp.inst.GetBuilding(guid);
if (building != null) break;
}
}
if (building == null)
{
Main.helper.Log($"Building with guid {guid} not found on client, may already be removed.");
return;
}
try
{
Main.helper.Log($"Removing building {building.UniqueName} at {building.transform.position}");
// Set flag to prevent sending packet back
isProcessingPacket = true;
// Set Player.inst to the correct player for this building
// This ensures the removal modifies the correct player's job lists
Player originalPlayer = Player.inst;
Player correctPlayer = Main.GetPlayerByBuilding(building);
if (correctPlayer != null)
{
Player.inst = correctPlayer;
}
// Use reflection to call the Remove method from the game assembly
MethodInfo removeMethod = typeof(Building).GetMethod("Remove", BindingFlags.Public | BindingFlags.Instance);
if (removeMethod != null)
{
removeMethod.Invoke(building, null);
}
else
{
// Fallback: destroy the building GameObject directly
Main.helper.Log("Remove method not found, using Destroy fallback");
building.destroyedWhileInPlay = true;
UnityEngine.Object.Destroy(building.gameObject);
}
// Restore original Player.inst
Player.inst = originalPlayer;
isProcessingPacket = false;
}
catch (Exception e)
{
isProcessingPacket = false;
Main.helper.Log($"Error removing building: {e.Message}");
Main.helper.Log(e.StackTrace);
}
}
public override void HandlePacketServer()
{
// Forward the remove packet to all other clients
SendToAll(clientId);
}
}
}

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Riptide.Demos.Steam.PlayerHosted;
using static KCM.Main;
namespace KCM.Packets.Lobby
@@ -29,84 +30,90 @@ namespace KCM.Packets.Lobby
public override void HandlePacketClient()
{
float savePercent = (float)received / (float)saveSize;
// Initialize saveData and chunksReceived on the first packet received
if (saveData.Length == 1)
// Initialize on first chunk OR if arrays aren't properly sized yet
// This handles out-of-order packet delivery
if (!loadingSave || saveData.Length != saveSize || chunksReceived.Length != totalChunks)
{
Main.helper.Log("Save Transfer started!");
Main.helper.Log($"Save Transfer initializing. saveSize={saveSize}, totalChunks={totalChunks}");
loadingSave = true;
ServerLobbyScript.LoadingSave.SetActive(true);
// save percentage
saveData = new byte[saveSize];
chunksReceived = new bool[totalChunks];
received = 0;
ServerLobbyScript.LoadingSave.SetActive(true);
}
// Skip if we already received this chunk (duplicate packet)
if (chunksReceived[chunkId])
{
Main.helper.Log($"[SaveTransfer] Duplicate chunk {chunkId} received, skipping.");
return;
}
// Copy the chunk data into the correct position in saveData
Array.Copy(saveDataChunk, 0, saveData, saveDataIndex, saveDataChunk.Length);
// Mark this chunk as received
chunksReceived[chunkId] = true;
// Seek to the next position to write to
received += chunkSize;
Main.helper.Log($"[SaveTransfer] Processed chunk {chunkId}/{totalChunks}. Received: {received} bytes of {saveSize}.");
ServerLobbyScript.ProgressBar.fillAmount = savePercent;
ServerLobbyScript.ProgressBarText.text = (savePercent * 100).ToString("0.00") + "%";
ServerLobbyScript.ProgressText.text = $"{((float)(received / 1000)).ToString("0.00")} KB / {((float)(saveSize / 1000)).ToString("0.00")} KB";
if (chunkId + 1 == totalChunks)
// Update progress bar
if (saveSize > 0)
{
Main.helper.Log($"Received last save transfer packet.");
float savePercent = (float)received / (float)saveSize;
string receivedKB = ((float)received / 1000f).ToString("0.00");
string totalKB = ((float)saveSize / 1000f).ToString("0.00");
Main.helper.Log(WhichIsNotComplete());
ServerLobbyScript.ProgressBar.fillAmount = savePercent;
ServerLobbyScript.ProgressBarText.text = (savePercent * 100).ToString("0.00") + "%";
ServerLobbyScript.ProgressText.text = $"{receivedKB} KB / {totalKB} KB";
}
else
{
ServerLobbyScript.ProgressBar.fillAmount = 0f;
ServerLobbyScript.ProgressBarText.text = "0.00%";
ServerLobbyScript.ProgressText.text = "0.00 KB / 0.00 KB";
}
// Check if all chunks have been received
if (IsTransferComplete())
{
// Handle completed transfer here
Main.helper.Log("Save Transfer complete!");
// Reset the loading state before processing
loadingSave = false;
LoadSaveLoadHook.saveBytes = saveData;
LoadSaveLoadHook.memoryStreamHook = true;
LoadSave.Load();
GameState.inst.SetNewMode(GameState.inst.playingMode);
LobbyManager.loadingSave = false;
LoadSaveLoadHook.saveContainer.Unpack(null);
Broadcast.OnLoadedEvent.Broadcast(new OnLoadedEvent());
ServerLobbyScript.LoadingSave.SetActive(false);
// Reset static state for next transfer
ResetTransferState();
}
}
public static void ResetTransferState()
{
saveData = new byte[1];
chunksReceived = new bool[1];
loadingSave = false;
received = 0;
}
public static bool IsTransferComplete()
{
return chunksReceived.All(x => x == true);
}
public static string WhichIsNotComplete()
{
string notComplete = "";
for (int i = 0; i < chunksReceived.Length; i++)
{
if (!chunksReceived[i])
{
notComplete += i + ", ";
}
}
return notComplete;
}
public override void HandlePacketServer()
{
}

View File

@@ -18,38 +18,26 @@ namespace KCM.Packets.Lobby
{
Main.helper.Log(GameState.inst.mainMenuMode.ToString());
// Hide server lobby
Main.TransitionTo((MenuState)200);
// This is run when user clicks "accept" on choose your map screeen
try
{
if (!LobbyManager.loadingSave)
{
SpeedControlUI.inst.SetSpeed(0);
SpeedControlUI.inst.SetSpeed(0);
try
{
typeof(MainMenuMode).GetMethod("StartGame", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(GameState.inst.mainMenuMode, null);
}
catch (Exception ex)
{
Main.helper.Log(ex.Message.ToString());
Main.helper.Log(ex.ToString());
}
SpeedControlUI.inst.SetSpeed(0);
}
else
try
{
LobbyManager.loadingSave = false;
GameState.inst.SetNewMode(GameState.inst.playingMode);
typeof(MainMenuMode).GetMethod("StartGame", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(GameState.inst.mainMenuMode, null);
}
catch (Exception ex)
{
Main.helper.Log(ex.Message.ToString());
Main.helper.Log(ex.ToString());
}
SpeedControlUI.inst.SetSpeed(0);
}
catch (Exception ex)
{
// Handle exception here
Main.helper.Log(ex.Message.ToString());
Main.helper.Log(ex.ToString());
}
@@ -57,47 +45,18 @@ namespace KCM.Packets.Lobby
public override void HandlePacketClient()
{
Start();
if (!LobbyManager.loadingSave)
{
Start();
}
else
{
ServerLobbyScript.LoadingSave.SetActive(true);
}
}
public override void HandlePacketServer()
{
//Start();
/*AIBrainsContainer.PreStartAIConfig aiConfig = new AIBrainsContainer.PreStartAIConfig();
int count = 0;
for (int i = 0; i < RivalKingdomSettingsUI.inst.rivalItems.Length; i++)
{
RivalItemUI r = RivalKingdomSettingsUI.inst.rivalItems[i];
bool flag = r.Enabled && !r.Locked;
if (flag)
{
count++;
}
}
int idx = 0;
aiConfig.startData = new AIBrainsContainer.PreStartAIConfig.AIStartData[count];
for (int j = 0; j < RivalKingdomSettingsUI.inst.rivalItems.Length; j++)
{
RivalItemUI item = RivalKingdomSettingsUI.inst.rivalItems[j];
bool flag2 = item.Enabled && !item.Locked;
if (flag2)
{
aiConfig.startData[idx] = new AIBrainsContainer.PreStartAIConfig.AIStartData();
aiConfig.startData[idx].landmass = item.flag.landmass;
aiConfig.startData[idx].bioCode = item.bannerIdx;
aiConfig.startData[idx].personalityKey = PersonalityCollection.aiPersonalityKeys[0];
aiConfig.startData[idx].skillLevel = item.GetSkillLevel();
idx++;
}
}
AIBrainsContainer.inst.aiStartInfo = aiConfig;
bool isControllerActive = GamepadControl.inst.isControllerActive;
if (isControllerActive)
{
ConsoleCursorMenu.inst.PrepForGamepad();
}*/
}
}
}

View File

@@ -299,13 +299,35 @@ namespace KCM
try
{
GameObject kcmUICanvas = Instantiate(Constants.MainMenuUI_T.Find("TopLevelUICanvas").gameObject);
if (Constants.MainMenuUI_T == null)
{
Main.helper.Log("MainMenuUI_T is null in ServerBrowser");
return;
}
var topLevelCanvas = ResolveMenuCanvas();
if (topLevelCanvas == null)
{
Main.helper.Log("Failed to resolve top-level menu canvas in ServerBrowser");
return;
}
GameObject kcmUICanvas = Instantiate(topLevelCanvas.gameObject);
for (int i = 0; i < kcmUICanvas.transform.childCount; i++)
Destroy(kcmUICanvas.transform.GetChild(i).gameObject);
kcmUICanvas.name = "KCMUICanvas";
kcmUICanvas.transform.SetParent(Constants.MainMenuUI_T);
kcmUICanvas.transform.SetParent(Constants.MainMenuUI_T, false);
kcmUICanvas.transform.SetAsLastSibling();
kcmUICanvas.SetActive(false);
var canvasComponent = kcmUICanvas.GetComponent<Canvas>();
if (canvasComponent != null)
{
canvasComponent.overrideSorting = true;
canvasComponent.sortingOrder = 999;
}
KCMUICanvas = kcmUICanvas.transform;
@@ -322,6 +344,8 @@ namespace KCM
serverLobbyPlayerRef = serverLobbyRef.transform.Find("Container/PlayerList/Viewport/Content");
serverLobbyChatRef = serverLobbyRef.transform.Find("Container/PlayerChat/Viewport/Content");
serverLobbyRef.SetActive(false);
serverBrowserRef.transform.SetAsLastSibling();
serverLobbyRef.transform.SetAsLastSibling();
//browser.transform.position = new Vector3(0, 0, 0);
@@ -435,6 +459,29 @@ namespace KCM
}
}
private Transform ResolveMenuCanvas()
{
string[] candidatePaths =
{
"TopLevelUICanvas",
"TopLevel",
"MainMenu/TopLevel/TopLevelUICanvas",
"MainMenu/TopLevel"
};
foreach (var path in candidatePaths)
{
var transform = Constants.MainMenuUI_T.Find(path);
if (transform != null)
{
Main.helper.Log($"ServerBrowser: using canvas path '{path}'.");
return transform;
}
}
return null;
}
private void Preload(KCModHelper helper)
{
helper.Log("Hello?");

View File

@@ -37,13 +37,20 @@ namespace KCM.ServerLobby
{
try
{
KCPlayer player;
Main.kCPlayers.TryGetValue(Main.GetPlayerByClientID(Client).steamId, out player);
// First check if the client still exists
if (!Main.TryGetPlayerByClientID(Client, out KCPlayer player) || player == null)
{
// Client no longer exists, stop the repeating invoke and destroy this entry
CancelInvoke("SetValues");
Destroy(gameObject);
return;
}
transform.Find("PlayerName").GetComponent<TextMeshProUGUI>().text = player.name;
transform.Find("Ready").gameObject.SetActive(player.ready);
var bannerTexture = World.inst.liverySets[player.banner].banners;
banner.texture = bannerTexture;
}
catch (Exception ex)

View File

@@ -201,7 +201,7 @@ namespace KCM
}
else
{
Main.helper.LogWarning($"Invalid seed '{WorldSeed.text}' entered. Generating a random seed.");
Main.helper.Log($"Invalid seed '{WorldSeed.text}' entered. Generating a random seed.");
World.inst.Generate();
definitiveSeed = World.inst.seed;
}

View File

@@ -15,6 +15,11 @@ namespace KCM.UI
class KaC_Button
{
public Button Button = null;
private static readonly string[] ButtonPaths =
{
"TopLevelUICanvas/TopLevel/Body/ButtonContainer/New",
"MainMenu/TopLevel/Body/ButtonContainer/New" // fallback for older versions
};
public string Name
{
@@ -84,14 +89,18 @@ namespace KCM.UI
set => Transform.SetSiblingIndex(value);
}
public KaC_Button(Transform parent = null)
{
Button b = Constants.MainMenuUI_T.Find("TopLevelUICanvas/TopLevel/Body/ButtonContainer/New").GetComponent<Button>();
public KaC_Button(Transform parent = null) : this(null, parent) { }
if (parent == null)
Button = GameObject.Instantiate(b);
else
Button = GameObject.Instantiate(b, parent);
public KaC_Button(Button b, Transform parent = null)
{
var templateButton = ResolveTemplateButton(b);
if (templateButton == null)
throw new InvalidOperationException("Template button not found in main menu UI.");
Button = parent == null
? GameObject.Instantiate(templateButton)
: GameObject.Instantiate(templateButton, parent);
foreach (Localize Localize in Button.GetComponentsInChildren<Localize>())
GameObject.Destroy(Localize);
@@ -99,20 +108,27 @@ namespace KCM.UI
Button.onClick = new Button.ButtonClickedEvent();
}
public KaC_Button(Button b, Transform parent = null)
private static Button ResolveTemplateButton(Button providedButton)
{
if (b == null)
b = Constants.MainMenuUI_T.Find("TopLevelUICanvas/TopLevel/Body/ButtonContainer/New").GetComponent<Button>();
if (providedButton != null)
return providedButton;
if (parent == null)
Button = GameObject.Instantiate(b);
else
Button = GameObject.Instantiate(b, parent);
foreach (var path in ButtonPaths)
{
var transform = Constants.MainMenuUI_T?.Find(path);
if (transform == null)
continue;
foreach (Localize Localize in Button.GetComponentsInChildren<Localize>())
GameObject.Destroy(Localize);
var button = transform.GetComponent<Button>();
if (button != null)
{
Main.helper?.Log($"Using menu button template at '{path}'.");
return button;
}
}
Button.onClick = new Button.ButtonClickedEvent();
Main.helper?.Log("Failed to find menu button template for KaC_Button.");
return null;
}
public override string ToString()