diff --git a/docs/scarpet/api/Entities.md b/docs/scarpet/api/Entities.md index 0ebc7a59..34584e8b 100644 --- a/docs/scarpet/api/Entities.md +++ b/docs/scarpet/api/Entities.md @@ -344,6 +344,11 @@ Boolean, true if the entity is swimming. Boolean, true if the entity is jumping. +### `query(e, 'swinging')` + +Returns `true` if the entity is actively swinging their hand, `false` if not and `null` if swinging is not applicable to +that entity. + ### `query(e, 'gamemode')` String with gamemode, or `null` if not a player. diff --git a/docs/scarpet/api/Events.md b/docs/scarpet/api/Events.md index 8ff9a8b7..ac3da637 100644 --- a/docs/scarpet/api/Events.md +++ b/docs/scarpet/api/Events.md @@ -137,6 +137,11 @@ the slot. ### `__on_player_swaps_hands(player)` Triggered when a player sends a command to swap their offhand item. Executed before the effect is applied on the server. +### `__on_player_swings_hand(player, hand)` +Triggered when a player starts swinging their hand. The event typically triggers after a corresponding event that caused it +(`player_uses_item`, `player_breaks_block`, etc.), but it triggers also after some failed events, like attacking the air. When +swinging continues as an effect of an action, no new swinging events will be issued until the swinging is stopped. + ### `__on_player_attacks_entity(player, entity)` Triggered when a player attacks entity, right before it happens server side. diff --git a/docs/scarpet/resources/editors/idea/4.txt b/docs/scarpet/resources/editors/idea/4.txt index a7065d6d..0238ef4b 100644 --- a/docs/scarpet/resources/editors/idea/4.txt +++ b/docs/scarpet/resources/editors/idea/4.txt @@ -23,9 +23,12 @@ __on_player_right_clicks_block(player, item_tuple, hand, block, face, hitvec) -> __on_player_starts_sneaking(player) -> __on_player_starts_sprinting(player) -> __on_player_stops_sneaking(player) -> -__on_player_stops_sprinting(player) -> +__on_player_stops_sprinting(player) -> +__on_player_swings_hand(player, hand) -> __on_player_switches_slot(player, from, to) -> -__on_player_swaps_hands(player) -> +__on_player_swaps_hands(player) -> +__on_player_takes_damage(player, amount, source, entity) -> +__on_player_trades(player, entity, buy_left, buy_right, sell) -> __on_player_uses_item(player, item_tuple, hand) -> __on_player_wakes_up(player) -> __on_player_escapes_sleep(player) -> @@ -38,4 +41,4 @@ __on_player_deals_damage(player, amount, entity) -> __on_player_dies(player) -> __on_player_respawns(player) -> __on_player_disconnects(player, reason) -> -__on_player_connects(player) -> +__on_player_connects(player) -> diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index 81706a3d..83cceb54 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -118,8 +118,11 @@ __on_player_starts_sprinting __on_player_stops_sneaking __on_player_stops_sprinting + __on_player_swings_hand __on_player_switches_slot __on_player_swaps_hands + __on_player_takes_damage + __on_player_trades __on_player_uses_item __on_player_wakes_up __on_player_escapes_sleep diff --git a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java index 0ce11682..33fdb428 100644 --- a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java +++ b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java @@ -1,9 +1,9 @@ package carpet.mixins; -import carpet.CarpetSettings; import net.minecraft.item.ItemStack; import net.minecraft.network.packet.c2s.play.ButtonClickC2SPacket; import net.minecraft.network.packet.c2s.play.CraftRequestC2SPacket; +import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket; import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; @@ -40,6 +40,7 @@ import static carpet.script.CarpetEventServer.Event.PLAYER_STARTS_SPRINTING; import static carpet.script.CarpetEventServer.Event.PLAYER_STOPS_SNEAKING; import static carpet.script.CarpetEventServer.Event.PLAYER_STOPS_SPRINTING; import static carpet.script.CarpetEventServer.Event.PLAYER_SWAPS_HANDS; +import static carpet.script.CarpetEventServer.Event.PLAYER_SWINGS_HAND; import static carpet.script.CarpetEventServer.Event.PLAYER_SWITCHES_SLOT; import static carpet.script.CarpetEventServer.Event.PLAYER_USES_ITEM; import static carpet.script.CarpetEventServer.Event.PLAYER_WAKES_UP; @@ -266,4 +267,17 @@ public class ServerPlayNetworkHandler_scarpetEventsMixin PLAYER_SWITCHES_SLOT.onSlotSwitch(player, player.inventory.selectedSlot, packet.getSelectedSlot()); } } + + @Inject(method = "onHandSwing", at = @At( + value = "INVOKE", target = + "Lnet/minecraft/server/network/ServerPlayerEntity;updateLastActionTime()V", + shift = At.Shift.BEFORE) + ) + private void onSwing(HandSwingC2SPacket packet, CallbackInfo ci) + { + if (PLAYER_SWINGS_HAND.isNeeded() && !player.handSwinging) + { + PLAYER_SWINGS_HAND.onHandAction(player, packet.getHand()); + } + } } diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java index 4b6b31b6..fe3a8c3a 100644 --- a/src/main/java/carpet/script/CarpetEventServer.java +++ b/src/main/java/carpet/script/CarpetEventServer.java @@ -693,6 +693,18 @@ public class CarpetEventServer handler.call( () -> Collections.singletonList(new EntityValue(player)), player::getCommandSource); } }; + public static final Event PLAYER_SWINGS_HAND = new Event("player_swings_hand", 2, false) + { + @Override + public void onHandAction(ServerPlayerEntity player, Hand hand) + { + handler.call( () -> Arrays.asList( + new EntityValue(player), + StringValue.of(hand == Hand.MAIN_HAND ? "mainhand" : "offhand") + ) + , player::getCommandSource); + } + }; public static final Event PLAYER_TAKES_DAMAGE = new Event("player_takes_damage", 4, false) { @Override @@ -938,6 +950,7 @@ 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 onEntityHandAction(ServerPlayerEntity player, Entity entity, Hand enumhand) { } + public void onHandAction(ServerPlayerEntity player, Hand enumhand) { } public void onEntityAction(Entity entity) { } public void onDimensionChange(ServerPlayerEntity player, Vec3d from, Vec3d to, RegistryKey fromDim, RegistryKey dimTo) {} public void onDamage(Entity target, float amount, DamageSource source) { } diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java index 89535a7c..283d3548 100644 --- a/src/main/java/carpet/script/value/EntityValue.java +++ b/src/main/java/carpet/script/value/EntityValue.java @@ -512,6 +512,11 @@ public class EntityValue extends Value put("sneaking", (e, a) -> e.isSneaking()?Value.TRUE:Value.FALSE); put("sprinting", (e, a) -> e.isSprinting()?Value.TRUE:Value.FALSE); put("swimming", (e, a) -> e.isSwimming()?Value.TRUE:Value.FALSE); + put("swinging", (e, a) -> { + if (e instanceof LivingEntity) return new NumericValue(((LivingEntity) e).handSwinging); + return Value.NULL; + }); + put("air", (e, a) -> new NumericValue(e.getAir())); put("persistence", (e, a) -> { if (e instanceof MobEntity) return new NumericValue(((MobEntity) e).isPersistent()); diff --git a/src/main/resources/assets/carpet/scripts/event_test.sc b/src/main/resources/assets/carpet/scripts/event_test.sc index 11842f56..a88a41fb 100644 --- a/src/main/resources/assets/carpet/scripts/event_test.sc +++ b/src/main/resources/assets/carpet/scripts/event_test.sc @@ -303,3 +303,12 @@ __on_player_trades(player, entity, buy_left, buy_right, sell) -> print(' - buy_right: '+ buy_right); print(' - sell: '+ sell) ); + +__on_player_swings_hand(player, hand) -> +( + print(''); + print('__on_player_swings_hand(player, hand)'); + print('player swings hand:'); + print(' - player: '+player); + print(' - hand: '+hand); +);