diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index e73d99ad..9882a423 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -2268,7 +2268,13 @@ It returns a `map` with a report indicating how many chunks were affected, and h * `layer_count_`: number of chunks for which a `` generation step has been performed * `layer_time_`: cumulative time for all chunks spent on generating `` step -# Iterating over larger areas of blocks +### add_chunk_ticket(pos, type, radius) + +Adds a chunk ticket at a position, which makes the game to keep the designated area centered around +`pos` with radius of `radius` loaded for a predefined amount of ticks, defined by `type`. Allowed types +are `portal`: 300 ticks, `teleport`: 5 ticks, and `unknown`: 1 tick. Radius can be from 1 to 32 ticks. + +This function is tentative - will likely change when chunk ticket API is properly fleshed out.# Iterating over larger areas of blocks These functions help scan larger areas of blocks without using generic loop functions, like nested `loop`. @@ -2993,7 +2999,7 @@ __on_tick() // can access blocks and entities in the overworld __on_tick_nether() // can access blocks and entities in the nether __on_tick_ender() // can access blocks and entities in the end __on_chunk_generated(x,z) // called after a chunk is promoted to the full chunk, - // prodiving lowest x and z coords in the chunk + // providing lowest x and z coords in the chunk // event will not work with optifine installed in the game __on_lightning(block, mode) // mode is `true` if lightning caused horse trap to spawn // player specific callbacks @@ -3011,6 +3017,7 @@ __on_player_takes_damage(player, amount, source, source_entity) __on_player_deals_damage(player, amount, entity) __on_player_dies(player) __on_player_respawns(player) +__on_player_changes_dimension(player, from_pos, from_dimension, to_pos, to_dimension) __on_player_rides(player, forward, strafe, jumping, sneaking) __on_player_jumps(player) __on_player_deploys_elytra(player) @@ -3024,6 +3031,11 @@ __on_player_drops_stack(player) __on_statistic(player, category, event, value) // player statistic changes +Couple special cases. +* `__on_player_changes_dimension` returns `null` as `to_pos` when player goes back to the overworld from the end +, since the respawn location of the player is not control by the teleport, or a player can see the end credits. After + the player is eligible to respawn in the overworld, `__on_player_respawns` will be triggered. + ### `/script event` command used to display current events and bounded functions. use `add_to` ro register new event, or `remove_from` to diff --git a/docs/scarpet/api/Events.md b/docs/scarpet/api/Events.md index 6408ac94..39992450 100644 --- a/docs/scarpet/api/Events.md +++ b/docs/scarpet/api/Events.md @@ -19,7 +19,7 @@ __on_tick() // can access blocks and entities in the overworld __on_tick_nether() // can access blocks and entities in the nether __on_tick_ender() // can access blocks and entities in the end __on_chunk_generated(x,z) // called after a chunk is promoted to the full chunk, - // prodiving lowest x and z coords in the chunk + // providing lowest x and z coords in the chunk // event will not work with optifine installed in the game __on_lightning(block, mode) // mode is `true` if lightning caused horse trap to spawn // player specific callbacks @@ -37,6 +37,7 @@ __on_player_takes_damage(player, amount, source, source_entity) __on_player_deals_damage(player, amount, entity) __on_player_dies(player) __on_player_respawns(player) +__on_player_changes_dimension(player, from_pos, from_dimension, to_pos, to_dimension) __on_player_rides(player, forward, strafe, jumping, sneaking) __on_player_jumps(player) __on_player_deploys_elytra(player) @@ -50,6 +51,11 @@ __on_player_drops_stack(player) __on_statistic(player, category, event, value) // player statistic changes +Couple special cases. +* `__on_player_changes_dimension` returns `null` as `to_pos` when player goes back to the overworld from the end +, since the respawn location of the player is not control by the teleport, or a player can see the end credits. After + the player is eligible to respawn in the overworld, `__on_player_respawns` will be triggered. + ### `/script event` command used to display current events and bounded functions. use `add_to` ro register new event, or `remove_from` to diff --git a/docs/scarpet/resources/editors/idea/4.txt b/docs/scarpet/resources/editors/idea/4.txt index 6200e26c..4799c846 100644 --- a/docs/scarpet/resources/editors/idea/4.txt +++ b/docs/scarpet/resources/editors/idea/4.txt @@ -5,6 +5,7 @@ __on_close __on_player_attacks_entity __on_player_breaks_block __on_player_clicks_block +__on_player_changes_dimension __on_player_deploys_elytra __on_player_drops_item __on_player_drops_stack diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index da7e1bf4..c17b3811 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -84,6 +84,7 @@ __on_player_attacks_entity __on_player_breaks_block __on_player_clicks_block + __on_player_changes_dimension __on_player_deploys_elytra __on_player_drops_item __on_player_drops_stack diff --git a/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java b/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java index 17bbd74d..51ddea2f 100644 --- a/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java +++ b/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java @@ -3,20 +3,25 @@ package carpet.mixins; import carpet.fakes.EntityInterface; import carpet.script.EntityEventsGroup; import com.mojang.authlib.GameProfile; +import net.minecraft.entity.Entity; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.stat.Stat; import net.minecraft.util.Hand; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; 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; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import static carpet.script.CarpetEventServer.Event.PLAYER_CHANGES_DIMENSION; import static carpet.script.CarpetEventServer.Event.PLAYER_DIES; import static carpet.script.CarpetEventServer.Event.PLAYER_FINISHED_USING_ITEM; import static carpet.script.CarpetEventServer.Event.STATISTICS; @@ -31,6 +36,8 @@ public abstract class ServerPlayerEntity_scarpetEventMixin extends PlayerEntity @Shadow protected abstract void consumeItem(); + @Shadow public boolean notInAnyWorld; + @Redirect(method = "consumeItem", at = @At( value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;consumeItem()V" @@ -77,4 +84,30 @@ public abstract class ServerPlayerEntity_scarpetEventMixin extends PlayerEntity if (!((EntityInterface)serverPlayerEntity.getVehicle()).isPermanentVehicle()) // won't since that method makes sure its not null serverPlayerEntity.setSneaking(sneaking); } + + private Vec3d previousLocation; + private DimensionType previousDimension; + + @Inject(method = "changeDimension", at = @At("HEAD")) + private void logPreviousCoordinates(DimensionType newDimension, CallbackInfoReturnable cir) + { + previousLocation = getPos(); + previousDimension = dimension; + } + + @Inject(method = "changeDimension", at = @At("RETURN")) + private void atChangeDimension(DimensionType newDimension, CallbackInfoReturnable cir) + { + if (PLAYER_CHANGES_DIMENSION.isNeeded()) + { + ServerPlayerEntity player = (ServerPlayerEntity) (Object)this; + Vec3d to = null; + if (!notInAnyWorld || previousDimension != DimensionType.THE_END || newDimension != DimensionType.OVERWORLD) + { + to = getPos(); + } + PLAYER_CHANGES_DIMENSION.onDimensionChange(player, previousLocation, to, previousDimension, newDimension); + } + } + } diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java index 447396c0..10ca5210 100644 --- a/src/main/java/carpet/script/CarpetEventServer.java +++ b/src/main/java/carpet/script/CarpetEventServer.java @@ -527,6 +527,26 @@ public class CarpetEventServer handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource); } }, + PLAYER_CHANGES_DIMENSION("player_changes_dimension", 5, false) + { + @Override + public void onDimensionChange(ServerPlayerEntity player, Vec3d from, Vec3d to, DimensionType fromDim, DimensionType dimTo) + { + // eligibility already checked in mixin + Value fromValue = ListValue.fromTriple(from.x, from.y, from.z); + Value toValue = (to == null)?Value.NULL:ListValue.fromTriple(to.x, to.y, to.z); + Value fromDimStr = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.DIMENSION_TYPE.getId(fromDim))); + Value toDimStr = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.DIMENSION_TYPE.getId(dimTo))); + + handler.call( () -> Arrays.asList( + ((c, t) -> new EntityValue(player)), + ((c, t) -> fromValue), + ((c, t) -> fromDimStr), + ((c, t) -> toValue), + ((c, t) -> toDimStr) + ), player::getCommandSource); + } + }, STATISTICS("statistic", 4, false) { private Identifier getStatId(Stat stat) @@ -599,8 +619,10 @@ public class CarpetEventServer public void onBlockBroken(ServerPlayerEntity player, BlockPos pos, BlockState previousBS) { } public void onBlockPlaced(ServerPlayerEntity player, BlockPos pos, Hand enumhand, ItemStack itemstack) { } public void onEntityAction(ServerPlayerEntity player, Entity entity, Hand enumhand) { } + public void onDimensionChange(ServerPlayerEntity player, Vec3d from, Vec3d to, DimensionType fromDim, DimensionType dimTo) {} public void onDamage(Entity target, float amount, DamageSource source) { } + public void onWorldEvent(ServerWorld world, BlockPos pos) { } public void onWorldEventFlag(ServerWorld world, BlockPos pos, int flag) { } } diff --git a/src/main/resources/assets/carpet/scripts/event_test.sc b/src/main/resources/assets/carpet/scripts/event_test.sc index 8e3d937a..036a0e38 100644 --- a/src/main/resources/assets/carpet/scripts/event_test.sc +++ b/src/main/resources/assets/carpet/scripts/event_test.sc @@ -220,3 +220,13 @@ __on_player_respawns(player) -> print('__on_player_respawns(player)'); print('Player '+player+' respawns.') ); + +__on_player_changes_dimension(player, from_pos, from_dimension, to_pos, to_dimension) -> +( + print(''); + print('__on_player_changes_dimension(player, from_pos, from_dimension, to_pos, to_dimension)'); + print('player changes dimensions:'); + print(' - player: '+player); + print(' - from '+from_dimension+' at '+map(from_pos, str('%.2f',_))); + print(' - to '+to_dimension+if(to_pos == null, '', ' at '+map(to_pos, str('%.2f',_)))); +)