Events
KubeJS TFC adds several JS events for use in your scripts
- Rock Settings
- Limiting Containers
- Register Climate Model
- Select Climate Model
- Start Fire
- Prospect
- Logging
- Animal Product
- Collapse
- Douse Fire
- Custom Food Traits
- Custom Item Stack Modifiers
- Representative Blocks
- Birthdays
- Register Interactions
- Modifying Worldgen Defaults
- Register Fauna Definitions
- Create Glass Operations
- Create Chunk Data Provider
- Register Item Stack Modifier Converters
Rock Settings
- Type:
startup_scripts
Defines a new layer or overrides an existing layer which can be referenced from a world preset json
Method Signature
event.defineRock(
id: String,
raw: Block,
hardened: Block,
gravel: Block,
cobble: Block,
sand: Block,
sandstone: Block,
spike: @Nullable Block,
loose: @Nullable Block,
mossyLoose: @Nullable Block
)
- 1st argument: A block, the registry name of the rock
- 2nd argument: A block, to be used as the raw stone block of the rock
- 3rd argument: A block, to be used as the hardened stone block of the rock
- 4th argument: A block, to be used as the gravel block of the rock
- 5th argument: A block, to be used as the cobble block of the rock
- 6th argument: A block, to be used as the sand block of the rock
- 7th argument: A block, to be used as the sandstone block of the rock
- 8th argument: A block, to be used as the spike block of the rock, may be
null
. Needs to have TFC’sROCK_SPIKE_PART
state property/be a rock spike - 9th argument: A block, to be used as the loose rock block of the rock, may be
null
. Needs to have TFC’sCOUNT_1_3
state property/be a loose rock - 10th argument: A block, to be used as the mossy loose rock block of the rock, may be
null
. Needs to have TFC’sCOUNT_1_3
state property/be a loose rock
Example
TFCEvents.rockSettings(event => {
event.defineRock(
'kubejs:vanilla_layer',
'minecraft:stone',
'minecraft:deepslate',
'minecraft:gravel',
'minecraft:cobblestone',
'minecraft:sand',
'minecraft:sandstone',
null,
null,
null
)
})
Limiting Containers
- Type:
server_scripts
TFC has an item size feature which it uses to limit which items can go into its containers. KubeJS TFC allows you to somewhat replicate this behavior with other mods’ containers, with some limitations
- It will only be able to apply to a container which registers a
MenuType
- It only applies to player interactions
- It only applies upon closing a menu
The basic functionality and idea is based off of a 1.12 addon that did much the same. It is licensed under the BSD License
Upon a player closing a container limited through this event, any items that are
- in the limited slots and
- are not within the size limits
will be removed from the container and spawned in world around the player
Method Signatures
event.limit(size: Size, allowsEqual?: boolean): void
event.limit(size: Size, min: number, max: number, allowsEqual?: boolean): void
event.lowerLimit(size: Size, allowsEqual?: boolean): void
event.lowerLimit(size: Size, min: number, max: number, allowsEqual?: boolean): void
: Limits the entire container to the specified size, requiring any items in it to be smaller than the provided size..limit(size: Size, allowsEqual?: boolean)
allowsEqual
determines if a size ofsmall
will accept items with a size ofsmall
, defaults totrue
: Limits the specified slot index range to the specified size, requiring any items in it to be smaller than the provided size..limit(size: Size, min: number, max: number, allowsEqual?: boolean)
allowsEqual
determines if a size ofsmall
will accept items with a size ofsmall
, defaults totrue
: Limits the entire container to the specified size, requiring any items in it to be larger than the provided size..lowerLimit(size: Size, allowsEqual?: boolean)
allowsEqual
determines if a size ofsmall
will accept items with a size ofsmall
, defaults totrue
: Limits the specified slot index range to the specified size, requiring any items in it to be larger than the provided size..lowerLimit(size: Size, min: number, max: number, allowsEqual?: boolean)
allowsEqual
determines if a size ofsmall
will accept items with a size ofsmall
, defaults totrue
Allowed size values: tiny
, very_small
, small
, normal
, large
, very_large
, and huge
Additionally, every event listener requires the name of a menu type1 in its declaration as a key for which menus the limits are applied to.
Example
TFCEvents.limitContainer('minecraft:generic_3x3', event => {
event.limit('large', 0, 4)
event.limit('small')
event.lowerLimit('normal', 0, 2)
})
Register Climate Model
- Type:
startup_scripts
TFC implements a system for local temperature, rainfall, fog, wind, and more. This is done through a ClimateModel
Method Signatures
// The event itself
event.register(name: ResourceLocation, modelBuilder: Consumer<ClimateModelbuilder>): void
// The ClimateModelBuidler
event.getTemperatureScale(): number
event.getRainfallScale(): number
event.getClimateSeed(): number
event.vector(x: number, z: number): Vec2
event.setCurrentTemperatureCalculation(calc: QuadFunction<LevelReader, BlockPos, number, number, number>): void
event.setAverageTemperatureCalculation(calc: BiFunction<LevelReader, BlockPos, number>): void
event.setAverageRainfallCalculation(calc: BiFunction<LevelReader, BlockPos, number>): void
event.setAriFog(calc: TriFunction<LevelReader, BlockPos, number, number>): void
event.setWaterFog(calc: TriFunction<LevelReader, BlockPos, number, number>): void
event.setWindVector(calc: TriFunction<Level, BlockPos, number, Vec2>): void
event.setOnWorldLoad(calc: Consumer<ServerLevel>): void
event.setOnChunkLoad(calc: TriConsumer<WorldgenLevel, ChunkAccess, ChunkData>): void
event.newNoise(noiseMaker: Function<OpenSimplex2D, Noise2D>): number
event.noise(index: number): Noise2D
event.getTfcWind(): TriFunction<Level, BlockPos, number, Vec2>
event.getTfcChunkLoad(): TriConsumer<WorldgenLevel, ChunkAccess, ChunkData>
event.getTfcCurrentTemperature(): QuadFunction<LevelReader, BlockPos, number, number, number>
event.getTfcAverageTemperature(): BiFunction<LevelReader, BlockPos, number>
event.getTfcAverageRainfall(): BiFunction<LevelReader, BlockPos, number>
event.getTfcAirFog(): TriFunction<LevelReader, BlockPos, number, number>
event.getTfcWaterFog(): TriFunction<LevelReader, BlockPos, number, number>
event.currentTemperature(level: LevelReader, pos: BlockPos, calendarTicks: number): number
event.averageTemperature(level: LevelReader, pos: BlockPos): number
event.averageRainfall(level: LevelReader, pos: BlockPos): number
The register method of the event has the following arguments:
- 1st argument: A resource location, the registry name of the model
- 2nd argument: A
ClimateModelBuilder
consumer, with the following methods:
: Returns the temperature scale of the level, defaults to.getTemperatureScale()
20000
if the level does not have a TFC-like generator
: Returns the rainfall scale of the level, defaults to.getRainfallScale()
20000
if the level does not have a TFC-like generator
: Returns the climate seed being used.getClimateSeed()
: Creates a new wind vector with the provided x and z components. Each component should be in the range [0, 1].vector(x: number, z: number)
: Sets how the model will determine the current temperature at a given temperature and time, accepts a callback with the following values:.setCurrentTemperatureCalculation(calc: QuadFunction<LevelReader, BlockPos, number, number, number>)
level: LevelReader
: The levelpos: BlockPos
: The positioncalendarTicks: number
: The calendar tick the calculation is being made atdaysInMonth: number
: The number of days in a month; andreturn: number
: A number should be returned in the callback, the temperature in °C
: Sets how the model will determine the average temperature at a given position, accepts a callback with the following values:.setAverageTemperatureCalculation(calc: BiFunction<LevelReader, BlockPos, number>)
level: LevelReader
: The levelpos: BlockPos
: The position; andreturn: number
: A number should be returned in the callback, the temperature in °C
: Sets how the model will determine the average rainfall at a given position, accepts a callback with the following values:.setAverageRainfallCalculation(calc: BiFunction<LevelReader, BlockPos, number>)
level: LevelReader
: The levelpos: BlockPos
: The position; andreturn: number
: A number should be returned in the callback, the rainfall in mm
: Sets how the model will determine the fogginess at a given position and time, accepts a callback with the following values:.setAirFog(calc: TriFunction<LevelReader, BlockPos, number, number>)
level: LevelReader
: The levelpos: BlockPos
: The positioncalendarTicks: number
: The calendar tick the calculation is being made at; andreturn: number
: A number, in the range [0, 1], should be returned in the callback, a multiplier on the view distance
: Sets how the model will determine the fogginess at a given position and time, accepts a callback with the following values:.setWaterFog(calc: TriFunction<LevelReader, BlockPos, number, number>)
level: LevelReader
: The levelpos: BlockPos
: The positioncalendarTicks: number
: The calendar tick the calculation is being made at; andreturn: number
: A number, in the range [0, 1], should be returned in the callback, a multiplier on the view distance
: Sets how the model will determine the wind strength at a given position and time, accepts a callback with the following values:.setWindVector(calc: TriFunction<Level, BlockPos, number, Vec2>)
level: LevelReader
: The levelpos: BlockPos
: The positioncalendarTicks: number
: The calendar tick the calculation is being made at; andreturn: Vec2
: A 2D vector, representing the strength and direction of wind, each component should be in the range [0, 1]. Vectors can be made through the.vector(x: number, z: number)
method described above
: Sets the model’s behavior when the world is loaded, accepts a consumer of a.setOnWorldLoad(calc: Consumer<ServerLevel>)
ServerLevel
: Sets the model’s behavior on chunk load, accepts a callback with the following values:.setOnChunkLoad(calc: TriConsumer<WorldgenLevel, ChunkAccess, ChunkData>)
level: WorldGenLevel
: The levelchunk: ChunkAccess
: The chunk being loadedchunkData: ChunkData
: Additional TFC data about the chunk, will be invalid if the level does not have a TFC-like generator
: Adds a new.newNoise(noiseMaker: Function<OpenSimplex2D, Noise2D>)
Noise2D
to the model and returns a number which can be used to retrieve it in calculations. Accepts a callback with the following values:simplex: OpenSimplex2D
: The baseOpenSimplex2D
that is used to make the noise; andreturn: Noise2D
: The final noise
: Gets the model’s.noise(index: number)
Noise2D
with the given index
: Returns the callback TFC uses for its Overworld wind calculations.getTfcWind()
: Returns the callback TFC uses for its Overworld chunk load actions.getTfcChunkLoad()
: Returns the callback TFC uses for its Overworld current temperature calculation.getTfcCurrentTemperature()
: Returns the callback TFC uses for its Overworld average temperature calculation.getTfcAverageTemperature()
: Returns the callback TFC uses for its Overworld average rainfall calculation.getTfcAverageRainfall()
: Returns the callback TFC uses for its Overworld air fogginess calculation.getTfcAirFog()
: Returns the callback TFC uses for its Overworld water fogginess calculation.getTfcWaterFog()
: Returns the current temperature in the model at the given position and time.currentTemperature(level: LevelReader, pos: BlockPos, calendarTicks: number)
: Returns the average temperature in the model at the given position.averageTemperature(level: LevelReader, pos: BlockPos)
: Returns the average rainfall in the model at the given position.averageRainfall(level: LevelReader, pos: BlockPos)
Internally, the components of a Vec2
are labeled x
and y
, but TFC uses the y
component for the z
direction
Example
TFCEvents.registerClimateModel(event => {
event.register('kubejs:hell', builder => {
var fogNoiseIndex = builder.newNoise(s => s.octaves(3).spread(0.1).abs())
var temperatureVarianceIndex = builder.newNoise(s => s.scaled(-360, 500).spread(0.6))
builder.setAverageTemperatureCalculation((level, pos) => 1000)
builder.currentTemperatureCalculation = (level, pos, calendarTicks, daysInMonth) => {
var variance = builder.noise(temperatureVarianceIndex).noise(pos.x, pos.z)
return 1000 + variance
}
builder.setAirFog((level, pos, calendarTicks) => builder.noise(fogNoiseIndex).noise(pos.x, pos.z))
builder.windVector = builder.tfcWind
})
})
Select Climate Model
- Type:
server_scripts
This event is fired when a world is loading and selecting the climate model to use
Method Signatures
event.getLevel(): Level
event.getModel(): ClimateModel
event.getModelName(): ResourceLocation
event.setModel(model: ClimateModel): void
: Returns the event’s level.getLevel()
: Returns the events current model, defaults to a biome based model, TFC sets the overworld to use its own overworld model.getModel()
: Returns the registry name of the event’s current model.getModelName()
: Sets the events climate model.setModel(model: ClimateModel)
Example
TFCEvents.selectClimateModel(event => {
if (event.level.dimensionKey.location() == 'minecraft:nether') {
event.setModel('kubejs:hell')
}
})
Start Fire
- Type:
server_scripts
TFC uses this event for lighting fires or optionally light-able blocks. This event should be cancelled if it was handled here. If you want your items to act like Flint and Steel or Torches, add them to either the tfc:starts_fires_with_items
tag or the tfc:starts_fires_with_durability
tags.
Method Signatures
event.getLevel(): Level
event.getBlock(): BlockContainerJS
event.getTargetedFace(): Direction
event.getEntity(): @Nullable Player
event.getItem(): ItemStack
event.isString(): boolean
: Returns the level of the event.getLevel()
: Returns the.getBlock()
BlockContainerJS
of the event
: Returns the direction of the clicked face.getTargetedFace()
: Returns the player of the event, may be null.getEntity()
: Returns the item stack used to start the fire.getItem()
: Returns true if the event is strong.isStrong()
Example
// Enables the player to light a charcoal forge underneath a Create fluid tank
const CharcoalForgeBlock = Java.loadClass("net.dries007.tfc.common.blocks.devices.CharcoalForgeBlock")
const CharcoalForge = Java.loadClass("net.dries007.tfc.common.blockentities.CharcoalForgeBlockEntity")
TFCEvents.startFire(event =>{
if (event.block.id == 'create:fluid_tank' && CharcoalForgeBlock.isValid(event.level, event.block.down.pos) && event.isStrong()) {
let be = event.block.down.entity
if (be instanceof CharcoalForge && be.light(event.block.down.blockState)) {
event.cancel()
}
}
})
Prospect
- Type:
server_scripts
Whenever a prospector’s pick is used, this event is fired. It is purely informational and cannot change anything
Method Signatures
event.getEntity(): Player
event.getBlock(): Block
event.getProspectResult(): ProspectResult
: Returns the player that prospected.getEntity()
: Returns the found block, or if the prospect result is.getBlock()
nothing
, the clicked block
: Results the prospect result, can be.getProspectResult()
nothing
,traces
,small
,medium
,large
,very_large
, andfound
Example
TFCEvents.prospect(event => {
if (event.prospectResult == 'found') {
event.entity.give('kubejs:gift_box')
}
})
Logging
- Type:
server_scripts
This event is fired when a tree is about to be felled by an axe. Cancelling it will cause the block to be broken normally
Method Signatures
event.getLevel(): Level
event.getAxe(): ItemStack
event.getBlock(): BlockContainerJS
event.getPos(): BlockPos
: Returns the level.getLevel()
: Returns the item stack of the axe used.getAxe()
: Returns the.getBlock()
BlockContainerJS
of the event
: Returns the position that was initially broken.getPos()
Example
TFCEvents.log(event => {
if (event.axe.hasTag('kubejs:logging_deny_list')) {
event.cancel()
}
})
Animal Product
- Type:
server_scripts
This event is fired whenever a sheep is sheared, a cow is milked, or similar action happens. Cancelling it will prevent the default behavior, which is controlled by each entity’s implementation. This event does not control if an entity can give products, it is for the sole purpose of modifying/blocking what happens when products are made
This event has a product, it may wither be an ItemStack
or a FluidStackJS
, not both. Only the non-empty type will retain modifications, attempting to change the type will void the original product
Method Signatures
event.getPlayer(): @Nullable Player
event.getAnimal(): Entity
event.getLevel(): Level
event.getBlock(): BlockContainerJS
event.getAnimalProperties(): TFCAnimalProperties
event.getTool(): ItemStack
event.getItemProduct(): ItemStack
event.getFluidProduct(): FluidStackJS
event.isItemProduct(): boolean
event.setItemProduct(item: ItemStack): void
event.setFluidProduct(fluid: FluidStackJS): void
event.getUses(): number
event.setUses(uses: number): void
: Returns the player that used the tool, may be null.getPlayer()
: Returns the animal the product comes from.getAnimal()
: Returns the level of the event.getLevel()
: Returns the.getBlock()
BlockContainerJS
of the event
: Returns the TFCAnimalProperties of the animal.getAnimalProperties()
: Returns the tool used.getTool()
: Returns an.getItemProduct()
ItemStack
, the item product, may be empty
: Returns a.getFluidProduct()
FluidStackJS
, the fluid product, may be empty
: Returns true if the item product is not empty.isItemProduct()
: Sets the item product to the given item stack.setItemProduct(item: ItemStack)
: Sets the fluid product to the given fluid.setFluidProduct(fluid: FluidStackJS)
: Returns how much wear the animal will take from this event.getUses()
: Sets the number of uses the animal will take from this event.setUses(uses: number)
Example
TFCEvents.animalProduct(event => {
if (event.animalProperties.geneticSize < 10) {
event.cancel()
}
})
Collapse
- Type:
server_scripts
This event is fired whenever a collapse happens, including fake collapses
Method Signature
event.getCenterBlock(): BlockContainerJS
event.getLevel(): Level
event.getRadiusSquared(): number
event.getSecondaryPositions(): List<BlockPos>
event.isFake(): boolean
: Returns the.getCenterBlock()
BlockContainerJS
of the center block of the collapse
: Returns the level of the collapse.getLevel()
: Returns the squared radius of the collapse, will be.getRadiusSquared()
0
if the collapse is fake
: Returns a list of.getSecondaryPositions()
BlockPos
es which are the positions that will collapse
: Returns true if the collapse is fake.isFake()
Example
TFCEvents.collapse(event => {
event.secondaryPositions.forEach(pos => {
event.level.playSound(null, pos, 'minecraft:block.wood.break', 'blocks', 1.0, 1.0)
})
})
Douse Fire
- Type:
server_scripts
This event fires when a fire-dousing item is used on a block or a water potion lands
Method Signature
event.getLevel(): Level
event.getBlock(): BlockContainerJS
event.getBounds(): AABB
event.getPlayer(): @Nullable Player
event.getPos(): BlockPos
: Returns the event’s level.getLevel()
: Returns the event’s.getBlock()
BlockContainerJS
: Returns an.getBounds()
AABB
representing the total effected area
: Returns the player that doused the fire, may be null.getPlayer()
: Returns the position that is being doused.getPos()
Example
// replicates TFC's behavior with regular fire blocks
TFCEvents.douseFire(event => {
if (event.block.id == 'kubejs:my_burning_block') {
level.removeBlock(event.block.pos, false)
event.cancel();
}
})
Custom Food Traits
- Type:
startup_scripts
Food traits are applied to food items while in a container or after completion of a recipe and are used to effect how fast an item rots
Method Signature
event.registerTrait(decayModifier: number, id: String): void
event.registerTraitWithTooltip(decayModifier: number, id: String): void
: Registers a food trait under the given id with the provided decay modifier.registerTrait(decayModifier: number, id: String)
: Registers a food trait under the given id with the provided decay modifier, this trait will have a tooltip on the item with a translation key of.registerTraitWithTooltip(decayModifier: number, id: String)
<id namespace>.tooltip.foodtrait.<id path>
Note: A higher decayModifier
means the food rots faster
Examples
TFCEvents.registerFoodTrait(event => {
event.registerTrait(2.0, 'kubejs:trash')
event.registerTraitWithTooltip(1.2, 'kubejs:stinky')
})
Custom Item Stack Modifiers
- Type:
startup_scripts
TFC uses item stack modifiers to, as one might imagine, modify item stacks created by recipes that support item stack providers. This event allows you to register custom modifiers with new functionality
Method Signatures
simple(id: String, applicator: Function<ItemStack, ItemStack>): void
withInput(id: String, applicator: BiFunction<ItemStack, ItemStack, ItemStack>): void
withInventory(id: String, applicator: TriFunction<ItemStack, ItemStack, Iterable<ItemStack>, ItemStack>): void
: Registers a modifier that is not input dependent.simple(id: String, applicator: Function<ItemStack, ItemStack>)
id: String
: A string, the registry id to register the modifier asapplicator: Function<ItemStack, ItemStack>
: A function that receives and returns anItemStack
, the output stack. Performs the modifications to the output stack
: Registers a modifier that is input dependent.withInput(id: String, applicator: BiFunction<ItemStack, ItemStack, ItemStack>)
id: String
: A string, the registry id to register the modifier asapplicator: BiFunction<ItemStack, ItemStack, ItemStack>
: A bi-function that receives twoItemStack
s, the output stack and the input stack2, and returns anItemStack
, the modified output stack. Performs the modifications to the output stack
: Registers a modifier that is input dependent and has access to an iterable view of the input inventory.withInventory(id: String, applicator: TriFunction<ItemStack, ItemStack, Iterable<ItemStack>, ItemStack>)
id: String
: A string, the registry id to register the modifier asapplicator: TriFunction<ItemStack, ItemStack, Iterable<ItemStack>, ItemStack>
: A tri-function that receives twoItemStack
s, the output stack and the input stack2, and anIterable<ItemStack>
, an iterable view of the input inventory, and returns anItemStack
, the modified output stack. Performs the modifications to the output stack
Examples
TFCEvents.registerItemStackModifier(event => {
// Doubles the stack size of the output
event.simple('kubejs:double', stack => {
stack.grow(stack.count);
return stack;
})
// Copies the input stack's nbt data to the output if present
event.withInput('kubejs:copy_nbt', (output, input) => {
let { nbt } = input
if (nbt) {
output.orCreateTag.merge(nbt)
}
return output
})
// Copies all of the input stacks' nbt into the output stack
event.withInventory('kubejs_copy_all_nbt', (output, input, inventory) => {
inventory.forEach(stack => {
let { nbt } = stack;
if (nbt) {
output.orCreateTag.merge(nbt)
}
})
return output
})
})
Register Representative Blocks
- Type:
startup_scripts
In 1.20, TFC added a representative blocks system for prospecting, essentially allowing ores of the same type but different grades to be viewed as the same when the prospector’s pick counts the blocks nearby, this event allows you to register new representatives
Method Signature
event.register(representative: Block, blocks: Block[]): void
- 1st argument: The block to represent the other blocks
- 2nd argument: An array of blocks, to be represented by the first argument when prospecting
Example
TFCEvents.prospectRepresentative(event => {
event.register('minecraft:clay', ['tfc:clay/loam', 'tfc:clay/silt', 'tfc:clay/sandy_loam', 'tfc:clay/silty_loam'])
})
Modify Birthdays
- Type:
startup_scripts
TFC has an easter egg in its calendar screen where on certain dates it will show someone’s birthday, this event allows you to add and remove names from the list of birthdays
Method Signatures
event.add(month: Month, day: number, name: String): void
event.remove(month: Month, day: number): void
event.removeAll(): void
: Adds a birthday to the given month and day.add(month: Month, day: number, name: String)
: Removes the birthday on the given month and day if there is one.remove(month: Month, day: number)
: Removes all birthdays.removeAll()
Example
TFCEvents.birthdays(event => {
event.add('august', 4, 'Barack Obama')
})
Register interactions
- Type:
startup_scripts
TFC has a custom system for performing certain interactions with items, most notably knapping, this event exposes the ability to create your own interactions
Method Signatures
event.interaction(ingredient: Ingredient, targetBlocks: boolean, targetAir: boolean, action: OnItemUseAction): void
event.interaction(ingredient: Ingredient, targetAir: boolean, action: OnItemUseAction): void
event.interaction(ingredient: Ingredient, action: OnItemUseAction): void
event.blockItemPlacement(item: Item, block: Block): void
: Registers the given ingredient for the provided action, the boolean params determine if blocks and air should be valid targets.interaction(ingredient: Ingredient, targetBlocks: boolean, targetAir: boolean, action: OnItemUseAction)
: Registers the given ingredient for the provided action, the boolean param determines if air is a valid target, blocks default to being a valid target.interaction(ingredient: Ingredient, targetAir: boolean, action: OnItemUseAction)
: Registers the given ingredient for the provided action, defaulting to blocks being valid targets and air not.interaction(ingredient: Ingredient, action: OnItemUseAction)
: Registers a block placement for the given item, placing the given block.blockItemPlacement(item: Item, block: Block)
Example
TFCEvents.registerInteractions(event => {
event.interaction('minecraft:diamond', (stack, ctx) => {
// Do what ever you want when a diamond is right clicked
return 'pass'
})
})
OnItemUseAction
The basis of an interaction, a callback with two parameters and a return value:
stack: ItemStack
: The item in the handcontext: UseOnContext
: The context of the eventreturn: InteractionResult
: The result of the interaction, may besuccess
,consume
,consume_partial
,pass
, orfail
Modifying Worldgen defaults
Type: startup_scripts
Allows for editing the default settings of TFC chunk generator at world creation, including editing the rock layers
Method Signatures
event.flatBedrock(flat?: boolean): void
event.setSpawnDistance(i: number): void
event.setSpawnCenterX(i: number): void
event.setSpawnCenterZ(i: number): void
event.setTemperatureScale(i: number): void
event.setTemperatureConstant(f: number): void
event.setRainfallScale(i: number): void
event.setRainfallConstant(f: number): void
event.setContinentalness(f: number): void
event.setGrassDensity(f: number): void
event.addRock(rock: RockSettings, name: String, bottom: boolean): void
event.addRockFromId(id: String, name: String, bottom: boolean): void
event.getRock(name: String): RockSettings
event.getRockNames(): Set<String>
event.removeRock(name: String): void
event.addToBottom(name: String): void
event.removeFromBottom(name: String): void
event.defineLayer(id: String, rockMap: Map<String, String>): void
event.removeLayer(layerId: String): void
event.getLayerIds(): List<String>
event.cleanSlate(): void
event.addOceanFloorLayer(name: String): void
event.removeOceanFloorLayer(name: String): void
event.getOceanFloorLayers(): List<String>
event.addLandLayer(name: String): void
event.removeLandLayer(name: String): void
event.getLandLayers(): List<String>
event.addVolcanicLayer(name: String): void
event.removeVolcanicLayer(name: String): void
event.getVolcanicLayers(): List<String>
event.addUpliftLayer(name: String): void
event.removeUpliftLayer(name: String): void
event.getUpliftLayers(): List<String>
Climate Modifiers
: Sets if the world should have flat bedrock, defaults to.flatBedrock(flat?: boolean)
false
, calling without any arguments sets it totrue
: Sets the distance from the spawn center that players may spawn, defaults to.setSpawnDistance(i: number)
4000
: Sets the spawn center on the x-coordinate, defaults to.setSpawnCenterX(i: number)
0
: Sets the spawn center on the z-coordinate, defaults to.setSpawnCenterZ(i: number)
0
: Sets the temperature scale of the world, the distance from pole-to-pole, defaults to.setTemperatureScale(i: number)
20000
: Sets the relative constant temperature of the world, defaults to.setTemperatureConstant(f: number)
0
: Sets the rainfall scale of the world, the distance from peak to peak, defaults to.setRainfallScale(i: number)
20000
: Sets the relative constant temperature of the world, defaults to.setRainfallConstant(f: number)
0
: Sets the proportion of the world that is land instead of water, defaults to.setContinentalness(f: number)
0.5
. A value of0
translates to -100% on the world creation screen and1
translates to +100%
: Sets the grass density of the world, defaults to.setGrassDensity(f: number)
0.5
. A value of0
translates to -100% on the world creation screen and1
translates to +100%
Rock Layer Settings Modifiers
TFC’s worldgen is primarily based around rocks, layers, and layer types3. There are 5 layer types, bottom
, ocean_floor
, land
, volcanic
, and uplift
, the bottom
layer type is unique in that it only possesses rocks, the rest only possess layers. Layer types determine which geologic environment a rock/layer will generate. Every layer type must have at least one entry. Layers and rocks are user defined and are referenced by name. Rocks define which blocks are placed where, see registering them for more about that. Layers are a list of rock-layer pairs, associating a rock with the layer that should generate underneath it
: Adds the given rock to the generator’s pool of available rocks.addRock(rock: RockSettings, name: String, bottom: boolean)
rock: RockSettings
: theRockSettings
to addname: String
: The name which the rock can be referenced bybottom: boolean
: If the rock should be added to the ‘bottom’ layer of the world
: Adds the given rock to the generator’s pool of available rocks.addRockFromId(id: String, name: String, bottom: boolean)
id: String
: the registered id of theRockSettings
to addname: String
: The name which the rock can be referenced bybottom: boolean
: If the rock should be added the the ‘bottom’ layer of the world
: Returns the.getRock(name: String)
RockSettings
with the given name
: Returns a set of the names of all the rocks currently in the generator’s pool of rocks.getRockNames()
: Removes the provided rock from the generator’s pool of available rocks and any references to it.removeRock(name: String)
: Adds the given rock to the ‘bottom’ layer.addToBottom(name: String)
: Removes the given rock from the ‘bottom’ layer.removeFromBottom(name: String)
: Defines a new layer.defineLayer(id: String, rockMap: Map<String, String>)
id:String
: the name of the layer to addrockMap: Map<STring, String>
: A map of rock names to layer names, associates a rock with the layer that will generate underneath it
: removes the given layer from the generator.removeLayer(layerId: String)
: returns a list of the names of all layers currently in the generator’s pool of layers.getLayerIds()
: Removes all rocks and layers from the generator.cleanSlate()
: Adds the given layer to the ‘ocean_floor’ layer type.addOceanFloorLayer(name: String)
: removes the given layer from the ‘ocean_floor’ layer type.removeOceanFloorLayer(name: String)
: Gets the layers currently in the ‘ocean_floor’ layer type.getOceanFloorLayers()
: Adds the given layer to the ‘land’ layer type.addLandLayer(name: String)
: removes the given layer from the ‘land’ layer type.removeLandLayer(name: String)
: Gets the layers currently in the ‘land’ layer type.getLandLayers()
: Adds the given layer to the ‘volcanic’ layer type.addVolcanicLayer(name: String)
: Removes the given layer from the ‘volcanic’ layer type.removeVolcanicLayer(name: String)
: Gets the layers currently in the ‘volcanic’ layer type.getVolcanicLayers()
: Adds the given layer to the ‘uplift’ layer type.addUpliftLayer(name: String)
: Removes the given layer from the ‘uplift’ layer type.removeUpliftLayer(name: String)
: Gets the layers that are currently in the ‘uplift’ layer type.getUpliftLayers()
Example
TFCEvents.defaultWorldSettings(event => {
event.rainfallScale = 4000
event.continentalness = -3.5
event.defineLayer('my_cool_layer', {
granite: 'my_cool_layer',
dolomite: 'my_cool_layer',
diorite: 'felsic'
})
event.addLandLayer('my_cool_layer')
})
Register Fauna Definitions
Type: startup_scripts
Allows for registering a fauna definition for any entity type
Method Signatures
event.replace(entityType: EntityType<?>, suffix?: String, placementType: SpawnPlacements$Type, heightmap: Heightmap$Types): void
event.and(entityType: EntityType<?>, suffix?: String, placementType: SpawnPlacements$Type, heightmap: Heightmap$Types): void
event.or(entityType: EntityType<?>, suffix?: String, placementType: SpawnPlacements$Type, heightmap: Heightmap$Types): void
: Registers a new fauna definition for the entity type and overwrites any spawn conditions it may have had before.replace(entityType: EntityType<?>, suffix?: String, placementType: SpawnPlacements$Type, heightmap: Heightmap$Types)
: Registers a new fauna definition for the entity type and ANDs any pre-existing spawn conditions it may have had before with the fauna’s rules.and(entityType: EntityType<?>, suffix?: String, placementType: SpawnPlacements$Type, heightmap: Heightmap$Types)
: Registers a new fauna definition for the entity type and ORs any pre-existing spawn conditions it may have had before with the fauna’s conditions, including other fauna definitions.or(entityType: EntityType<?>, suffix?: String, placementType: SpawnPlacements$Type, heightmap: Heightmap$Types)
All of these methods have the same arguments, which are described below
entityType: EntityType<?>
: The entity type to register the fauna forsuffix?: String
: An optional suffix to the autogenerated fauna id, which by default is just the entity type’s id. Suffixed to the end of the id with a/
. May benull
or simply not presentplacementType: SpawnPlacements$Type
: Any ofon_ground
,in_water
,no_restrictions
, orin_lava
and determines where the entity may be placedheightmap: Heightmap$Types
: Any ofworld_surface_wg
,world_surface
,ocean_floor_wg
,ocean_floor
,motion_blocking
, ormotion_blocking_no_leaves
. See the Minecraft Wiki for an explanation for what each of these mean
Example
TFCEvents.registerFaunas(event => {
event.replace('minecraft:pig', 'on_ground', 'world_surface_wg')
})
Create Glass Operations
Type: startup_scripts
Allows for the creation of new glass operations for use in glassworking recipes
For multiplayer connections the order and names of the new operations must be the same, otherwise the connection will be refused
All operations created via this event will have kubejs_
prefixed to their name
For multiplayer connections the order and names of the new operations must be the same, otherwise the connection will be refused
All operations created via this event will have kubejs_
prefixed to their name
Method Signatures
event.create(name: String, displayStack?: Supplier<ItemStack>, customSound?: ResourceLocation, minHeat?: number)
event.createPowder(powderItemId: ResourceLocation, name: String, customSound?: ResourceLocation, minHeat?: number)
: Creates a new glass operation with the given name.create(name: String, displayStack?: Supplier<ItemStack>, customSound?: ResourceLocation, minHeat?: number)
name: String
: The name of the operation, will be prepended withkubejs_
displayStack?: Supplier<ItemStack>
: An item stack that will be used to display the operation in JEI, if the item istfc:blowpipe_with_glass
,tfc:ceramic_blowpipe_with_glass
will also be displayed. OptionalcustomSound?: ResourceLocation
: The registry id of a custom sound to play when the operation is performed. Optional, defaults tominecraft:block.anvil.use
minHeat?: number
: The minimum heat required to perform the operation. Optional, defaults to 480°C
: Creates a new glass operation with the given name and enables it to be added via the powder bowl.createPowder(powderItemId: ResourceLocation, name: String, customSound?: ResourceLocation, minHeat?: number)
powderItemId: ResourceLocation
: The registry id of an item to use as this operation’s powder, requires thetfc:powders
tag in order to be put in a bowl. Will be used as the display item in JEIname: String
: The name of the operations, will be prepended withkubejs_
customSound?: ResourceLocation
: The registry id of a custom sound to play when the operation is performed. Optional, defaults tominecraft:block.anvil.use
minHeat: number
: The minimum heat required to perform the operation. Optional, defaults to 480°C
Example
TFCEvents.createGlassOperations(event => {
event.createPowder('kubejs:quartz_powder', 'quartz')
})
Create Chunk Data Provider
Type: server_scripts
When used with a specific chunk generator type, this event allows for custom generation of TFC’s ChunkData permitting fauna definitions, climate placement modifiers, TFC’s climate-based structure modifier, and any other configured features which are dependent on the world generator to be TFC-like (erosion, boulders, etc.) to function properly with level generators other than TFC’s.
Chunk Generator
Due to how TFC’s chunk data works, this functionality is inherently tied to a ChunkGenerator
. KubeJS TFC adds a new generator type, kubejs_tfc:wrapped
which will wrap any arbitrary chunk generator and imitate its function while providing TFC’s additional values.
In its json definition, the generator definition has the following fields:
type
must bekubejs_tfc:wrapped
event_key
: The key which the event is fired for. A string.settings
: Same astfc_settings
in TFC’s chunk generator. These values are unlikely to be used except for the rock layer settings which can be used in custom rock generation.generator
: A chunk generator.
Rock Surface Rule Source
In addition, a custom surface rule source that uses the blocks of the RockSettings
, as provided via the rocks callback in the event. This rule source only works with the kubejs_tfc:wrapped
generator wrapping a minecraft:noise
4 chunk generator
In its json definition, the rule source has the following fields:
type
must bekubejs_tfc:rock
fallback_state
: A block state. Used when theRockSettings
at a point could not be found, or the world’s chunk generator is not compatible with this rule sourcerock_block
: A string, one ofraw
,hardened
,gravel
,cobble
,sand
, orsandstone
. Specifies which block from theRockSettings
to use. Optional, defaults toraw
Example
{
"type": "kubejs_tfc:rock",
"rock_block": "sandstone",
"fallback_state": {
"Name": "minecraft:sandstone"
}
}
Method Signatures
event.getWorldSeed(): number
event.getNormalNoise(id: ResourceLocation): NormalNoise
event.partial(gen: BiConsumer<ChunkData, ChunkAccess>): void
event.full(gen: BiConsumer<ChunkData, ChunkAccess>): void
event.erosionalAquifer(aquifer: Function<ChunkAccess, Aquifer>): void
event.rocks(getter: RocksGetter): void
: Returns the seed of the world the chunk data provider is being applied to.getWorldSeed()
: Returns the.getNormalNoise(id: ResourceLocation)
NormalNoise
defined by the noise parameters at the given id
: Sets the calculation for the information required to promote a chunk’s.partial(gen: BiConsumer<ChunkData, ChunkAccess>)
ChunkData
toPARTIAL
. Accepts a callback with two parameters and no return value. If not set, or.generatePartial(...)
is never called, the chunk data will be filled with zero values. The parameters are:data: ChunkData
: TFC’s ChunkData..generatePartial(...)
should be called here..generateFull(...)
can be called here, but there is no guarantee that the chunk will have access to heightmaps during this callback. The parameters for.generatePartial(...)
are:rainfallLayer: LerpFloatLayer
: A LerpFloatLayer of the yearly average rainfall at the corners of the chunk. Used in TFC’s climate model to determine the rainfall at a positiontemperatureLayer: LerpFloatLayer
: A LerpFloatLayer of the yearly average temperature at the corners of the chunk. Used by TFC’s climate model to determine the average temperature at a positionforestType: ForestType
: The forest type of the chunk, may benone
,sparse
,edge
,normal
, orold_growth
forestWeirdness: number
: A number, in the range [0, 1], for the ‘weirdness’ of forests in the chunk. Used by TFC’s forest configured featureforestDensity: number
: A number, in the range [0, 1], for the density of the forests in the chunk. Used by TFC’s forest configured feature
chunk: ChunkAccess
: The chunk data is being generated for. Note: Heightmap access is not guaranteed during this callback
: Sets the calculation for the information required to promote the chunks.full(gen: BiConsumer<ChunkData, ChunkAccess>)
ChunkData
fromPARTIAL
toFULL
. Accepts a callback with two parameters and no return value. If not set, or.generateFull(...)
is never called, the data will be promoted with values matching theocean_floor_wg
heightmap for surface heights and 20 less than the quart average of the surface heights. The parameters are:data: ChunkData
: TFC’s ChunkData..generateFull(...)
should be called here and the chunk is guaranteed to have access to theWORLD_SURFACE_WG
andOCEAN_FLOOR_WG
heightmaps during this callback. The parameters for.generateFull(...)
are:surfaceHeight: int[256]
: An array of integer values of size256
(16
*16
;BlockPos
resolution) representing the surface height of the world. Value indexes arex + 16 * z
wherex
andz
are the local x and z coordinates within the chunk and are in the range [0, 15]. This is where thesurfaceY
parameter of aRocksGetter
callback is gotten from.aquiferSurfaceHeight: int[16]
: An array of integer values of size16
(4
*4
;QuartPos
resolution) representing the height of aquifer surfaces. Only used by TFCAquifers
chunk: ChunkAccess
: The chunk data is being generated for
: Sets the calculation for the.erosionalAquifer(aquifer: Function<ChunkAccess, Aquifer>)
Aquifer
of a given chunk. This aquifer is used by TFC’s erosion feature to place subterranean liquids. Accepts a callback with one parameter and a return value. If not set, an aquifer that only fills air will be returned. The parameters are:chunk: ChunkAccess
: The chunk the aquifer is being generated forreturn: Aquifer
: AnAquifer
. See TFCAquifer for TFC’s implementation.
: Sets the Calculation for the.rocks(getter: RocksGetter)
RockSettings
at a position. Used by several configured feature types to determine what blocks to place. Accepts a callback with 6 parameters and a return value. If not set, or when null is returned, aRockSettings
made entirely of air is returned. The parameters are:x: number
: A number, the x coordinatey: number
: A number, the y coordinatez: number
: A number, the z coordinatesurfaceY: number
: A number, the surface elevation of the block column, as determined from the calculation provided in.full(...)
cache: @Nullable ChunkRockDataCache
: A ChunkRockDataCache which may benull
. Holds the layer height and skew amounts per layerrockLayers: RockLayerSettings
: The RockLayerSettings defined in the chunk generator’ssettings
objectreturn: RockSettings
: A RockSettings describing the rock at the position. Ideally retrieved from theRockLayerSettings
The
RockLayerSettings
provided in the parameters of the callback has a method,.sampleAtLayer(pointRock: int, layerN: int)
which returns aRockSettings
. The parameters are:pointRock: int
: A 32-bit signed integer. The bottom two bits are used to select which primary rock type is used at the 0th layer0b00
: Ocean layer0b01
: Volcanic layer0b10
: Land layer0b11
: Uplift layer
And the top 30 bits are used as a seed for a random number generator used to pick from the layer’s mappings for the next layer when
layerN
is greater than0
layerN: int
: How many times to iterate to a layer’s next layer as described in the layer’s mapping. Accepts any non-negative number; thebottom
pseudo-layer points towards itself
Example
The json chunk generator definition
"generator": {
"type": "kubejs_tfc:wrapped",
"event_key": "nether",
"settings": {
"flat_bedrock": false,
"spawn_distance": 0,
"spawn_center_x": 0,
"spawn_center_z": 0,
"temperature_scale": 0,
"rainfall_scale": 0,
"continentalness": 0,
"rock_layer_settings": {
"rocks": {
"nether": {
"raw": "minecraft:netherrack",
"hardened": "minecraft:blackstone",
"gravel": "minecraft:gravel",
"cobble": "minecraft:basalt",
"sand": "minecraft:soul_sand",
"sandstone": "minecraft:soul_soil"
}
},
"layers": [
{
"id": "nether",
"layers": {
"nether": "bottom"
}
}
],
"bottom": [ "nether" ],
"ocean_floor": [ "nether" ],
"volcanic": [ "nether" ],
"land": [ "nether" ],
"uplift": [ "nether" ]
}
},
"generator": {
"type": "minecraft:noise",
"biome_source": {
"type": "minecraft:multi_noise",
"preset": "minecraft:nether"
},
"settings": "minecraft:nether"
}
}
The event with matching key
TFCEvents.createChunkDataProvider('nether', event => {
const rain = TFC.misc.lerpFloatLayer(0, 0, 0, 0);
const tempLayer = TFC.misc.newOpenSimplex2D(event.worldSeed + 4621678939469)
.spread(0.2)
.octaves(3)
.scaled(70, 90);
const forestLayer = TFC.misc.newOpenSimplex2D(event.worldSeed + 98713856895664)
.spread(0.8)
.terraces(9)
.affine(6, 12)
.scaled(6, 18, 0, 1);
const rockTypeNoise = TFC.misc.newOpenSimplex2D(event.worldSeed + 3216548497)
.spread(0.061)
.scaled(0, 3) // 0: Oceanic; 1: Volcanic; 2: Land; 3: Uplift
.map(val => Math.round(val));
const rockLayerNoise = TFC.misc.newOpenSimplex2D(event.worldSeed + 9774532562233)
.spread(0.000697)
.scaled(0x80000000, 0x7fffffff) // Effectively acts as a random number generator within the range of Java's int type
.map(val => val << 2) // Shift up two bits so the type noise is what is used for rock types instead of the random number
.add(rockTypeNoise);
const rockLayerHeightNoise = TFC.misc.newOpenSimplex2D(event.worldSeed + 30121796313692)
.octaves(6)
.scaled(12, 34)
.spread(0.009);
// Noises defined through json can be gotten through this method
const surfaceNoise = event.getNormalNoise('minecraft:surface');
// Precompute the aquifer heights as constants as this is nether and will not realistically change
var aquifer = [];
var i = 0;
while (i < 16) {
aquifer.push(0);
i++;
}
event.partial((data, chunk) => {
var x = chunk.pos.minBlockX;
var z = chunk.pos.minBlockZ;
var temp = TFC.misc.lerpFloatLayer(
tempLayer.noise(x, z),
tempLayer.noise(x, z + 15),
tempLayer.noise(x + 15, z),
tempLayer.noise(x + 15, z + 15)
);
data.generatePartial(
rain,
temp,
forestLayer.noise(x, z) * 4, // Kube accepts ordinal numbers for enum constants
forestLayer.noise(x * 78423 + 869, z),
forestLayer.noise(x, z * 651349 - 698763)
);
});
event.full((data, chunk) => {
var heights = [];
// In the nether this will always return 127, but this is included as a demonstration of
// using height maps and properly indexing the height values within the array
for (let x = 0 ; x < 16 ; x++) {
for (let z = 0 ; z < 16 ; z++) {
let height = chunk.getHeight('ocean_floor_wg', x, z);
heights[x + 16 * z] = height;
}
}
data.generateFull(heights, aquifer);
});
event.rocks((x, y, z, surfaceY, cache, rockLayers) => {
let layer = 0;
let layerHeight = 0;
let deltaY = surfaceY - y;
do {
// A simplified version of what TFC does for its layer depth
// Of note is the lack of skewing for either the rock layer or the heights
layerHeight = rockLayerHeightNoise.noise(x >> 5, z >> 5) + surfaceNoise.getValue(x, 56, z);
if (deltaY <= layerHeight) {
break;
}
deltaY -= layerHeight;
layer++;
} while (deltaY > 0);
return rockLayers.sampleAtLayer(rockLayerNoise.noise(x, z), layer);
});
})
Item Stack Modifier Converters
Type: startup_scripts
KubeJS TFC’s wrapper around TFC’s ItemStackProvider
s holds its item stack modifiers in json form. Typically, this is fine; but when converting the canon ISP class to the wrapper type, the ISMs need to be converted to json. This is not supported by default
This event allows scripters to register custom ISM -> json converters for types not already handled
By default, all TFC, Firmalife, and TFC Casting with Channels ISM types have converters. Additionally, all simple (extends ItemStackModifier$SingleInstance
) ISM types, including custom kube modifiers, are converted automatically
Method Signature
<T extends ItemStackModifier> event.register(type: Class<T>, converter: BiConsumer<T, JsonObject>): void
- 1st argument: The class to register a converter for
- 2nd argument: A callback with two parameters
- The modifier to be converted
- A
JsonObject
; this already has thetype
property
Example
TFCEvents.registerItemStackModifierConverters(event => {
event.register(Java.loadClass('com.sunshine_mods.sunny_tfc.common.SunnyModifier'), (modifier, json) => {
json.addProperty('sun_value', modifier.sunValue());
json.addProperty('brightness', modifier.brightness());
})
})
-
A full list of
MenuType
s can be accessed by running/kubejs dump_registry minecraft:menu
in-game ↩ -
These terms are unofficial and exist to better help explain TFC’s worldgen ↩
-
Or any generator type which extends
NoiseBasedChunkGenerator
and overrides.buildSurface(ChunkAccess,WorldGenerationContext,RandomState,StructureManager,BiomeManager,Registry<Biome>,Blender)
↩