// Mini update is done even when not the active location public void miniUpdate() { NPCMonitor.check(loc); checkBuildings(); #if false // Apparently this is causing A LOT of lag. Let's skip it when we can. if (Game1.locationAfterWarp != loc || Game1.fadeToBlackAlpha <= 0.97) { return; } var layer = loc.map.GetLayer("Buildings"); NPC checkWith = Game1.getCharacterFromName("Penny"); // This bug has something to do with GameLocation.openDoor (I think). // Investigate actual cause later, instead of this messy patch /**/ Tile firstValid = null; Tile firstNonsolid = null; Vector2 nonSolidPos = new Vector2(); for (int ix = 0; ix < layer.LayerWidth; ++ix) { for (int iy = 0; iy < layer.LayerHeight; ++iy) { Tile tmp = layer.Tiles[ix, iy]; if (tmp != null) { if (firstValid != null) { firstValid = tmp; } Rectangle rect = checkWith.GetBoundingBox(); rect = new Rectangle(ix * Game1.tileSize + Game1.tileSize / 8, iy * Game1.tileSize + Game1.tileSize / 8, rect.Width, rect.Height); if (tmp.TileIndex != 0 && !loc.isCollidingPosition(rect, Game1.viewport, checkWith)) { Log.Async("Found non-solid pos: " + ix + ", " + iy); firstNonsolid = tmp; nonSolidPos = new Vector2(ix, iy); ix = layer.LayerWidth; break; } } } } Tile tileFix = firstValid; if (firstNonsolid != null) { tileFix = firstNonsolid;//*/ }
public static void update() { if (Multiplayer.mode == Mode.Singleplayer) { return; } if (MultiplayerUtility.latestID > prevLatestId) { sendFunc(new LatestIdPacket()); } prevLatestId = MultiplayerUtility.latestID; //Log.Async("pos:" + Game1.player.position.X + " " + Game1.player.position.Y); // Clients sometimes get stuck in the top-right corner and can't move on second day+ if (Game1.player.currentLocation != null && Game1.player.currentLocation.name == "FarmHouse" && Game1.player.currentLocation == Game1.currentLocation && Game1.player.currentLocation != Game1.getLocationFromName(Game1.player.currentLocation.name)) { Game1.player.currentLocation = Game1.getLocationFromName(Game1.player.currentLocation.name); Game1.currentLocation = Game1.player.currentLocation; Game1.currentLocation.resetForPlayerEntry(); } // Really don't understand why it breaks without this // But as soon as you get to the second day, it does. Ugh. Game1.player.FarmerSprite.setOwner(Game1.player); if (Game1.newDay) { didNewDay = true; Game1.freezeControls = prevFreezeControls = true; Game1.player.CanMove = false; if (!sentNextDayPacket) { ChatMenu.chat.Add(new ChatEntry(null, Game1.player.name + " is in bed.")); if (mode == Mode.Host) { server.broadcast(new ChatPacket(255, Game1.player.name + " is in bed.")); } else if (mode == Mode.Client) { client.stage = Client.NetStage.Waiting; SaveGame oldLoaded = SaveGame.loaded; var it = NewSaveGame.Save(true); while (it.Current < 100) { it.MoveNext(); Thread.Sleep(5); } MemoryStream tmp = new MemoryStream(); SaveGame.serializer.Serialize(tmp, SaveGame.loaded); sendFunc(new NextDayPacket()); sendFunc(new ClientFarmerDataPacket(Encoding.UTF8.GetString(tmp.ToArray()))); //SaveGame.loaded = oldLoaded; } sentNextDayPacket = true; } if (waitingOnOthers() && Game1.fadeToBlackAlpha > 0.625f) { Game1.fadeToBlackAlpha = 0.625f; } } else { sentNextDayPacket = false; } // We want people to wait for everyone //Log.Async("menu:"+Game1.activeClickableMenu); if (Game1.activeClickableMenu is SaveGameMenu && Game1.activeClickableMenu.GetType() != typeof(NewSaveGameMenu)) { Game1.activeClickableMenu = new NewSaveGameMenu(); } else if (Game1.activeClickableMenu is ShippingMenu) { //Log.Async("Savegame:" + Util.GetInstanceField(typeof(ShippingMenu), Game1.activeClickableMenu, "saveGameMenu")); SaveGameMenu menu = ( SaveGameMenu )Util.GetInstanceField(typeof(ShippingMenu), Game1.activeClickableMenu, "saveGameMenu"); if (menu != null && menu.GetType() != typeof(NewSaveGameMenu)) { Util.SetInstanceField(typeof(ShippingMenu), Game1.activeClickableMenu, "saveGameMenu", new NewSaveGameMenu()); } } if (Game1.currentLocation != null && Game1.currentLocation.currentEvent != null) { Events.fix(); } else { Events.reset(); } // Causing issues after going a day? Maybe? // Plus it only fixes a few of the time pauses /*Game1.player.forceTimePass = true; * Game1.paused = false; * if ( prevFreezeControls != Game1.freezeControls ) * { * sendFunc( new PauseTimePacket() ); * } * prevFreezeControls = Game1.freezeControls;*/ if (Multiplayer.mode == Mode.Host && server != null) { server.update(); if (server == null) { return; } if (server.clients == null) { return; } foreach (Server.Client client_ in server.clients) { if (client_.stage != Server.Client.NetStage.Playing) { continue; } if (client_.farmer == null) { continue; } doUpdatePlayer(client_.farmer); } } else if (Multiplayer.mode == Mode.Client && client != null) { client.update(); if (client == null) { return; } if (client.others == null) { return; } foreach (KeyValuePair <byte, Farmer> other in client.others) { if (other.Value == null) { continue; } doUpdatePlayer(other.Value); } } if (Game1.gameMode == 6) { return; // Loading? } // ^ TODO: Check if != 3 works if (Multiplayer.mode == Mode.Host && server != null && server.playing || Multiplayer.mode == Mode.Client && client != null && client.stage == Client.NetStage.Playing) { if (Game1.newDay) { return; } NPCMonitor.startChecks(); foreach (GameLocation loc in Game1.locations) { if (!locations.ContainsKey(loc.name)) { locations.Add(loc.name, new LocationCache(loc)); } locations[loc.name].miniUpdate(); if (Game1.player.currentLocation == loc) { locations[loc.name].update(); } if (loc is Farm) { BuildableGameLocation farm = loc as BuildableGameLocation; foreach (Building building in farm.buildings) { if (building.indoors == null) { continue; } if (!locations.ContainsKey(building.nameOfIndoors)) { locations.Add(building.nameOfIndoors, new LocationCache(building.indoors)); } locations[loc.name].miniUpdate(); if (Game1.currentLocation != loc) { locations[building.nameOfIndoors].update(); } NPCMonitor.check(building.indoors); } } if (loc.name == "FarmHouse") { //Log.Async("Terrain features count for " + loc.name + " " + loc + ": " + loc.terrainFeatures.Count); //Log.Async("Object count for " + loc.name + " " + loc + ": " + loc.objects.Count); } } NPCMonitor.endChecks(); } }
public LocationCache(GameLocation theLoc) { loc = theLoc; // This could be done even better with macros. // (Although it wouldn't be as bad in the first place if I could use templates.) // Sigh. Still cleaner than copying those methods for every new TerrainFeature/Object type. monitors.Add(typeof(HoeDirt), new SpecificMonitor <TerrainFeature, HoeDirt, HoeDirtState, TerrainFeatureUpdatePacket <HoeDirt> > ( this, loc.terrainFeatures, (obj) => new HoeDirtState(obj), (loc_, pos) => new TerrainFeatureUpdatePacket <HoeDirt>(loc_, pos) )); monitors.Add(typeof(Tree), new SpecificMonitor <TerrainFeature, Tree, TreeState, TerrainFeatureUpdatePacket <Tree> >( this, loc.terrainFeatures, (obj) => new TreeState(obj), (loc_, pos) => new TerrainFeatureUpdatePacket <Tree>(loc_, pos) )); monitors.Add(typeof(FruitTree), new SpecificMonitor <TerrainFeature, FruitTree, FruitTreeState, TerrainFeatureUpdatePacket <FruitTree> >( this, loc.terrainFeatures, (obj) => new FruitTreeState(obj), (loc_, pos) => new TerrainFeatureUpdatePacket <FruitTree>(loc_, pos) )); monitors.Add(typeof(Door), new SpecificMonitor <Object, Door, DoorState, ObjectUpdatePacket <Door> >( this, loc.objects, (obj) => new DoorState(obj), (loc_, pos) => new ObjectUpdatePacket <Door>(loc_, pos) )); monitors.Add(typeof(Fence), new SpecificMonitor <Object, Fence, FenceState, FenceUpdatePacket>( this, loc.objects, (obj) => new FenceState(obj), (loc_, pos) => new FenceUpdatePacket(loc_, pos) )); monitors.Add(typeof(Object), new SpecificMonitor <Object, Object, ObjectState, ObjectUpdatePacket <Object> >( this, loc.objects, (obj) => new ObjectState(obj), (loc_, pos) => new ObjectUpdatePacket <Object>(loc_, pos) )); monitors.Add(typeof(CrabPot), new SpecificMonitor <Object, CrabPot, CrabPotState, ObjectUpdatePacket <CrabPot> >( this, loc.objects, (obj) => new CrabPotState(obj), (loc_, pos) => new ObjectUpdatePacket <CrabPot>(loc_, pos) )); monitors.Add(typeof(Chest), new ChestMonitor(this)); loc.terrainFeatures.CollectionChanged += new NotifyCollectionChangedEventHandler(terrainFeaturesChanged); loc.objects.CollectionChanged += new NotifyCollectionChangedEventHandler(objectsChanged); // Pre-populate monitor caches so it knows what to watch. Otherwise it would only do new things foreach (KeyValuePair <Vector2, TerrainFeature> tf in loc.terrainFeatures) { Type type = tf.Value.GetType(); if (monitors.ContainsKey(type)) { monitors[type].addCache(tf.Key, tf.Value); } } foreach (KeyValuePair <Vector2, Object> obj in loc.objects) { Type type = obj.Value.GetType(); if (monitors.ContainsKey(type)) { monitors[type].addCache(obj.Key, obj.Value); } } ignoreUpdates = true; checkBuildings(); checkLocationSpecificStuff(); ignoreUpdates = false; NPCMonitor.ignoreUpdates = true; NPCMonitor.check(loc); NPCMonitor.ignoreUpdates = false; }