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
- 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.
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. 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 Mods
menu and click theUpgrade
button 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.1
or earlier - you'll need to run a command for a continued smooth experience. PressWin + R
, pastesetx DOTNET_EnableWriteXorExecute 0
in 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.
Pull Request: https://github.com/tModLoader/tModLoader/pull/4134
Short Summary
- Upgrading mods will no longer completely reset their
.csproj
files, 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 theCodeAssist
PackageReference
are 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
Asset
class. - 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.ImmediateLoad
during 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
ShaderData
constructors 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
.hjson
files 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
ref
orout
parameters.
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
-
NPC
withknockBackResist
values of 0 are supposed to be immune to knockback, but the old implementation would apply knockback to NPC ifNPC.HitModifiers.Knockback.Flat
were assigned a value. - This was deemed incorrect, so a
DisableKnockback
method was added to disable knockback altogether. It is automatically applied to NPC withknockBackResist
values 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 setactive
tofalse
forNPC
,Projectile
andItem
- Should reduce issues with dummy and despawned entities being assumed
active
by accident, and subsequentGetGlobal
calls 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
Preview
to 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.PostDraw
will 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 theExtraJumpState
structure- The
ExtraJumpState
object for an extra jump can be obtained via theGetJumpState
methods 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
blockExtraJumps
field, 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.sandStorm
is 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_X
andPlayer.isPerformingJump_X
for all vanilla jumps are now accessed via theExtraJumpState
for the respective extra jump- If you were setting one or more of these fields to
false
in 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.accFlipper
andPlayer.sandStorm
are 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.DebuffImmunitySets
withNPCID.Sets.SpecificDebuffImmunity
,NPCID.Sets.ImmuneToAllBuffs
, andNPCID.Sets.ImmuneToRegularBuffs
to simplify modder code. - Added buff immunity inheritance through the
BuffID.Sets.GrantImmunityWith
set 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.OnPickup
which functions the same as theGlobalItem
hook. - The hook has been added for convenience, to reduce the need to make a separate
GlobalItem
class when many of the effects modders want to make are stored on aModPlayer
instance
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.IsSpaceGun
addedGlobalInfoDisplay.ModifyDisplayParameters
replacesModifyDisplayValue
/ModifyDisplayName
/ModifyDisplayColor
GenPass.Disable
andGenPass.Enabled
TooltipLine.Hide
andTooltipLine.Visible
ModTree.Shake
'screateLeaves
parameter now defaults totrue
- Automatic TranslationsNeeded.txt feature
GlobalInfoDisplay.ModifyDisplayColor
has newdisplayShadowColor
parameterDamageClassLoader.GetDamageClass
addedTileRestingInfo
constructor changedModTile.IsTileBiomeSightable
hookSceneMetrics.GetLiquidCount
addedNPCID.Sets.BelongsToInvasionGoblinArmy
/BelongsToInvasionFrostLegion
/BelongsToInvasionPirate
/BelongsToInvasionMartianMadness
/NoInvasionMusic
/InvasionSlotCount
addedArmorIDs.Head.Sets.IsTallHat
addedGoreID.Sets.PaintedFallingLeaf
added- All
LocalizationCategory
implementations 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.
-
ModWaterStyle
now requires an additional texture,_Slope
. SeeExampleWaterStyle
for details. -
GrantPrefixBenefits
is only called ifItem.accessory
istrue
. This applies in mod accessory slots too now. - Reforging is now implemented via
Item.ResetPrefix
. This setsprefix
to 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.TouchDamageImmediate
and possiblyID.TileID.Sets.TouchDamageBleeding
-
ID.TileID.Sets.TouchDamageVines
->ID.TileID.Sets.TouchDamageImmediate
andID.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()
,fastForwardTimeToDawn
orfastForwardTimeToDusk
- The following all change from
Terraria.WorldGen
toTerraria.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.OpenDoorID
removed, useTileID.Sets.OpenDoorID
instead -
ModTile.CloseDoorID
removed, useTileID.Sets.CloseDoorID
instead -
NPCSpawnInfo.PlanteraDefeated
removed, use(NPC.downedPlantBoss && Main.hardMode)
instead -
ModNPC.ScaleExpertStats
->ModNPC.ApplyDifficultyAndPlayerScaling
, parameters changed.bossLifeScale
->balance
(bossAdjustment
is different, see the docs for details) -
GlobalNPC.ScaleExpertStats
->GlobalNPC.ApplyDifficultyAndPlayerScaling
, parameters changed.bossLifeScale
->balance
(bossAdjustment
is different, see the docs for details) -
ModNPC.CanTownNPCSpawn
parameters changed, copy the implementation ofNPC.SpawnAllowed_Merchant
in 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.IsLavaImmuneRegardlessOfRarity
or add a method hook toOn_Item.CheckLavaDeath
-
GlobalItem.CanBurnInLava
-> UseItemID.Sets.IsLavaImmuneRegardlessOfRarity
or add a method hook toOn_Item.CheckLavaDeath
-
ModItem.ExtractinatorUse
parameters changed -
GlobalItem.ExtractinatorUse
parameters changed -
Player.QuickSpawnClonedItem
->Player.QuickSpawnItem
-
ModPlayer.clientClone
-> Renamed toCopyClientState
and replaceItem.Clone
usages withItem.CopyNetStateTo
-
ModPlayer.PlayerConnect
parameters changed -
ModPlayer.PlayerDisconnect
parameters changed -
ModPlayer.OnEnterWorld
parameters changed -
ModPlayer.OnRespawn
parameters changed -
ModTree.GrowthFXGore
->ModTree.TreeLeaf
-
Terraria.DataStructures.BossBarDrawParams.LifePercentToShow
removed, useLife / LifeMax
instead -
Terraria.DataStructures.BossBarDrawParams.ShieldPercentToShow
removed, useShield / ShieldMax
instead -
ModBossBar.ModifyInfo
life 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] = true
if you previously had this method return true -
GlobalProjectile.SingleGrappleHook
-> inSetStaticDefaults
, useProjectileID.Sets.SingleGrappleHook[Type] = true
if 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.ModifyWorldGenTasks
parameters changed -
ModLoader.ItemCreationContext
->DataStructures.ItemCreationContext
-
ModLoader.RecipeCreationContext
->DataStructures.RecipeItemCreationContext
-
ModLoader.InitializationContext
->ModLoader.InitializationItemCreationContext
-
Terraria.Recipe.Condition
->Terraria.Condition
-
Condition.InGraveyardBiome
->Condition.InGraveyard
-
Item.IsCandidateForReforge
removed, usemaxStack == 1 || Item.AllowReforgeForStackableItem
orItem.Prefix(-3)
to check whether an item is reforgeable -
Item.CloneWithModdedDataFrom
removed, useClone
,ResetPrefix
orRefresh
-
ModLoader.Mod.CreateTranslation
removed, useLocalization.Language.GetOrRegister
. See Localization Changes Details below. -
ModLoader.Mod.AddTranslation
removed, useLocalization.Language.GetOrRegister
. See Localization Changes Details below. -
ModLoader.ModTranslation
removed, useLocalization.LocalizedText
instead. 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/CanDrop
andModTile.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, overrideDefaultContainerName
instead -
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.closeness
is nowhorizontalHoldoutOffset
, usehorizontalHoldoutOffset = Main.DrawPlayerItemPos(1f, itemtype) - originalClosenessValue
to 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.PreReforge
return type changed frombool
tovoid
, no longer used to prevent reforging. UseCanReforge
for that purpose. -
Player.CanBuyItem
removed, usePlayer.CanAfford
instead. Note that the method will no longer mistakenly attempt to consume custom currencies. -
Player.rocketDamage
->Player.specialistDamage
-
AmmoID.Sets.IsRocket
->AmmoID.Sets.IsSpecialist
-
ModPrefix.GetTooltipLines
added. Some modders might want to move prefix specific tooltip lines fromGlobalItem.ModifyTooltips
to 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.AutoLightSelect
removed. See the porting notes in PR 3479 for more information on how to adapt to this change. -
Player.BiomeTorchPlaceStyle
andPlayer.BiomeCampfirePlaceStyle
parameters 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.DisplayName
andModItem.Tooltip
, for example, can no longer be assigned in code.-
ModConfig
is 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
ModTranslation
usages 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.4
tModLoader. - 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
.AbsorbTeamDamageBuff
references that value for the buff tooltip viapublic override LocalizedText Description => base.Description.WithFormatArgs(AbsorbTeamDamageAccessory.DamageAbsorptionPercent);
.AbsorbTeamDamageAccessory
also references the value in it's own tooltip.ExampleDamageModificationPlayer
also references that value inModifyHurt
andOnHurt
via theDamageAbsorptionMultiplier
property. 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.cs
and.hjson
files. This shows the power of properly using localization files and binding values to them.
-
ModConfig
is 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:
ConsumableDodge
example, 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
ModifyHitNPC
andOnHitNPC
hooks. 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
HitModifiers
fields 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.IsPylonForSale
has been replaced byModPylon.GetNPCShopEntry
. Please see the documentation and ExamplePylonTile -
Mod/GlobalNPC.SetupShop
is nowModifyActiveShop
. This hook still exists to allow for custom shop modification, but you should consider moving to the newModNPC.AddShops
andGlobalNPC.ModifyShop
hooks - The
Item[]
inModifyActiveShop
will 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.KillMultitile
code andModTile.Drop
code can be deleted or simplified by following the porting notes. - All mods with any
ModTile
must 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
/CopyClientStateTo
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.CopyClientStateTo
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.CopyNetStateTo
instead ofItem.Clone
inModPlayer.CopyClientState
- Use
Item.IsNetStateDifferent
instead ofItem.IsNotSameTypePrefixAndStack
inModPlayer.SendClientChanges
- Item instances altered by
CopyNetStateTo
are not initialized! Do not attempt to read properties or retrieveModItem
orGlobalItem
instances from them! The only valid operation on anItem
which was updated withCopyNetStateTo
isIsNetStateDifferent
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.ModifyMaxStats
withStatModifier
arguments 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.statLifeMax2
in 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
,ConsumedLifeFruit
andConsumedManaCrystals
properties- These properties are directly tied to the vanilla stat increases and can also be manually set by modders
- Adds helper methods
Player.UseHealthMaxIncreasingItem
andPlayer.UseManaMaxIncreasingItem
for displaying the visual effects - Adds
ModResourceDisplaySet
allowing for custom life/mana draw styles (similar to boss bar styles) that can be selected in settings - Adds
ModResourceOverlay
to 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
,ExampleLifeFruit
andExampleManaCrystal
on how to properly set permanent stat increases - Temporary stat increases to
Player.statLifeMax2
andPlayer.statManaMax2
can 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.ConsumedLifeFruit
andPlayer.ConsumedManaCrystals
instead of checkingPlayer.statLifeMax
orPlayer.statManaMax
due 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_Item
it'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.SacrificeTotal
has been removed and tModPorter should have changed it toItem.ResearchUnlockCount
already. -
CreativeItemSacrificesCatalog.Instance.SacrificeCountNeededByItemId[Type] = #;
lines can be changed toItem.ResearchUnlockCount = #;
-
ModItem
s 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
ModItem
s 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.