public void HandleDeath(Farmer whoDied, long?damagerID = null) { if (!IsGameInProgress) { return; } if (damagerID.HasValue) { foreach (Farmer killer in Game1.getOnlineFarmers()) { if (damagerID.Value == killer.UniqueMultiplayerID) { Console.WriteLine($"{whoDied.Name} has been killed by {killer.Name}"); //[124] is the sword e-mote icon NetworkUtility.SendChatMessageToAllPlayers($"[peach]{killer.Name} [124] {whoDied.Name}"); break; } } } else { NetworkUtility.SendChatMessageToAllPlayers($"[peach]{whoDied.Name} died"); Console.WriteLine($"Received news that {whoDied.Name} was killed"); } alivePlayers.Remove(whoDied.UniqueMultiplayerID); foreach (Farmer player in Game1.getAllFarmers()) { if (player != Game1.player && player != null) { Game1.server?.sendMessage(player.UniqueMultiplayerID, new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player, (int)NetworkUtility.MessageTypes.BROADCAST_ALIVE_COUNT, alivePlayers.Count)); } } if (alivePlayers.Count == 1) { long winnerID = alivePlayers[0]; foreach (Farmer player in Game1.getOnlineFarmers()) { if (player != null && player.UniqueMultiplayerID == winnerID) { HandleWin(player, whoDied); return; } } HandleWin(null, whoDied); } else if (alivePlayers.Count == 0) { HandleWin(null, whoDied); } else { NetworkUtility.SendChatMessageToAllPlayers($"'{whoDied.Name}' has died! {alivePlayers.Count} players remain..."); } }
public static bool Prefix(BasicProjectile __instance, GameLocation location, Farmer player) { bool damagesMonsters = ModEntry.BRGame.ModHelper.Reflection.GetField <NetBool>(__instance, "damagesMonsters").GetValue().Value; Console.WriteLine($"damage, m = {damagesMonsters}"); if (!damagesMonsters || true && SlingshotPatch5.GetFarmerBounds(player).Intersects(__instance.getBoundingBox())) //TODO: remove? { //TODO: modify slingshot damage here? int damage = __instance.damageToFarmer.Value; damage = Math.Min(damage, 10); if (player == Game1.player) { Console.WriteLine("sending slingshot damage to self"); ModEntry.BRGame.TakeDamage(damage); } else { Console.WriteLine("sending slingshot damage to other player"); NetworkUtility.SendDamageToPlayer(damage, player, Game1.player.UniqueMultiplayerID); } try { if (!HitShaker.IsPlayerFlashing(player.UniqueMultiplayerID)) { var r = ModEntry.BRGame.ModHelper.Reflection; r.GetMethod(__instance, "explosionAnimation", false)?.Invoke(location); } } catch (Exception) { } } return(false); }
private void HandleWin(Farmer winner, Farmer whoDied) { if (whoDied == null && winner == null) { NetworkUtility.SendChatMessageToAllPlayers($"Ending game to avoid eternal wait."); } else if (winner == null) { NetworkUtility.SendChatMessageToAllPlayers($"'{whoDied.Name}' died, but no one was present to claim the victory."); } else { NetworkUtility.SendChatMessageToAllPlayers($"[orange]#1 VALLEY ROYALE '{winner.Name.ToUpper()}'"); } IsGameInProgress = false; ClientEndGame(); foreach (Farmer player in Game1.getOnlineFarmers()) { if (player != Game1.player && player != null) { NetworkUtility.BroadcastGameEndToClient(player); } } int timeBetweenRound = modConfig.TimeInSecondsBetweenRounds; if (timeBetweenRound >= 0) { NetworkUtility.SendChatMessageToAllPlayers($"Starting new game in {timeBetweenRound} seconds..."); waitingForNextRoundToStart = true; WhenToStartNextRound = DateTime.Now + new TimeSpan(hours: 0, minutes: 0, seconds: timeBetweenRound); } int hatID = 10; //Chicken hat if (winner != null && (winner.hat == null || winner.hat.Value == null || winner.hat.Value.ParentSheetIndex != hatID) && (winner.Items == null || !winner.Items.Any(x => x is StardewValley.Objects.Hat && x.ParentSheetIndex == hatID))) { if (Game1.player == winner) { winner.addItemToInventory(new StardewValley.Objects.Hat(hatID)); } else { var message = new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player, (int)NetworkUtility.MessageTypes.GIVE_HAT); Game1.server?.sendMessage(winner.UniqueMultiplayerID, message); } } }
public void ProcessPlayerJoin(NetFarmerRoot farmerRoot) { Console.WriteLine($"(Game) Player joining..."); Storm.SendPhasesData(farmerRoot.Value.UniqueMultiplayerID); //If you run immediately it does nothing Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(1000); //TODO: reduce/increase maybe? NetworkUtility.WarpFarmer(farmerRoot.Value, new TileLocation("Forest", 100, 20)); }); if (IsGameInProgress && alivePlayers.Count <= 1) { //Restart the game, or nothing will ever happen HandleWin(null, null); } }
public static void Prefix(Microsoft.Xna.Framework.Rectangle areaOfEffect, ref int minDamage, ref int maxDamage, bool isBomb, float knockBackModifier, int addedPrecision, float critChance, float critMultiplier, bool triggerMonsterInvincibleTimer, Farmer who, NetCollection <NPC> ___characters, GameLocation __instance) { //Console.WriteLine($"{who.Name} attacked with {minDamage} to {maxDamage} damage"); var players = Game1.getOnlineFarmers().Where(x => x != who && x.currentLocation == who.currentLocation); foreach (Farmer player in players) { if (player.GetBoundingBox().Intersects(areaOfEffect)) { if (maxDamage >= 0) { int damageAmount = Game1.random.Next(minDamage, maxDamage + 1); bool crit = false; if (who != null && Game1.random.NextDouble() < (double)(critChance + (float)who.LuckLevel * (critChance / 40f))) //Change? { crit = true; __instance.playSound("crit"); } damageAmount = (crit ? ((int)((float)damageAmount * critMultiplier)) : damageAmount); damageAmount = Math.Max(1, damageAmount + ((who != null) ? (who.attack * 3) : 0)); Console.WriteLine($"Calculated {damageAmount} damage to deal to {player.Name}"); NetworkUtility.SendDamageToPlayer(damageAmount, player, Game1.player.UniqueMultiplayerID); } } } }
public void ServerStartGame() { if (IsGameInProgress) { Console.WriteLine("A game is already in progress!"); return; } IsGameInProgress = true; Console.WriteLine("Server start game"); NetworkUtility.SendChatMessageToAllPlayers("Game starting!"); //Wipe objects foreach (GameLocation location in Game1.locations) { location.Objects.Clear(); location.debris.Clear(); } Game1.MasterPlayer.Money = 0; //Spawn chests new Chests().SpawnAndFillChests(); #region Store tree locations or replant Random random = new Random(); if (trees.Count == 0) //Store info { foreach (GameLocation gameLocation in Game1.locations) { foreach (var pair in gameLocation.terrainFeatures.Pairs) { TerrainFeature feature = pair.Value; if (feature is Tree tree && tree.growthStage.Value >= 5) { Vector2 vector = pair.Key; trees.Add(new TileLocation(gameLocation.Name, (int)vector.X, (int)vector.Y)); } } } } else //Replant { //Delete all trees foreach (GameLocation gameLocation in Game1.locations) { List <Vector2> toRemove = new List <Vector2>(); foreach (Vector2 vector in gameLocation.terrainFeatures.Keys) { TerrainFeature feature = gameLocation.terrainFeatures[vector]; if (feature is Tree tree && tree.growthStage.Value >= 5) { toRemove.Add(vector); } } foreach (Vector2 vector in toRemove) { gameLocation.terrainFeatures.Remove(vector); } } //Replant foreach (TileLocation treeLocation in trees) { treeLocation.GetGameLocation().terrainFeatures.Remove(treeLocation.CreateVector2()); treeLocation.GetGameLocation().terrainFeatures.Add(treeLocation.CreateVector2(), new Tree(random.Next(1, 4), 100)); } } #endregion //Remove resource clumps (e.g. boulders) other than stumps and hollow logs var rc = Game1.getFarm().resourceClumps; foreach (var a in rc.Where(a => a.parentSheetIndex.Value != 600 || a.parentSheetIndex.Value != 602).ToList()) { rc.Remove(a); } //Remove small stones and weeds var farmObjects = Game1.getFarm().objects; var keys = farmObjects.Keys.ToList(); for (int i = 0; i < keys.Count(); i++) { var key0 = keys[i]; if (farmObjects[key0].name == "Stone" || farmObjects[key0].name == "Weeds") { farmObjects.Remove(key0); } } //Setup alive players alivePlayers.Clear(); foreach (Farmer player in Game1.getOnlineFarmers()) { if (player != null && !(player == Game1.player && !modConfig.ShouldHostParticipate)) { Console.WriteLine($"Adding {player.Name} to the game"); alivePlayers.Add(player.UniqueMultiplayerID); } } //Storm index int stormIndex = Storm.GetRandomStormIndex(); //Spawn players in & Tell the clients to start game var chosenSpawns = new Spawns().ScatterPlayers(Game1.getOnlineFarmers()); foreach (Farmer player in chosenSpawns.Keys) { if (player == Game1.player) { ClientStartGame(alivePlayers.Count, modConfig.ShouldHostParticipate, stormIndex); if (modConfig.ShouldHostParticipate) { NetworkUtility.WarpFarmer(player, chosenSpawns[player]); } else { player.warpFarmer(new TileLocation("Forest", 100, 20).CreateWarp()); } } else { NetworkUtility.BroadcastGameStartToClient(player, alivePlayers.Count, modConfig.ShouldHostParticipate, stormIndex); NetworkUtility.WarpFarmer(player, chosenSpawns[player]); } } //Remove horses/NPCs foreach (GameLocation loc in Game1.locations) { foreach (NPC horse in loc.characters.Where(x => ModEntry.Config.KillAllNPCs || x is StardewValley.Characters.Horse).ToList()) { loc.characters.Remove(horse); } } //Freeze time Game1.timeOfDay = 1400; FreezeTime.TimeFrozen = true; }
public void TakeDamage(int damage, long?damagerID = null) { if (ModEntry.BRGame.IsGameInProgress) { dummyMonster = dummyMonster ?? new StardewValley.Monsters.Monster(); try { bool oldIsEating = Game1.player.isEating; Game1.player.isEating = false; //Prevent invincibility Game1.player.takeDamage(damage, false, dummyMonster); //If you pass in null as monster the player won't take damage Game1.player.isEating = oldIsEating; }catch (Exception) { Console.WriteLine("Ignoring exception in takeDamage"); } Farmer damager = null; if (Game1.currentLocation != null && Game1.currentLocation.farmers != null) { foreach (Farmer player in Game1.currentLocation?.farmers) { //Hit shake timer / Invincibility frames if (player != Game1.player && player != null) { var objects = new object[] { (int)NetworkUtility.MessageTypes.TELL_PLAYER_HIT_SHAKE_TIMER, 1200 }; //Hard coded in Farmer.MovePosition if (Game1.IsServer) { Game1.server.sendMessage(player.UniqueMultiplayerID, new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player, objects)); } else { NetworkUtility.RelayMessageFromClientToAnotherPlayer(player.UniqueMultiplayerID, objects); } if (player.UniqueMultiplayerID == damagerID) { damager = player; } } } } //Knockback (knock the player) if (damager != null && damage > 0 && (DateTime.Now - knockbackImmunityTimeActivated).TotalMilliseconds >= knockbackImmunityMilliseconds) { double amount = 10 + 8 * (-1 + 2 / (1 + Math.Pow(Math.E, -0.03 * damage))); amount = Math.Min(18, amount); //Just in case Vector2 displacement = Vector2.Subtract(Game1.player.Position, damager.Position); if (displacement.LengthSquared() != 0) { displacement.Normalize(); displacement.Y = displacement.Y * -1; displacement = Vector2.Multiply(displacement, (float)amount); Console.WriteLine($"setting trajectory to {displacement.X},{displacement.Y}"); Game1.player.setTrajectory((int)displacement.X, (int)displacement.Y); } } if (Game1.player.health <= 0) { //They are dead now Console.WriteLine($"I AM DEAD!"); Random random = new Random(); //Spawn their items onto the floor foreach (var item in Game1.player.Items) { if (item != null) { if (!(item is Tool) || item is StardewValley.Tools.MeleeWeapon || item is StardewValley.Tools.Slingshot) { Debris debris = new Debris(item, Game1.player.getStandingPosition(), Game1.player.getStandingPosition() + new Microsoft.Xna.Framework.Vector2(64 * (float)(random.NextDouble() * 2 - 1), 64 * (float)(random.NextDouble() * 2 - 1))); Game1.currentLocation.debris.Add(debris); } } } var oldLocation = Game1.player.currentLocation; var oldPosition = new xTile.Dimensions.Location( (int)Game1.player.Position.X - Game1.viewport.Width / 2, (int)Game1.player.Position.Y - Game1.viewport.Height / 2); Game1.player.clearBackpack(); Game1.player.health = maxHealth; //Otherwise they will go the the Doctor on the next update tick //Game1.player.warpFarmer(new TileLocation("Forest", 100, 20).CreateWarp());//Marnie's cow pen SpectatorMode.EnterSpectatorMode(oldLocation, oldPosition); if (Game1.IsServer) { ModEntry.BRGame.HandleDeath(Game1.player, damagerID); } else { if (damagerID.HasValue) { Game1.client.sendMessage(new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player, (int)NetworkUtility.MessageTypes.TELL_SERVER_I_DIED, Game1.player.UniqueMultiplayerID, damagerID.Value)); } else { Game1.client.sendMessage(new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player, (int)NetworkUtility.MessageTypes.TELL_SERVER_I_DIED, Game1.player.UniqueMultiplayerID)); } } } } }
public static void QuarterSecUpdate(List <long> alivePlayers) { if (!Game1.IsServer) { return; } //var (currentPhase, currentPhaseAmount) = GetCurrentPhase(); var tp = GetCurrentPhase(); var currentPhase = tp.Item1; var currentPhaseAmount = tp.Item2; //var amounts = new Dictionary<GameLocation, (double amount, Direction direction, Phase.TwoPointRectangle closeInRectangle)>(); var amounts = new Dictionary <GameLocation, Tuple <double, Direction, Phase.TwoPointRectangle> >(); foreach (Farmer player in Game1.getOnlineFarmers()) { var currentLocation = player.currentLocation; if (currentLocation != null && !amounts.ContainsKey(currentLocation)) { amounts.Add(currentLocation, GetStormAmountInLocation(currentPhase, currentPhaseAmount, currentLocation)); } } foreach (var pair in amounts) { var gameLocation = pair.Key; //var (amount, direction, closeInRectangle) = pair.Value; var t = pair.Value; var amount = t.Item1; var direction = t.Item2; var closeInRectangle = t.Item3; Rectangle bounds = GetStormBounds(direction, amount, gameLocation, closeInRectangle); foreach (Farmer farmer in gameLocation.farmers.Where(x => alivePlayers.Contains(x.UniqueMultiplayerID))) { bool contains = bounds.Contains(Utility.Vector2ToPoint(farmer.Position)); if (contains && (closeInRectangle == null) || (!contains) && (closeInRectangle != null)) { int damage = (int)(ModEntry.Config.StormDamagePerSecond * 1.2); //Effectively 20 damage per 1.2 sec because invincibility lasts 1.2 sec if (Game1.MasterPlayer == farmer) { ModEntry.BRGame.TakeDamage(damage); } else { NetworkUtility.SendDamageToPlayer(damage, farmer); } } } } //When the phase has closed in, two players could not kill eachother and the game would last indefinitely. //When time > phasetime*1.3, damage them anyway if (DateTime.Now - startTime >= TimeSpan.FromTicks((long)(totalLengthOfPhases.Ticks * 2))) { int damage = 10; foreach (long id in ModEntry.BRGame.alivePlayers.ToList()) { if (Game1.MasterPlayer.UniqueMultiplayerID == id) { ModEntry.BRGame.TakeDamage(damage); } else { NetworkUtility.SendDamageToPlayerServerOnly(damage, id); } } } }
public override void Entry(IModHelper helper) { Events = helper.Events; if (AntiCheat.HasIllegalMods()) { Game1.quit = true; Console.Clear(); Monitor.Log("You have an illegal mod installed. Please uninstall it before using this mod.", LogLevel.Warn); if (AntiCheat.IllegalMod != null) { Monitor.Log($"- '{AntiCheat.IllegalMod}'", LogLevel.Warn); } Monitor.Log("Press any key to continue...", LogLevel.Warn); Console.ReadKey(); return; } var config = helper.ReadConfig <ModConfig>(); if (config == null) { config = new ModConfig(); helper.WriteConfig(config); } Config = config; BRGame = new Game(helper, config); Patch.PatchAll("ilyaki.battleroyale"); try { //Remove player limit var multiplayer = helper.Reflection.GetField <Multiplayer>(typeof(Game1), "multiplayer").GetValue(); multiplayer.playerLimit = config.PlayerLimit;//250 is the Galaxy limit (it's multiplied by two for some reason, so set 125) }catch (Exception) { Monitor.Log("Error setting player limit. The max is 125", LogLevel.Error); } helper.ConsoleCommands.Add("br_start", "Start the game. Alternative to pressing Right control", (c, a) => { if (Game1.IsServer) { BRGame.ServerStartGame(); } }); Events.Input.ButtonPressed += (o, e) => { if (Game1.IsServer && e.Button.TryGetKeyboard(out Keys key) && key == Keys.RightControl) { BRGame.ServerStartGame(); } if (e.Button.TryGetKeyboard(out Keys key2) && key2 == Keys.RightAlt) { var loc = Game1.player.currentLocation; int x = Game1.player.getTileX(); int y = Game1.player.getTileY(); Monitor.Log($"tile location={loc.Name}, pos=({x},{y})", LogLevel.Info); Monitor.Log($"my id : {Game1.player.UniqueMultiplayerID}", LogLevel.Info); Monitor.Log($"precise position = {Game1.player.Position}", LogLevel.Info); /*Game1.player.addItemToInventory(new StardewValley.Tools.Slingshot()); * Game1.player.addItemToInventory(new StardewValley.Tools.Slingshot(33)); * * var xd = new int[] { 388, 390, 378, 380, 384, 382, 386, 441 }; * foreach(int asdf in xd) * { * Game1.player.addItemToInventory(new StardewValley.Object(asdf, 100)); * }*/ } }; Events.GameLoop.UpdateTicked += (o, e) => BRGame?.Update(Game1.currentGameTime); Events.GameLoop.UpdateTicked += (o, e) => HitShaker.Update(Game1.currentGameTime); Events.GameLoop.UpdateTicked += (o, e) => SpectatorMode.Update(); //https://github.com/funny-snek/Always-On-Server-for-Multiplayer/blob/master/Always%20On%20Server/ModEntry.cs string currentSavedInviteCode = ""; Events.GameLoop.UpdateTicked += (o, e) => { if (e.IsMultipleOf(60 * 5) && Game1.server != null && Game1.options.enableServer == true && !string.Equals(currentSavedInviteCode, Game1.server.getInviteCode())) { currentSavedInviteCode = Game1.server.getInviteCode(); try { //helper.DirectoryPath StreamWriter sw = new StreamWriter("InviteCode.txt"); //Should be in the same folder as StardewModdingAPI.exe sw.WriteLine(currentSavedInviteCode); sw.Close(); } catch (Exception b) { Console.WriteLine("Exception writing InviteCode: " + b.Message); } } }; Events.Player.Warped += (o, e) => { if (e.NewLocation != null && (e.NewLocation is StardewValley.Locations.Woods || e.NewLocation.Name == "BugLand")) { e.NewLocation.characters.Clear(); } }; Events.Display.RenderingHud += (o, e) => { if (!SpectatorMode.InSpectatorMode) { Storm.Draw(Game1.spriteBatch); } }; Events.Display.Rendered += (o, e) => { if (SpectatorMode.InSpectatorMode) //Spectator mode can only see the storm when it is drawn above everything { Storm.Draw(Game1.spriteBatch); if (Game1.activeClickableMenu == null) { string message = "Spectating"; SpriteText.drawStringWithScrollBackground(Game1.spriteBatch, message, Game1.viewport.Width / 2 - SpriteText.getWidthOfString(message) / 2, 16, "", 1f, -1); } } }; helper.ConsoleCommands.Add("br_kick", "Kick a player. Usage: br_kick <player ID>", (a, b) => { if (!Game1.IsServer) { Monitor.Log("Need to be the server host", LogLevel.Info); } else if (b.Length != 1) { Monitor.Log("Need 1 argument", LogLevel.Info); } else if (!long.TryParse(b[0], out long x)) { Monitor.Log("Not a valid number", LogLevel.Info); } else { try { var f = Game1.getOnlineFarmers().First(p => p != Game1.player && p.UniqueMultiplayerID == x); NetworkUtility.KickPlayer(f, "You have been kicked by the host."); } catch (Exception) { Monitor.Log($"Could not find player with id {x}", LogLevel.Info); } } }); helper.ConsoleCommands.Add("br_setNumberOfPlayerSlots", "Sets the number of player slots. Usage: br_setNumberOfPlayerSlots <number of slots>", (a, b) => { if (!Game1.IsServer) { Monitor.Log("Need to be the server host", LogLevel.Info); } else if (b.Length != 1) { Monitor.Log("Need 1 argument", LogLevel.Info); } else if (!int.TryParse(b[0], out int n)) { Monitor.Log("Not a valid number", LogLevel.Info); } else { n = Math.Abs(n); var emptyCabins = Game1.getFarm().buildings.Where(z => z.daysOfConstructionLeft.Value <= 0 && z.indoors.Value is Cabin).ToArray(); if (n > emptyCabins.Length) { for (int i = 0; i < n - emptyCabins.Length; i++) { var blueprint = new BluePrint("Log Cabin"); var building = new Building(blueprint, new Vector2(-10000, 0)); Game1.getFarm().buildings.Add(building); try { foreach (var warp in building.indoors.Value.warps) { //warp.TargetName = "Forest"; Helper.Reflection.GetField <NetString>(warp, "targetName", true).SetValue(new NetString("Forest")); warp.TargetX = 100; warp.TargetY = 20; } } catch (Exception) { } } Monitor.Log($"Added {n - emptyCabins.Length} player slots", LogLevel.Info); } else if (n < emptyCabins.Length) { for (int i = 0; i < emptyCabins.Length - n; i++) { Game1.getFarm().buildings.Remove(emptyCabins[i]); } Monitor.Log($"Removed {emptyCabins.Length - n} player slots", LogLevel.Info); } else { Monitor.Log($"There are already {n} player slots", LogLevel.Info); } } }); }
private static bool ProcessMessage(byte[] msgData, Farmer sourceFarmer) { var subMessageType = (NetworkUtility.MessageTypes)BitConverter.ToInt32(msgData, 0); Console.WriteLine($"Receiving special message, type = {subMessageType}. Message length = {msgData.Length}"); switch (subMessageType) { case (NetworkUtility.MessageTypes.TAKE_DAMAGE): int damage = BitConverter.ToInt32(msgData, 4); long?damagerID = null; if (msgData.Length > 8) { damagerID = BitConverter.ToInt64(msgData, 8); } Console.WriteLine($"Taking {damage} damage from another player"); ModEntry.BRGame.TakeDamage(damage, damagerID); return(false); case (NetworkUtility.MessageTypes.SERVER_BROADCAST_GAME_START): if (!Game1.IsServer) { int numberOfPlayers = BitConverter.ToInt32(msgData, 4); int stormIndex = BitConverter.ToInt32(msgData, 8); bool isHostParticipating = BitConverter.ToBoolean(msgData, 12); ModEntry.BRGame.ClientStartGame(numberOfPlayers, isHostParticipating, stormIndex); } return(false); case NetworkUtility.MessageTypes.WARP: int tileX = BitConverter.ToInt32(msgData, 4); int tileY = BitConverter.ToInt32(msgData, 8); StringBuilder sb = new StringBuilder(); for (int i = 12; i < msgData.Length; i++) { sb.Append((char)msgData[i]); } string locationName = sb.ToString().Substring(1); Console.WriteLine($"I was told by the server to move to {locationName} @ ({tileX},{tileY})"); //Face downwards & Warp Game1.player.FacingDirection = 2; Game1.player.warpFarmer(new TileLocation(locationName, tileX, tileY).CreateWarp()); return(false); case (NetworkUtility.MessageTypes.SERVER_BROADCAST_GAME_END): if (!Game1.IsServer) { ModEntry.BRGame.ClientEndGame(); } return(false); case (NetworkUtility.MessageTypes.RELAY_MESSAGE_TO_ANOTHER_PLAYER): if (Game1.IsServer) { long targetUniqueID = BitConverter.ToInt64(msgData, 4); byte[] messageData = new byte[msgData.Length - 12]; Array.Copy(msgData, 12, messageData, 0, msgData.Length - 12); if (targetUniqueID == Game1.player.UniqueMultiplayerID) { Console.WriteLine("Received relay instruction addressed to myself"); ProcessMessage(messageData, sourceFarmer); return(false); } else { Console.WriteLine($"Relaying a message to {targetUniqueID}..."); Game1.server.sendMessage(targetUniqueID, new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player, (object)messageData)); return(false); } } else { Console.WriteLine("Accidentally received relay instruction as a client"); return(false); } case (NetworkUtility.MessageTypes.TELL_SERVER_I_DIED): if (msgData.Length > 12) { ModEntry.BRGame.HandleDeath(sourceFarmer, BitConverter.ToInt64(msgData, 12)); } else { ModEntry.BRGame.HandleDeath(sourceFarmer); } return(false); case NetworkUtility.MessageTypes.SERVER_BROADCAST_CHAT_MESSAGE: string message = Encoding.UTF8.GetString(msgData.Skip(4).ToArray()).Substring(1); string colorName = "white"; try { colorName = message.Substring(1, message.Substring(1).IndexOf(']')); Console.WriteLine($"color = {colorName}"); } catch (Exception) { } var color = StardewValley.Menus.ChatMessage.getColorFromName(colorName); if (color == Microsoft.Xna.Framework.Color.White) { color = Microsoft.Xna.Framework.Color.Gold; } Game1.chatBox.addMessage(message, color); return(false); case (NetworkUtility.MessageTypes.TELL_PLAYER_HIT_SHAKE_TIMER): int howLongMilliseconds = BitConverter.ToInt32(msgData, 4); HitShaker.SetHitShakeTimer(sourceFarmer.UniqueMultiplayerID, howLongMilliseconds); return(false); case NetworkUtility.MessageTypes.BROADCAST_ALIVE_COUNT: int howManyPlayersAlive = BitConverter.ToInt32(msgData, 4); if (ModEntry.BRGame.OverlayUI != null) { ModEntry.BRGame.OverlayUI.AlivePlayers = howManyPlayersAlive; } return(false); case NetworkUtility.MessageTypes.SEND_PHASE_DATA: try { var b = new BinaryFormatter(); var phases = (List <Phase>[])b.Deserialize(new MemoryStream(msgData.Skip(4).ToArray())); Console.WriteLine($"Received phases data from server, info: Length={phases.Length}"); Storm.Phases = phases; }catch (Exception) { Console.WriteLine("Unable to process phases data. Kicking to prevent glitches..."); long id = sourceFarmer.UniqueMultiplayerID; NetworkUtility.SendChatMessageToPlayerWithoutMod(id, "Unable to process phases data. Kicking to prevent glitches..."); Game1.server.sendMessage(id, new OutgoingMessage((byte)19, id, new object[0])); Game1.server.playerDisconnected(id); Game1.otherFarmers.Remove(id); } return(false); case NetworkUtility.MessageTypes.KICK_PLAYER: StringBuilder sb2 = new StringBuilder(); for (int i = 4; i < msgData.Length; i++) { sb2.Append((char)msgData[i]); } string kickMsg = sb2.ToString().Substring(1); Console.WriteLine($"Kicked. Reason: \"{kickMsg}\""); Game1.client.disconnect(); System.Threading.Tasks.Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(300); Game1.activeClickableMenu = new StardewValley.Menus.DialogueBox($"Kicked. Reason: \"{kickMsg}\""); }); return(false); case NetworkUtility.MessageTypes.SEND_MY_VERSION_TO_SERVER: if (Game1.IsServer) { int major = BitConverter.ToInt32(msgData, 4); int minor = BitConverter.ToInt32(msgData, 8); byte[] sha = msgData.Skip(12).ToArray(); Console.WriteLine($"Received version from client {sourceFarmer.Name}/{sourceFarmer.UniqueMultiplayerID}: {major}.{minor}"); new AutoKicker().AcknowledgeClientVersion(sourceFarmer.UniqueMultiplayerID, major, minor, sha); if (ModEntry.BRGame.IsGameInProgress) { System.Threading.Tasks.Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(1000); Game1.server.sendMessage(sourceFarmer.UniqueMultiplayerID, new OutgoingMessage(NetworkUtility.uniqueMessageType, Game1.player, (int)NetworkUtility.MessageTypes.TELL_NEW_PLAYER_TO_SPECTATE)); }); } } return(false); case NetworkUtility.MessageTypes.TELL_NEW_PLAYER_TO_SPECTATE: if (!Game1.IsServer) { System.Threading.Tasks.Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(1000); if (!ModEntry.BRGame.alivePlayers.Contains(Game1.player.UniqueMultiplayerID)) { var oldLocation = Game1.player.currentLocation; var oldPosition = new xTile.Dimensions.Location( (int)Game1.player.Position.X - Game1.viewport.Width / 2, (int)Game1.player.Position.Y - Game1.viewport.Height / 2); SpectatorMode.EnterSpectatorMode(oldLocation, oldPosition); } }); } return(false); case NetworkUtility.MessageTypes.GIVE_HAT: int hatID = 10; //Chicken hat Game1.player?.addItemToInventory(new StardewValley.Objects.Hat(hatID)); return(false); default: return(true); } }