Skip to main content

Writing a script

Now that you have set up your environment, you can proceed onto writing transformer scripts.

Koremods DSL

Defining transformers

Transformers can be added inside the transformers scoped function that provides a TransformerBuilder. From there, you can use the provided methods to define transformers for classes, methods and fields. Each of them takes in a number of strings necessary to locate the target, and a consumer function that acceptsthe respective ASM node type.

Example usage:

transformers {
// Transform ClassNode
`class`("com.example.Example", ::transformExample)
// Transform MethodNode
method(
"com.example.Example", // Class name
"sayHello", // Method name
constructMethodDescriptor(void, "java/lang/String"), // Method descriptor
::transformSayHello // Transformer function
)
// Transform FieldNode
field(
"com.example.Example", // Class name
"foo", // Field name
"java/lang/String", // Field type
::transformFoo // Transformer function
)
}

Bytecode API

Koremods bundles Koffee, an ASM wrapper written in Kotlin. Koffee provides a bytecode assembly DSL where instructions are represented by Kotlin properties, as well as syntax sugar for common code, such as init, clinit, object construction etc.

Koremods extends Koffee's API to provide functions for transforming nodes, injecting instructions and locating bytecode sequences.

See the Koremods Script KDocs for parameters and details.

Remapping API

Koremods Modlauncher extends the Koremods DSL with a remapping API that can be used to map class, method and field names to the running environment's mappings.

In a MinecraftForge environment, the supplied arguments should be in mojang_srg format. Remapping classes isn't needed as they're already mapped to SRG during setup.

You can easily get the desired mojang_srg names to use with the remapping api from Linkie or other available tools.

Example usage:

mapClassName("net.minecraft.server.level.ServerLevel")

mapMethodName("m_109089_") // renderLevel

mapFieldName("f_8329_") // level

Script Features

Sandbox

Koremods scripts are executed in an isolated environment to ensure they can only access necessary classes and resources. This helps improve security and makes them less prone to bugs.

The following classes and packages are available for use in koremods scripts:

  • Java standard library
    • java.lang
    • java.util
  • Kotlin
    • kotlin
  • ASM
    • org.objectweb.asm
  • Log4J
    • org.apache.logging.log4j
  • Koffee
    • codes.som.koffee
  • Koremods
    • wtf.gofancy.koremods.Identifier
    • wtf.gofancy.koremods.script.KoremodsKtsScript
    • wtf.gofancy.script.ImportScript
    • wtf.gofancy.koremods.dsl

Attempting to load unavailable classes will result in a ClassNotAvailableInSandboxException.

Importing Scrips

You can import members of other scripts into your script using the @ImportScript annotation on the file, and supplying it with paths relative to the current directory.

IntelliJ IDEA Integration

An IDE restart may be required after modifying imported scrips to fully enable autocompletion features.

For example:
Importing a script called bar.core.kts, which is in the same directory and contains the function greet:

foo.core.kts
@file:ImportScript("bar.core.kts")

greet("World")

Live Debugging

Thanks to IntelliJ Idea's Kotlin Script integration, you can place breakpoints into scripts directly and debug them during runtime. No additional setup is required. This applies to pre-compiled scripts and remote debugging as well.

FML mod dependency

Starting with version 0.4.7, Koremods Modlauncher registers a FML mod with the modid koremods. You can make your mod depend on it to ensure users have the right Koremods version installed and help reduce errors.

Example usage:

mods.toml
[[dependencies.examplemod]]
# the modid of the dependency
modId="koremods"
# Does this dependency have to exist - if not, ordering below must be specified
mandatory=true
# The version range of the dependency
versionRange="[0.4.8,)"
# # An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatatory
ordering="NONE"
# Side this dependency is applied on - BOTH, CLIENT or SERVER
side="BOTH"

See Also