diff --git a/README.md b/README.md index 2e11039..7984c1c 100644 --- a/README.md +++ b/README.md @@ -404,7 +404,7 @@ Currently, supported these components of items: ## Conium script APIs -Documents are not done yet. +See the [Conium scripting](./document/script/kotlin/README.md). ## Bedrock script APIs @@ -412,7 +412,7 @@ Not completed bedrock script APIs supports now, only framework able to runs the ### Grammars -About typescript grammar, supported by 'language-translator': [Typescript supports](https://github.com/cao-awa/language-translator/tree/main/doc/typescript) +About typescript grammar, supported by ```language-translator``` or called ```fluxia```: [Typescript supports](https://github.com/cao-awa/language-translator/tree/main/doc/typescript) ### APIs diff --git a/build.gradle b/build.gradle index bfb5972..73e7a5b 100644 --- a/build.gradle +++ b/build.gradle @@ -146,6 +146,10 @@ loom { } } +runClient { + args("--username", "cao_awa") +} + // Add the datagenned files into the jar. sourceSets { main { diff --git a/document/script/kotlin/event/README.md b/document/script/kotlin/event/README.md index f3d4469..1a82bd0 100644 --- a/document/script/kotlin/event/README.md +++ b/document/script/kotlin/event/README.md @@ -2,15 +2,21 @@ ## Event types -| Key | Notes | -|------------------:|:-----------------------------------:| -| SERVER_TICK | Trigger in every server tick | -| ITEM_USE_ON_BLOCK | Trigger when an item use on a block | -| BREAK_BLOCK | Trigger when breaking block | -| PLACE_BLOCK | Trigger when placing block | -| PLACED_BLOCK | Trigger when block placed | -| USE_BLOCK | Trigger when using block | -| USED_BLOCK | Trigger when block used | +| Key | Notes | Environment | Cancelable | +|------------------:|:-----------------------------------:|------------:|-----------:| +| SERVER_TICK | Trigger in every server tick | SERVER | false | +| ITEM_USE_ON_BLOCK | Trigger when an item use on a block | ALL | true | +| BREAKING_BLOCK | Trigger when breaking block | ALL | true | +| BREAK_BLOCK | Trigger when broking block | SERVER | true | +| BROKEN_BLOCK | Trigger when broken block | ALL | false | +| PLACE_BLOCK | Trigger when placing block | ALL | true | +| PLACED_BLOCK | Trigger when block placed | ALL | false | +| USE_BLOCK | Trigger when using block | ALL | true | +| USED_BLOCK | Trigger when block used | ALL | false | +| ENTITY_DAMAGE | Trigger when entity damaging | ALL | true | +| ENTITY_DAMAGED | Trigger when entity damaged | ALL | false | +| ENTITY_DIE | Trigger when entity dying | ALL | true | +| ENTITY_DIED | Trigger when entity died | ALL | false | ## Context args @@ -22,7 +28,7 @@ For example: request( // This is the event type. PLACE_BLOCK, - // This is the conext args. + // This is the context args. SERVER_WORLD, // This also. BLOCK_POS, @@ -30,20 +36,20 @@ request( ITEM_STACK ) { _, world, pos, stack -> // When you defines how many context args in 'request', - // then you must defines they in arising context as consistent order and quantity. + // then you must define them in arising context as consistent order and quantity. true } request( // This is the event type. PLACE_BLOCK, - // This is the conext args. + // This is the context args. SERVER_WORLD, // This also. ITEM_STACK ) { _, world, stack -> - // Here missing 'BLOCK_POS', so arising context also must missing it. - // Arising context should match to 'request' required args. + // Here missing 'BLOCK_POS', so arising context also must miss it to match requiring args. + // Arising context should match the required arguments for 'request'. true } ``` @@ -58,34 +64,49 @@ This is the ```DynamicArgs``` transform(or adapter) mechanism, dynamic args use For details, see [ConiumEventArgTypes](/src/main/java/com/github/cao/awa/conium/event/type/ConiumEventArgTypes.kt) and [DynamicArgsBuilder#transform](/src/main/java/com/github/cao/awa/conium/parameter/DynamicArgsBuilder.kt). If required arg is still unable to found when the dynamic args for-each to all other args and runs all transform presets,\ -then this ```request``` of this event will not be arising, because the parameters of arising and presaging don't receive null value. +then this ```request``` of this event will not be arising, because the parameters of ```arising``` and ```presaging``` don't receive null value. Avoid the trouble of guessing yourself, all args possible to uses for every event is here, \ if you are finding not rarely used parameters, then you need read the ```ConiumEventArgTypes```. ### SERVER_TICK -SERVER +| Key | Transform from | +|-------:|:--------------:| +| SERVER | * | ### ITEM_USE_ON_BLOCK +### BREAKING_BLOCK + ### BREAK_BLOCK -### PLACE_BLOCK +### BROKEN_BLOCK -```ITEM_PLACEMENT_CONTEXT``` () +### PLACE_BLOCK -```WORLD``` (transform from ```ITEM_PLACEMENT_CONTEXT```) \ -```SERVER_WORLD``` (transform from ```ITEM_PLACEMENT_CONTEXT```) \ -```CLIENT_WORLD``` (transform from ```ITEM_PLACEMENT_CONTEXT```) \ -```ITEM_STACK``` (transform from ```ITEM_PLACEMENT_CONTEXT```) \ -```PLAYER``` (transform from ```ITEM_PLACEMENT_CONTEXT```) \ -```SERVER_PLAYER``` (transform from ```ITEM_PLACEMENT_CONTEXT```) \ -```CLIENT_PLAYER``` (transform from ```ITEM_PLACEMENT_CONTEXT```) \ -```BLOCK_POS``` (transform from ```ITEM_PLACEMENT_CONTEXT```) +| Key | Transform from | Environment | +|-----------------------:|:----------------------:|------------:| +| ITEM_PLACEMENT_CONTEXT | * | ALL | +| WORLD | ITEM_PLACEMENT_CONTEXT | ALL | +| SERVER_WORLD | ITEM_PLACEMENT_CONTEXT | SERVER | +| CLIENT_WORLD | ITEM_PLACEMENT_CONTEXT | CLIENT | +| ITEM_STACK | ITEM_PLACEMENT_CONTEXT | ALL | +| PLAYER | ITEM_PLACEMENT_CONTEXT | ALL | +| SERVER_PLAYER | ITEM_PLACEMENT_CONTEXT | SERVER | +| CLIENT_PLAYER | ITEM_PLACEMENT_CONTEXT | CLIENT | +| BLOCK_POS | ITEM_PLACEMENT_CONTEXT | ALL | ### PLACED_BLOCK ### USE_BLOCK ### USED_BLOCK + +### ENTITY_DAMAGE + +### ENTITY_DAMAGED + +### ENTITY_DIE + +### ENTITY_DIED diff --git a/sample/datapacks/tests/data/awa/script/conium_fools_day.kts b/sample/datapacks/tests/data/awa/script/conium_fools_day.kts index 73346a1..2f38cc9 100644 --- a/sample/datapacks/tests/data/awa/script/conium_fools_day.kts +++ b/sample/datapacks/tests/data/awa/script/conium_fools_day.kts @@ -3,12 +3,12 @@ import net.minecraft.server.network.ServerPlayerEntity import java.util.* import net.minecraft.util.math.Vec3d +val random = Random() + request( SERVER_TICK, SERVER ) { _, server -> - val random = Random() - server.worlds.forEach { world -> world.iterateEntities().forEach { entity -> if (entity != null && entity !is ServerPlayerEntity) { @@ -34,6 +34,15 @@ request( true } +request( + PLACE_BLOCK, + SERVER_WORLD +) { _, world -> + println(world) + + true +} + // Let blue bed explosion! request( USE_BLOCK, @@ -48,3 +57,21 @@ request( true } + +request( + ENTITY_DIE, + LIVING_ENTITY +).presage { _, entity -> + println("${entity} dying") + + false +} + +request( + ENTITY_DEAD, + LIVING_ENTITY +) { _, entity -> + println("${entity} dead") + + true +} diff --git a/src/main/java/com/github/cao/awa/conium/bedrock/event/BedrockBeforeEvents.kt b/src/main/java/com/github/cao/awa/conium/bedrock/event/BedrockBeforeEvents.kt index 82a0dae..a0e6831 100644 --- a/src/main/java/com/github/cao/awa/conium/bedrock/event/BedrockBeforeEvents.kt +++ b/src/main/java/com/github/cao/awa/conium/bedrock/event/BedrockBeforeEvents.kt @@ -11,5 +11,6 @@ class BedrockBeforeEvents { val EVENTS = BedrockBeforeEvents() } + @BedrockScriptApi val itemUseOn = BedrockItemUseOnBeforeEvent() } diff --git a/src/main/java/com/github/cao/awa/conium/bedrock/event/item/use/BedrockItemUseOnBeforeEvent.kt b/src/main/java/com/github/cao/awa/conium/bedrock/event/item/use/BedrockItemUseOnBeforeEvent.kt index 6dc44fd..c564e33 100644 --- a/src/main/java/com/github/cao/awa/conium/bedrock/event/item/use/BedrockItemUseOnBeforeEvent.kt +++ b/src/main/java/com/github/cao/awa/conium/bedrock/event/item/use/BedrockItemUseOnBeforeEvent.kt @@ -13,11 +13,10 @@ import com.github.cao.awa.conium.parameter.ParameterSelective1 @BedrockScriptApi @BedrockScriptApiFacade("ItemUseOnBeforeEventSignal") class BedrockItemUseOnBeforeEvent { + @BedrockScriptApi fun subscribe(action: ParameterSelective1) { val currentPosting = BedrockEventContext.currentPosting!! - println("$currentPosting subscribing to item use on") - ConiumEventContextBuilder.request( ConiumEventType.ITEM_USE_ON_BLOCK, ConiumEventArgTypes.ITEM_USAGE_CONTEXT diff --git a/src/main/java/com/github/cao/awa/conium/block/event/breaking/ConiumBreakingBlockEvent.kt b/src/main/java/com/github/cao/awa/conium/block/event/breaking/ConiumBreakingBlockEvent.kt new file mode 100644 index 0000000..12bbc4a --- /dev/null +++ b/src/main/java/com/github/cao/awa/conium/block/event/breaking/ConiumBreakingBlockEvent.kt @@ -0,0 +1,30 @@ +package com.github.cao.awa.conium.block.event.breaking + +import com.github.cao.awa.conium.event.ConiumEvent +import com.github.cao.awa.conium.event.context.ConiumEventContext +import com.github.cao.awa.conium.event.context.ConiumEventContextBuilder.requires +import com.github.cao.awa.conium.event.type.ConiumEventArgTypes +import com.github.cao.awa.conium.event.type.ConiumEventType +import com.github.cao.awa.conium.parameter.ParameterSelective +import com.github.cao.awa.conium.parameter.ParameterSelective4 +import net.minecraft.block.AbstractBlock.AbstractBlockState +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World + +class ConiumBreakingBlockEvent : ConiumEvent>() { + override fun requirement(): ConiumEventContext { + return requires( + ConiumEventArgTypes.WORLD, + ConiumEventArgTypes.PLAYER, + ConiumEventArgTypes.BLOCK_POS, + ConiumEventArgTypes.BLOCK_STATE + ).attach( + forever(ConiumEventType.BREAKING_BLOCK) + ).arise { identity, world, player, blockPos, state -> + noFailure(identity) { + it.arise(world, player, blockPos, state) + } + } + } +} diff --git a/src/main/java/com/github/cao/awa/conium/block/event/breaking/ConiumBrokenBlockEvent.kt b/src/main/java/com/github/cao/awa/conium/block/event/breaking/ConiumBrokenBlockEvent.kt new file mode 100644 index 0000000..8130d7f --- /dev/null +++ b/src/main/java/com/github/cao/awa/conium/block/event/breaking/ConiumBrokenBlockEvent.kt @@ -0,0 +1,31 @@ +package com.github.cao.awa.conium.block.event.breaking + +import com.github.cao.awa.conium.event.ConiumEvent +import com.github.cao.awa.conium.event.context.ConiumEventContext +import com.github.cao.awa.conium.event.context.ConiumEventContextBuilder.requires +import com.github.cao.awa.conium.event.type.ConiumEventArgTypes +import com.github.cao.awa.conium.event.type.ConiumEventType +import com.github.cao.awa.conium.parameter.ParameterSelective +import com.github.cao.awa.conium.parameter.ParameterSelective3 +import com.github.cao.awa.conium.parameter.ParameterSelective4 +import net.minecraft.block.AbstractBlock.AbstractBlockState +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.util.math.BlockPos +import net.minecraft.world.World + +class ConiumBrokenBlockEvent : ConiumEvent>() { + override fun requirement(): ConiumEventContext { + return requires( + ConiumEventArgTypes.WORLD, + ConiumEventArgTypes.PLAYER, + ConiumEventArgTypes.BLOCK_POS, + ConiumEventArgTypes.BLOCK_STATE + ).attach( + forever(ConiumEventType.BROKEN_BLOCK) + ).arise { identity, world, player, blockPos, state -> + noFailure(identity) { + it.arise(world, player, blockPos, state) + } + } + } +} diff --git a/src/main/java/com/github/cao/awa/conium/datapack/script/ConiumScriptManager.kt b/src/main/java/com/github/cao/awa/conium/datapack/script/ConiumScriptManager.kt index 58a30d0..b04874d 100644 --- a/src/main/java/com/github/cao/awa/conium/datapack/script/ConiumScriptManager.kt +++ b/src/main/java/com/github/cao/awa/conium/datapack/script/ConiumScriptManager.kt @@ -147,12 +147,12 @@ class ConiumScriptManager : SinglePreparationResourceReloader().let { scripts -> // Load commons. - scripts.add(ScriptEval(defaultCommons)) + scripts.add(ScriptEval(defaultCommons, "ConiumCommons")) // Bedrock common is only load when conium allow bedrock. if (Conium.allowBedrock) { - scripts.add(ScriptEval(defaultBedrockCommons, "ConiumCommons")) - scripts.add(ScriptEval(defaultBedrockScriptInit, "ConiumCommons", "ConiumBedrockCommons")) + scripts.add(ScriptEval(defaultBedrockCommons, "ConiumBedrockCommons", "ConiumCommons")) + scripts.add(ScriptEval(defaultBedrockScriptInit, "ConiumBedrockScriptInit", "ConiumCommons", "ConiumBedrockCommons")) } for (script in prepared) { @@ -165,7 +165,7 @@ class ConiumScriptManager : SinglePreparationResourceReloader if (path.endsWith(".kts")) { // Load script data after. - scripts.add(ScriptEval(content, "ConiumCommons")) + scripts.add(ScriptEval(content, path, "ConiumCommons")) } else if (!Conium.allowBedrock) { // When disabled bedrock script allows, then script won't be load. LOGGER.warn("Conium are disabled bedrock script, ignored '$identifier'") @@ -174,6 +174,7 @@ class ConiumScriptManager : SinglePreparationResourceReloader Unit ): ResultWithDiagnostics { // Import scripts to this script. - val content = ScriptExport.import(this.exportedScript, source, *defaultImports) + val content = ScriptExport.import(this.exportedScript, scriptEval.codes, *scriptEval.defaultImports) + + LOGGER.info( + "Evaluating script '{}'", + scriptEval.source + ) // The 'eval' in host will compile and evaluate the script. val result = host.eval( @@ -337,17 +340,34 @@ class ConiumScriptManager : SinglePreparationResourceReloader resultCallback() - } + is ResultWithDiagnostics.Failure -> { + LOGGER.error( + "Error running script '{}': {}", + scriptEval.source, + result.reports + ) - println(result) + resultCallback() + } + } return result } diff --git a/src/main/java/com/github/cao/awa/conium/entity/event/damage/ConiumEntityDamageEvent.kt b/src/main/java/com/github/cao/awa/conium/entity/event/damage/ConiumEntityDamageEvent.kt new file mode 100644 index 0000000..c26b050 --- /dev/null +++ b/src/main/java/com/github/cao/awa/conium/entity/event/damage/ConiumEntityDamageEvent.kt @@ -0,0 +1,29 @@ +package com.github.cao.awa.conium.entity.event.damage + +import com.github.cao.awa.conium.event.ConiumEvent +import com.github.cao.awa.conium.event.context.ConiumEventContext +import com.github.cao.awa.conium.event.context.ConiumEventContextBuilder.requires +import com.github.cao.awa.conium.event.type.ConiumEventArgTypes +import com.github.cao.awa.conium.event.type.ConiumEventType +import com.github.cao.awa.conium.parameter.ParameterSelective +import com.github.cao.awa.conium.parameter.ParameterSelective4 +import net.minecraft.entity.LivingEntity +import net.minecraft.entity.damage.DamageSource +import net.minecraft.world.World + +class ConiumEntityDamageEvent : ConiumEvent>() { + override fun requirement(): ConiumEventContext { + return requires( + ConiumEventArgTypes.WORLD, + ConiumEventArgTypes.LIVING_ENTITY, + ConiumEventArgTypes.DAMAGE_SOURCE, + ConiumEventArgTypes.FLOAT + ).attach( + forever(ConiumEventType.ENTITY_DAMAGE) + ).arise { identity, world, livingEntity, damageSource, amount -> + noFailure(identity) { + it.arise(world, livingEntity, damageSource, amount) + } + } + } +} diff --git a/src/main/java/com/github/cao/awa/conium/entity/event/damage/ConiumEntityDamagedEvent.kt b/src/main/java/com/github/cao/awa/conium/entity/event/damage/ConiumEntityDamagedEvent.kt new file mode 100644 index 0000000..2deb7e6 --- /dev/null +++ b/src/main/java/com/github/cao/awa/conium/entity/event/damage/ConiumEntityDamagedEvent.kt @@ -0,0 +1,29 @@ +package com.github.cao.awa.conium.entity.event.damage + +import com.github.cao.awa.conium.event.ConiumEvent +import com.github.cao.awa.conium.event.context.ConiumEventContext +import com.github.cao.awa.conium.event.context.ConiumEventContextBuilder.requires +import com.github.cao.awa.conium.event.type.ConiumEventArgTypes +import com.github.cao.awa.conium.event.type.ConiumEventType +import com.github.cao.awa.conium.parameter.ParameterSelective +import com.github.cao.awa.conium.parameter.ParameterSelective4 +import net.minecraft.entity.LivingEntity +import net.minecraft.entity.damage.DamageSource +import net.minecraft.world.World + +class ConiumEntityDamagedEvent : ConiumEvent>() { + override fun requirement(): ConiumEventContext { + return requires( + ConiumEventArgTypes.WORLD, + ConiumEventArgTypes.LIVING_ENTITY, + ConiumEventArgTypes.DAMAGE_SOURCE, + ConiumEventArgTypes.FLOAT + ).attach( + forever(ConiumEventType.ENTITY_DAMAGED) + ).arise { identity, world, livingEntity, damageSource, amount -> + noFailure(identity) { + it.arise(world, livingEntity, damageSource, amount) + } + } + } +} diff --git a/src/main/java/com/github/cao/awa/conium/entity/event/die/ConiumEntityDeadEvent.kt b/src/main/java/com/github/cao/awa/conium/entity/event/die/ConiumEntityDeadEvent.kt new file mode 100644 index 0000000..95cecea --- /dev/null +++ b/src/main/java/com/github/cao/awa/conium/entity/event/die/ConiumEntityDeadEvent.kt @@ -0,0 +1,28 @@ +package com.github.cao.awa.conium.entity.event.die + +import com.github.cao.awa.conium.event.ConiumEvent +import com.github.cao.awa.conium.event.context.ConiumEventContext +import com.github.cao.awa.conium.event.context.ConiumEventContextBuilder.requires +import com.github.cao.awa.conium.event.type.ConiumEventArgTypes +import com.github.cao.awa.conium.event.type.ConiumEventType +import com.github.cao.awa.conium.parameter.ParameterSelective +import com.github.cao.awa.conium.parameter.ParameterSelective3 +import net.minecraft.entity.LivingEntity +import net.minecraft.entity.damage.DamageSource +import net.minecraft.world.World + +class ConiumEntityDeadEvent : ConiumEvent>() { + override fun requirement(): ConiumEventContext { + return requires( + ConiumEventArgTypes.WORLD, + ConiumEventArgTypes.LIVING_ENTITY, + ConiumEventArgTypes.DAMAGE_SOURCE + ).attach( + forever(ConiumEventType.ENTITY_DEAD) + ).arise { identity, world, livingEntity, damageSource -> + noFailure(identity) { + it.arise(world, livingEntity, damageSource) + } + } + } +} diff --git a/src/main/java/com/github/cao/awa/conium/entity/event/die/ConiumEntityDieEvent.kt b/src/main/java/com/github/cao/awa/conium/entity/event/die/ConiumEntityDieEvent.kt new file mode 100644 index 0000000..46155ec --- /dev/null +++ b/src/main/java/com/github/cao/awa/conium/entity/event/die/ConiumEntityDieEvent.kt @@ -0,0 +1,28 @@ +package com.github.cao.awa.conium.entity.event.die + +import com.github.cao.awa.conium.event.ConiumEvent +import com.github.cao.awa.conium.event.context.ConiumEventContext +import com.github.cao.awa.conium.event.context.ConiumEventContextBuilder.requires +import com.github.cao.awa.conium.event.type.ConiumEventArgTypes +import com.github.cao.awa.conium.event.type.ConiumEventType +import com.github.cao.awa.conium.parameter.ParameterSelective +import com.github.cao.awa.conium.parameter.ParameterSelective3 +import net.minecraft.entity.LivingEntity +import net.minecraft.entity.damage.DamageSource +import net.minecraft.world.World + +class ConiumEntityDieEvent : ConiumEvent>() { + override fun requirement(): ConiumEventContext { + return requires( + ConiumEventArgTypes.WORLD, + ConiumEventArgTypes.LIVING_ENTITY, + ConiumEventArgTypes.DAMAGE_SOURCE + ).attach( + forever(ConiumEventType.ENTITY_DIE) + ).arise { identity, world, livingEntity, damageSource -> + noFailure(identity) { + it.arise(world, livingEntity, damageSource) + } + } + } +} diff --git a/src/main/java/com/github/cao/awa/conium/entity/renderer/model/ConiumEntityModel.kt b/src/main/java/com/github/cao/awa/conium/entity/renderer/model/ConiumEntityModel.kt index f129415..2461957 100644 --- a/src/main/java/com/github/cao/awa/conium/entity/renderer/model/ConiumEntityModel.kt +++ b/src/main/java/com/github/cao/awa/conium/entity/renderer/model/ConiumEntityModel.kt @@ -51,6 +51,13 @@ class ConiumEntityModel(root: ModelPart) : EntityModel( return TexturedModelData.of(modelData, textureWidth, textureHeight) } + /** + * Create the entity texture model with conium schema. + * + * @author cao_awa + * + * @since 1.0.0 + */ fun createTextureModelData(modelData: ModelData, modelParts: MutableMap, context: Context, json: JsonObject): TexturedModelData { // Texture data, the texture path is handled in the entity model template. val texture = json["texture"].asJsonObject @@ -66,6 +73,14 @@ class ConiumEntityModel(root: ModelPart) : EntityModel( ) } + /** + * Create the entity texture model with bedrock schema. + * + * @author cao_awa + * @author Ryan 100c + * + * @since 1.0.0 + */ fun createBedrockTextureModelData(modelData: ModelData, modelParts: MutableMap, context: Context, geometries: JsonArray): TexturedModelData { // Only allow one of geometry to creating. val geometry = geometries[0].asJsonObject diff --git a/src/main/java/com/github/cao/awa/conium/event/ConiumEvent.kt b/src/main/java/com/github/cao/awa/conium/event/ConiumEvent.kt index 0db60aa..f25df42 100644 --- a/src/main/java/com/github/cao/awa/conium/event/ConiumEvent.kt +++ b/src/main/java/com/github/cao/awa/conium/event/ConiumEvent.kt @@ -1,10 +1,16 @@ package com.github.cao.awa.conium.event import com.github.cao.awa.conium.block.event.breaking.ConiumBreakBlockEvent +import com.github.cao.awa.conium.block.event.breaking.ConiumBreakingBlockEvent +import com.github.cao.awa.conium.block.event.breaking.ConiumBrokenBlockEvent import com.github.cao.awa.conium.block.event.place.ConiumPlaceBlockEvent import com.github.cao.awa.conium.block.event.place.ConiumPlacedBlockEvent import com.github.cao.awa.conium.block.event.use.ConiumUseBlockEvent import com.github.cao.awa.conium.block.event.use.ConiumUsedBlockEvent +import com.github.cao.awa.conium.entity.event.damage.ConiumEntityDamageEvent +import com.github.cao.awa.conium.entity.event.damage.ConiumEntityDamagedEvent +import com.github.cao.awa.conium.entity.event.die.ConiumEntityDeadEvent +import com.github.cao.awa.conium.entity.event.die.ConiumEntityDieEvent import com.github.cao.awa.conium.event.context.ConiumEventContext import com.github.cao.awa.conium.event.server.tick.ConiumServerTickEvent import com.github.cao.awa.conium.event.trigger.ListTriggerable @@ -25,6 +31,12 @@ abstract class ConiumEvent

: ListTriggerable

() { @JvmField val serverTick = ConiumServerTickEvent() + @JvmField + val breakingBlock = ConiumBreakingBlockEvent() + + @JvmField + val brokenBlock = ConiumBrokenBlockEvent() + @JvmField val breakBlock = ConiumBreakBlockEvent() @@ -40,6 +52,18 @@ abstract class ConiumEvent

: ListTriggerable

() { @JvmField val usedBlock = ConiumUsedBlockEvent() + @JvmField + val entityDamage = ConiumEntityDamageEvent() + + @JvmField + val entityDamaged = ConiumEntityDamagedEvent() + + @JvmField + val entityDie = ConiumEntityDieEvent() + + @JvmField + val entityDead = ConiumEntityDeadEvent() + /** * Before event fires, create event context by requirements. * @@ -69,11 +93,20 @@ abstract class ConiumEvent

: ListTriggerable

() { fun init() { this.events[ConiumEventType.ITEM_USE_ON_BLOCK] = this.itemUseOnBlockEvent this.events[ConiumEventType.SERVER_TICK] = this.serverTick + + this.events[ConiumEventType.BREAKING_BLOCK] = this.breakingBlock this.events[ConiumEventType.BREAK_BLOCK] = this.breakBlock + this.events[ConiumEventType.BROKEN_BLOCK] = this.brokenBlock this.events[ConiumEventType.PLACE_BLOCK] = this.placeBlock this.events[ConiumEventType.PLACED_BLOCK] = this.placedBlock this.events[ConiumEventType.USE_BLOCK] = this.useBlock this.events[ConiumEventType.USED_BLOCK] = this.usedBlock + + this.events[ConiumEventType.ENTITY_DAMAGE] = this.entityDamage + this.events[ConiumEventType.ENTITY_DAMAGED] = this.entityDamaged + this.events[ConiumEventType.ENTITY_DIE] = this.entityDie + this.events[ConiumEventType.ENTITY_DEAD] = this.entityDead + } fun clearEntitySubscribes() { diff --git a/src/main/java/com/github/cao/awa/conium/event/type/ConiumEventArgTypes.kt b/src/main/java/com/github/cao/awa/conium/event/type/ConiumEventArgTypes.kt index 38f9bdf..822bdb2 100644 --- a/src/main/java/com/github/cao/awa/conium/event/type/ConiumEventArgTypes.kt +++ b/src/main/java/com/github/cao/awa/conium/event/type/ConiumEventArgTypes.kt @@ -13,6 +13,7 @@ import net.minecraft.world.World import com.github.cao.awa.conium.parameter.type.DynamicArgTypeBuilder.arg import net.minecraft.block.AbstractBlock.AbstractBlockState import net.minecraft.entity.LivingEntity +import net.minecraft.entity.damage.DamageSource import net.minecraft.item.ItemPlacementContext import net.minecraft.item.ItemStack import net.minecraft.server.MinecraftServer @@ -21,74 +22,149 @@ import net.minecraft.util.hit.BlockHitResult object ConiumEventArgTypes { @JvmField - val ITEM_USAGE_CONTEXT: DynamicArgType = arg("item_usage_context") + val ITEM_USAGE_CONTEXT: DynamicArgType @JvmField - val ITEM_PLACEMENT_CONTEXT: DynamicArgType = arg("item_placement_context") + val ITEM_PLACEMENT_CONTEXT: DynamicArgType @JvmField - val ITEM_STACK: DynamicArgType = arg( - "item_stack", - DynamicArgsBuilder.transform(ITEM_PLACEMENT_CONTEXT) { placement -> placement.stack } - ) + val ITEM_STACK: DynamicArgType @JvmField - val ACTION_RESULT: DynamicArgType = arg("action_result") + val ACTION_RESULT: DynamicArgType @JvmField - val SERVER: DynamicArgType = arg("server") + val SERVER: DynamicArgType @JvmField - val WORLD: DynamicArgType = arg("world") + val WORLD: DynamicArgType @JvmField - val SERVER_WORLD: DynamicArgType = arg( - "server_world", - DynamicArgsBuilder.transform(WORLD) { world -> world as? ServerWorld }, - DynamicArgsBuilder.transform(ITEM_PLACEMENT_CONTEXT) { placement -> placement.world as? ServerWorld } - ) + val SERVER_WORLD: DynamicArgType @JvmField - val CLIENT_WORLD: DynamicArgType = arg( - "client_world", - DynamicArgsBuilder.transform(WORLD) { world -> world as? ClientWorld }, - DynamicArgsBuilder.transform(ITEM_PLACEMENT_CONTEXT) { placement -> placement.world as? ClientWorld } - ) + var CLIENT_WORLD: DynamicArgType @JvmField - val BLOCK_POS: DynamicArgType = arg( - "block_pos", - DynamicArgsBuilder.transform(ITEM_PLACEMENT_CONTEXT) { placement -> placement.blockPos } - ) + val BLOCK_POS: DynamicArgType @JvmField - val BLOCK_STATE: DynamicArgType = arg( - "block_state" - ) + val BLOCK_STATE: DynamicArgType @JvmField - val BLOCK_HIT_RESULT: DynamicArgType = arg("block_hit_result") + val BLOCK_HIT_RESULT: DynamicArgType @JvmField - val PLAYER: DynamicArgType = arg( - "player", - DynamicArgsBuilder.transform(ITEM_PLACEMENT_CONTEXT) { placement -> placement.player } - ) + val LIVING_ENTITY: DynamicArgType @JvmField - val LIVING_ENTITY: DynamicArgType = arg("living_entity") + val PLAYER: DynamicArgType @JvmField - val SERVER_PLAYER: DynamicArgType = arg( - "server_player", - DynamicArgsBuilder.transform(PLAYER) { player -> player as? ServerPlayerEntity }, - DynamicArgsBuilder.transform(ITEM_PLACEMENT_CONTEXT) { placement -> placement.player as? ServerPlayerEntity } - ) + val SERVER_PLAYER: DynamicArgType @JvmField - val CLIENT_PLAYER: DynamicArgType = arg( - "client_player", - DynamicArgsBuilder.transform(PLAYER) { player -> player as? ClientPlayerEntity }, - DynamicArgsBuilder.transform(ITEM_PLACEMENT_CONTEXT) { placement -> placement.player as? ClientPlayerEntity } - ) + val CLIENT_PLAYER: DynamicArgType + + @JvmField + val DAMAGE_SOURCE: DynamicArgType + + @JvmField + val INT: DynamicArgType + + @JvmField + val LONG: DynamicArgType + + @JvmField + val FLOAT: DynamicArgType + + @JvmField + val DOUBLE: DynamicArgType + + init { + ITEM_USAGE_CONTEXT = arg("item_usage_context") + + ITEM_PLACEMENT_CONTEXT = arg("item_placement_context") + + ITEM_STACK = arg( + "item_stack", + DynamicArgsBuilder.transform(::ITEM_PLACEMENT_CONTEXT) { placement -> placement.stack } + ) + + ACTION_RESULT = arg("action_result") + + SERVER = arg("server") + + WORLD = arg("world") + + SERVER_WORLD = arg( + "server_world", + DynamicArgsBuilder.transform(::WORLD) { world -> world as? ServerWorld }, + DynamicArgsBuilder.transform(::ITEM_PLACEMENT_CONTEXT) { placement -> placement.world as? ServerWorld } + ) + + CLIENT_WORLD = arg( + "client_world", + DynamicArgsBuilder.transform(::WORLD) { world -> world as? ClientWorld }, + DynamicArgsBuilder.transform(::ITEM_PLACEMENT_CONTEXT) { placement -> placement.world as? ClientWorld } + ) + + BLOCK_POS = arg( + "block_pos", + DynamicArgsBuilder.transform(::ITEM_PLACEMENT_CONTEXT) { placement -> placement.blockPos } + ) + + BLOCK_STATE = arg("block_state") + + BLOCK_HIT_RESULT = arg("block_hit_result") + + LIVING_ENTITY = arg("living_entity") + + PLAYER = arg( + "player", + DynamicArgsBuilder.transform(::ITEM_PLACEMENT_CONTEXT) { placement -> placement.player } + ) + + SERVER_PLAYER = arg( + "server_player", + DynamicArgsBuilder.transform(::PLAYER) { player -> player as? ServerPlayerEntity }, + DynamicArgsBuilder.transform(::ITEM_PLACEMENT_CONTEXT) { placement -> placement.player as? ServerPlayerEntity } + ) + + CLIENT_PLAYER = arg( + "client_player", + DynamicArgsBuilder.transform(::PLAYER) { player -> player as? ClientPlayerEntity }, + DynamicArgsBuilder.transform(::ITEM_PLACEMENT_CONTEXT) { placement -> placement.player as? ClientPlayerEntity } + ) + + DAMAGE_SOURCE = arg("damage_source") + + INT = arg( + "int", + DynamicArgsBuilder.transform(::LONG, Long::toInt), + DynamicArgsBuilder.transform(::FLOAT, Float::toInt), + DynamicArgsBuilder.transform(::DOUBLE, Double::toInt), + ) + + LONG = arg( + "long", + DynamicArgsBuilder.transform(::INT, Int::toLong), + DynamicArgsBuilder.transform(::FLOAT, Float::toLong), + DynamicArgsBuilder.transform(::DOUBLE, Double::toLong), + ) + + FLOAT = arg( + "float", + DynamicArgsBuilder.transform(::INT, Int::toFloat), + DynamicArgsBuilder.transform(::LONG, Long::toFloat), + DynamicArgsBuilder.transform(::DOUBLE, Double::toFloat), + ) + + DOUBLE = arg( + "double", + DynamicArgsBuilder.transform(::INT, Int::toDouble), + DynamicArgsBuilder.transform(::LONG, Long::toDouble), + DynamicArgsBuilder.transform(::FLOAT, Float::toDouble), + ) + } } diff --git a/src/main/java/com/github/cao/awa/conium/event/type/ConiumEventType.kt b/src/main/java/com/github/cao/awa/conium/event/type/ConiumEventType.kt index a9eed6d..6ed7231 100644 --- a/src/main/java/com/github/cao/awa/conium/event/type/ConiumEventType.kt +++ b/src/main/java/com/github/cao/awa/conium/event/type/ConiumEventType.kt @@ -1,15 +1,77 @@ -package com.github.cao.awa.conium.event.type; +package com.github.cao.awa.conium.event.type -public enum ConiumEventType { +import com.github.cao.awa.conium.mixin.server.interaction.ServerPlayerInteractionManagerMixin +import com.github.cao.awa.conium.mixin.client.interaction.ClientPlayerInteractionManagerMixin +import com.github.cao.awa.conium.mixin.block.BlockStateMixin + +enum class ConiumEventType { SERVER_TICK, ITEM_USE_ON_BLOCK, // Block. + /** + * The event where that block is be mining. + * + * This event is cancelable. + * + * @see BlockStateMixin.breakingBlock + * + * @author cao_awa + * + * @since 1.0.0 + */ + BREAKING_BLOCK, + + /** + * The event where that block is be breaking. + * + * This event is cancelable. + * + * ``This event is only for server side`` + * + * @see ServerPlayerInteractionManagerMixin.tryBreakBlock + * + * @author cao_awa + * + * @since 1.0.0 + */ BREAK_BLOCK, + + /** + * The event where that block is be mined. + * + * This event is not cancelable. + * + * @see ServerPlayerInteractionManagerMixin.tryBreakBlock + * @see ClientPlayerInteractionManagerMixin.breakBlock + * + * @author cao_awa + * + * @since 1.0.0 + */ + BROKEN_BLOCK, PLACE_BLOCK, PLACED_BLOCK, USE_BLOCK, USED_BLOCK, + + // Entity. + ENTITY_DAMAGE, + ENTITY_DAMAGED, + + /** + * The event where that entity was dying. + * + * @since 1.0.0 + */ + ENTITY_DIE, + + /** + * The event where that entity was died. + * + * @since 1.0.0 + */ + ENTITY_DEAD, } diff --git a/src/main/java/com/github/cao/awa/conium/mixin/block/AbstractBlockMixin.java b/src/main/java/com/github/cao/awa/conium/mixin/block/AbstractBlockMixin.java new file mode 100644 index 0000000..088ccd9 --- /dev/null +++ b/src/main/java/com/github/cao/awa/conium/mixin/block/AbstractBlockMixin.java @@ -0,0 +1,17 @@ +package com.github.cao.awa.conium.mixin.block; + +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(AbstractBlock.class) +public interface AbstractBlockMixin { + @Invoker("onUse") + ActionResult invokeOnUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit); +} diff --git a/src/main/java/com/github/cao/awa/conium/mixin/block/BlockItemMixin.java b/src/main/java/com/github/cao/awa/conium/mixin/block/BlockItemMixin.java index ca092bf..e97a776 100644 --- a/src/main/java/com/github/cao/awa/conium/mixin/block/BlockItemMixin.java +++ b/src/main/java/com/github/cao/awa/conium/mixin/block/BlockItemMixin.java @@ -17,30 +17,64 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(BlockItem.class) public class BlockItemMixin { + /** + * Inject to {@code place} to trigger event {@code PLACE_BLOCK}. + * + * @param context the placement context + * + * @see ConiumEventType#PLACE_BLOCK + * @see com.github.cao.awa.conium.block.event.place.ConiumPlaceBlockEvent ConiumPlaceBlockEvent + * @see com.github.cao.awa.conium.block.event.place.ConiumPlacedBlockEvent ConiumPlacedBlockEvent + * @see BlockItemMixin#placedBlock + * + * @author cao_awa + * + * @since 1.0.0 + */ @Inject( method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;", at = @At("HEAD"), cancellable = true ) public void placeBlock(ItemPlacementContext context, CallbackInfoReturnable cir) { - ConiumEventContext eventContext = ConiumEvent.request(ConiumEventType.PLACE_BLOCK); + // Request the event. + ConiumEventContext placeBlockContext = ConiumEvent.request(ConiumEventType.PLACE_BLOCK); // Fill the context args. - eventContext.put(ConiumEventArgTypes.ITEM_PLACEMENT_CONTEXT, context); + placeBlockContext.put(ConiumEventArgTypes.ITEM_PLACEMENT_CONTEXT, context); - if (eventContext.presaging(this)) { - eventContext.arising(this); + if (placeBlockContext.presaging(this)) { + // Only presaging state is true can be continues. + placeBlockContext.arising(this); } else { // Cancel this event when presaging was rejected the event. cir.setReturnValue(ActionResult.FAIL); } } + /** + * Redirect the {@code onPlaced} to trigger event {@code PLACED_BLOCK}. + * + * @param instance the block + * @param world the world + * @param pos the position of placed block + * @param state the state of placed block + * @param placer the placer + * @param itemStack the item stack that used to place the block + * + * @see ConiumEventType#PLACED_BLOCK + * @see com.github.cao.awa.conium.block.event.place.ConiumPlacedBlockEvent ConiumPlacedBlockEvent + * @see com.github.cao.awa.conium.block.event.place.ConiumPlaceBlockEvent ConiumPlaceBlockEvent + * @see BlockItemMixin#placeBlock + * + * @author cao_awa + * + * @since 1.0.0 + */ @Redirect( method = "place(Lnet/minecraft/item/ItemPlacementContext;)Lnet/minecraft/util/ActionResult;", at = @At( @@ -49,23 +83,24 @@ public void placeBlock(ItemPlacementContext context, CallbackInfoReturnable eventContext = ConiumEvent.request(ConiumEventType.PLACED_BLOCK); + // Request the event. + ConiumEventContext placedBlockContext = ConiumEvent.request(ConiumEventType.PLACED_BLOCK); // Fill the context args. - eventContext.put(ConiumEventArgTypes.WORLD, world); + placedBlockContext.put(ConiumEventArgTypes.WORLD, world); - eventContext.put(ConiumEventArgTypes.LIVING_ENTITY, placer); + placedBlockContext.put(ConiumEventArgTypes.LIVING_ENTITY, placer); - eventContext.put(ConiumEventArgTypes.BLOCK_POS, pos); - eventContext.put(ConiumEventArgTypes.BLOCK_STATE, state); + placedBlockContext.put(ConiumEventArgTypes.BLOCK_POS, pos); + placedBlockContext.put(ConiumEventArgTypes.BLOCK_STATE, state); - eventContext.put(ConiumEventArgTypes.ITEM_STACK, itemStack); + placedBlockContext.put(ConiumEventArgTypes.ITEM_STACK, itemStack); - if (eventContext.presaging(this)) { + if (placedBlockContext.presaging(this)) { // Only presaging state is true can be continues. instance.onPlaced(world, pos, state, placer, itemStack); - eventContext.arising(this); + placedBlockContext.arising(this); } } } diff --git a/src/main/java/com/github/cao/awa/conium/mixin/block/BlockMixin.java b/src/main/java/com/github/cao/awa/conium/mixin/block/BlockMixin.java index 1af09f9..17ac6be 100644 --- a/src/main/java/com/github/cao/awa/conium/mixin/block/BlockMixin.java +++ b/src/main/java/com/github/cao/awa/conium/mixin/block/BlockMixin.java @@ -1,29 +1,9 @@ package com.github.cao.awa.conium.mixin.block; -import com.github.cao.awa.conium.event.ConiumEvent; -import com.github.cao.awa.conium.event.context.ConiumEventContext; -import com.github.cao.awa.conium.event.type.ConiumEventArgTypes; -import com.github.cao.awa.conium.event.type.ConiumEventType; -import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ActionResult; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -@Mixin(AbstractBlock.class) -public interface BlockMixin { - @Invoker("onUse") - ActionResult invokeOnUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit); +@Mixin(Block.class) +public class BlockMixin { + // } diff --git a/src/main/java/com/github/cao/awa/conium/mixin/block/BlockStateMixin.java b/src/main/java/com/github/cao/awa/conium/mixin/block/BlockStateMixin.java index eeaf2ce..7cc77e8 100644 --- a/src/main/java/com/github/cao/awa/conium/mixin/block/BlockStateMixin.java +++ b/src/main/java/com/github/cao/awa/conium/mixin/block/BlockStateMixin.java @@ -13,7 +13,6 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; @@ -21,15 +20,13 @@ @Mixin(AbstractBlock.AbstractBlockState.class) public abstract class BlockStateMixin { - @Shadow protected abstract BlockState asBlockState(); - @Inject( method = "onBlockBreakStart", at = @At("HEAD"), cancellable = true ) - public void breakBlock(World world, BlockPos pos, PlayerEntity player, CallbackInfo ci) { - ConiumEventContext eventContext = ConiumEvent.request(ConiumEventType.BREAK_BLOCK); + public void breakingBlock(World world, BlockPos pos, PlayerEntity player, CallbackInfo ci) { + ConiumEventContext eventContext = ConiumEvent.request(ConiumEventType.BREAKING_BLOCK); AbstractBlock.AbstractBlockState self = cast(); @@ -74,7 +71,7 @@ public ActionResult useBlock(Block instance, BlockState blockState, World world, if (usingContext.presaging(blockState)) { usingContext.arising(blockState); - ActionResult result = ((BlockMixin) instance).invokeOnUse(blockState, world, blockPos, playerEntity, blockHitResult); + ActionResult result = ((AbstractBlockMixin) instance).invokeOnUse(blockState, world, blockPos, playerEntity, blockHitResult); usedContext.put(ConiumEventArgTypes.ACTION_RESULT, result); diff --git a/src/main/java/com/github/cao/awa/conium/mixin/client/interaction/ClientPlayerInteractionManagerMixin.java b/src/main/java/com/github/cao/awa/conium/mixin/client/interaction/ClientPlayerInteractionManagerMixin.java new file mode 100644 index 0000000..a595c22 --- /dev/null +++ b/src/main/java/com/github/cao/awa/conium/mixin/client/interaction/ClientPlayerInteractionManagerMixin.java @@ -0,0 +1,47 @@ +package com.github.cao.awa.conium.mixin.client.interaction; + +import com.github.cao.awa.conium.event.ConiumEvent; +import com.github.cao.awa.conium.event.context.ConiumEventContext; +import com.github.cao.awa.conium.event.type.ConiumEventArgTypes; +import com.github.cao.awa.conium.event.type.ConiumEventType; +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.OperatorBlock; +import net.minecraft.client.network.ClientPlayerInteractionManager; +import net.minecraft.fluid.FluidState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ClientPlayerInteractionManager.class) +public class ClientPlayerInteractionManagerMixin { + @Redirect( + method = "breakBlock", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/block/Block;onBroken(Lnet/minecraft/world/WorldAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)V" + ) + ) + public void breakBlock(Block instance, WorldAccess world, BlockPos pos, BlockState state) { + ConiumEventContext eventContext = ConiumEvent.request(ConiumEventType.BROKEN_BLOCK); + + // Fill the context args. + eventContext.put(ConiumEventArgTypes.WORLD, (World) world); + + eventContext.put(ConiumEventArgTypes.BLOCK_POS, pos); + eventContext.put(ConiumEventArgTypes.BLOCK_STATE, state); + + if (eventContext.presaging(instance)) { + // Only presaging state is true can be continues. + instance.onBroken(world, pos, state); + + eventContext.arising(instance); + } + } +} diff --git a/src/main/java/com/github/cao/awa/conium/mixin/entity/LivingEntityMixin.java b/src/main/java/com/github/cao/awa/conium/mixin/entity/LivingEntityMixin.java new file mode 100644 index 0000000..80bf2c3 --- /dev/null +++ b/src/main/java/com/github/cao/awa/conium/mixin/entity/LivingEntityMixin.java @@ -0,0 +1,117 @@ +package com.github.cao.awa.conium.mixin.entity; + +import com.github.cao.awa.conium.event.ConiumEvent; +import com.github.cao.awa.conium.event.context.ConiumEventContext; +import com.github.cao.awa.conium.event.type.ConiumEventArgTypes; +import com.github.cao.awa.conium.event.type.ConiumEventType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.server.world.ServerWorld; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(LivingEntity.class) +public class LivingEntityMixin { + @Unique + private LivingEntity cast() { + return (LivingEntity) (Object) this; + } + + @Inject( + method = "damage", + at = @At("HEAD"), + cancellable = true + ) + public void damage(ServerWorld world, DamageSource damageSource, float amount, CallbackInfoReturnable cir) { + // Request the entity damage event. + ConiumEventContext eventContext = ConiumEvent.request(ConiumEventType.ENTITY_DAMAGE); + + LivingEntity self = cast(); + + // Fill the context args. + eventContext.put(ConiumEventArgTypes.WORLD, world); + + eventContext.put(ConiumEventArgTypes.DAMAGE_SOURCE, damageSource); + eventContext.put(ConiumEventArgTypes.LIVING_ENTITY, self); + eventContext.put(ConiumEventArgTypes.FLOAT, amount); + + if (eventContext.presaging(self)) { + // Only presaging state is true can be continues. + eventContext.arising(self); + } else { + // Cancel this event when presaging was rejected the event. + cir.setReturnValue(false); + } + } + + @Inject( + method = "applyDamage", + at = @At("RETURN") + ) + public void damaged(ServerWorld world, DamageSource damageSource, float amount, CallbackInfo ci) { + // Request the entity damaged event. + ConiumEventContext eventContext = ConiumEvent.request(ConiumEventType.ENTITY_DAMAGED); + + LivingEntity self = cast(); + + // Fill the context args. + eventContext.put(ConiumEventArgTypes.WORLD, world); + + eventContext.put(ConiumEventArgTypes.DAMAGE_SOURCE, damageSource); + eventContext.put(ConiumEventArgTypes.LIVING_ENTITY, self); + eventContext.put(ConiumEventArgTypes.FLOAT, amount); + + // The entity damaged event is not cancelable, only arising the context. + if (eventContext.presaging(self)) { + eventContext.arising(self); + } + } + + @Inject( + method = "onDeath", + at = @At("HEAD"), + cancellable = true + ) + public void dying(DamageSource damageSource, CallbackInfo ci) { + // Request the entity dying event. + ConiumEventContext eventContext = ConiumEvent.request(ConiumEventType.ENTITY_DIE); + + LivingEntity self = cast(); + + // Fill the context args. + eventContext.put(ConiumEventArgTypes.DAMAGE_SOURCE, damageSource); + eventContext.put(ConiumEventArgTypes.LIVING_ENTITY, self); + + if (eventContext.presaging(self)) { + // Only presaging state is true can be continues. + eventContext.arising(self); + } else { + // Cancel this event when presaging was rejected the event. + ci.cancel(); + } + } + + @Inject( + method = "onDeath", + at = @At("RETURN") + ) + public void dead(DamageSource damageSource, CallbackInfo ci) { + // Request the entity dead event. + ConiumEventContext eventContext = ConiumEvent.request(ConiumEventType.ENTITY_DEAD); + + LivingEntity self = cast(); + + // Fill the context args. + eventContext.put(ConiumEventArgTypes.DAMAGE_SOURCE, damageSource); + eventContext.put(ConiumEventArgTypes.LIVING_ENTITY, self); + + // The entity dead event is not cancelable, only arising the context. + if (eventContext.presaging(self)) { + eventContext.arising(self); + } + } +} diff --git a/src/main/java/com/github/cao/awa/conium/mixin/renderer/entity/EntityRenderersMixin.java b/src/main/java/com/github/cao/awa/conium/mixin/renderer/entity/EntityRenderersMixin.java index a41a3d3..b611715 100644 --- a/src/main/java/com/github/cao/awa/conium/mixin/renderer/entity/EntityRenderersMixin.java +++ b/src/main/java/com/github/cao/awa/conium/mixin/renderer/entity/EntityRenderersMixin.java @@ -2,20 +2,15 @@ import com.github.cao.awa.conium.client.entity.renderer.ConiumEntityRenderers; import com.google.common.collect.ImmutableMap; -import net.minecraft.client.model.ModelPartBuilder; -import net.minecraft.client.model.ModelPartData; -import net.minecraft.client.model.ModelTransform; import net.minecraft.client.render.entity.EntityRenderer; import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.EntityRenderers; -import net.minecraft.client.render.entity.model.EntityModelPartNames; import net.minecraft.entity.EntityType; import net.minecraft.registry.Registries; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.Map; @@ -29,26 +24,27 @@ public class EntityRenderersMixin { method = "reloadEntityRenderers", at = @At("HEAD") ) - private static void reloadEntityRenderers(EntityRendererFactory.Context ctx, CallbackInfoReturnable, EntityRenderer>> cir) { + private static void reloadEntityRenderersContext(EntityRendererFactory.Context ctx, CallbackInfoReturnable, EntityRenderer>> cir) { currentContext = ctx; } - @Redirect( + @Inject( method = "reloadEntityRenderers", - at = @At( - value = "INVOKE", - target = "Lcom/google/common/collect/ImmutableMap$Builder;build()Lcom/google/common/collect/ImmutableMap;" - ) + at = @At("RETURN"), + cancellable = true ) - private static ImmutableMap, EntityRenderer> reloadEntityRenderers(ImmutableMap.Builder, EntityRenderer> builder) { + private static void reloadEntityRenderers(EntityRendererFactory.Context ctx, CallbackInfoReturnable, EntityRenderer>> cir) { + ImmutableMap.Builder, EntityRenderer> builder = ImmutableMap.builder(); + ConiumEntityRenderers.renderers.forEach((entityType, factory) -> { - System.out.println("Loading renderer: " + entityType); try { builder.put(entityType, factory.create(currentContext)); } catch (Exception var5) { throw new IllegalArgumentException("Failed to create model for " + Registries.ENTITY_TYPE.getId(entityType), var5); } }); - return builder.build(); + builder.putAll(cir.getReturnValue()); + + cir.setReturnValue(builder.build()); } } diff --git a/src/main/java/com/github/cao/awa/conium/mixin/server/interaction/ServerPlayerInteractionManagerMixin.java b/src/main/java/com/github/cao/awa/conium/mixin/server/interaction/ServerPlayerInteractionManagerMixin.java new file mode 100644 index 0000000..822f957 --- /dev/null +++ b/src/main/java/com/github/cao/awa/conium/mixin/server/interaction/ServerPlayerInteractionManagerMixin.java @@ -0,0 +1,112 @@ +package com.github.cao.awa.conium.mixin.server.interaction; + +import com.github.cao.awa.conium.event.ConiumEvent; +import com.github.cao.awa.conium.event.context.ConiumEventContext; +import com.github.cao.awa.conium.event.type.ConiumEventArgTypes; +import com.github.cao.awa.conium.event.type.ConiumEventType; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.OperatorBlock; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.network.ServerPlayerInteractionManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.GameMode; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ServerPlayerInteractionManager.class) +public abstract class ServerPlayerInteractionManagerMixin { + @Shadow protected ServerWorld world; + + @Shadow @Final protected ServerPlayerEntity player; + + @Shadow public abstract boolean isCreative(); + + @Shadow private GameMode gameMode; + + @Inject( + method = "tryBreakBlock", + at = @At(value = "HEAD"), + cancellable = true + ) + public void tryBreakBlock(BlockPos pos, CallbackInfoReturnable cir) { + BlockState blockState = this.world.getBlockState(pos); + if (!this.player.getMainHandStack().getItem().canMine(blockState, this.world, pos, this.player)) { + cir.setReturnValue(false); + } else { + Block block = blockState.getBlock(); + if (block instanceof OperatorBlock && !this.player.isCreativeLevelTwoOp()) { + this.world.updateListeners(pos, blockState, blockState, Block.NOTIFY_ALL); + cir.setReturnValue(false); + } else if (this.player.isBlockBreakingRestricted(this.world, pos, this.gameMode)) { + cir.setReturnValue(false); + } else { + // Request the block break event. + ConiumEventContext breakContext = ConiumEvent.request(ConiumEventType.BREAK_BLOCK); + + // Fill the context args. + + breakContext.put(ConiumEventArgTypes.WORLD, world); + + breakContext.put(ConiumEventArgTypes.PLAYER, player); + + breakContext.put(ConiumEventArgTypes.BLOCK_POS, pos); + breakContext.put(ConiumEventArgTypes.BLOCK_STATE, blockState); + + // Arising the block break context. + if (breakContext.presaging(block)) { + breakContext.arising(block); + } else { + // Cancel this event when presaging was rejected the event. + cir.setReturnValue(false); + return; + } + + BlockState brokenState = block.onBreak(this.world, pos, blockState, this.player); + boolean removedBlock = this.world.removeBlock(pos, false); + if (removedBlock) { + block.onBroken(this.world, pos, brokenState); + + // Request the block broken event. + ConiumEventContext brokenContext = ConiumEvent.request(ConiumEventType.BROKEN_BLOCK); + + // Fill the context args. + brokenContext.inherit(breakContext); + brokenContext.put(ConiumEventArgTypes.BLOCK_STATE, brokenState); + + // The block broken event is not cancelable, only arising the context. + if (breakContext.presaging(block)) { + breakContext.arising(block); + } + } + + if (isCreative()) { + cir.setReturnValue(true); + } else { + ItemStack itemStack = this.player.getMainHandStack(); + boolean canHarvest = this.player.canHarvest(brokenState); + itemStack.postMine(this.world, brokenState, pos, this.player); + if (removedBlock && canHarvest) { + block.afterBreak( + this.world, + this.player, + pos, + brokenState, + this.world.getBlockEntity(pos), + itemStack.copy() + ); + } + + cir.setReturnValue(true); + } + } + } + } +} diff --git a/src/main/java/com/github/cao/awa/conium/parameter/DynamicArgs.kt b/src/main/java/com/github/cao/awa/conium/parameter/DynamicArgs.kt index afdfb86..2893dd2 100644 --- a/src/main/java/com/github/cao/awa/conium/parameter/DynamicArgs.kt +++ b/src/main/java/com/github/cao/awa/conium/parameter/DynamicArgs.kt @@ -6,13 +6,20 @@ import com.mojang.datafixers.util.Function3 class DynamicArgs

( private val trigger: Function3, Any?>, P, R>, - vararg args: DynamicArgType<*> + vararg args: () -> DynamicArgType<*> ) { private val queryArgs: MutableList> = CollectionFactor.arrayList(args.size) private var lifecycle: DynamicArgsLifecycle = DynamicArgsLifecycle.ONCE + constructor(trigger: Function3, Any?>, P, R>, vararg args: DynamicArgType<*>) : this(trigger, *args.map { + val getter: () -> DynamicArgType<*> = { it } + getter + }.toList().toTypedArray()) + + constructor(trigger: Function3, Any?>, P, R>) : this(trigger, *mutableListOf<() -> DynamicArgType<*>>().toTypedArray()) + init { - this.queryArgs.addAll(args) + this.queryArgs.addAll(args.map { it() }) } fun lifecycle(lifecycle: DynamicArgsLifecycle): DynamicArgs { diff --git a/src/main/java/com/github/cao/awa/conium/parameter/DynamicArgsBuilder.kt b/src/main/java/com/github/cao/awa/conium/parameter/DynamicArgsBuilder.kt index 1f30797..001e720 100644 --- a/src/main/java/com/github/cao/awa/conium/parameter/DynamicArgsBuilder.kt +++ b/src/main/java/com/github/cao/awa/conium/parameter/DynamicArgsBuilder.kt @@ -739,5 +739,167 @@ class DynamicArgsBuilder { arg7 ).lifecycle(DynamicArgsLifecycle.TRANSFORM) } + + @JvmStatic + @SuppressWarnings("UNCHECKED_CAST") + fun transform( + arg1: () -> DynamicArgType, + p: ParameterSelective1 + ): DynamicArgs, R?> { + return DynamicArgs, R?>({ _, args, _ -> + p.arise( + args[arg1()] as P1 + ) + }, arg1).lifecycle(DynamicArgsLifecycle.TRANSFORM) + } + + @JvmStatic + @SuppressWarnings("UNCHECKED_CAST") + fun transform( + arg1: () -> DynamicArgType, + p: ParameterSelective2 + ): DynamicArgs, R?> { + return DynamicArgs, R?>({ identity, args, _ -> + p.arise( + identity, + args[arg1()] as P1 + ) + }, arg1).lifecycle(DynamicArgsLifecycle.TRANSFORM) + } + + @JvmStatic + @SuppressWarnings("UNCHECKED_CAST") + fun transform( + arg1: () -> DynamicArgType, + arg2: () -> DynamicArgType, + p: ParameterSelective3 + ): DynamicArgs, R?> { + return DynamicArgs, R?>({ identity, args, _ -> + p.arise( + identity, + args[arg1()] as P1, + args[arg2()] as P2 + ) + }, arg1, arg2).lifecycle(DynamicArgsLifecycle.TRANSFORM) + } + + @JvmStatic + @SuppressWarnings("UNCHECKED_CAST") + fun transform( + arg1: () -> DynamicArgType, + arg2: () -> DynamicArgType, + arg3: () -> DynamicArgType, + p: ParameterSelective4 + ): DynamicArgs, R?> { + return DynamicArgs, R?>({ identity, args, _ -> + p.arise( + identity, + args[arg1()] as P1, + args[arg2()] as P2, + args[arg3()] as P3 + ) + }, arg1, arg2, arg3).lifecycle(DynamicArgsLifecycle.TRANSFORM) + } + + @JvmStatic + @SuppressWarnings("UNCHECKED_CAST") + fun transform( + arg1: () -> DynamicArgType, + arg2: () -> DynamicArgType, + arg3: () -> DynamicArgType, + arg4: () -> DynamicArgType, + p: ParameterSelective5 + ): DynamicArgs, R?> { + return DynamicArgs, R?>({ identity, args, _ -> + p.arise( + identity, + args[arg1()] as P1, + args[arg2()] as P2, + args[arg3()] as P3, + args[arg4()] as P4 + ) + }, arg1, arg2, arg3, arg4).lifecycle(DynamicArgsLifecycle.TRANSFORM) + } + + @JvmStatic + @SuppressWarnings("UNCHECKED_CAST") + fun transform( + arg1: () -> DynamicArgType, + arg2: () -> DynamicArgType, + arg3: () -> DynamicArgType, + arg4: () -> DynamicArgType, + arg5: () -> DynamicArgType, + p: ParameterSelective6 + ): DynamicArgs, R?> { + return DynamicArgs, R?>({ identity, args, _ -> + p.arise( + identity, + args[arg1()] as P1, + args[arg2()] as P2, + args[arg3()] as P3, + args[arg4()] as P4, + args[arg5()] as P5 + ) + }, arg1, arg2, arg3, arg4, arg5).lifecycle(DynamicArgsLifecycle.TRANSFORM) + } + + @JvmStatic + @SuppressWarnings("UNCHECKED_CAST") + fun transform( + arg1: () -> DynamicArgType, + arg2: () -> DynamicArgType, + arg3: () -> DynamicArgType, + arg4: () -> DynamicArgType, + arg5: () -> DynamicArgType, + arg6: () -> DynamicArgType, + p: ParameterSelective7 + ): DynamicArgs, R?> { + return DynamicArgs, R?>({ identity, args, _ -> + p.arise( + identity, + args[arg1()] as P1, + args[arg2()] as P2, + args[arg3()] as P3, + args[arg4()] as P4, + args[arg5()] as P5, + args[arg6()] as P6 + ) + }, arg1, arg2, arg3, arg4, arg5, arg6).lifecycle(DynamicArgsLifecycle.TRANSFORM) + } + + @JvmStatic + @SuppressWarnings("UNCHECKED_CAST") + fun transform( + arg1: () -> DynamicArgType, + arg2: () -> DynamicArgType, + arg3: () -> DynamicArgType, + arg4: () -> DynamicArgType, + arg5: () -> DynamicArgType, + arg6: () -> DynamicArgType, + arg7: () -> DynamicArgType, + p: ParameterSelective8 + ): DynamicArgs, R?> { + return DynamicArgs, R?>( + { identity, args, _ -> + p.arise( + identity, + args[arg1()] as P1, + args[arg2()] as P2, + args[arg3()] as P3, + args[arg4()] as P4, + args[arg5()] as P5, + args[arg6()] as P6, + args[arg7()] as P7 + ) + }, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7 + ).lifecycle(DynamicArgsLifecycle.TRANSFORM) + } } } diff --git a/src/main/java/com/github/cao/awa/conium/script/ScriptExport.kt b/src/main/java/com/github/cao/awa/conium/script/ScriptExport.kt index 237f3c7..a17b221 100644 --- a/src/main/java/com/github/cao/awa/conium/script/ScriptExport.kt +++ b/src/main/java/com/github/cao/awa/conium/script/ScriptExport.kt @@ -35,8 +35,6 @@ class ScriptExport( importing.addAll(it.substring(it.indexOf(":") + 1).split(",").toSet().map(String::trim)) } - println("Importing: $importing : exported: $exported") - for (sourceName in importing) { exported[sourceName]?.let { for (import in it.imports) { diff --git a/src/main/java/com/github/cao/awa/conium/script/eval/ScriptEval.kt b/src/main/java/com/github/cao/awa/conium/script/eval/ScriptEval.kt index bf0be93..9d8c875 100644 --- a/src/main/java/com/github/cao/awa/conium/script/eval/ScriptEval.kt +++ b/src/main/java/com/github/cao/awa/conium/script/eval/ScriptEval.kt @@ -1,5 +1,5 @@ package com.github.cao.awa.conium.script.eval -class ScriptEval(val codes: String, vararg val defaultImports: String) { +class ScriptEval(val codes: String, val source: String, vararg val defaultImports: String) { } diff --git a/src/main/resources/assets/conium/scripts/conium.commons.kts b/src/main/resources/assets/conium/scripts/conium.commons.kts index 525313e..51ee690 100644 --- a/src/main/resources/assets/conium/scripts/conium.commons.kts +++ b/src/main/resources/assets/conium/scripts/conium.commons.kts @@ -23,11 +23,17 @@ import com.github.cao.awa.conium.event.type.ConiumEventArgTypes.ACTION_RESULT import com.github.cao.awa.conium.event.type.ConiumEventType import com.github.cao.awa.conium.event.type.ConiumEventType.SERVER_TICK import com.github.cao.awa.conium.event.type.ConiumEventType.ITEM_USE_ON_BLOCK +import com.github.cao.awa.conium.event.type.ConiumEventType.BREAKING_BLOCK import com.github.cao.awa.conium.event.type.ConiumEventType.BREAK_BLOCK +import com.github.cao.awa.conium.event.type.ConiumEventType.BROKEN_BLOCK import com.github.cao.awa.conium.event.type.ConiumEventType.PLACE_BLOCK import com.github.cao.awa.conium.event.type.ConiumEventType.PLACED_BLOCK import com.github.cao.awa.conium.event.type.ConiumEventType.USE_BLOCK import com.github.cao.awa.conium.event.type.ConiumEventType.USED_BLOCK +import com.github.cao.awa.conium.event.type.ConiumEventType.ENTITY_DAMAGE +import com.github.cao.awa.conium.event.type.ConiumEventType.ENTITY_DAMAGED +import com.github.cao.awa.conium.event.type.ConiumEventType.ENTITY_DIE +import com.github.cao.awa.conium.event.type.ConiumEventType.ENTITY_DEAD import com.github.cao.awa.conium.script.ScriptExport import com.github.cao.awa.conium.script.ScriptExport.Companion.accessExportedField diff --git a/src/main/resources/conium.mixins.json b/src/main/resources/conium.mixins.json index ef29937..b38a63a 100644 --- a/src/main/resources/conium.mixins.json +++ b/src/main/resources/conium.mixins.json @@ -3,7 +3,11 @@ "minVersion": "0.8", "package": "com.github.cao.awa.conium.mixin", "compatibilityLevel": "JAVA_21", + "injectors": { + "defaultRequire": 1 + }, "mixins": [ + "block.AbstractBlockMixin", "block.BlockItemMixin", "block.BlockMixin", "block.BlockStateMixin", @@ -12,6 +16,7 @@ "component.map.builder.ComponentMapBuilderAccessor", "datapack.DataPackContentsMixin", "entity.EntityAccessor", + "entity.LivingEntityMixin", "entity.attribute.DefaultAttributeRegistryMixin", "item.FuelRegistryMixin", "item.ItemMixin", @@ -22,13 +27,12 @@ "registry.NamedRegistryEntryListMixin", "registry.RegistryEntryReferenceMixin", "registry.SimpleRegistryMixin", - "server.MinecraftServerMixin" + "server.MinecraftServerMixin", + "server.interaction.ServerPlayerInteractionManagerMixin" ], - "injectors": { - "defaultRequire": 1 - }, "client": [ "client.MinecraftClientAccessor", + "client.interaction.ClientPlayerInteractionManagerMixin", "renderer.entity.EntityRenderDispatcherMixin", "renderer.entity.EntityRenderersMixin", "renderer.item.ItemModelsAccessor", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index b15c202..5129ddb 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -42,7 +42,7 @@ "recommends": { "fabric": "*", "lithium": "*", - "sepals": "*", + "sepals": ">=1.0.5", "sodium": "*" }, "breaks": {