3.0.0 includes a massive list of exciting features and breaking changes. This document will serve as a guide for module authors updating their modules.
The most exciting new feature is Mixins! Module authors now have the ability to write Mixins in their modules. This replaces the old ASM system, which was clunky and hard to work with. Check out the Mixins wiki page to get started.
For all code, both normal module code and Mixin code, Rhino (the JavaScript engine CT uses) will now automatically remap all MC names (fields, methods, and classes)! This means you no longer have to use obfuscated name at all when writing modules. This is a huge ergonomic win which will greatly increase readability for code which goes outside the built-in API that CT provides.
Libraries can now provide their own custom trigger types. Here is an example:
// MyLib/index.js
const customTrigger = createCustomTrigger('mylib:seconds');
let numSeconds = 0;
register('step', () => {
customTrigger.trigger(numSeconds++);
});
// MyModule/index.js
register('mylib:seconds', second => {
ChatLib.chat(`Second ${second}`);
});
MyModule
of course needs to depend on MyLib
so it runs first and registers its trigger. Custom trigger names must be unique, so it is a good idea to prefix them with a unique identifier (in the example, this is mylib:
). They are also case-insensitive like builtin triggers.
If you need to allow users to use cancel
, you should create a CancellableEvent
and pass it in as the last parameter. After calling trigger
, you can check event.isCancelled()
These custom triggers are designed to be used with Mixins to provide triggers for arbitrary MC functionality.
Sound
now supports playing sounds from Minecraft. To do this, setsource
to something likeminecraft:entity.experience_orb.pickup
- Added a new
BossBars
API - Added
Client.copy(text: string)
- Added
Sound.setLoop()
andSound.setLoopDelay()
- Added middle-click tracking to
CPS
TODO: Add more things here?
This update includes many API changes that will break a wide range of modules. Some of this is due to the fact that the mod has been updated from 1.8.9, released in 2015, to 1.19, released in 2022. That's a 7-year jump and Minecraft changed a lot during that time, changing many APIs and concepts in their codebase. However, we are also taking this opportunity to update many of our APIs to be a bit more polished. Both of these result in quite the list of breaking changes
These are API changes that typically involve consistency and affect multiple different APIs.
- All MC wrapper classes (
Entity
,Player
, etc.) now all have a.toMC()
method that exposes the underlying Minecraft value. This change makes these APIs much more uniform, as previously some adhered to this scheme and others didn't. - We have removed all server-side methods, which wouldn't have done anything anyway if used outside of singleplayer. Specifically, the following methods have been removed:
Entity
:setAir()
,dropItem()
,setIsOutsideBorder()
,setPosition()
,setAngles()
,setOnFire()
,extinguish()
,move()
,setIsSilent()
,addVelocity()
,setIsSneaking()
,setIsSprinting()
, andsetIsInvisible()
LivingEntity
:addPotionEffect()
,clearPotionEffects()
,setHP()
, andsetAbsorption()
Settings
:setDifficulty()
World
:getSeed()
andgetType()
Particle
:multiplyVelocity()
- Methods which use to return an enum as a string or number now return an enum
Here is a list of targeted changes for various different APIs:
- Triggers
- The following less-used trigger have been removed:
screenshotTaken
,pickupItem
,chatComponentClicked
,chatComponentHovered
,renderSlot
,guiDrawBackground
,renderBossHealth
,renderDebug
,renderCrosshair
,renderHotbar
,renderExperience
,renderArmor
,renderHealth
,renderFood
,renderMountHealth
,renderAir
,renderPortal
,renderJumpBar
,renderChat
,renderHelmet
,renderHand
,renderScoreboard
,renderTitle
,preItemRender
,renderItemIntoGui
,noteBlockPlay
,noteBlockChange
,renderItemOverlayIntoGui
,renderSlotHighlight
,postRenderEntity
, andpostRenderTileEntity
- All of these triggers had less than 10 uses over all releases on our website. If you maintain one of the few releases who used one of these triggers, they can be replaced with a custom Mixin.
- The following triggers have been removed in favor of other triggers:
attackEntity
,hitBlock
, andblockBreak
(replaced byplayerInteract
);guiMouseRelease
(replaced by a parameter inguiMouseClick
) playerInteract
now passes the interacted-with object as the second argument instead of the object's position (which can be retrieved via a method on the object wrapper, which is either anEntity
,Block
, orItem
). The list of events has also changed.guiMouseClick
now takes a boolean after the mouse button which indicates if the mouse button was pressed (true
) or released (false
)guiMouseDrag
now takes two mouse deltas as its first two arguments. The rest of the arguments are unchanged.guiOpened
now takes the openedScreen
as its first argument.renderTileEntity
has been renamed torenderBlockEntity
, and no longer passes in the position as an argument (access it by callingBlockEntity.getBlockPos()
)ClassFilterTrigger
: RemovedsetPacketClass
andsetPacketClasses
. UsesetFilteredClass
andsetFilteredClasses
instead- The full message for
chat
triggers is no longer accessed withEventLib
(which no longer exists). Instead, useevent.message
, which will return aTextComponent
. This has thegetFormattedText()
andgetUnformattedText()
methods, which replace the second parameter of the oldEventLib
method serverConnect
andserverDisconnect
no longer pass an event as the third parameterscrolled
now passes in the actual scroll amount, not just -1 or 1 to indicate a directiondropItem
takes different parameters:- It now takes the
Item
, a boolean to indicate whether the user is dropping just 1 (false
) or the entire stack (true
), and the event which can still be cancelled. - It previously took a
PlayerMP
(which was always the player since this is a client mod) and the item's position/motion, both of which can be obtained by methods onItem
- It now takes the
renderEntity
no longer takes the entity's position as an argument. Instead, callEntity.getPos()
spawnParticle
no longer passes in the particle type (which no longer exists in the MC codebase). Instead, the class can be access from the particle wrapper's underlying MC typerenderOverlay
no longer passes in the event, as it was unused previouslyitemTooltip
now receives a list ofTextComponent
objects instead of a list of strings- Removed all Trigger classes from the global namespace
- Removed
CancellableEvent
from the global scope
- The following less-used trigger have been removed:
Message
/TextComponent
Message
has been removed, and its primary functionality (i.e.chat()
/actionBar()
) has been added toTextComponent
TextComponent
has been heavily changed such that it can be easily introspected. It now implementsList<NativeObject>
, and each object is of the form{ text: '...', bold: true, underline: true, ... }
. This form can also be used to construct and create newTextComponent
sTextComponent
is now immutable. Methods such aswithText()
can be used to return a modifiedTextComponent
based on the original
- The
/ct
command- Removed
/ct copy
. Replace this withClient.copy(text: String)
- Removed the following aliases:
reload
(an alias ofload
)file
(an alias offiles
)settings
andsetting
(an alias ofconfig
)sim
(an alias ofsimulate
)
/ct files
now opens the modules folder instead of its parent folder/ct console
now opens the JS console. Use/ct console general
to open the general console
- Removed
Entity
- Removed
getRider()
. Entities can have multiple riders, so this method doesn't make sense. Replace all usages with thegetRiders()
method - Removed
isAirborne()
, which no longer exists in the MC API getDimension()
now returns anEntity.DimensionType
enum value instead of an int
- Removed
LivingEntity
- Name changed from
EntityLivingBase
- Renamed
getItemInSlot()
togetStackInSlot()
, which matches the method of the same name inInventory
- Name changed from
TileEntity
is nowBlockEntity
PotionEffect
- This API has been completely reworked, and is now similar to the
Block
API. ThePotionEffect
object represents a specific instance of an effect, and will have aPotionEffectType
, which represents the kind of effect it is. Check out the docs for more info on how to use this new API - Renamed
isDurationMax()
toisInfinite()
- This API has been completely reworked, and is now similar to the
Item
- This API has also been completely reworked, similarly to
PotionEffect
andBlock
. It has been split into anItem
class which represents a single stack of items in an inventory, and anItemType
class which represents the type of theItem
. - Renamed
isDamagable()
toisDamageable()
, fixing the typo - Removed
getRawNBT()
, prefer usinggetNBT()
which gives access to a wide range of powerful NBT-related APIs - You can no longer wrap empty ItemStacks. Creating an Item with an empty stack will throw an error. Use
Item.fromMC
instead.
- This API has also been completely reworked, similarly to
NBTTagList.removeTag()
now wraps the removed element in CT's NBT wrappersNBTTagCompound.getTag()
andNBTTagCompound.getTagList()
now returns a wrapped version instead of the raw MC versionChunk
- Renamed
getAllTileEntities()
togetAllBlockEntities()
- Renamed
getAllTilesEntitiesOfType()
togetAllBlockEntitiesOfType()
- Renamed
Block
- Removed
getMetadata()
as blocks no longer have this in newer MC versions - Renamed
isPowered()
andgetRedstoneStrength()
toisReceivingPower()
andgetReceivingPower()
, respectively, to differentiate them from the new methodsisEmittingPower(BlockFace)
andgetEmittingPower(BlockFace)
- Removed
BlockFace
- Renamed
fromMCEnumFacing()
tofromMC()
- Enum values are now UPPER_CASE
- Renamed
BlockType
: RemovedgetDefaultMetadata()
andgetHarvestLevel()
Scoreboard
- Remove
Scoreboard.getScoreboardTitle()
in favor of the less verboseScoreboard.getTitle()
Scoreboard.getTitle()
now returnsTextComponent
instead ofString
Score
- is now mutable. You can now edit the score, name, number format, and team
getPoints
/setPoints
are renamed togetScore
/setScore
- Added
addLine()
,createTeam()
,removeIndex()
,removeScores()
methods getLines
now actually sorts by descending instead of ascending
- Remove
Book
now usesTextComponent
instead ofMessage
Settings
- Renamed all methods in the
skin
object to indicate they return whether the part is enabled, not the actual part themselves (i.e.getCape()
->isCapeEnabled()
) - Renamed
video.getGraphics()
tovideo.getGraphicsMode()
- Removed
video.get3dAnaglyph()
(3D Anaglyph no longer exists in MC) - The following methods have had their return values changed to enums:
video.getGraphicsMode()
now returnsSettings.GraphicsMode
instead ofnumber
video.getClouds()
now returnsSettings.CloudRenderMode
instead ofnumber
video.getParticles()
now returnsSettings.ParticlesMode
instead ofnumber
chat.getVisibility()
now returnsSettings.ChatVisibility
instead ofstring
- Renamed all methods in the
ChatLib
clearChat()
no longer takes any chat line IDs, and instead will always clear the chat. To selectively-delete message using their ID, usedeleteChat(id: number)
- Removed
getChatMessage()
. Instead, you can access the entire message as aTextComponent
viaevent.message
Player
- Removed
getRawYaw()
as it provided no extra value getUUID()
now returns theUUID
object instead of astring
lookingAt()
now returnsnull
when looking at nothing instead of aBlockType
draw()
now takes an object to align withRenderer.drawPlayer()
- Removed
PlayerMP.draw()
now takes an object to align withRenderer.drawPlayer()
World
- Removed all
Sound
-related methods. Instead, use theSound
class getDifficulty()
now returnsSettings.Difficulty?
- Renamed
getAllTileEntities()
togetAllBlockEntities()
- Renamed
getAllTilesEntitiesOfType()
togetAllBlockEntitiesOfType()
- Removed all
Sound
- Removed
priority
- The
attenuation
field is now the distance. Added anattenuationType
field which takes aSound.AttenuationType
setCategory
now takes aSound.Category
- Removed
KeyBind.register...()
methods now return theKeyBind
instead of the trigger. Use the respectiveunregister...()
methods if necessary.Display
- Removed
DisplayLine
, lines are now instances ofText
- The user must now call the
draw()
method manually. This allows it to be rendered in any arbitrary trigger
- Removed
Text
- Added background color and alignment to replace the functionality in
DisplayLine
- Added background color and alignment to replace the functionality in
Image
- Remove deprecated constructors. Instead, use the static helper methods:
Image.fromFile(File)
,Image.fromFile(string)
,Image.fromAsset(string)
, andImage.fromUrl(String[, String])
- Remove deprecated constructors. Instead, use the static helper methods:
Renderer
/Tessellator
Tessellator
has been renamed toRenderer3d
. Some of its methods may have changed and/or moved toRenderer
Renderer.color()
has been replaced withRenderer.getColor()
. The newcolor()
method is used to color the vertices instead- Removed
drawShape
. Instead, create aShape
and invoke itsdraw()
method begin()
now no longer translates to the player's camera position. Instead, useRenderer.translateToPlayer()
begin()
now takes aRenderer.VertexFormat
as an optional second argumentdrawString
now takes an optionalcolor
parameter as its 4th argumentdrawPlayer
now takes an object, as even more parameters were added. Check the javadocs for a full description of the parameters- Removed
drawLine()
'sdrawMode
argument - Removed
drawCircle()
'sdrawMode
argument - Removed
getDrawMode()
andsetDrawMode()
. Pass the drawMode tobegin
- Removed
retainTransforms()
- Most of
Renderer3d
's rendering should be inpostRenderWorld
- Removed
enableAlpha()
anddisableAlpha()
as they do nothing on modern versions
Gui
/GuiHandler
GuiHandler
has been removed. It only had one relevant method (openGui()
), which can be replaced byClient.currentGui.set()
- Removed
isControlDown()
,isAltDown()
, andisShiftDown()
. Instead, use the method that already exist onScreen
:hasControlDown()
,hasAltDown()
, andhasShiftDown()
- The various
register...()
methods now return theGui
instance for method chaining. Use theunregister...()
methods for unregistering the respective triggers. - The
mouseDragged
trigger no longer takestimeSinceLastClick
. If you really need this, you can track it yourself addButton
now returns the ID instead of returning theGui
instance. This ID is used in various button APIs, primarily to indicate which button is clicked. This is a change in the MC API that we propogated to our API.- Removed a bunch of random draw method that didn't really belong in the class. They delegated to existing methods on
Screen
, so if you really want to, you can still call them, albeit with slightly different names and parameters.
TabList
- Renamed
getHeaderMessage()
togetHeaderComponent()
, and it now returns aTextComponent
instead of aMessage
- Renamed
getFooterMessage()
togetFooterComponent()
, and it now returns aTextComponent
instead of aMessage
- Added
addName()
,getList()
, andremoveNames()
getNames()
now returns a list ofName
- Added
Name
- acts similarly to
Scoreboard.Score
, with the following methods getLatency()
,setLatency()
,getName()
,setName()
,getTeam()
,setTeam()
, andremove()
- acts similarly to
- Renamed
Team
Team.getNameTagVisibility()
andTeam.getDeathMessageVisibility()
now return aTeam.Visibility
instead of a string- Added
setColor()
Client
getChatGUI
was renamed togetChatGui
to match the naming ofgetTabGui
Server.getPing()
now returns -1 if not in a world- Removed
Config.modulesFolder
. UseChatTriggers.MODULES_FOLDER
or the string"./config/ChatTriggers/modules"
- Renamed
ChatTriggers.loadCT()
andChatTriggers.unloadCT()
toload()
andunload()
- Provided JS API:
- Split
print
intoprint
andprintln
.print
will no longer emit a trailing newline
- Split
- The assets directory has changed from
config/ChatTriggers/images
toconfig/ChatTriggers/assets