Update Migration Guide - tModLoader/tModLoader GitHub Wiki
This page contains guides for migrating your code to new methods and functionality of newer tModLoader versions. When a tModLoader update requires rewriting code, we will present the information here. For migration information from past versions, see Update Migration Guide Previous Versions
- tModPorter
- v2025.08
- v2025.07
- v2025.06
- v2025.05
- v2025.04
- v2025.03
- v2025.02
- v2025.01
- v2024.12
- v2024.11
- v2024.10
- v2024.09
- v2024.08
- v2024.07
- v2024.06
- v2024.05
- v2024.04
- v2024.03
- v2024.02
- v2024.01
- v2023.12
- v2023.11
- v2023.09
- v2023.08
- v2023.X (1.4.4)
tModPorter is a tool that automatically applies code fixes to mod source code for changes made to tModLoader. As a modder, the first step in updating a mod after a major tModLoader release is usually to run tModPorter. tModPorter will modify your source code files to fix or provide suggestions on how to fix your code for the new update. Please also read the relevant corresponding porting notes below to be fully aware of changes made in case you need to adapt your code further.
To run tModPorter, visit the Workshop->Develop Mods menu in game and click on the "Run tModPorter" button. You should see a window pop up with the status of the process. Once it is complete, you should see "Complete!" and a message noting how many files were affected. tModPorter might not fix your mod completely, you may need to still fix some things manually, see the instructions in the next section.


Some tModPorter fixes will add comments to your mods source code for changes that might require additional work from the modder. Open Visual Studio and begin working on updating parts of the code that tModPorter either couldn't port or left a comment with instructions. To find all comments, first go to Tools -> Options -> Environment -> Task List and add tModPorter as a custom token. Then close it and open View -> Task List, which will list all comments. You can also use the search bar to filter specific comments.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4515
Short Summary
ModAchievementhas been added, allowing mods to add new achievements to the game. (Note that these are not actual steam achievements and won't appear on steam)- Achievement menu has been updated with search, additional filters, and the option to reset all achievements.
- ExampleMod has been updated with plenty of examples, please read them and the PR description before starting to make your own
ModAchievement, there are several important nuances toModAchievementthat are taught in the examples.
Porting Notes
- If you have manually manipulated the achievements previously, please use this new system.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4709
Short Summary
- Tiles and walls can now specify a 'conversion fallback tile'. When a modded conversion attempts to convert a tile but there is no registered conversion for that tile, the tile will be converted as if it was the fallback tile.
- Use
(Tile|Wall)Loader.RegisterConversionFallbackand(Tile|Wall)Loader.RegisterSimpleConversionas described in the PR description to indicate tile conversion fallback types.- Overriding
Mod(Tile|Wall).Convertis now only required for advanced use cases whereRegisterSimpleConversiondoesn't suffice.
Porting Notes
- If your mod already implements tile conversion logic, consider adapting to the new options in this PR where appropriate for better compatibility and easier to maintain code:
- Use
(Tile|Wall)Loader.RegisterSimpleConversionfor conversions which don't need any additional logic beyond converting the tile/wall.- Use
(Tile|Wall)Loader.RegisterConversionFallbackfor conversions which do need special logic but should still be treated as a pure counterpart for other conversions.- Remove explicit conversion code when the fallback conversion would produce the same result.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4686
Short Summary
(Global|Mod)Tile.ReplaceTileadded, it is called when a tile is being replaced via the block swap feature.
Porting Notes
- If a block-swappable tile has
KillMultiTileorKillTilelogic, you might want to test it with block swap and decide ifReplaceTileshould be used to implement some or all of the same effects.
Pull Request: https://github.com/tModLoader/tModLoader/pull/3760
Short Summary
- Added
ExampleCustomUseStyleWeapon, showcasing an implementation ofUseStyleandUseItemHitbox, andUseItemFrameto implement a custom item use style.- Added
ItemLoader.RegisterUseStyleto allow mods to safely determine a unique custom use style ID.- Added helper methods:
Utils.CornerRectangle,Utils.BoundingRectangle, andUtils.Including
Porting Notes
- Replace magic numbers (made up numbers) for custom
Item.useStylevalues with the result ofItemLoader.RegisterUseStyle. This will allow greater compatibility and will avoid the potential of conflicting values between mods.
Pull Request: https://github.com/tModLoader/tModLoader/pull/3860
Short Summary
- A "Translation" tag has been added to the Steam Workshop for mods, allowing users to filter by (or filter out) mods that add translations. It will automatically be set during publishing for mods setting
translationMod = truein build.txt.
Porting Notes
- The tag will be applied the next time the mod is published. Upload a new release if you want the tag right away.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4776
Short Summary
TileID.Sets.ClearedOnWorldLoadadded to support properly cleaning up temporary tiles similar to the tiles placed by Ice Rod.ModSystem.PostWorldLoadadded for situations whereModSystem.OnWorldLoadis too early.
Porting Notes
- If currently using a detour, IL edit, or the
WorldFile.OnWorldLoadevent for code covered by the new features in this PR, consider using these new features instead.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4731
Short Summary
- Projects can import
tModLoader.targetsto reference tModLoader without being built as a mod by setting the propertyBuildModinstead of redefining the target that would build a mod.- This feature is intended for non-mod tools or libraries that need access to tModLoader references but shouldn't be packaged as a mod when the project is built.
Porting Notes
- Replace
<Target Name="BuildMod"></Target>with<BuildMod>false</BuildMod>within aPropertyGroup.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4727
Short Summary
- The
tModCodeAssistcode analyzer (formallytModLoader.CodeAssist) has been reworked and is now directly included in tModLoader releases.- This new implementation will be much easier to update and we intend to add more requested code fixes to the analyzer. We welcome suggestions and feedback at the thread.
- If you are unaware, this feature is responsible for the suggestions in your IDE to change code like
item.useStyle = 5;toitem.useStyle = ItemUseStyleID.Shoot;.- This also fixes the issue where the old
tModLoader.CodeAssistwould cause issues for users who had bad nuget settings.
Porting Notes
- If you run into issues in your IDE after this update, you likely need to run "Upgrade .csproj file" from the
Mod Sourcesmenu. (To remove the old reference totModLoader.CodeAssist)
Pull Request: https://github.com/tModLoader/tModLoader/pull/4701
Short Summary
- Support for interactable projectiles added. Projectiles can now be targeted by smart select and draw a smart select highlight.
- Use
ProjectileID.Sets.IsInteractableand follow the logic inExampleInteractableProjectileto make an interactable projectile.
Porting Notes
- Replace any detours or IL edits on the
Projectile.IsInteractiblemethod withProjectileID.Sets.IsInteractableusage- Consider upgrading existing projectiles that can be right clicked directly with this smart cursor support for better compatibility and user experience.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4539
Short Summary
- Add
(Mod|GlobalNPC).PreHoverInteracthooks. Lets modders override or piggyback off of right clicking on or hovering over an NPC
Pull Request: https://github.com/tModLoader/tModLoader/pull/4704
Short Summary
- Adds
ExampleVineand some documentation.
Porting Notes
- We encourage any mod with vine tiles to compare your code against
ExampleVineandExampleVineGlobalTile. It is possible your vines do not match the vanilla behavior, such as converting properly when the grass tile changes (Clentaminator), rendering properly (offset and flipping), not cutting when the user is using the staff of regrowth, breaking when the tile above is block swapped, incorrectly growing on activated tiles, incorrectly growing on bottom slope tiles, not propagating paint to newly grown vines, etc.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4702
Short Summary
- Fixes manually setting bestiary stars. Mods can now set
ContentSamples.NpcBestiaryRarityStarsinSetStaticDefaults.
Porting Notes
- Mods setting
ContentSamples.NpcBestiaryRarityStarsinGlobalNPC.SetBestiarycurrently work by accident, but we recommend settingContentSamples.NpcBestiaryRarityStarsinSetStaticDefaultsinstead.
Pull Request: https://github.com/tModLoader/tModLoader/pull/2566
Short Summary
- Many vanilla sound behaviors have been fixed
- Sounds no longer stop when pausing the game by default
- Sounds using the same
SoundStyle.SoundPathnow properly honorSoundStyle.Identifierand won't be seen as the same soundSoundStylenow hasLimitsArePerVariant,RerollAttempts, andPauseBehaviorfields to further customize sound behavior.
Porting Notes
- In fixing various bugs, this PR does change some existing behaviors some modders might have unwittingly relied on. We recommend that modders test the sounds in their mod that relate to the following:
- Sounds now continue playing when the game is paused by default. If this is not desired, consider setting setting
SoundStyle.PauseBehaviortoPauseBehavior.StopWhenGamePaused(orPauseBehavior.PauseWithGame).- Various changes to
IsTheSameAsnow means that someSoundStylethat previously were seen as the same are now seen as different and vice versa. If you have multipleSoundStyleusing the sameSoundPathbut want them to behave independently for sound limiting purposes, make sure to setIdentifier.- Consider setting
SoundStyle.LimitsArePerVariantif making use of the variants feature to allow each variant to have an independent instance limit.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4212
Short Summary
ModConfig.SaveChangeshas been added to allow mod code to safely modify and save changes toModConfig.ModConfig.HandleAcceptClientChangesReplyadded to facilitate reacting to the reply of save requests forServerSideconfigs.ModConfig.AcceptClientChangescan now make changes to the pending config values before accepting.ExampleFullscreenUI.cshas been updated to showcase usingModConfig.SaveChangescorrectly.
Porting Notes
- If using reflection to access
UIModConfig.SaveConfig, useModConfig.SaveChangesinstead.- If your mod has UI, consider using
ModConfig.SaveChangesto save user preferences to preserve UI positioning and toggles.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4684
Short Summary
- Negative NPCIDs, such as Pinky, are now usable with NPCDefinition
Porting Notes
- Due to some negative values now being valid for
NPCDefinition.Type, theNPCDefinition.Typefor an "unloaded"NPCDefinitionhas changed from-1to-66. If you have code checkingNPCDefinition.Type == -1directly, it would be better to checkNPCDefinition.IsUnloadedinstead.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4340
Short Summary
ModAccessorySlotnow supports loadouts by default.
Porting Notes
- If loadout support is not wanted for a
ModAccessorySlot, setHasEquipmentLoadoutSupportto falseModAccessorySlotwithout custom backgrounds that support loadouts will be tinted with loadout colors as normal. If using a custom slot background, however, they will not be affected. A new hook,ModAccessorySlot.BackgroundDrawColor, can be used to further customize the color.Player.DropItemis now obsolete, usePlayer.TryDroppingSingleIteminstead.(Mod|Global)CanAccessoryBeEquippedWith/CanEquipAccessoryandModAccessorySlot.CanAcceptItemcan now be called on the server and remote clients instead of just the local client. This might mean some syncing issues need to be addressed.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4325
Short Summary
ModTile/ModWall.VanillaFallbackOnModDeletionhas finally been implemented. See the PR description for images depicting what this means.- Users can use the
/purgeunloadedchat command to remove tiles in a world from mods they are no longer using.- Modders can assign values to
VanillaFallbackOnModDeletionto dictate which vanilla tile a deleted tile should revert back to.
Porting Notes
- Nothing is required, but if you want to make it possible for your mod to be removed from a world, consider assigning values to
VanillaFallbackOnModDeletion.- The default fallback of
Dirtshould work, but if something is more appropriate it can be used.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4629
Short Summary
- Adds customization for town NPC and boss death messages.
- Adds
ModNPC.DeathMessagewhich modifies the message broadcasted when a town NPC or boss dies. This also affects what the town NPC's tombstone says in hardcore mode. This allows custom death messages similar to "The Twins", which were previously not possible. Color can also be modified withModNPC.ModifyDeathMessage.- Adds
NPCID.Sets.IsTownChildwhich prevents tombstones from being spawned in hardcore and sets the death message to "X has left!" unless specified otherwise by the method above. This is what the Angler and Princess use.
Porting Notes
ModNPC.BossLoot(name, potionType)became obsoleted and replaced withModNPC.BossLoot(potionType). Both will still be called for now but you should consider changing toDeathMessageahead of time.- If you had a workaround for paired or group bosses, you can get rid of it and use
DeathMessageinstead to prevent duplicate boss defeat messages.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4655
Short Summary
- Wall blending has been fixed to work as intended for modded walls. Wall blending is when the border between different types of walls don't have a thin black line between them.
- Previously all modded walls blended with each other, but that has been fixed and each wall will now only blend with walls they are intended to blend with.
- Please see the pull request for more information, there are images and animations that show the original issue and fixed behaviors.
Porting Notes
- Add
Main.wallBlend[Type] = ModContent.WallType<OtherWall>();to anyModWallwhere blending was intended. This only needs to be done on one of the walls in a pair, since this is indicating that this wall should be considered to be the other wall for the purposes of blending.WallID.Sets.BlendTypenever worked in the first place, despite being recommended on our wiki previously. If you were using it, remove it and useMain.wallBlendinstead.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4606
Short Summary
UpdateVisibleAccessoryandUpdateItemDyehooks added toModItemandGlobalItemCustomVisualEquipTypefolder in ExampleMod showcases a full custom visual equip type example
Porting Notes
- If you have modded visual elements that don't show up properly on the player select screen, such as a custom equip type layer, you should move code assigning those flags/fields to
UpdateVisibleAccessorywhile checking thathideVisualif false. (Follow the examples)- Existing methods like
UpdateAccessory,UpdateVanity, andUpdateEquipscouldn't perfectly work for custom draw flags like these.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4399
Short Summary
Player.breathEffectivenessadded to facilitate compatibility for adjusting underwater breathing time- Adjusting
Player.breathdirectly to implement a Breathing Reed or Diving Helmet effect is no longer the best option.breathMax = 200;added toPlayer.ResetEffects, so it is no longer necessary for mods to do it.
Porting Notes
- Remove
Player.breathMax = 200;fromModPlayer.ResetEffects.- If adjusting
Player.breathpreviously, consider instead adjustingPlayer.breathEffectivenessfor more compatibility.- Technically
Player.breathis the breath capacity andPlayer.breathEffectivenessis how long each unit of breath lasts, so advanced situations might warrant adjusting both, see PR for details.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4618
Short Summary
- This PR allows
SoundStyle'sPitch,PitchVariance, andPitchRangeproperties to produce pitch values outside the-1..+1octave range they were previously restricted to.
Porting Notes
- Check if any of your code has accidentally relied on the previously present internal clamping, and alter it to always produce the pitch range you intend it to.
// This used to produce [0.25...1.0], but will now produce [0.25...1.25]`. SoundStyle { Pitch = 0.75f, PitchVariance = 1.00f } // So change to this for the old behavior to remain: SoundStyle { PitchRange = (0.25f, 1.0f) }
Pull Request: https://github.com/tModLoader/tModLoader/pull/4381
Short Summary
- Custom ID sets (ID sets are arrays indexed by a content ID like
ItemID.Sets.IsDrill) are now fully supported. UseModSystem.ResizeArraysor a class annotated with[ReinitializeDuringResizeArrays]to correctly initialize them.- Custom ID sets can be registered with a name ("named ID set") allowing multiple mods to access the same array. After registration they can be used exactly as an existing ID set would be used.
- You might know of this concept by other names like "content tags".
- See the PR description for more information.
Porting Notes
- There are no breaking changes, but the custom and named ID sets supported in this PR might greatly simplify existing code, especially for cross-mod situations where data is accessed by multiple mods.
- There are some situations that were incorrect before but now throw errors during loading due to this PR. The most common issue is calling
EquipLoader.AddEquipTexturefor an equip type that has already been autoloaded using[AutoloadEquip]. To fix, get rid of one or the other.
Added Convert() hook for ModBlockTypes, Tile/WallLoader.RegisterConversion(), and other biome conversion related features and Modifiable chlorophyte conversions
Pull Request: https://github.com/tModLoader/tModLoader/pull/4566, https://github.com/tModLoader/tModLoader/pull/4630
Short Summary
- Adds
ModTile/ModWall.Converthook to allow modded tiles to be converted via clentaminator, purification powder, hardmode worldgen or infection spreading.- Adds
Tile/WallLoader.RegisterConversionmethods to provide or block 'global' conversions for tiles.- Adds
WorldGen.ConvertTile/Wall()andSpreadInfectionToNearbyTilehelper methods to cut down on repeated code- Adds
BiomeConversionID.PurificationPowderfor conversion hooks.- Adds
ModBiomeConversionto register custom conversions.- Adds
BiomeConversionID.Chlorophyteand callsConverthooks when chlorophyte attempts to purify nearby tiles inhardUpdateWorld
Pull Request: https://github.com/tModLoader/tModLoader/pull/4528
Short Summary
- Full example of a
ModTileEntity,BasicTileEntity.cs, that should be complex enough to be useful but simple enough to use as a template.- Various new helper methods:
TileObjectData.TopLeft,TileEntity.TryGet,ModTileEntity.Generic_HookPostPlaceMyPlayer/Generic_Hook_AfterPlacement,Point16.Deconstruct. Please seeBasicTileEntity.csand the PR details to see how these are used.TileID.Sets.PreventsTileHammeringIfOnTopOfItadded to help implement chest-like tiles that shouldn't break easily.- Various bug fixes and related documentation, see PR for details.
Porting Notes
- Nothing is required, but the new example and helper methods can be used to clean up existing Tile Entity code.
TileID.Sets.PreventsTileHammeringIfOnTopOfItcan replace some workarounds.- See the PR for full porting note details.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4551
Short Summary
- Chandeliers and other rigid swaying tiles can now customize their physics and flame visuals behaviors (
ModTile.AdjustMultiTileVineParametersandModTile.GetTileFlameData)ModTile.EmitParticlesadded to simplify spawning tile dust and gore with the correct timing and behaviorAnimation.NewTemporaryAnimationsupport.ModTiles can now use custom 1-off animations, similar to how the MushroomStatue behaves.ExampleChandelieradded, showing off all these hooks and more.- Modded torches now work with Torch God event and The Constant rain extinguishing feature.
Porting Notes
- Revisit
TileDrawing.TileCounterType.MultiTileVinetiles and see if any of the new features would help make them better.- Consider moving tile dust and gore code from
DrawEffectstoEmitParticles. Doing so would allow simplifying code greatly by removing the boilerplate code.- Update torch tiles with dust spawning if you had used
ExampleTorchas a guide.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4587
Short Summary
ModMapLayernow supports ordering. (GetDefaultPositionandGetModdedConstraints)- Previously all modded map layers would be drawn in load order after all existing layers.
Porting Notes
- Adjust your
ModMapLayerto use the new ordering methods if desired.- Many users might expect Pings to show above all layers, so adding
public override Position GetDefaultPosition() => new Before(IMapLayer.Pings);would be recommended for that.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4572
Short Summary
- Fixes
ModItem.WeaponPrefix's default implementation to automatically include prefixes fromDamageClass.Generic- To opt-out of GenericPrefixes, set this to false
Pull Request: https://github.com/tModLoader/tModLoader/pull/4392
Short Summary
- Frost and Pumpkin moon music had higher priority than all other music and could not be overridden.
- They now both have the proper
Eventpriority.
Porting Notes
- If you had workarounds for this, they can be removed.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4535
Short Summary
- The ExampleMod relic,
MinionBossRelic.cs, did not match the vanilla behavior completely. It animated at a slower frame rate and was blurry due to interpolation. This example has been fixed.AddSpecialPointnow supports custom rendering, which allows 60fps rendering rather than the 15fps rendering ofAddSpecialLegacyPoint
Porting Notes
- Fix your relic tiles using the changes to
MinionBossRelic.csin this PR as a guide.- Consider using
AddSpecialPointinstead ofAddSpecialLegacyPointforModTile.SpecialDrawusages that would benefit from rendering at 60fps rather than 15fps. The pull request description has steps to do this.- Consider adjusting
ModTile.AnimateTileframeCounter logic to count to multiples of 4 for smoother animation. The updatedModTile.AnimateTiledocs explain why values that are not multiples of 4 results in jerky animation
Pull Request: https://github.com/tModLoader/tModLoader/pull/4553
Short Summary
PlayerDeathReason.ByCustomReason(string)is nowObsolete, replaced byPlayerDeathReason.ByCustomReason(NetworkText)to correctly support localization of death messages.- Previously users would see death messages in the language of the player that died, not their own selected language.
Porting Notes
- If already using
LocalizedText, changelocalizedText.Format(substitutions)tolocalizedText.ToNetworkText(substitutions).- If still using a string directly, consider supporting custom death message localization by following the example shown in
ExampleOnBuyItem.SetStaticDefaultsandOnCreated.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4548
Short Summary: Mods which are built from locations outside the Mod Sources folder via the command line/visual studio will now show in the Mod Sources menu. See the "How to use" section of the PR to learn how to use this feature. This can give some developers more flexibility over their paths and workflows
Porting Notes: Symbolic links in the Mod Sources folder pointing to other folders might now result in duplicate entries in the Develop Mods menu. Deleting those links will fix this.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4503
Short Summary
GlobalTile.PreShakeTreeandGlobalTile.ShakeTreeadded to allow customizing drops from shaking vanilla trees.ShakeTrees.csshowcases using these hooks.
Porting Notes
ModTreeandModPalmTreeCountsAsTreeTypenow default toTreeTypes.Custominstead ofTreeTypes.ForestandTreeTypes.Palmrespectively. This means that modded tress no longer default to having all the vanilla tree shake drops. Adjust this back if that behavior was desired.
Pull Request: https://github.com/tModLoader/tModLoader/pull/3993
Short Summary and Porting Notes
ConsumeItemhooks, callbacks and methods have been replaced withConsumeIngredient/IngredientQuantityhooks which have an additionalbool isDecraftingparameter.
- This allows you to apply discounts when shimmering to prevent infinite craft-shimmer exploits.
- The current classes and hooks are marked
[Obsolete]but remain functional- Added read-only property
Recipe.DecraftDisabled, exposing previously internal state- The
internalfieldRecipe.alchemyhas been removed, as its functionality is now covered byRecipe.IngredientQuantityRules.Alchemy
Pull Request: https://github.com/tModLoader/tModLoader/pull/4530
Short Summary
- If you would like to make your mods' music slightly louder than vanilla's intended volume range, or to use old music files whose volume was adjusted for pre-1.4 TML, you are now able to opt out of the internally used XACT-matching volume remapping, via either the new
MusicID.Sets.SkipsVolumeRemapset, or the newMod.MusicSkipsVolumeRemapproperty.- The default music volume behaviors remain unchanged. As before this PR and since TML for 1.4, by default any given music track is lowered in playback volume to better match vanilla music volume in-game, matching it best if the file had a peak amplitude of
+0.0dB. If the volume remap is skipped for a music track, then it will be able to play at about twice the volume of vanilla tracks.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4463
Short Summary: Previously, ModPlayer.DrawEffects' fullBright parameter required modifying any of the color parameters to actually have effect. This requirement has been removed making it easier to use correctly.
Porting Notes: If using fullBright, you can remove any workaround code setting r, g, b, or a.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4442
Short Summary
- Enemy banner tiles are now fully supported, and
EnemyBanner.csshows a fully correct implementation.ModBannerTileadded. It contains all the code common to enemy banner tiles and should be used.- Various other fixes and documentation related to banners.
Porting Notes
- Read the porting notes in the pull request description to learn how to use this new feature.
- Existing banner tile examples in other mods have various bugs, please read the porting notes even if your mod already has banner tiles.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4430
Short Summary
- Allows modders to "categorize" a custom bestiary info element, giving more control over where the element will be drawn in a given Bestiary entry.
Porting Notes
- Implement
ICategorizedBestiaryInfoElementand theElementCategoryproperty to support this feature forIBestiaryInfoElementin your mods.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4352
Short Summary
- Sending and receiving bools through
BitsByteorBinaryWriterwas inconvenient, new methods have been added.
Porting Notes
- Consider using the new
BinaryReader.ReadFlagsandBinaryWriter.WriteFlagsmethods to simplify and improve the readability of your code.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4429
Short Summary
- Allows modders to "register" their multi-tiles to sway in the wind and with player interaction, facilitating implementing swaying multi-tiles such as banners, chandeliers, vines, etc.
ExampleWideBanneradded,ExampleAnimatedTile/"Red Firefly in a Bottle" (a lantern tile) updated.TileObjectData.IsTopLeftadded. Various methods made public.
Porting Notes
- Please update your banners, lanterns, chandeliers, etc to use the new tile swaying mechanics for consistency with vanilla tiles.
TileDrawing.TileCounterType/AddSpecialPoint/CrawlToTopOfVineAndAddSpecialPoint/CrawlToBottomOfReverseVineAndAddSpecialPointare all now public- Consider replacing
if (tile.TileFrameX == 0 && tile.TileFrameY == 0) {orif (tile.TileFrameX % FullTileWidth == 0 && tile.TileFrameY % FullTileHeight == 0) {checks withTileObjectData.IsTopLeft(tile)for cleaner code if appropriate.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4424
Short Summary
- Mods are now required to have a unique icon and mod description.
icon.pngwill automatically be scaled up for workshop publishing, meaning modders no longer need to create aicon_workshop.pngfor their icon on the workshop unless they want the workshop icon to be more detailed than the regular icon.
Porting Notes
- Make sure your mod has a unique icon and description if you can no longer publish the mod.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4367
Short Summary
ModCloudadded to allow custom clouds.- Textures in a folder named "Clouds" will now be autoloaded as
ModCloudunlessMod.CloudAutoloadingEnabledis false.
Porting Notes
- If you happened to have a folder named "Clouds" that doesn't contain
ModClouds, you can addCloudAutoloadingEnabled = false;to yourModclass constructor.
Pull Request: https://github.com/tModLoader/tModLoader/commit/0d55bc751d5b2b7c5fabb5ea5e3a028a2215283a
Short Summary: Player.breathMax now resets to 200 and Player.breath is capped to Player.breathMax.
Porting Notes: If your mod previously reset Player.breathMax or Player.breath, it is no longer necessary.
Pull Request: https://github.com/tModLoader/tModLoader/commit/7accd386a4f795fd1df50a02abc88ec1774f8f33
Short Summary: Afterimage example code in ExampleMod was incorrect. If you used it as a guide, please fix your usage of it.
Porting Notes: Change for (int k = 0; k < Projectile.oldPos.Length; k++) to for (int k = Projectile.oldPos.Length - 1; k > 0; k--) to draw afterimages from furthest to closest for the proper afterimage layering.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4427
Short Summary: SpriteCharacterData is now public. Public getters for _spriteCharacters and _defaultCharacterData
Porting Notes: If your mod previously used reflection, consider updating or verifying compatibility.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4403
Short Summary
- Adds
HurtModifiers.Cancel()andHurtInfo.Cancelled, making it easier for mods to make a player situationally ignore certain damage instances.- Cancelling a hurt has the same effect as returning true from FreeDodge, though even undodgeable hurts can be cancelled. Unlike FreeDodge, immune frames are not applied, so the player can still be hit by another attack this tick, or the same attack next hit.
Porting Notes
- None. Modders do not need to check if a
HurtInfoisCancelled, tModLoader will not be passing cancelled hurts to hooks.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4369
Short Summary
ModPlayer.ArmorSetBonusActivatedandModPlayer.ArmorSetBonusHeldadded to facilitate triggering modded armor set bonus effects without workarounds.- ExampleMod updated to now showcase an armor set effect, armor set shadows, and more varied
ModKeybindusage.
Porting Notes
- If you were using a custom hotkey or detour/IL edit to activate armor set bonuses, consider migrating to
ModPlayer.ArmorSetBonusActivatedorModPlayer.ArmorSetBonusHeld
Pull Request: https://github.com/tModLoader/tModLoader/pull/4175
Short Summary
ModItemcan now belong to multiple prefix categories, either via theirDamageClassor by overridingModItem.MeleePrefix/WeaponPrefix/RangedPrefix/MagicPrefixDamageClass.GetPrefixInheritanceadded to allow DamageClasses to declare which vanilla prefix categories weapons using it should inherit. (For example, a Melee/Magic hybrid class might want weapons to get Melee and Magic prefixes)
Porting Notes
- Some existing items in your mod may now count towards multiple prefix categories, especially those using a custom
DamageClass. Test these items and determine if their prefixes are desired. AdjustDamageClass.GetPrefixInheritanceorModItem.MeleePrefix/WeaponPrefix/RangedPrefix/MagicPrefixas appropriate.- The
MultiplePrefixSupportTestMod.tmodmod contained in the PR description can be used to easily compare prefix results, please use it to verify that the item prefixes are as expected.- If using
Item.GetPrefixCategory, useItem.GetPrefixCategoriesinstead and adjust your logic
Pull Request: https://github.com/tModLoader/tModLoader/pull/4275
Short Summary
TileObjectDataclass has been fully documented- Basic Tile wiki page updated
- Fixed several issues related to
TileObjectData/tile placement:- Modded tiles with alternate placements would sometimes require a workaround to not break when placed
- Fixed
TileObjectData.GetTileStyle/GetTileInfoincorrectly ignoringStyleMultiplierwhen used withStyleLineSkip, which will allow tiles also usingStyleWrapLimitto function correctly.ExampleDoorOpenfixed to not break when opened to the left.TileObjectDataShowcase.csadded to showcase and visualize advancedTileObjectDatausage, such as left and right placements, random placements, animation, toggle states, custom anchors, and multiple styles.
Porting Notes
- Modders should fix their open door tiles if they are using
TileObjectData.newTile.CopyFrom(TileObjectData.GetTileData(TileID.OpenDoor, 0));or if their doors break when opening to the left.- Modders should double check that tiles using placement alternates (
TileObjectData.newAlternate/TileObjectData.addAlternate()) work as expected. The fixes should not cause issues, but it is possible that incorrect workarounds to issues fixed in this PR are now broken.- Modders should use
StyleLineSkipandStyleMultiplierwhere correct. This should reduce the amount of workarounds such as usingRegisterItemDroporGetItemDropsto fix item drops that are incorrectly being calculated.
Pull Request: https://github.com/tModLoader/tModLoader/pull/3501
Short Summary
ProjectileID.Sets.Explosive[]to match the behavior of vanilla explosives without having to useaiStyle 16- New
Projectile.HurtPlayer(Rectangle hitbox)method which will damage the local player if they intersect the hitbox.- New
PrepareBombToBlowhook to implement explosives correctly.- A full set of rocket projectiles as well as rocket launcher and rocket ammo items, showing how they all connect to each other.
Porting Notes
- If you were using
Projectile.aiStyle = ProjAIStyleID.Explosive(16) to match the vanilla behavior of explosives, you can now useProjectileID.Sets.Explosive[]. Also overridePrepareBombToBlowand add the explosion resizing logic there.- Rocket ammo should have
ProjectileID.Sets.SpecificLauncherAmmoProjectileMatchesdefined for all applicable vanilla launchers.- Rocket launchers should set
AmmoID.Sets.SpecificLauncherAmmoProjectileFallbackto the closest vanilla launcher to inherit ammo-specific projectiles from.- If you were using
PickAmmo()or similar to fix your rocket ammo shooting the wrong projectile for the Snowman Cannon and Celebration Mk2, double check that because it is probably not necessary anymore.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4222
Short Summary
NPCID.Sets.PlayerDistanceWhilePetting[]to change the distance away the player stands while petting Town Pets/Slimes.NPCID.Sets.IsPetSmallForPetting[]to change whether the player's arm will be angled up or down while petting Town Pets/Slimes.(Mod|Global)NPC.ChatBubblePosition(ref Vector2 position, ref SpriteEffects spriteEffects)to change the chat bubble that appears while hovering over a Town NPC.(Mod|Global)NPC.EmoteBubblePosition(ref Vector2 position, ref SpriteEffects spriteEffects)to change the emote bubble on NPCs.(Mod|Global)NPC.PartyHatPosition(ref Vector2 position, ref SpriteEffects spriteEffects)to have more control over the party hat on Town NPCs.- New
NPCID.Sets.NPCFramingGroup[Type] = 8which has no predefined offsets for the party hat.
Pull Request: https://github.com/tModLoader/tModLoader/commit/5108256b0839172203b1534035755e9064a7780e
Short Summary
(ModPlayer|ModProjectile|GlobalProjectile)EmitEnchantmentVisualsAthooks added. These facilitate weapon enchantment visuals.MeleeEffectshas been used for this, but only covers items and does not cover projectiles. With both hooks it is now possible to fully support weapon enchantment visuals.ExampleFlaskandExampleWeaponImbueshowcase a full implementation of a flask potion and corresponding weapon imbue, the most common type of weapon enchantment.
Porting Notes
- Mods with weapon enchantments (such as flasks, frost armor, or magma stone-type effects) should implement the
EmitEnchantmentVisualsAthook. The code will be quite similar to theMeleeEffectscode you are already using, seeExampleWeaponEnchantmentPlayer.csfor an example.- Use
Player.MeleeEnchantActiveinstead of settingPlayer.meleeEnchantto a high value, if you want.- Consider testing projectiles in your mod while weapon enchantments are active, set
Projectile.noEnchantments = truefor special projectiles that shouldn't be affected by weapon enchantment effects (buffs) or visuals (dust).- If weapon enchantment visuals on melee projectiles seem to be incorrectly positioned, such as would likely happen on "energy swords" such as Excalibur, consider using
Projectile.noEnchantmentVisuals = trueandProjectile.EmitEnchantmentVisualsAtas shown inExampleSwingingEnergySwordProjectileto manually position the enchantment visuals.
Pull Request: https://github.com/tModLoader/tModLoader/commit/2f6c9a25a3ac178af30f8bd58e1c411b77ab006d
Short Summary
ItemLoader.UseItem((Mod|Global)Item.UseItem) calls added back toPlayer.QuickHealandPlayer.QuickMana. This was missing since 1.3.
Porting Notes
- Check that UseItem logic dealing with health/mana potions still works with quick heal and quick mana hotkeys.
Nothing this month.
Pull Request: https://github.com/tModLoader/tModLoader/commit/30b2b9b1e3347a1c98ebe6924811ba5e82391dc3
Short Summary: Shaders no longer need to declare all the parameters expected by the game
Pull Request: https://github.com/tModLoader/tModLoader/commit/06996a53d6071cbd33653b8bfda2628ca47c8777
Short Summary
GoreID.Sets.LiquidDroplethas been added to completely support modded liquid droplet gore. The oldGoreID.Sets.DrawBehindapproach resulted in some slight visual bugs.
Porting Notes
- Replace usages of
GoreID.Sets.DrawBehindwithGoreID.Sets.LiquidDropletin modded liquid droplet gore. Compare against ExampleDroplet.cs.
Pull Request: https://github.com/tModLoader/tModLoader/commit/6e66b805a8ba15adf1a3b25710d558cea3a5416d
Short Summary
ModTile/GlobalTile.CanPlacehas not worked correctly, this has been fixed.
Porting Notes
- Verify that your
CanPlacecode is still correct and get rid of any manual workarounds. Note thatCanPlaceis still called during block swap by design.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4120
Short Summary: It was previously impossible to declare that an item was a tool for the creative mode duplication menu. This is now possible with ItemID.Sets.DuplicationMenuToolsFilter
Short Summary
- Modders should double check their
Item.shopCustomPriceusage. We've recently become aware of mods settingshopCustomPricefar lower thanItem.value. We've determined that a custom price0.44 timesthe regular value would allow a user with max happiness and a discount card to sell the item back to a shop for more than the purchase price after leaving and entering the world. This is because the normalItem.valueis used to determine the sell price. Either raiseshopCustomPriceor lowerItem.valueto avoid this exploit.
This release includes an update from .NET 6 to .NET 8. Modders will need to install the .NET 8 SDK and update Visual Studio to at least VS2022 17.8. After that, restart the computer. See below for details.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4037
Short Summary
- Upgrades tModLoader from .NET6 to .NET8.
- Players have reported noticeable performance improvements. World generation benchmarks finish 10% faster!
- Mod developers will benefit from access to new C# and .NET features, such as
ref fields,generic math,unsafe accessors, and more.
Porting Notes
- Install the .NET 8 SDK
- To update your mods' project files - access the
Develop Modsmenu and click theUpgradebutton near your mod. Due to#4134, this is now a safe operation to perform. Future runtime updates will not require this step.- If you're a developer who's using
Windows 8.1or earlier - you'll need to run a command for a continued smooth experience. PressWin + R, pastesetx DOTNET_EnableWriteXorExecute 0in the "Run" window, and press enter. A PC restart is also recommended for ensured compatibility. Players do not really need to do this.- .NET 8 development in Visual Studio requires VS2022 17.8 or later. If updating from VS2019 - make sure to export your customization/configuration for a re-import post-update.
- You may need to restart the computer as well.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4134
Short Summary
- Upgrading mods will no longer completely reset their
.csprojfiles, when possible. It's now a safe operation to perform.- All files in the mod template produced by the "Create Mod" dialog have been slightly improved, including the default mod icon.
- Properties like
LangVersion,TargetFramework,PlatformTarget, and theCodeAssistPackageReferenceare removed in favor of coming from the always-importedtModLoader.targets. If you have any edge-cases that this change interferes with - let us know. Conditional groups are currently skipped just in case.
Short Summary
- We've noticed that many mods do not use
Assets<T>as efficiently as they can. These changes and accompanying guides will help modders improve their mod's load times and performance. - A new Assets wiki page has been made to teach modders various guidelines on how to properly use the
Assetclass. - ExampleMod has been updated to follow these new guidelines. It serves as a practical example of the guidelines taught in the Asset wiki page.
- Log messages will warn about mods that spend a long time using
AssetRequestMode.ImmediateLoadduring mod loading. - ShaderData now has a constructor that takes a
Asset<Effect>, allowing for more efficient Shader loading.
Porting Notes
- Please read the new Assets wiki page and apply the guidelines taught within.
- Replace
ShaderDataconstructors with the newAsset<Effect>approach:
Old:
new ArmorShaderData(new Ref<Effect>(Mod.Assets.Request<Effect>("Assets/Effects/ExampleEffect", AssetRequestMode.ImmediateLoad).Value), "ExampleDyePass")
New:
new ArmorShaderData(Mod.Assets.Request<Effect>("Assets/Effects/ExampleEffect"), "ExampleDyePass")
Pull Request: https://github.com/tModLoader/tModLoader/pull/4060
Short Summary: ModProjectile.ModifyFishingLine has been made obsolete and ModItem.ModifyFishingLine has been added to replace it. Basically, the pole item now controls the string position and color instead of the bobber projectile, matching the Terraria behavior.
Porting Notes: Move logic from the bobber projectile's ModProjectile.ModifyFishingLine to the rod item's ModItem.ModifyFishingLine.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4052
Short Summary: Mod.DisplayNameClean property added. Use this when outputting the display names of mods to logs or console window. Also use it if your mod has the ability to search or filter by mod display name, such as a search bar.
Porting Notes: Change Mod.DisplayName to Mod.DisplayNameClean if appropriate.
Pull Request: https://github.com/tModLoader/tModLoader/pull/3943
Short Summary: BuilderToggle now has more functionality, such as custom drawing, ordering, and left and right click methods.
Porting Notes: BuilderToggle.DisplayColorTexture is now obsolete. Use BuilderToggle.Draw/DrawHover instead and modify drawParams.Color.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4053
Short Summary
- Sand tiles and associated falling sand and sandgun projectiles are now natively supported.
- If your mod implemented sand tiles previously they should still work. You can consult ExampleSand to see how it can be done with much cleaner code. Modded sand examples available previously online have slight inconsistencies with bugfixes added in 1.4.4 Terraria, so it might be worth switching to the native approach for exact behavior consistency.
Porting Notes
- If you used reflection to access
WorldGen.SpawnFallingBlockProjectile, it is no longer private and can be called normally.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4087
Short Summary
- TML will no longer interfere in cases where mod developers want to utilize
.hjsonfiles for non-localization needs (such as content and data declarations), as long as the files' names don't begin with language codes (e.g.en-US). - If you're going to make use of this - it's recommended that you use consistent suffixes in your asset enumeration patterns (e.g.
*.weather.hjson,*.data.hjson,*.recipe.hjson), as to not repeat our initial mistake.
Porting Notes
-
LocalizationLoader.(GetCultureAndPrefixFromPath -> TryGetCultureAndPrefixFromPath). Unlikely that anyone used it.
Pull Requests: https://github.com/tModLoader/tModLoader/pull/4088 https://github.com/tModLoader/tModLoader/pull/4089
Short Summary
- Improves mod loading times by up to 10%
- Methods for custom hooks are no longer specified via reflection, and instead use the 'lambda expression' syntax
- The only mods with runtime breakage are those with custom hooks that have
reforoutparameters.
Examples of adding custom hooks (for an imaginary method OnThrow in MyInterface):
// GlobalItem hook
GlobalHookList<GlobalItem> HookOnThrow = ItemLoader.AddModHook(GlobalHookList<GlobalItem>.Create(g => ((MyInterface)g).OnThrow));
// ModPlayer hook
HookList<ModPlayer> HookOnThrow = PlayerLoader.AddModHook(HookList<ModPlayer>.Create(p => ((MyInterface)p).OnThrow));Ping Chicken Bones or Mirsario on Discord if you need help updating your mod or implementing custom hooks.
Pull Request: https://github.com/tModLoader/tModLoader/commit/03a47b82c764e73243aa809f0d033f4dfbaaa793
Short Summary
-
NPCwithknockBackResistvalues of 0 are supposed to be immune to knockback, but the old implementation would apply knockback to NPC ifNPC.HitModifiers.Knockback.Flatwere assigned a value. - This was deemed incorrect, so a
DisableKnockbackmethod was added to disable knockback altogether. It is automatically applied to NPC withknockBackResistvalues of 0
Porting Notes
- If, for some reason, your mod depended on this behavior, you'll have to devise a workaround. This behavior has been deemed incorrect so an easy workaround has not been implemented.
Pull Request: https://github.com/tModLoader/tModLoader/commit/247c77b853aa299c39328d3484ab9e072d4cc1d1
Short Summary: Fixes multiple bobbers causing sonar buff related issues.
Porting Notes: If you are using Projectile.localAI[2] in bobber projectiles, use your own GlobalProjectile field instead. The fix uses it.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4032
Short Summary
-
SetDefaults(0)andTurnToAir()will now setactivetofalseforNPC,ProjectileandItem - Should reduce issues with dummy and despawned entities being assumed
activeby accident, and subsequentGetGlobalcalls failing.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4033
Short Summary
- Outer types will be checked for jit filter attributes such as
[ExtendsFromMod("ModName)"] - This makes it easier to use lambdas which reference types from weakly referenced mods
Short Summary
- A commit has been pushed to
Previewto fix an accidental long-present misbehavior of main menu interfaces being recalculated every frame, with the fix improving performance among other things. - This misbehavior has resulted in some of our recent main menu GUIs being written without proper manual
Recalculate()calls, making them dependent on this bug, as due to it everything looked fine to us in testing.
Porting Notes
- If your mod contains custom user interfaces that get shown in main menu - please ensure that they didn't get borked on preview, and if they did - insert manual
Recalculate()calls when first activating the interface, or when it should be refreshed. As you usually would when writing GUIs.
Example fixes:
PR 3922: Bad Tile Object Data leading to Render Mismatch
Short Summary:
- There was a visual bug with tModLoader that could lead to 'floating' tiles
- Annoyingly, these issues are sometimes caused by incorrect code in the ModTile loading immediately before the 1st affected ModTile, leading to bugs that are hard to track down.
- This PR fixes the issue by resetting the affected fields in CopyFrom. This PR also throws errors in CopyFrom to instruct the modder that their code is not doing what they think it is, and will give you an error while developing your mod if applicable
Bug Fix Commit: NPC.aiStyle now defaults to -1 for modded NPCs
Short Summary:
- ai = -1 is for custom AI applications. The tModLoader code expected to handle -1 as the default, but had been written as zero due to a typo.
- If you had been using aiStyle 0 implicitly by leaving it as default, then you will need to explicitly assign it going forward
Fix 3825: TileDrawing.IsVisible(tile) now public
Short Summary:
- Terraria 1.4.4 added echo tiles and coating, but ExampleMod and other mods have not adapted their code.
- Many mods using
ModTile.PostDrawwill erroneously draw torch flames and spawn dust when the tile is invisible. - Made
TileDrawing.IsVisible(tile)method public, updated ExampleMod to use.
PR 3750: ModConfig.AcceptClientChanges parameters changed.
Short Summary: string parameter replaced with NetworkText parameter for better localization support.
PR 3684: TileID.Sets.CanPlaceNextToNonSolidTile added
Short Summary:
- New
TileID.Sets.CanPlaceNextToNonSolidTile[]which allows players to place tiles next to non-solid tiles. - Allows for the same placement behavior of Cobwebs, Coin Piles, Living Fire Blocks, Smoke Blocks, and Bubble Blocks.
PR 3552 added a proper API for implementing and modifying extra mid-air jumps.
Short Summary:
- Adds
ExtraJump, a singleton type representing an extra jump that is controlled via theExtraJumpStatestructure- The
ExtraJumpStateobject for an extra jump can be obtained via theGetJumpStatemethods inPlayer - Extra jumps can be disabled for the "current update tick" or consumed entirely
-
NOTE:
ExtraJumpState.Disable()will consume the extra jump if it is available and prematurely stops it if it's currently active
-
NOTE:
- The
- Adds new methods related to checking the state of the player's extra jumps to
Player- Also includes a
blockExtraJumpsfield, which prevents any extra jumps from being used, but does not stop the currently active jump nor consume any remaining extra jumps
- Also includes a
- Flipper swimming is now considered an "extra jump" and can be accessed via
Player.GetJumpState(ExtraJump.Flipper) -
Player.sandStormis now more directly related to the state of the Sandstorm in a Bottle extra jump
ExampleMod contains examples for simple and complex extra jumps, as well as an example for modifying an extra jump.
The PR's original comment contains snippets for enabling/disabling an extra jump, temporarily disabling extra jumps in a ModBuff and changing the horizontal movement modifications for an extra jump.
Porting Notes:
-
Player.hasJumpOption_X,Player.canJumpAgain_XandPlayer.isPerformingJump_Xfor all vanilla jumps are now accessed via theExtraJumpStatefor the respective extra jump- If you were setting one or more of these fields to
falsein order to disable the extra jump, useExtraJumpState.Disable()instead - If you were disabling all extra jumps:
- Set
Player.blockExtraJumps = true;for temporary disabling - Call
Player.ConsumeAllExtraJumps()(optionally followed byPlayer.StopExtraJumpInProgress()) for permanent disabling until the player lands
- Set
- If you were setting one or more of these fields to
-
Player.accFlipperandPlayer.sandStormare now properties, so any code that was using them will have to be rebuilt
PR 3453 reworks NPC buff immunities
Short Summary:
- Replace
NPCID.Sets.DebuffImmunitySetswithNPCID.Sets.SpecificDebuffImmunity,NPCID.Sets.ImmuneToAllBuffs, andNPCID.Sets.ImmuneToRegularBuffsto simplify modder code. - Added buff immunity inheritance through the
BuffID.Sets.GrantImmunityWithset and corresponding methods.
Porting Notes:
- If your mod has any NPCs or does anything with buff immunity, you'll need to update their buff immunity code. Read the Porting Notes section of PR 3453.
- Mods should consider using the new buff immunity inheritance system for buff inheritance compatibility.
PR 3770: Rename (Mod|Global)Projectile.Kill hook to OnKill
Short Summary: (Mod|Global)Projectile.Kill renamed to OnKill to better match the behavior and other similar hooks.
Porting Notes: Run tModPorter or rename usages of (Mod|Global)Projectile.Kill to OnKill
PR 3759: ModPlayer.OnPickup hook
Short Summary:
- Adds
ModPlayer.OnPickupwhich functions the same as theGlobalItemhook. - The hook has been added for convenience, to reduce the need to make a separate
GlobalItemclass when many of the effects modders want to make are stored on aModPlayerinstance
PR 3746: Add modded world header data
Short Summary:
- Modded world data can be now be saved into a 'header' in the .twld file. The header can be read without deserializing the entire .twld file, and the modded data is accessible in the world select menu and during vanilla world loading.
- The list of mods the world was last played with is now shown in the world select menu, just like for players
- The list of mods (and version of those mods) the world was generated with is now stored in the header. Only applies to worlds generated in the future of course.
See PR 3746 for more details and usage examples
PR 2918: Modded Emote Bubble
Short Summary:
- Modders can now make custom emotes
- Modders can adjust how NPC pick emotes
- ExampleMod shows off several custom emotes and custom emote spawning
PR 3731: Modded Builder Toggles
Short Summary: Modders can now make builder toggles, which are those small icons top left of the inventory that are used for block swap, wire visibility, etc.
Porting Notes: If you previously made builders toggles using your own approach, use the tModLoader approach.
PR 3710: Better Changelogs
Short Summary: Expand ChangeLog functionality
Porting Notes:
- tModLoader no longer adds it's own text when a changelog.txt is provided. We recommend adding to your own changelog.txt files based on ExampleMod's changelog.txt
- All 4 fields in the example, such as
{ModVersion}, are replaced with the info from tModLoader during publishing for convenience.
PR 3568: Rubblemaker support
Short Summary: Modders can now add tiles to the Rubblemaker
ItemID.Sets.IsSpaceGunaddedGlobalInfoDisplay.ModifyDisplayParametersreplacesModifyDisplayValue/ModifyDisplayName/ModifyDisplayColorGenPass.DisableandGenPass.EnabledTooltipLine.HideandTooltipLine.VisibleModTree.Shake'screateLeavesparameter now defaults totrue- Automatic TranslationsNeeded.txt feature
GlobalInfoDisplay.ModifyDisplayColorhas newdisplayShadowColorparameterDamageClassLoader.GetDamageClassaddedTileRestingInfoconstructor changedModTile.IsTileBiomeSightablehookSceneMetrics.GetLiquidCountaddedNPCID.Sets.BelongsToInvasionGoblinArmy/BelongsToInvasionFrostLegion/BelongsToInvasionPirate/BelongsToInvasionMartianMadness/NoInvasionMusic/InvasionSlotCountaddedArmorIDs.Head.Sets.IsTallHataddedGoreID.Sets.PaintedFallingLeafadded- All
LocalizationCategoryimplementations now virtual
The tModLoader team took advantage of the release of Terraria 1.4.4.9 to implement a wide variety of breaking changes. These changes are large features that have been highly requested from the community. The extent of the changes, as well as changes in Terraria, are so large that all mods will need to update to continue working on 1.4.4. tModLoader for 1.4.3 will continue to be available to users as the 1.4.3-legacy steam beta option. If a modder intends to continue updating their mod for 1.4.3 users, they should use backups or Git to maintain copies of their source code for 1.4.3 and 1.4.4.
This migration guide assumes the mod has already been migrated to 1.4.3. If that is not the case, do that first.
The first step in migrating to 1.4.4 is following the Localization Changes section below. Once that is done, switch to the None branch on steam by following the instructions. Launch tModLoader, make sure it says Terraria v1.4.4.9 and tModLoader v2023.6.x.y in the corner. Next, visit the Workshop->Develop Mods menu in game and click on the "Run tModPorter" button. After that completed, you are ready to open Visual Studio and begin working on updating parts of the code that tModPorter either couldn't port or left a comment with instructions (to find all comments, first, go to Tools -> Options -> Environment -> Task List, and add tModPorter as a custom token. Then close it, and opening View -> Task List will list all comments, where you can also use the search bar to filter specific comments). As 1.4.4 continues to update, you might need to "Run tModPorter" again if an update breaks something.
The largest change to tModLoader is that localization is now done fully in the .hjson localization files. You MUST follow the Migrating from 1.4.3 to 1.4.4 instructions. Failure to do this step will make porting a mod extremely tedious. More details can be found in Localization Changes details.
Terraria 1.4.4 has many new features and changes. The 1.4.4 changelog details these changes. Modders should be aware of the changes in case they would impact the balance or functionality of their mods. For example, NPC can now have 20 buffs and Player can now have 44 buffs by default.
Of specific note is the Shimmer, modders should consider how content in their mod would interact with the Shimmer. ExampleMod contains examples of various shimmer features, such as transforming NPC, decrafting examples, and transforming items.
-
ModWaterStylenow requires an additional texture,_Slope. SeeExampleWaterStylefor details. -
GrantPrefixBenefitsis only called ifItem.accessoryistrue. This applies in mod accessory slots too now. - Reforging is now implemented via
Item.ResetPrefix. This setsprefixto 0 and then refreshes the item. Make sure any custom fields set by custom prefixes are not serialized independently.
All of the changes in this section will be handled by tModPorter and are listed here for completeness. Modders can skip this section and go directly to Big change concepts to see the changes that require the modder to make big changes to their mod.
-
GameContent.UI.ResourceSets.HorizontalBarsPlayerReosurcesDisplaySet->GameContent.UI.ResourceSets.HorizontalBarsPlayerResourcesDisplaySet
-
NetMessage.SendObjectPlacment->NetMessage.SendObjectPlacement
-
ID.TileID.Sets.TouchDamageSands->ID.TileID.Sets.Suffocate -
ID.TileID.Sets.TouchDamageOther->ID.TileID.Sets.TouchDamageImmediateand possiblyID.TileID.Sets.TouchDamageBleeding -
ID.TileID.Sets.TouchDamageVines->ID.TileID.Sets.TouchDamageImmediateandID.TileID.Sets.TouchDamageDestroyTile -
DustID.Fire->DustID.Torch -
MessageID.SendNPCBuffs->MessageID.NPCBuffs -
MessageID.Unlock->MessageID.LockAndUnlock -
MessageID.StartPlaying->MessageID.InitialSpawn -
MessageID.SpawnBoss->MessageID.SpawnBossUseLicenseStartEvent -
MessageID.Teleport->MessageID.TeleportEntity -
MessageID.ClientHello->MessageID.Hello -
MessageID.LoadPlayer->MessageID.PlayerInfo -
MessageID.RequestWorldInfo->MessageID.RequestWorldData -
MessageID.RequestTileData->MessageID.SpawnTileData -
MessageID.StatusText->MessageID.StatusTextSize -
MessageID.FrameSection->MessageID.TileFrameSection -
MessageID.SpawnPlayer->MessageID.PlayerSpawn -
MessageID.PlayerHealth->MessageID.PlayerLifeMana -
MessageID.TileChange->MessageID.TileManipulation -
MessageID.MenuSunMoon->MessageID.SetTime -
MessageID.ChangeDoor->MessageID.ToggleDoorState -
MessageID.UnusedStrikeNPC->MessageID.UnusedMeleeStrike -
MessageID.StrikeNPC->MessageID.DamageNPC -
MessageID.PlayerPVP->MessageID.TogglePVP -
MessageID.HealEffect->MessageID.PlayerHeal -
MessageID.PlayerZone->MessageID.SyncPlayerZone -
MessageID.ResetItemOwner->MessageID.ReleaseItemOwnership -
MessageID.PlayerTalkingNPC->MessageID.SyncTalkNPC -
MessageID.ItemAnimation->MessageID.ShotAnimationAndSound -
MessageID.MurderSomeoneElsesProjectile->MessageID.MurderSomeoneElsesPortal -
Main.fastForwardTime-> Removed, useIsFastForwardingTime(),fastForwardTimeToDawnorfastForwardTimeToDusk - The following all change from
Terraria.WorldGentoTerraria.WorldBuilding.GenVars:configuration,structures,copper,iron,silver,gold,copperBar,ironBar,silverBar,goldBar,mossTile,mossWall,lavaLine,waterLine,worldSurfaceLow,worldSurface,worldSurfaceHigh,rockLayerLow,rockLayer,rockLayerHigh,snowTop,snowBottom,snowOriginLeft,snowOriginRight,snowMinX,snowMaxX,leftBeachEnd,rightBeachStart,beachBordersWidth,beachSandRandomCenter,beachSandRandomWidthRange,beachSandDungeonExtraWidth,beachSandJungleExtraWidth,shellStartXLeft,shellStartYLeft,shellStartXRight,shellStartYRight,oceanWaterStartRandomMin,oceanWaterStartRandomMax,oceanWaterForcedJungleLength,evilBiomeBeachAvoidance,evilBiomeAvoidanceMidFixer,lakesBeachAvoidance,smallHolesBeachAvoidance,surfaceCavesBeachAvoidance2,maxOceanCaveTreasure,numOceanCaveTreasure,oceanCaveTreasure,skipDesertTileCheck,UndergroundDesertLocation,UndergroundDesertHiveLocation,desertHiveHigh,desertHiveLow,desertHiveLeft,desertHiveRight,numLarva,larvaY,larvaX,numPyr,PyrX,PyrY,jungleOriginX,jungleMinX,jungleMaxX,JungleX,jungleHut,mudWall,JungleItemCount,JChestX,JChestY,numJChests,tLeft,tRight,tTop,tBottom,tRooms,lAltarX,lAltarY,dungeonSide,dungeonLocation,dungeonLake,crackedType,dungeonX,dungeonY,lastDungeonHall,maxDRooms,numDRooms,dRoomX,dRoomY,dRoomSize,dRoomTreasure,dRoomL,dRoomR,dRoomT,dRoomB,numDDoors,DDoorX,DDoorY,DDoorPos,numDungeonPlatforms,dungeonPlatformX,dungeonPlatformY,dEnteranceX,dSurface,dxStrength1,dyStrength1,dxStrength2,dyStrength2,dMinX,dMaxX,dMinY,dMaxY,skyLakes,generatedShadowKey,numIslandHouses,skyLake,floatingIslandHouseX,floatingIslandHouseY,floatingIslandStyle,numMCaves,mCaveX,mCaveY,maxTunnels,numTunnels,tunnelX,maxOrePatch,numOrePatch,orePatchX,maxMushroomBiomes,numMushroomBiomes,mushroomBiomesPosition,logX,logY,maxLakes,numLakes,LakeX,maxOasis,numOasis,oasisPosition,oasisWidth,oasisHeight,hellChest,hellChestItem,statueList,StatuesWithTraps -
WorldGen.houseCount->WorldBuilding.GenVars.skyIslandHouseCount
-
UI.UIElement.MouseDown->UI.UIElement.LeftMouseDown -
UI.UIElement.MouseUp->UI.UIElement.LeftMouseUp -
UI.UIElement.Click->UI.UIElement.LeftClick -
UI.UIElement.DoubleClick->UI.UIElement.LeftDoubleClick -
Player.VanillaUpdateEquip-> Removed, use eitherGrantPrefixBenefits(ifItem.accessory) orGrantArmorBenefits(for armor slots) -
Player.IsAValidEquipmentSlotForIteration->Player.IsItemSlotUnlockedAndUsable -
Item.DefaultToPlacableWall->Item.DefaultToPlaceableWall
-
UI.UIElement.OnMouseDown->UI.UIElement.OnLeftMouseDown -
UI.UIElement.OnMouseUp->UI.UIElement.OnLeftMouseUp -
UI.UIElement.OnClick->UI.UIElement.OnLeftClick -
UI.UIElement.OnDoubleClick->UI.UIElement.OnLeftDoubleClick -
Player.discount->Player.discountAvailable -
Item.canBePlacedInVanityRegardlessOfConditions->Item.hasVanityEffects
The following contains smaller scale changes to tModLoader members. More elaborate changes are handled in separate categories below.
-
ModTile.OpenDoorIDremoved, useTileID.Sets.OpenDoorIDinstead -
ModTile.CloseDoorIDremoved, useTileID.Sets.CloseDoorIDinstead -
NPCSpawnInfo.PlanteraDefeatedremoved, use(NPC.downedPlantBoss && Main.hardMode)instead -
ModNPC.ScaleExpertStats->ModNPC.ApplyDifficultyAndPlayerScaling, parameters changed.bossLifeScale->balance(bossAdjustmentis different, see the docs for details) -
GlobalNPC.ScaleExpertStats->GlobalNPC.ApplyDifficultyAndPlayerScaling, parameters changed.bossLifeScale->balance(bossAdjustmentis different, see the docs for details) -
ModNPC.CanTownNPCSpawnparameters changed, copy the implementation ofNPC.SpawnAllowed_Merchantin vanilla if you to count money, and be sure to set a flag when unlocked, so you don't count every tick -
ModItem.SacrificeTotal->Item.ResearchUnlockCount -
ModItem.OnCreate->ModItem.OnCreated -
GlobalItem.OnCreate->GlobalItem.OnCreated -
ModItem.CanBurnInLava-> UseItemID.Sets.IsLavaImmuneRegardlessOfRarityor add a method hook toOn_Item.CheckLavaDeath -
GlobalItem.CanBurnInLava-> UseItemID.Sets.IsLavaImmuneRegardlessOfRarityor add a method hook toOn_Item.CheckLavaDeath -
ModItem.ExtractinatorUseparameters changed -
GlobalItem.ExtractinatorUseparameters changed -
Player.QuickSpawnClonedItem->Player.QuickSpawnItem -
ModPlayer.clientClone-> Renamed toCopyClientStateand replaceItem.Cloneusages withItem.CopyNetStateTo -
ModPlayer.PlayerConnectparameters changed -
ModPlayer.PlayerDisconnectparameters changed -
ModPlayer.OnEnterWorldparameters changed -
ModPlayer.OnRespawnparameters changed -
ModTree.GrowthFXGore->ModTree.TreeLeaf -
Terraria.DataStructures.BossBarDrawParams.LifePercentToShowremoved, useLife / LifeMaxinstead -
Terraria.DataStructures.BossBarDrawParams.ShieldPercentToShowremoved, useShield / ShieldMaxinstead -
ModBossBar.ModifyInfolife and shield current and max values are now separate to allow for hp/shield number text draw -
ModItem/GlobalItem.ModifyHitNPC/OnHitNPC/ModifyHitPvp/OnHitPvp-> See Player/NPC damage hooks rework section below -
ModNPC/GlobalNPC.HitEffect/ModifyHitPlayer/OnHitPlayer/ModifyHitNPC/OnHitNPC/ModifyHitByItem/OnHitByItem/ModifyHitByProjectile/OnHitByProjectile/ModifyIncomingHit/ModifyCollisionData/StrikeNPC-> See Player/NPC damage hooks rework section below -
ModProjectile/GlobalProjectile.ModifyHitNPC/OnHitNPC/ModifyHitPlayer/OnHitPlayer/ModifyDamageScaling-> See Player/NPC damage hooks rework section below -
ModPlayer.ModifyHurt/OnHurt/PostHurt/ModifyHitNPCWithItem/OnHitNPCWithItem/ModifyHitNPCWithProj/OnHitNPCWithProj/ModifyHitByNPC/OnHitByNPC/ModifyHitByProjectile/OnHitByProjectile/CanHitNPC/ModifyHitNPC/OnHitNPC/PreHurt/Hurt-> See Player/NPC damage hooks rework section below -
ModProjectile.SingleGrappleHook-> inSetStaticDefaults, useProjectileID.Sets.SingleGrappleHook[Type] = trueif you previously had this method return true -
GlobalProjectile.SingleGrappleHook-> inSetStaticDefaults, useProjectileID.Sets.SingleGrappleHook[Type] = trueif you previously had this method return true -
ModPrefix.AutoStaticDefaults-> Nothing to override anymore. Use hjson files and/or override DisplayName to adjust localization -
ModPrefix.ValidateItem->ModPrefix.AllStatChangesHaveEffectOn -
ModSystem.SetLanguage-> UseOnLocalizationsLoaded. New hook is called at slightly different times, so read the documentation -
ModSystem.ModifyWorldGenTasksparameters changed -
ModLoader.ItemCreationContext->DataStructures.ItemCreationContext -
ModLoader.RecipeCreationContext->DataStructures.RecipeItemCreationContext -
ModLoader.InitializationContext->ModLoader.InitializationItemCreationContext -
Terraria.Recipe.Condition->Terraria.Condition -
Condition.InGraveyardBiome->Condition.InGraveyard -
Item.IsCandidateForReforgeremoved, usemaxStack == 1 || Item.AllowReforgeForStackableItemorItem.Prefix(-3)to check whether an item is reforgeable -
Item.CloneWithModdedDataFromremoved, useClone,ResetPrefixorRefresh -
ModLoader.Mod.CreateTranslationremoved, useLocalization.Language.GetOrRegister. See Localization Changes Details below. -
ModLoader.Mod.AddTranslationremoved, useLocalization.Language.GetOrRegister. See Localization Changes Details below. -
ModLoader.ModTranslationremoved, useLocalization.LocalizedTextinstead. See Localization Changes Details below. -
InfoDisplay.InfoName->InfoDisplay.DisplayName -
InfoDisplay.DisplayValue-> suggestion: Set displayColor to InactiveInfoTextColor if your display value is "zero" or shows no valuable information -
DamageClass.ClassName->DamageClass.DisplayName -
GlobalTile.Drop/CanDropandModTile.Drop/CanDrop-> These methods changed drastically. See Tile Drop Changes for more information. -
ModTile.ChestDrop-> Now useItemDrop, if needed. See Tile Drop Changes for more information. -
ModTile.DresserDrop-> Now useItemDrop, if needed. See Tile Drop Changes for more information. -
ModTile.ContainerName-> Removed, overrideDefaultContainerNameinstead -
TileLoader.ContainerName->TileLoader.DefaultContainerName, parameters changed -
ModBuff.ModifyBuffTip->ModBuff.ModifyBuffText, parameters changed -
GlobalBuff.ModifyBuffTip->GlobalBuff.ModifyBuffText, parameters changed -
ModNPC/GlobalNPC.DrawTownAttackSwing-> Parameters changed -
ModNPC/GlobalNPC.DrawTownAttackGun-> Parameters changed.closenessis nowhorizontalHoldoutOffset, usehorizontalHoldoutOffset = Main.DrawPlayerItemPos(1f, itemtype) - originalClosenessValueto adjust to the change. See docs for how to use hook with an item type. -
ModNPC/GlobalNPC.SetupShop->ModifyActiveShop. Shops have drastically changed, see Shop Changes for more information. -
ModNPC.OnChatButtonClicked-> Parameters changed -
ModNPC.ModifyActiveShop-> Parameters changed. Shops have drastically changed, see Shop Changes for more information. -
GlobalNPC.ModifyActiveShop-> Parameters changed. Shops have drastically changed, see Shop Changes for more information. -
ModPylon.GetNPCShopEntry-> Parameters changed. Shops have drastically changed, see Shop Changes for more information. -
ModPylon.IsPylonForSale->ModPylon.GetNPCShopEntry, see ExamplePylonTile for an example. To register to specific NPC shops, use the new shop system directly in ModNPC.AddShop, GlobalNPC.ModifyShop or ModSystem.PostAddRecipes -
ModItem/GlobalItem.PreReforgereturn type changed frombooltovoid, no longer used to prevent reforging. UseCanReforgefor that purpose. -
Player.CanBuyItemremoved, usePlayer.CanAffordinstead. Note that the method will no longer mistakenly attempt to consume custom currencies. -
Player.rocketDamage->Player.specialistDamage -
AmmoID.Sets.IsRocket->AmmoID.Sets.IsSpecialist -
ModPrefix.GetTooltipLinesadded. Some modders might want to move prefix specific tooltip lines fromGlobalItem.ModifyTooltipsto it for better code maintainability. -
Mods.{ModName}.TownNPCMood.{NPCName}.*localization entries relocated toMods.{ModName}.NPCs.{NPCName}.TownNPCMood.*. See the porting notes in PR 3446 for more information. -
ModItem.AutoLightSelectremoved. See the porting notes in PR 3479 for more information on how to adapt to this change. -
Player.BiomeTorchPlaceStyleandPlayer.BiomeCampfirePlaceStyleparameters changed
Issue 3074 contains the proposed changes.
PR 3101 contains the actual changes, as well as ExampleMod changes.
PR 3302 contains additional changes specific to ModConfig.
Localization explains localization and porting instructions for modders.
Contributing Localization contains instructions for translators and translation mod makers.
Short Summary:
- Translations are now fully in localization files (.hjson files).
ModItem.DisplayNameandModItem.Tooltip, for example, can no longer be assigned in code.-
ModConfigis now fully localizable by default. (See PR #3302 for more information)
-
- Localization files are automatically updated with entries for new content and managed by tModLoader. More organization options available.
- New content will appear in localization files after loading. Edits to .hjson files will be detected by tModLoader and loaded into the game as soon as they are saved, allowing modders and translators to quickly test and update translations.
- All
ModTranslationusages are now replaced withLocalizedText - All translation keys now follow a more predictable pattern:
Mods.ModName.Category.ContentName.DataName - Contributing translations, directly or through translation mods, has been streamlined.
Porting Notes:
- Modders MUST follow the Migrating from 1.4.3 to 1.4.4 section in the localization guide on the wiki prior to attempting to update a mod on
1.4.4tModLoader. - Modders with hardcoded values in localization files, such as "10% increased melee damage", "5 armor penetration", etc should consider updating their code to have less duplication by following the Binding Values to Localizations section on the wiki.
- ExampleStatBonusAccessory showcases our recommended approach for writing clean and maintainable item tooltips. In the example, all the numbers denoting the effects of the accessory only exist in code, not in both code and translation files. Most notably with this new approach, there is no risk of the tooltip and actual behavior being out of sync. Previously a modder could update an accessory but forget to update the tooltip, or forget to update tooltips for other languages, resulting in items that behave differently than how they claim to behave.
-
AbsorbTeamDamageBuff, AbsorbTeamDamageAccessory, and ExampleDamageModificationPlayer further build on this idea. In these examples, the actual damage absorption stat,
DamageAbsorptionPercent(set to 30), only exists inAbsorbTeamDamageAccessory.AbsorbTeamDamageBuffreferences that value for the buff tooltip viapublic override LocalizedText Description => base.Description.WithFormatArgs(AbsorbTeamDamageAccessory.DamageAbsorptionPercent);.AbsorbTeamDamageAccessoryalso references the value in it's own tooltip.ExampleDamageModificationPlayeralso references that value inModifyHurtandOnHurtvia theDamageAbsorptionMultiplierproperty. If the modder wished to change this accessory to absorb 35% of damage instead of 30% of damage, the modder would only need to change the value in 1 place, rather than several places in multiple.csand.hjsonfiles. This shows the power of properly using localization files and binding values to them.
-
ModConfigis now localized by default, see the porting notes section of PR #3302 for porting information specific toModConfig.
PR 3212, PR 3355, and PR 3359 drastically changes how player and npc hit hooks are structured.
Short Summary:
Player and NPC hit hooks (OnHit, ModifyHit, OnHitBy, etc) have been simplified with common architecture, and had many new features added.
The goal of this change is to improve mod compatibility by making the damage calculations an explicit equation, where mods contribute modifiers, and tModLoader calculates the result.
Many examples of how to make hit/hurt modifying accessories and weapon effects have been added, demonstrating the new system.
-
ExampleDodgeBuff/ExampleDamageModificationPlayer:
ConsumableDodgeexample, similar to - ExampleDefenseDebuff: Multiplicative defense debuff, similar to Broken Armor
- AbsorbTeamDamageAccessory/AbsorbTeamDamageBuff/ExampleDamageModificationPlayer: Damage absorption example, similar to Paladins Shield item.
-
HitModifiersShowcase: Extensive examples of new
ModifyHitNPCandOnHitNPChooks. Disable damage variation, modify knockback, modify crit bonus damage, flat armor penetration, percentage armor penetration, etc examples. - ExampleWhipDebuff and ExampleWhipAdvancedDebuff: Show proper tag damage, both flat and scaling varieties.
- PartyZombie: Shows an NPC that is "resistant" to a specific damage class, taking less damage
-
ExampleAdvancedFlailProjectile: Shows ModifyDamageScaling replacement, as well as proper usage of various
HitModifiersfields and properties to scale damage and knockback dynamically. - ExamplePaperAirplaneProjectile: Shows a projectile dealing bonus damage to an npc that is weak to it.
tModPorter will be able to convert the hook signatures, but you will need to read the Porting Notes (in particular the FAQ), to figure out how to convert old damage modification code into the new system.
Porting Notes:
Too many to write here, please read the PR descriptions if you have questions after running tModPorter.
PR 3219 has changed how NPC shops are done.
Short Summary:
- NPC shops are now declarative, meaning they get registered, and items can be added to them with conditions, similarly to NPC drops (loot) and recipes
- Adding items to shops, or hiding items from shops is now as easy as adding or disabling recipes
- Info mods can traverse the NPCShopDatabase to show how to obtain an item. All the conditions for items appearing in shops have been localized.
- Registering multiple shops per NPC is perfectly fine, and selecting the shop to be opened when chatting can now be done via the ref string shop parameter in OnChatButtonClicked
Porting Notes:
-
ModPylon.IsPylonForSalehas been replaced byModPylon.GetNPCShopEntry. Please see the documentation and ExamplePylonTile -
Mod/GlobalNPC.SetupShopis nowModifyActiveShop. This hook still exists to allow for custom shop modification, but you should consider moving to the newModNPC.AddShopsandGlobalNPC.ModifyShophooks - The
Item[]inModifyActiveShopwill now contain null entries. This distinguishes slots which have not been filled, from slots which are intentionally left empty (as in the case of DD2 Bartender) - Please take a look at the changes to Example Mod in the PR to more easily understand the new system.
PR 3210 has changed how tiles drop items.
Short Summary:
- Tiles and walls now automatically drop the items that place it. This process supports tiles with multiple styles.
- Block Swap feature now supports modded torches, chests, and drawers.
- Other miscellaneous fixes.
Porting Notes:
- The vast majority of
ModTile.KillMultitilecode andModTile.Dropcode can be deleted or simplified by following the porting notes. - All mods with any
ModTilemust follow the porting notes, failure to adjust your code for this major change will result in duplicate drops. - There are too many changes to write here. Please read the Porting Notes section in the Pull Request after running tModPorter.
PR 3174 has added new approaches to Player.clientClone to improve performance.
Short Summary:
Item.Clone can become very performance expensive with many mods. Only type, stack and prefix are required to tell if an item has changed in the inventory and needs to be re-synced.
This PR replaces usages of Item.Clone in Player.clientClone with Item.CopyNetStateTo. Additionally, a single Player (and ModPlayer) instance is reused for all clientClone/CopyClientState calls, acting as a 'storage copy' rather than making a new one each frame.
Please note that tModPorter is not smart enough to identify Item.Clone usages in ModPlayer.CopyClientState calls automatically. You will need to replace these yourself or an exception will be thrown at runtime.
Porting Notes:
-
ModPlayer.clientClone->ModPlayer.CopyClientState - Use
Item.CopyNetStateToinstead ofItem.CloneinModPlayer.CopyClientState - Use
Item.IsNetStateDifferentinstead ofItem.IsNotSameTypePrefixAndStackinModPlayer.SendClientChanges - Item instances altered by
CopyNetStateToare not initialized! Do not attempt to read properties or retrieveModItemorGlobalIteminstances from them! The only valid operation on anItemwhich was updated withCopyNetStateToisIsNetStateDifferent
HoldStyleShowcase, HitModifiersShowcase, and UseStyleShowcase briefly show usage of Item.NetStateChanged(); to trigger an item to sync.
PR 2909 greatly changed the API for modifying the player's max health and mana, rendering custom sprites over the player's hearts and mana stars and even added an API for creating custom display sets.
Short Summary:
- Adds
ModPlayer.ModifyMaxStatswithStatModifierarguments for permanent adjustments to max health/mana- While this hook is intended to be used for permanent stat adjustments, it can also easily support temporary adjustments as well
- However, do note that this hook runs very early in the player update logic. It runs shortly after
ModPlayer.ResetEffects- Temporary adjustments that rely on buffs or other player variables affected by armor, accessories, etc. should still use the old method of modifying
Player.statLifeMax2in one of the update hooks inModPlayer
- Temporary adjustments that rely on buffs or other player variables affected by armor, accessories, etc. should still use the old method of modifying
- Adds
Player.ConsumedLifeCrystals,ConsumedLifeFruitandConsumedManaCrystalsproperties- These properties are directly tied to the vanilla stat increases and can also be manually set by modders
- Adds helper methods
Player.UseHealthMaxIncreasingItemandPlayer.UseManaMaxIncreasingItemfor displaying the visual effects - Adds
ModResourceDisplaySetallowing for custom life/mana draw styles (similar to boss bar styles) that can be selected in settings - Adds
ModResourceOverlayto allow for drawing custom hearts/mana/effects over the vanilla (or modded) life/mana UI elements
ExampleMod contains examples for a custom display set and custom resource overlays.
ExampleStatIncreasePlayer, ExampleLifeFruit and ExampleManaCrystal showcase how to handle permanent stat increases.
Porting Notes:
- Refer to
ExampleStatIncreasePlayer,ExampleLifeFruitandExampleManaCrystalon how to properly set permanent stat increases - Temporary stat increases to
Player.statLifeMax2andPlayer.statManaMax2can still be performed as usual- Though they should not be changed in
ModPlayer.ModifyMaxStats, since that runs too early for the changes to be kept
- Though they should not be changed in
- Use
Player.ConsumedLifeCrystals,Player.ConsumedLifeFruitandPlayer.ConsumedManaCrystalsinstead of checkingPlayer.statLifeMaxorPlayer.statManaMaxdue to the stat fields being adjustable by mods
PR 3063: Fix Quick Heal and Quick Mana consuming non-consumables
Short Summary: Adds item.consumable as a check in Quick Heal and Quick Mana.
Porting Notes: For Quick heal, Quick Mana non-consummables, it is recommended to use Item.consumable field instead of overriding ConsumeItem()
PR 3360: Add ModSystem.ClearWorld
Short Summary: Adds ModSystem.ClearWorld which runs on world clear. The new best place to clear/initialize world related data structures.
Porting Notes: Consider replacing overrides of OnWorldLoad with ClearWorld to reset world related data. Generally no need to override OnWorldUnload anymore. Use Unload if you want to fully clean up all memory, but empty lists are nothing to worry about.
PR 3341: Unify Localized Conditions
Short Summary: Terraria.Recipe.Condition has been moved to Terraria.Condition and can now be applied to more things. Recipes, item variants, drops and shops. Added SimpleItemDropRuleCondition class to help make drop conditions more easily.
Porting Notes: Terraria.Recipe.Condition -> Terraria.Condition (tModPorter). Recipe parameter removed from condition delegate, since it was almost always unused. Custom conditions will have to change from _ => calculation or recipe => calculation to () => calculation
Commit 56f6657: Change HookGen Namespace Style
Short Summary:
- Hookgen namespaces (
IL.andOn.) have been removed in favor ofOn_andIL_prepended to the type name. - No longer will you get 3 different namespace suggestions when you use VS to import a Terraria type name.
- Want On Item hooks? Just use
On_Itemit's in the same namespace asItem!
Porting Notes:
-
On.Terraria.Player->Terraria.On_Player -
IL.Terraria.Player->Terraria.IL_Player - As usual, tModPorter can convert your old code automatically.
PR 3242: Default Research Unlock Value changed to 1
Short Summary:
- All items will now default to needing 1 item to research.
- The previous value of 0 left items unresearchable since many modders don't bother to implement journey mode features
- Modders can clean up their code:
-
ModItem.SacrificeTotalhas been removed and tModPorter should have changed it toItem.ResearchUnlockCountalready. -
CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = #;lines can be changed toItem.ResearchUnlockCount = #; -
ModItems withItem.ResearchUnlockCount = 1;orCreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 1;lines can be deleted, since the default is 1.
-
Porting Notes:
- This is almost entirely optional. The only thing is
ModItems that should never exist in the inventory, or should otherwise not be researchable, now needItem.ResearchUnlockCount = 0;added where previously, they would be unsearchable by default. (Note:CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = 0;will result in bugs, useItem.ResearchUnlockCount = 0;) - Modders might consider using this opportunity to add research values matching vanilla values to their
ModItem: Journey Mode Research wiki page.