User:Pathoschild/Modding wishlist

From Stardew Valley Wiki
Jump to: navigation, search

A list of requested changes in the game code to support modders. This list does not include complex refactoring or rewriting, which is unlikely to be accepted.

Wishlist

Small changes

  • ☐ Change NPC.CanSocialize to a { get; set; } property, and set it in the constructor instead. (That will let mods change the value without subclassing NPC.)
  • ☐ Remove unused BloomComponent, BloomSettings, and all code which references them (this is broken and never enabled).

Medium changes

  • ☐ Some XNB files have a separate display name field, but only in non-English. Using display names consistently regardless of language would let mods rename things without breaking keys:
    • Data\Bundles
    • Data\CraftingRecipes
    • Data\CookingRecipes
    • Data\Weapons
  • ☐ Get the greenhouse, farmhouse, and mailbox locations from icons on the map Paths layer, instead of static values in code. That would let map modders easily move them.
  • ☐ Get the spouse room offset from Data/NPCDispositions, instead of hardcoding it in FarmHouse.loadSpouseRoom.
  • ☐ Call Game1.hooks.OnGameLocation_CheckAction from overridden checkAction methods too, not only the base one.
  • ☐ Add an Item.CustomData field of type SerialisableDictionary<string, string> read/written to the save file, similar to Game1.CustomData. This would always be empty in vanilla code, but would let mods easily store custom info about the item.

Refactoring

  • ☐ Replace Item.ParentSheetIndex with three properties:
    field type notes
    ID string An ID unique across all item types (like parsnip or radish_salad). That would allow unambiguous and human-readable item references throughout the code (e.g. gift tastes, machine behaviour, etc), fix bugs like the wallpaper glitch, and make it easy to avoid ID collisions in mods (e.g. spacechase0.JsonAssets/watermelon).
    Sheet Texture2D The spritesheet to draw (e.g. Game1.objectSpriteSheet). This lets modders easily add custom items with their own spritesheet, and simplifies draw logic.
    SheetIndex int Equivalent to the old ParentSheetIndex, but for the Sheet texture. No longer used as an ID.

    Files like Data/ObjectInformation would be updated to use the new IDs:

    # old format
    634: "Apricot/50/15/Basic -79/Apricot/A tender little fruit with a rock-hard pit."
    629: "Apricot Sapling/500/-300/Basic -74/Apricot Sapling/Takes 28 days to produce a mature Apricot tree. Bears fruit in the spring. Only grows if the 8 surrounding \"tiles\" are empty."
    
    # new format
    apricot: "634/Apricot/50/15/Basic -79/A tender little fruit with a rock-hard pit."
    apricot_sapling: "629/Apricot Sapling/500/-300/Basic -74/Takes 28 days to produce a mature Apricot tree. Bears fruit in the spring. Only grows if the 8 surrounding \"tiles\" are empty."
    

    With equivalent changes in files like Data/NPCGiftTastes:

    # old format
    Universal_Like: "-2 -7 -26 -75 -80 72 395 613 634 635 636 637 638 724 459"
    
    # new format
    Universal_Like: "-2 -7 -26 -75 -80 apple apricot cherry coffee maple_syrup mead orange peach pomegranate shrimp"
    

    Creating a vanilla item would use a key lookup like before:

    Object item = new Object("apricot"); // equivalent to new Object("apricot", "Maps/springobjects", 634, ...);
    

    This also avoids needing to check item types in most code (e.g. no need to exclude bigcraftables in gift tastes, since there's no possible ID overlap with the IDs listed in Data/NPCGiftTastes).

  • ☐ Change all const fields to static readonly. They're accessed the same way and the performance difference is negligible, but that'll make the decompiled code much easier to understand, and avoid issues where const values get 'baked in' to mod assemblies.

Done in Stardew Valley 1.3.27

Bug fixes

  • ☑ Fix strange null handling with net fields (mostly fixed).
  • ☑ Fix bee houses hardcoded to check Farm location, instead of their current location.
  • ☑ On the load menu, clicking the 'back' button clicks the slot under it.
  • Object.getOne() doesn't copy the 1.2+ fields: name, DisplayName, preserve, preservedParentSheetIndex, and honeyType.

Small changes

  • ☑ Include Stardew Valley.pdb in the release, so we get line numbers when a crash happens in game code.
  • ☑ Add a SerializableDictionary<string, string> CustomData property to SaveData, for SMAPI mods to safely store data.
  • ☑ Remove Farmer namespace (so we don't need to alias the Farmer class anymore).
  • ☑ Make these Game1 fields protected instead of private: _debugStringBuilder, _fpsList, _fpsStopwatch, _fps, _newDayTask, _bgColor, screen, lightingBlend, drawFarmBuildings, drawHUD, drawDialogueBox, drawOverlays, and renderScreenBuffer. That will let SMAPI override the draw loop without reflection calls.
  • ☑ Make LocalizedContentManager.languageCodeString public. That will let SMAPI override the draw loop without reflection calls.
  • ☑ Remove LocalizedContentManager.LanguageOverride; it's unused, and that way SMAPI won't need to handle it.
  • ☑ Replace ChatBox.enableCheats() with a property.
  • ☑ Make these methods/properties virtual:
    • Item:
      • canStackWith
      • CompareTo
    • ☑ LocalizedContentManager:
      • CreateTemporary
      • Load(assetName, language)
      • LoadBase
      • CreateTemporary
      • LoadString
      • LoadBaseString
    • Buildings/Building:
      • textureName
      • resetTexture
      • showUpgradeAnimation
      • getNameOfNextUpgrade
      • showDestroyedAnimation
      • updateInteriorWarps
      • drawInConstruction
    • Buildings/Stable:
      • grabHorse
    • Locations/FarmHouse:
      • showSpouseRoom
      • loadMapForUpgradeLevel
      • setMapForUpgradeLevel
      • loadSpouseRoom
    • Menus/ChatBox:
      • textboxEnter
      • runCommand (and mark it protected)
      • addInfoMessage
      • globalInfoMessage
      • addErrorMessage
      • listPlayers
      • showHelp
      • setText
      • messageColor (and mark it protected)
      • receiveChatMessage
      • addMessage
    • Menus/IClickableMenu:
      • receiveRightClick (currently abstract)
    • Network/NetAudioCueManager:
      • Update
    • Objects/Chest:
      • grabItemFromChest
      • addItem
      • grabItemFromInventory
      • isEmpty
      • clearNulls
      • draw (last overload)
    • Objects/Object:
      • cutWeed
      • isAnimalProduct
      • canBeShipped
      • rot
      • isForage
      • initializeLightSource
      • consumeRecipe
      • performUseAction
      • grabItemFromAutoGrabber
      • farmerAdjacentAction
      • addWorkingAnimation
      • drawAsProp
      • sellToStorePrice
    • Projectiles/Projectile:
      • update
    • TV
  • Make Farmer.friendships internal to avoid confusion (replaced with friendshipData) (would require significant changes to how the class is serialised).
  • Include Stardew Valley.xml in the release (if available), so we get code documentation (no code documentation available).

Medium changes

  • ☑ Add Game1.hooks to let SMAPI intercept some core game logic.
  • ☑ Add Game1.input, which centralises Keyboard.GetState(), Mouse.GetState(), and GamePad.GetState().
  • ☑ Add a GameLocation.IsGreenhouse property, set it to true for the greenhouse, and use it anywhere the game checks .Name.Equals("Greenhouse"). That will let mods add custom indoor locations where crops can grow.
  • ☑ Change GameLocation.updateSeasonalTilesheets to enable custom seasonal tilesheets.
  • ☑ Instead of hardcoding non-social NPCs in new SocialMenu(...), add a virtual npc.CanSocialise field.
  • ☑ Integrate SMAPI's SDate features into the new WorldDate (like comparison operators and DayOfWeek).
  • ☑ Add events to NetList for item added/removed/replaced (similar to the ones NetDictionary has). SMAPI will use them to watch for changes in some collections (like player inventory).

Refactoring

  • ☑ Change static Multiplayer class into a Game1.multiplayer field so SMAPI can override it, and make its methods non-static and virtual.
  • ☑ Use interfaces instead of concrete types to let SMAPI/mods override them:
    • Farmer:
      • IList<Buff> buffs
      • IList<OutgoingMessage> messageQueue
    • Game1:
      • NetBase<IWorldState> netWorldState (create interface)
      • IGameServer GameServer (create interface)
      • ISoundBank soundBank (create interface with thin wrapper around SoundBank)
      • IList<GameLocation> locations
      • IList<Item> itemsToShip
      • IList<IClickableMenu> onScreenMenus
      • IList<DelayedAction> delayedActions
      • IDictionary<int, string> objectInformation
      • IDictionary<int, string> bigCraftablesInformation
      • IDictionary<string, string> NPCGiftTastes
  • Use Game1.CreateContentManager consistently.
  • ☑ Internal changes to CoopMenu so SMAPI can hook into it.
  • ☑ Replace obj.getType() == type with obj is type to support mod subclasses in various places.
  • Update the bundled Mono to the latest version (declined, too big a change).
  • Include a full (non-stripped) bundled Mono, to avoid issues with mod code (declined, too big a change).

Done in Stardew Valley 1.3.28

Small changes

  • ☑ When creating honey, set preservedParentSheetIndex to the flower's item ID.
  • ☑ Make LoadGameMenu's inner classes public.
  • ☑ Change ItemGrabMenu.sourceItem to public readonly object context, and track non-objects too. Suggested values:
    • Chest instance when opening a chest (like current sourceItem);
    • auto-grabber / Mill / JunimoHut instance when viewing their output;
    • AdventureGuild / LibraryMuseum / JunimoNoteMenu / FishingRod instance for their rewards;
    • Farm.shippingBin for the shipping bin;
    • Item instance if opened by a method like addItemByMenuIfNecessary;
    • null if not applicable.
  • ☑ Change GameLocation.IsGreenhouse to a { get; set; } property, and set it in the location constructor instead.
  • ☑ When logging an exception, use Console.WriteLine(exception.ToString()) instead of Console.WriteLine(exception.GetType()) + Console.WriteLine(exception.Message) + Console.WriteLine(exception.StackTrace). This will let SMAPI detect exception messages more easily.
  • ☑ Make these methods virtual:
    • Character:
      • checkForFootstep
    • Locations\DecoratableLocation:
      • isTileOnWall
      • setFloors
      • setWallpapers
      • getFloorAt
      • getWallForRoomAt
      • setFloor
      • getWalls (and make it non-static)
      • getFloors (and make it non-static)

Done in Stardew Valley 1.3.32

Small changes

  • ☑ Tweak accessibility modifiers:
    class changes
    Multiplayer
    • Make field protected: disconnectingFarmers.
    Network/NetBufferReadStream,
    Network/NetBufferWriteStream
    • Make classes public.
    Network/LidgrenServer
    • Make fields protected: peers and server.
    • Make methods protected virtual: sendMessage(NetConnection, OutgoingMessage) and parseDataMessageFromClient.
    SDKs/GalaxyNetClient
    • make fields protected: client.
    • make methods protected virtual: onReceiveConnection, onReceiveMessage, onReceiveDisconnect, and onReceiveError.
    SDKs/GalaxyNetServer
    • make class public.
    • make fields protected: server and peers.
    • make methods protected virtual: onReceiveConnection, onReceiveMessage, onReceiveDisconnect, onReceiveError, and sendMessage(GalaxyID, OutgoingMessage).
  • ☑ Changes to use IsGreenhouse:
    location changes
    Crop.newDay
    // from:
    if (... || !this.seasonsToGrowIn.Contains(Game1.currentSeason) || ...)
    
    // to: 
    if (... || (!environment.IsGreenhouse && !this.seasonsToGrowIn.Contains(Game1.currentSeason)) || ...)
    
    HoeDirt.canPlantThisSeedHere
    // from:
    if (!Game1.currentLocation.IsOutdoors || crop.seasonsToGrowIn.Contains(Game1.currentSeason))
    
    // to:
    if (!Game1.currentLocation.IsOutdoors || Game1.currentLocation.IsGreenhouse || crop.seasonsToGrowIn.Contains(Game1.currentSeason))
    
    HoeDirt.plant
    // from:
    if (!who.currentLocation.isFarm && who.currentLocation.IsOutdoors)
    
    // to: 
    if (!who.currentLocation.isFarm && !who.currentLocation.IsGreenhouse && who.currentLocation.IsOutdoors)
    
    // from:
    if (!who.currentLocation.isOutdoors || crop.seasonsToGrowIn.Contains(Game1.currentSeason))
    
    // to:
    if (!who.currentLocation.isOutdoors || who.currentLocation.IsGreenhouse || crop.seasonsToGrowIn.Contains(Game1.currentSeason))
    

Done in Stardew Valley 1.4

Bug fixes

  • When a fence is placed, its maxHealth is assigned to the same NetFloat instance as health. This causes the max health to deteriorate over time until the game is reloaded. (To fix it, this.maxHealth = this.health should become this.maxHealth.Value = this.health.Value.)
  • Fix crash when wearing the Jukebox Ring (only obtainable via mods) in the mines.
  • Fix MineShaft checking character count instead of monster count, which causes issues like ladders not spawning if a horse is present.

Small changes

  • ☑ Add the game version to the save file. (That enables game/mod migrations when loading a save from an older game version.)
  • ☑ Change Utility.getAllCharacters(List<T>) to also return the list, to simplify usage.
  • ☑ Tweak accessibility modifiers:
    class changes
    InteriorDoor
    InteriorDoorDictionary
    • make classes public.
    NPC
    • make fields public: scheduleTimeToTry, NO_TRY.
    • make methods public: getTextureName (also it probably doesn't need to handle the rival anymore).
    Locations/GameLocation
    • make fields public: interiorDoors.
    • make methods public: reloadMap, updateWarps.
    Menus/GameMenu
    • make fields public: tabs, pages.
    Menus/ShopMenu
    • make fields public: forSale, categoriesToSellHere, itemPriceAndStock, hoverPrice, heldItem, hoveredItem, currency, currentItemIndex.
    Menus/TitleMenu
    • make fields public: birds, cloudsTexture, titleButtonsTexture.
    Minigames/AbigailGame
    • make class public;
    • make fields public: storeItems, abigailPortraitDuration, quit, died, targetMonster;
    • make all CowboyMonster, Dracula, and Outlaw fields public.
    Objects/Fence
    • make fields public: fenceTexture.
    SDKs/GalaxyNetClient
    • make field protected: client.
    TerrainFeatures/Bush
    • make fields public: texture.
    TerrainFeatures/Tree
    • make fields public: texture.
  • ☑ Changes to use IsGreenhouse:
    location changes
    FruitTree.dayUpdate
    // from:
    if (... && (!Game1.currentSeason.Equals("winter") || Game1.currentLocation.name.Value.ToLower().Contains("greenhouse")))
    
    // to: 
    if (... && (!Game1.IsWinter || Game1.currentLocation.IsGreenhouse))
    
    // from:
    if (... || environment.name.Value.ToLower().Contains("greenhouse"))
    
    // to:
    if (... || environment.IsGreenhouse)
    
    // from:
    if (environment.name.Value.ToLower().Contains("greenhouse"))
    
    // to:
    if (environment.IsGreenhouse)
    
    FruitTree.performUseAction
    // from:
    if (... || Game1.currentLocation.name.Value.ToLower().Contains("greenhouse")))
    
    // to: 
    if (... || Game1.currentLocation.IsGreenhouse))
    
    Tree.dayUpdate
    // from:
    if (!Game1.currentSeason.Equals("winter") || this.treeType == 6 || environment.Name.ToLower().Contains("greenhouse"))
    
    // to: 
    if (!Game1.IsWinter || this.treeType == 6 || environment.IsGreenhouse)
    
  • ☑ Make methods virtual:
    class methods
    Game1 _draw, drawHUD, drawMouseCursor, drawOverlays, drawWeather, renderScreenBuffer
  • ☑ Remove unused content files:
    • Characters/schedules/beforePathfinding/*;
    • Characters/schedules/newSchedules/*;
    • Characters/schedules/spring/*.
  • ☑ Remove unused code:
    • TerrainFeatures/DiggableWall;
    • TerrainFeatures/TerrainFeatureFactory.
  • ☑ In GameLocation.loadObjects, split the door-finding logic into a separate updateDoors method for reuse.
  • ☑ In Farmhouse.loadSpouseRoom, avoid dictionary.Add to fix a common crash when a mod has already added that property there.
  • ☑ Remove confusing content folder fallback logic in Game1.Initialize, where the game looks for a hardcoded Windows path (and usually crashes with a confusing error) if the XACT folder isn't found.
  • ☑ Load NPC schedules data through a helper function so it's easier to track down schedule load issues.

Medium changes

  • ☑ Change the beehouse logic to allow honey from any hoed-dirt flower, instead of the vanilla subset.
  • ☑ Fix reharvestable crops always dropping the min number of items, instead of a random number between the min and max values. (Stardew Valley 1.4 also adjusts the crop data so the end result for vanilla crops matches the 1.3.36 behavior.)
  • ☑ Add an ICue interface and change references to Cue. That would let SMAPI/mods take control of sounds and music, which is hard to do currently.
  • ☑ Some XNB files have a separate display name field, but only in non-English. Using display names consistently regardless of language would let mods rename things without breaking keys:
    • Data\BigCraftablesInformation
    • Data\ObjectInformation
  • ☑ Consolidate Crop.harvest logic so it's consistent between scythe and hand harvesting.
  • ☑ Move the Data\* loading logic out of the FarmAnimal and NPC constructors into reloadData() methods (so animal/NPC data can be refreshed when the asset changes).
  • ☑ Reload farm animal & NPC data when the save is loaded, to fix inconsistency bugs and simplify mod changes to fields like an NPC's default location.