private void OnModMessageReceived(object sender, ModMessageReceivedEventArgs e) { if (e.FromModID != this.ModManifest.UniqueID) { return; } ModEntry.Log($"[{(Context.IsMainPlayer ? "host" : "farmhand")}] Received {e.Type} from {e.FromPlayerID}.", LogLevel.Trace); switch (e.Type) { // farmhand requested metadata case MessageId.RequestMetadata: if (Context.IsMainPlayer) { // client requests settings and state, send it: InitResponseMessage response = new InitResponseMessage { Settings = DeepWoodsSettings.Settings, State = DeepWoodsSettings.DeepWoodsState, LevelNames = Game1.locations.OfType <DeepWoods>().Select(p => p.Name).ToArray() }; ModEntry.SendMessage(response, MessageId.Metadata, e.FromPlayerID); } break; // host sent metadata case MessageId.Metadata: if (!Context.IsMainPlayer) { InitResponseMessage response = e.ReadAs <InitResponseMessage>(); DeepWoodsSettings.Settings = response.Settings; DeepWoodsSettings.DeepWoodsState = response.State; ModEntry.DeepWoodsInitServerAnswerReceived(response.LevelNames); } break; // farmhand requested that we load and activate a DeepWoods level case MessageId.RequestWarp: if (Context.IsMainPlayer) { // load level int level = e.ReadAs <int>(); DeepWoods deepWoods = DeepWoodsManager.AddDeepWoodsFromObelisk(level); // send response WarpMessage response = new WarpMessage { Level = deepWoods.Level, Name = deepWoods.Name, EnterLocation = new Vector2(deepWoods.enterLocation.Value.X, deepWoods.enterLocation.Value.Y) }; ModEntry.SendMessage(response, MessageId.Warp, e.FromPlayerID); } break; // host loaded area for warp case MessageId.Warp: if (!Context.IsMainPlayer) { WarpMessage data = e.ReadAs <WarpMessage>(); DeepWoodsManager.AddBlankDeepWoodsToGameLocations(data.Name); DeepWoodsManager.WarpFarmerIntoDeepWoodsFromServerObelisk(data.Name, data.EnterLocation); } break; // host sent 'lowest level reached' update case MessageId.SetLowestLevelReached: if (!Context.IsMainPlayer) { DeepWoodsState.LowestLevelReached = e.ReadAs <int>(); } break; // host sent 'received stardrop from unicorn' update case MessageId.SetUnicornStardropReceived: if (Context.IsMainPlayer) { DeepWoodsState.PlayersWhoGotStardropFromUnicorn.Add(e.FromPlayerID); } break; // host added/removed location case MessageId.AddLocation: if (!Context.IsMainPlayer) { string name = e.ReadAs <string>(); DeepWoodsManager.AddBlankDeepWoodsToGameLocations(name); } break; case MessageId.RemoveLocation: if (!Context.IsMainPlayer) { string name = e.ReadAs <string>(); DeepWoodsManager.RemoveDeepWoodsFromGameLocations(name); } break; default: ModEntry.Log(" ignored unknown type.", LogLevel.Trace); break; } }
private void Warp(ExitDirection exitDir) { if (Game1.locationRequest == null) { bool warped = false; string targetDeepWoodsName = null; Location?targetLocationWrapper = null; if (level.Value == 1 && exitDir == ExitDirection.TOP) { targetDeepWoodsName = "Woods"; targetLocationWrapper = WOODS_WARP_LOCATION; } else if (GetExit(exitDir) is DeepWoodsExit exit) { targetDeepWoodsName = exit.TargetLocationName; if (exit.TargetLocation.X == 0 && exit.TargetLocation.Y == 0) { if (Game1.getLocationFromName(targetDeepWoodsName) is DeepWoods exitDeepWoods) { exit.TargetLocation = new Location(exitDeepWoods.enterLocation.X, exitDeepWoods.enterLocation.Y); } } targetLocationWrapper = exit.TargetLocation; } else if (CastEnterDirToExitDir(EnterDir) == exitDir) { targetDeepWoodsName = parentName.Value; if (ParentExitLocation.X == 0 && ParentExitLocation.Y == 0) { if (Game1.getLocationFromName(targetDeepWoodsName) is DeepWoods parentDeepWoods) { ParentExitLocation = parentDeepWoods.GetExit(EnterDirToExitDir(EnterDir)).Location; } } targetLocationWrapper = ParentExitLocation; } ModEntry.Log($"Trying to warp from {this.Name}: (ExitDir: {exitDir}, Position: {Game1.player.Position.X}, {Game1.player.Position.Y}, targetDeepWoodsName: {targetDeepWoodsName}, targetLocation: {(targetLocationWrapper?.X ?? -1)}, {(targetLocationWrapper?.Y ?? -1)})", LogLevel.Trace); if (targetLocationWrapper.HasValue && targetDeepWoodsName != null) { Location targetLocation = targetLocationWrapper.Value; if (!(targetLocation.X == 0 && targetLocation.Y == 0)) { if (exitDir == ExitDirection.LEFT) { targetLocation.X += 1; } else if (exitDir == ExitDirection.BOTTOM) { targetLocation.Y += 1; } if (targetDeepWoodsName != "Woods") { DeepWoodsManager.currentWarpRequestName = targetDeepWoodsName; DeepWoodsManager.currentWarpRequestLocation = new Vector2(targetLocation.X * 64, targetLocation.Y * 64); if (!Game1.IsMasterGame) { DeepWoodsManager.AddBlankDeepWoodsToGameLocations(targetDeepWoodsName); } } Game1.warpFarmer(targetDeepWoodsName, targetLocation.X, targetLocation.Y, false); warped = true; } } if (!warped) { ModEntry.Log("Warp from " + this.Name + " failed. (ExitDir: " + exitDir + ")", LogLevel.Warn); } } }
// This method is also called by the patch in DeepWoodsMTNCompatibilityMod. // We return false when we handled this message, so Harmony will cancel the original MTN handler. private static bool InternalProcessIncomingMessage(IncomingMessage msg) { if (msg.MessageType == Settings.Network.DeepWoodsMessageId) { int deepwoodsMessageType = msg.Reader.ReadInt32(); int randId = Game1.random.Next(); ModEntry.Log("InterceptProcessIncomingMessage[" + randId + "], master id: " + Game1.MasterPlayer.UniqueMultiplayerID + ", local id: " + Game1.player.UniqueMultiplayerID + ", msg.FarmerID: " + msg.FarmerID + ", deepwoodsMessageType: " + deepwoodsMessageType, StardewModdingAPI.LogLevel.Debug); Farmer who = Game1.getFarmer(msg.FarmerID); if (who == null || who == Game1.player) { ModEntry.Log(" who is null or local!", StardewModdingAPI.LogLevel.Warn); return(true); // execute original } if (deepwoodsMessageType == NETWORK_MESSAGE_DEEPWOODS_INIT) { ModEntry.Log(" [" + randId + "] deepwoodsMessageType == NETWORK_MESSAGE_DEEPWOODS_INIT", StardewModdingAPI.LogLevel.Debug); if (Game1.IsMasterGame) { // Client requests settings and state, send it: List <string> deepWoodsLevelNames = new List <string>(); foreach (var location in Game1.locations) { if (location is DeepWoods deepWoods) { deepWoodsLevelNames.Add(deepWoods.Name); } } object[] data = new object[deepWoodsLevelNames.Count + 4]; data[0] = NETWORK_MESSAGE_DEEPWOODS_INIT; data[1] = JsonConvert.SerializeObject(Settings); data[2] = JsonConvert.SerializeObject(DeepWoodsState); data[3] = (int)deepWoodsLevelNames.Count; for (int i = 0; i < deepWoodsLevelNames.Count; i++) { data[i + 4] = deepWoodsLevelNames[i]; } ModEntry.Log(" [" + randId + "] Client requests settings and state, deepWoodsLevelNames.Count: " + deepWoodsLevelNames.Count + ", deepWoodsLevelNames: " + String.Join(", ", deepWoodsLevelNames.ToArray()), StardewModdingAPI.LogLevel.Debug); who.queueMessage(Settings.Network.DeepWoodsMessageId, Game1.MasterPlayer, data); } else { // Server sent us settings and state! Settings = JsonConvert.DeserializeObject <DeepWoodsSettings>(msg.Reader.ReadString()); DeepWoodsState = JsonConvert.DeserializeObject <DeepWoodsStateData>(msg.Reader.ReadString()); int numDeepWoodsLevelNames = msg.Reader.ReadInt32(); List <string> deepWoodsLevelNames = new List <string>(); for (int i = 0; i < numDeepWoodsLevelNames; i++) { deepWoodsLevelNames.Add(msg.Reader.ReadString()); } ModEntry.Log(" [" + randId + "] Server sent us settings and state, deepWoodsLevelNames.Count: " + deepWoodsLevelNames.Count + ", deepWoodsLevelNames: " + String.Join(", ", deepWoodsLevelNames.ToArray()), StardewModdingAPI.LogLevel.Debug); ModEntry.DeepWoodsInitServerAnswerReceived(deepWoodsLevelNames); } } else { if (!Game1.IsMasterGame && !ModEntry.IsDeepWoodsGameRunning) { if (ModEntry.HasRequestedInitMessageFromServer) { ModEntry.Log("Got message from server before init message!", StardewModdingAPI.LogLevel.Warn); } else { ModEntry.Log("Got message from server before init message, never sent init message request!", StardewModdingAPI.LogLevel.Warn); } } if (deepwoodsMessageType == NETWORK_MESSAGE_DEEPWOODS_WARP) { ModEntry.Log(" [" + randId + "] deepwoodsMessageType == NETWORK_MESSAGE_DEEPWOODS_WARP", StardewModdingAPI.LogLevel.Debug); DeepWoodsWarpMessageData data = ReadDeepWoodsWarpMessage(msg.Reader); if (Game1.IsMasterGame) { // Client requests that we load and activate a specific DeepWoods level they want to warp into. DeepWoods deepWoods = DeepWoodsManager.AddDeepWoodsFromObelisk(data.Level); // Send message to client telling them we have the level ready. ModEntry.Log(" [" + randId + "] Client requests that we load and activate a specific DeepWoods level they want to warp into: data.Level:" + data.Level, StardewModdingAPI.LogLevel.Debug); who.queueMessage(Settings.Network.DeepWoodsMessageId, Game1.MasterPlayer, new object[] { NETWORK_MESSAGE_DEEPWOODS_WARP, deepWoods.level.Value, deepWoods.Name, new Vector2(deepWoods.enterLocation.Value.X, deepWoods.enterLocation.Value.Y) }); } else { // Server informs us that we can warp now! ModEntry.Log(" [" + randId + "] Server informs us that we can warp now: data.Level:" + data.Level + ", data.Name:" + data.Name, StardewModdingAPI.LogLevel.Debug); DeepWoodsManager.AddBlankDeepWoodsToGameLocations(data.Name); DeepWoodsManager.WarpFarmerIntoDeepWoodsFromServerObelisk(data.Name, data.EnterLocation); } } else if (deepwoodsMessageType == NETWORK_MESSAGE_DEEPWOODS_LEVEL) { ModEntry.Log(" [" + randId + "] deepwoodsMessageType == NETWORK_MESSAGE_DEEPWOODS_LEVEL", StardewModdingAPI.LogLevel.Debug); if (!Game1.IsMasterGame && who == Game1.MasterPlayer) { DeepWoodsState.LowestLevelReached = msg.Reader.ReadInt32(); ModEntry.Log(" [" + randId + "] DeepWoodsState.LowestLevelReached: " + DeepWoodsState.LowestLevelReached, StardewModdingAPI.LogLevel.Debug); } } else if (deepwoodsMessageType == NETWORK_MESSAGE_RCVD_STARDROP_FROM_UNICORN) { ModEntry.Log(" [" + randId + "] deepwoodsMessageType == NETWORK_MESSAGE_RCVD_STARDROP_FROM_UNICORN", StardewModdingAPI.LogLevel.Debug); if (Game1.IsMasterGame) { DeepWoodsState.PlayersWhoGotStardropFromUnicorn.Add(who.UniqueMultiplayerID); } } else if (deepwoodsMessageType == NETWORK_MESSAGE_DEEPWOODS_ADDREMOVE) { ModEntry.Log(" [" + randId + "] deepwoodsMessageType == NETWORK_MESSAGE_DEEPWOODS_ADDREMOVE", StardewModdingAPI.LogLevel.Debug); if (!Game1.IsMasterGame) { bool added = msg.Reader.ReadByte() != 0; string name = msg.Reader.ReadString(); ModEntry.Log(" [" + randId + "] added: " + added + ", name: " + name, StardewModdingAPI.LogLevel.Debug); if (added) { DeepWoodsManager.AddBlankDeepWoodsToGameLocations(name); } else { DeepWoodsManager.RemoveDeepWoodsFromGameLocations(name); } } } else { ModEntry.Log(" [" + randId + "] unknown deepwoodsMessageType: " + deepwoodsMessageType + "!", StardewModdingAPI.LogLevel.Warn); return(true); // execute original } } return(false); // don't execute original } return(true); // execute original }