public static void onUpdate(object sender, EventArgs args) { try { Multiplayer.update(); // We need our load menu to be able to do things if (Game1.activeClickableMenu is TitleMenu) { if (TitleMenu.subMenu != null && (TitleMenu.subMenu.GetType() == typeof(LoadGameMenu))) { LoadGameMenu oldLoadMenu = ( LoadGameMenu )TitleMenu.subMenu; NewLoadMenu newLoadMenu = new NewLoadMenu(); IPrivateField <object> task = instance.Helper.Reflection.GetPrivateField <object>(oldLoadMenu, "_initTask"); newLoadMenu._initTask = (Task <List <SFarmer> >)task.GetValue(); TitleMenu.subMenu = newLoadMenu; } } prevMenu = Game1.activeClickableMenu; } catch (Exception e) { Log.error("Exception during update: " + e); } }
/// <summary>Get the locale codes (like <c>ja-JP</c>) used in asset keys.</summary> /// <param name="reflection">Simplifies access to private game code.</param> private IDictionary <string, LanguageCode> GetKeyLocales(Reflector reflection) { // get the private code field directly to avoid changed-code logic IPrivateField <LanguageCode> codeField = reflection.GetPrivateField <LanguageCode>(typeof(LocalizedContentManager), "_currentLangCode"); // remember previous settings LanguageCode previousCode = codeField.GetValue(); string previousOverride = this.LanguageCodeOverride; // create locale => code map IDictionary <string, LanguageCode> map = new Dictionary <string, LanguageCode>(StringComparer.InvariantCultureIgnoreCase); this.LanguageCodeOverride = null; foreach (LanguageCode code in Enum.GetValues(typeof(LanguageCode))) { codeField.SetValue(code); map[this.GetKeyLocale.Invoke <string>()] = code; } // restore previous settings codeField.SetValue(previousCode); this.LanguageCodeOverride = previousOverride; return(map); }
/**** ** Field values ** (shorthand since this is the most common case) ****/ /// <summary>Get the value of a private instance field.</summary> /// <typeparam name="TValue">The field type.</typeparam> /// <param name="obj">The object which has the field.</param> /// <param name="name">The field name.</param> /// <param name="required">Whether to throw an exception if the private field is not found.</param> /// <returns>Returns the field value, or the default value for <typeparamref name="TValue"/> if the field wasn't found and <paramref name="required"/> is false.</returns> /// <remarks> /// This is a shortcut for <see cref="GetPrivateField{TValue}(object,string,bool)"/> followed by <see cref="IPrivateField{TValue}.GetValue"/>. /// When <paramref name="required" /> is false, this will return the default value if reflection fails. If you need to check whether the field exists, use <see cref="GetPrivateField{TValue}(object,string,bool)" /> instead. /// </remarks> public TValue GetPrivateValue <TValue>(object obj, string name, bool required = true) { IPrivateField <TValue> field = this.GetPrivateField <TValue>(obj, name, required); return(field != null ? field.GetValue() : default(TValue)); }
/// <summary>Get the value of a private static field.</summary> /// <typeparam name="TValue">The field type.</typeparam> /// <param name="type">The type which has the field.</param> /// <param name="name">The field name.</param> /// <param name="required">Whether to throw an exception if the private field is not found.</param> /// <returns>Returns the field value, or the default value for <typeparamref name="TValue"/> if the field wasn't found and <paramref name="required"/> is false.</returns> /// <remarks> /// This is a shortcut for <see cref="GetPrivateField{TValue}(Type,string,bool)"/> followed by <see cref="IPrivateField{TValue}.GetValue"/>. /// When <paramref name="required" /> is false, this will return the default value if reflection fails. If you need to check whether the field exists, use <see cref="GetPrivateField{TValue}(Type,string,bool)" /> instead. /// </remarks> public TValue GetPrivateValue <TValue>(Type type, string name, bool required = true) { this.AssertAccessAllowed(type); IPrivateField <TValue> field = this.GetPrivateField <TValue>(type, name, required); return(field != null ? field.GetValue() : default(TValue)); }
public TValue GetPrivateValue <TValue>(Type type, string name, bool required = true) { this.DeprecationManager.Warn($"{nameof(IReflectionHelper)}.GetPrivate*", "2.3", DeprecationLevel.Notice); IPrivateField <TValue> field = (IPrivateField <TValue>) this.GetField <TValue>(type, name, required); return(field != null ? field.GetValue() : default(TValue)); }
private void GameEvents_UpdateTick(object sender, EventArgs e) { if (Game1.activeClickableMenu is CarpenterMenu carpenter) { if (carpenter.CurrentBlueprint.name == "Aquaponics") { IPrivateField <Building> cBuilding = Helper.Reflection.GetPrivateField <Building>(carpenter, "currentBuilding"); if (!(cBuilding.GetValue() is Aquaponics)) { cBuilding.SetValue(new Aquaponics(Vector2.Zero, Game1.getFarm())); } } } }
private void OnPreRenderGuiEvent(object sender, EventArgs e) { if (Game1.activeClickableMenu is Billboard) { Billboard menu = (Billboard)Game1.activeClickableMenu; FieldInfo calendarField = menu.GetType().GetField("calendarDays", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (calendarField == null) { this.Monitor.Log("Could not find field 'calendarDays' in Billboard!", LogLevel.Error); return; } List <ClickableTextureComponent> calendarDays = (List <ClickableTextureComponent>)calendarField.GetValue(menu); IPrivateField <string> hoverField = this.Helper.Reflection.GetPrivateField <string>(menu, "hoverText"); string hoverText = hoverField.GetValue(); if (calendarDays != null && !(hoverText.Contains("Shrooms") || hoverText.Contains("shrooms"))) { for (int day = 1; day <= 28; day++) { ClickableTextureComponent component = calendarDays[day - 1]; if (component.bounds.Contains(Game1.getMouseX(), Game1.getMouseY())) { List <int> shrooms = this.GetShroomLayers(day - Game1.dayOfMonth); if (hoverText.Length > 0) { hoverText += "\n"; } if (shrooms.Count > 0) { hoverText += "Shrooms: " + string.Join(", ", shrooms); } else { hoverText += "No shrooms"; } break; } } hoverField.SetValue(hoverText); } } }
public void selectChannel(StardewValley.Farmer who, string answer) { string a = answer.Split(' ')[0]; CustomTVMod.monitor.Log("Select Channel:" + a, LogLevel.Trace); if (a == "more") { showChannels(currentpage + 1); } if (actions.ContainsKey(a)) { actions[a].Invoke(tv, tvScreen.GetValue(), who, a); } return; }
/// <summary>Temporarily dismount and set up the player to interact with a tile, then return it to the previous state afterwards.</summary> /// <param name="action">The action to perform.</param> private void TemporarilyFakeInteraction(Action action) { // get references SFarmer player = Game1.player; IPrivateField <Horse> mountField = this.Reflection.GetPrivateField <Horse>(Game1.player, "mount"); // save current state Horse mount = mountField.GetValue(); Vector2 mountPosition = this.Current.position; WateringCan wateringCan = player.CurrentTool as WateringCan; int waterInCan = wateringCan?.WaterLeft ?? 0; float stamina = player.stamina; Vector2 position = player.position; int facingDirection = player.facingDirection; int currentToolIndex = player.CurrentToolIndex; bool canMove = Game1.player.canMove; // fix player frozen due to animations when performing an action // move mount out of the way mountField.SetValue(null); this.Current.position = new Vector2(-5, -5); // perform action try { action(); } finally { // move mount back this.Current.position = mountPosition; mountField.SetValue(mount); // restore previous state if (wateringCan != null) { wateringCan.WaterLeft = waterInCan; } player.stamina = stamina; player.position = position; player.facingDirection = facingDirection; player.CurrentToolIndex = currentToolIndex; Game1.player.canMove = canMove; } }
public static void onUpdate(object sender, EventArgs args) { if (DEBUG) { Game1.options.pauseWhenOutOfFocus = false; } try { IPlatform.instance.update(); Multiplayer.update(); // We need our load menu to be able to do things if (Game1.activeClickableMenu is TitleMenu) { if (TitleMenu.subMenu is LoadGameMenu) { Log.debug("Found vanilla load game menu, replacing with ours."); Multiplayer.lobby = true; LoadGameMenu oldLoadMenu = ( LoadGameMenu )TitleMenu.subMenu; NewLoadMenu newLoadMenu = new NewLoadMenu(); IPrivateField <object> task = instance.Helper.Reflection.GetPrivateField <object>(oldLoadMenu, "_initTask"); newLoadMenu._initTask = (Task <List <SFarmer> >)task.GetValue(); Log.debug("Stole the save listing task, set it to: " + task); TitleMenu.subMenu = newLoadMenu; } } prevMenu = Game1.activeClickableMenu; } catch (Exception e) { Log.error("Exception during update: " + e); } }
/// <summary>Render the UI.</summary> /// <param name="spriteBatch">The sprite batch being drawn.</param> public override void draw(SpriteBatch spriteBatch) { this.Monitor.InterceptErrors("drawing the lookup info", () => { ISubject subject = this.Subject; // disable when game is using immediate sprite sorting // (This prevents Lookup Anything from creating new sprite batches, which breaks its core rendering logic. // Fortunately this very rarely happens; the only known case is the Stardew Valley Fair, when the only thing // you can look up anyway is the farmer.) if (!this.ValidatedDrawMode) { IPrivateField <SpriteSortMode> sortModeField = this.Reflection.GetPrivateField <SpriteSortMode>(Game1.spriteBatch, "spriteSortMode", required: false) // XNA ?? this.Reflection.GetPrivateField <SpriteSortMode>(Game1.spriteBatch, "_sortMode"); // MonoGame if (sortModeField.GetValue() == SpriteSortMode.Immediate) { this.Monitor.Log("Aborted the lookup because the game's current rendering mode isn't compatible with the mod's UI. This only happens in rare cases (e.g. the Stardew Valley Fair).", LogLevel.Warn); this.exitThisMenu(playSound: false); return; } this.ValidatedDrawMode = true; } // calculate dimensions int x = this.xPositionOnScreen; int y = this.yPositionOnScreen; const int gutter = 15; float leftOffset = gutter; float topOffset = gutter; float contentWidth = this.width - gutter * 2; float contentHeight = this.height - gutter * 2; int tableBorderWidth = 1; // get font SpriteFont font = Game1.smallFont; float lineHeight = font.MeasureString("ABC").Y; float spaceWidth = DrawHelper.GetSpaceWidth(font); // draw background // (This uses a separate sprite batch because it needs to be drawn before the // foreground batch, and we can't use the foreground batch because the background is // outside the clipping area.) using (SpriteBatch backgroundBatch = new SpriteBatch(Game1.graphics.GraphicsDevice)) { backgroundBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, null); backgroundBatch.DrawSprite(Sprites.Letter.Sheet, Sprites.Letter.Sprite, x, y, scale: this.width / (float)Sprites.Letter.Sprite.Width); backgroundBatch.End(); } // draw foreground // (This uses a separate sprite batch to set a clipping area for scrolling.) using (SpriteBatch contentBatch = new SpriteBatch(Game1.graphics.GraphicsDevice)) { // begin draw GraphicsDevice device = Game1.graphics.GraphicsDevice; device.ScissorRectangle = new Rectangle(x + gutter, y + gutter, (int)contentWidth, (int)contentHeight); contentBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, null, new RasterizerState { ScissorTestEnable = true }); // scroll view this.CurrentScroll = Math.Max(0, this.CurrentScroll); // don't scroll past top this.CurrentScroll = Math.Min(this.MaxScroll, this.CurrentScroll); // don't scroll past bottom topOffset -= this.CurrentScroll; // scrolled down == move text up // draw portrait if (subject.DrawPortrait(contentBatch, new Vector2(x + leftOffset, y + topOffset), new Vector2(70, 70))) { leftOffset += 72; } // draw fields float wrapWidth = this.width - leftOffset - gutter; { // draw name & item type { Vector2 nameSize = contentBatch.DrawTextBlock(font, $"{subject.Name}.", new Vector2(x + leftOffset, y + topOffset), wrapWidth, bold: Constant.AllowBold); Vector2 typeSize = contentBatch.DrawTextBlock(font, $"{subject.Type}.", new Vector2(x + leftOffset + nameSize.X + spaceWidth, y + topOffset), wrapWidth); topOffset += Math.Max(nameSize.Y, typeSize.Y); } // draw description if (subject.Description != null) { Vector2 size = contentBatch.DrawTextBlock(font, subject.Description?.Replace(Environment.NewLine, " "), new Vector2(x + leftOffset, y + topOffset), wrapWidth); topOffset += size.Y; } // draw spacer topOffset += lineHeight; // draw custom fields if (this.Fields.Any()) { ICustomField[] fields = this.Fields; float cellPadding = 3; float labelWidth = fields.Where(p => p.HasValue).Max(p => font.MeasureString(p.Label).X); float valueWidth = wrapWidth - labelWidth - cellPadding * 4 - tableBorderWidth; foreach (ICustomField field in fields) { if (!field.HasValue) { continue; } // draw label & value Vector2 labelSize = contentBatch.DrawTextBlock(font, field.Label, new Vector2(x + leftOffset + cellPadding, y + topOffset + cellPadding), wrapWidth); Vector2 valuePosition = new Vector2(x + leftOffset + labelWidth + cellPadding * 3, y + topOffset + cellPadding); Vector2 valueSize = field.DrawValue(contentBatch, font, valuePosition, valueWidth) ?? contentBatch.DrawTextBlock(font, field.Value, valuePosition, valueWidth); Vector2 rowSize = new Vector2(labelWidth + valueWidth + cellPadding * 4, Math.Max(labelSize.Y, valueSize.Y)); // draw table row Color lineColor = Color.Gray; contentBatch.DrawLine(x + leftOffset, y + topOffset, new Vector2(rowSize.X, tableBorderWidth), lineColor); // top contentBatch.DrawLine(x + leftOffset, y + topOffset + rowSize.Y, new Vector2(rowSize.X, tableBorderWidth), lineColor); // bottom contentBatch.DrawLine(x + leftOffset, y + topOffset, new Vector2(tableBorderWidth, rowSize.Y), lineColor); // left contentBatch.DrawLine(x + leftOffset + labelWidth + cellPadding * 2, y + topOffset, new Vector2(tableBorderWidth, rowSize.Y), lineColor); // middle contentBatch.DrawLine(x + leftOffset + rowSize.X, y + topOffset, new Vector2(tableBorderWidth, rowSize.Y), lineColor); // right // track link area if (field is ILinkField linkField) { this.LinkFieldAreas[linkField] = new Rectangle((int)valuePosition.X, (int)valuePosition.Y, (int)valueSize.X, (int)valueSize.Y); } // update offset topOffset += Math.Max(labelSize.Y, valueSize.Y); } } } // update max scroll this.MaxScroll = Math.Max(0, (int)(topOffset - contentHeight + this.CurrentScroll)); // draw scroll icons if (this.MaxScroll > 0 && this.CurrentScroll > 0) { this.ScrollUpButton.draw(contentBatch); } if (this.MaxScroll > 0 && this.CurrentScroll < this.MaxScroll) { this.ScrollDownButton.draw(spriteBatch); } // end draw contentBatch.End(); } // draw cursor this.drawMouse(Game1.spriteBatch); }, this.OnDrawError); }
private void CurrentLocationChanged(object sender, EventArgsCurrentLocationChanged e) { GameLocation loc = e.NewLocation; if (!Game1.killScreen && Game1.farmEvent == null && loc.currentEvent == null) { foreach (ModEvent ev in this.Events) { int?id = ev.getID(); if (id == null) { continue; } if (id < 0) { continue; } if (ev.Location == loc.name) { this.Monitor.Log(id.ToString(), LogLevel.Trace); if (ev.Repeatable) { Game1.player.eventsSeen.Remove((int)id); } int eventID = -1; try { eventID = this.Helper.Reflection.GetPrivateMethod(loc, "checkEventPrecondition").Invoke <int>(ev.Condition); } catch { this.Monitor.Log("Failed to check condition for event " + id + "(at '" + loc.name + "')", LogLevel.Error); } if (eventID != -1) { loc.currentEvent = new Event(ev.Data, eventID); if (Game1.player.getMount() != null) { loc.currentEvent.playerWasMounted = true; Game1.player.getMount().dismount(); } foreach (NPC character in loc.characters) { character.clearTextAboveHead(); } Game1.eventUp = true; Game1.displayHUD = false; Game1.player.CanMove = false; Game1.player.showNotCarrying(); IPrivateField <List <Critter> > crittersF = this.Helper.Reflection.GetPrivateField <List <Critter> >(loc, "critters"); List <Critter> critters = crittersF.GetValue(); if (critters == null) { return; } critters.Clear(); crittersF.SetValue(critters); break; } } } } }