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.
Soundnow supports playing sounds from Minecraft. To do this, setsourceto something likeminecraft:entity.experience_orb.pickup- Added a new
BossBarsAPI - 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) playerInteractnow 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.guiMouseClicknow takes a boolean after the mouse button which indicates if the mouse button was pressed (true) or released (false)guiMouseDragnow takes two mouse deltas as its first two arguments. The rest of the arguments are unchanged.guiOpenednow takes the openedScreenas its first argument.renderTileEntityhas been renamed torenderBlockEntity, and no longer passes in the position as an argument (access it by callingBlockEntity.getBlockPos())ClassFilterTrigger: RemovedsetPacketClassandsetPacketClasses. UsesetFilteredClassandsetFilteredClassesinstead- The full message for
chattriggers 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 oldEventLibmethod serverConnectandserverDisconnectno longer pass an event as the third parameterscrollednow passes in the actual scroll amount, not just -1 or 1 to indicate a directiondropItemtakes 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
renderEntityno longer takes the entity's position as an argument. Instead, callEntity.getPos()spawnParticleno 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 typerenderOverlayno longer passes in the event, as it was unused previouslyitemTooltipnow receives a list ofTextComponentobjects instead of a list of strings- Removed all Trigger classes from the global namespace
- Removed
CancellableEventfrom the global scope
- The following less-used trigger have been removed:
Message/TextComponentMessagehas been removed, and its primary functionality (i.e.chat()/actionBar()) has been added toTextComponentTextComponenthas 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 newTextComponentsTextComponentis now immutable. Methods such aswithText()can be used to return a modifiedTextComponentbased on the original
- The
/ctcommand- Removed
/ct copy. Replace this withClient.copy(text: String) - Removed the following aliases:
reload(an alias ofload)file(an alias offiles)settingsandsetting(an alias ofconfig)sim(an alias ofsimulate)
/ct filesnow opens the modules folder instead of its parent folder/ct consolenow opens the JS console. Use/ct console generalto 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.DimensionTypeenum 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
TileEntityis nowBlockEntityPotionEffect- This API has been completely reworked, and is now similar to the
BlockAPI. ThePotionEffectobject 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
PotionEffectandBlock. It has been split into anItemclass which represents a single stack of items in an inventory, and anItemTypeclass 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.fromMCinstead.
- 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 returnsTextComponentinstead ofStringScore- is now mutable. You can now edit the score, name, number format, and team
getPoints/setPointsare renamed togetScore/setScore
- Added
addLine(),createTeam(),removeIndex(),removeScores()methods getLinesnow actually sorts by descending instead of ascending
- Remove
Booknow usesTextComponentinstead ofMessageSettings- Renamed all methods in the
skinobject 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.GraphicsModeinstead ofnumbervideo.getClouds()now returnsSettings.CloudRenderModeinstead ofnumbervideo.getParticles()now returnsSettings.ParticlesModeinstead ofnumberchat.getVisibility()now returnsSettings.ChatVisibilityinstead ofstring
- Renamed all methods in the
ChatLibclearChat()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 aTextComponentviaevent.message
Player- Removed
getRawYaw()as it provided no extra value getUUID()now returns theUUIDobject instead of astringlookingAt()now returnsnullwhen looking at nothing instead of aBlockTypedraw()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 theSoundclass getDifficulty()now returnsSettings.Difficulty?- Renamed
getAllTileEntities()togetAllBlockEntities() - Renamed
getAllTilesEntitiesOfType()togetAllBlockEntitiesOfType()
- Removed all
Sound- Removed
priority - The
attenuationfield is now the distance. Added anattenuationTypefield which takes aSound.AttenuationType setCategorynow takes aSound.Category
- Removed
KeyBind.register...()methods now return theKeyBindinstead 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/TessellatorTessellatorhas been renamed toRenderer3d. Some of its methods may have changed and/or moved toRendererRenderer.color()has been replaced withRenderer.getColor(). The newcolor()method is used to color the vertices instead- Removed
drawShape. Instead, create aShapeand invoke itsdraw()method begin()now no longer translates to the player's camera position. Instead, useRenderer.translateToPlayer()begin()now takes aRenderer.VertexFormatas an optional second argumentdrawStringnow takes an optionalcolorparameter as its 4th argumentdrawPlayernow takes an object, as even more parameters were added. Check the javadocs for a full description of the parameters- Removed
drawLine()'sdrawModeargument - Removed
drawCircle()'sdrawModeargument - 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/GuiHandlerGuiHandlerhas 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 theGuiinstance for method chaining. Use theunregister...()methods for unregistering the respective triggers. - The
mouseDraggedtrigger no longer takestimeSinceLastClick. If you really need this, you can track it yourself addButtonnow returns the ID instead of returning theGuiinstance. 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 aTextComponentinstead of aMessage - Renamed
getFooterMessage()togetFooterComponent(), and it now returns aTextComponentinstead 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
TeamTeam.getNameTagVisibility()andTeam.getDeathMessageVisibility()now return aTeam.Visibilityinstead of a string- Added
setColor()
ClientgetChatGUIwas renamed togetChatGuito match the naming ofgetTabGui
Server.getPing()now returns -1 if not in a world- Removed
Config.modulesFolder. UseChatTriggers.MODULES_FOLDERor the string"./config/ChatTriggers/modules" - Renamed
ChatTriggers.loadCT()andChatTriggers.unloadCT()toload()andunload() - Provided JS API:
- Split
printintoprintandprintln.printwill no longer emit a trailing newline
- Split
- The assets directory has changed from
config/ChatTriggers/imagestoconfig/ChatTriggers/assets