From 690c85f3b0d25cc438c9ab781c6ca9172ad6e0ba Mon Sep 17 00:00:00 2001 From: gnembon Date: Sun, 14 Jun 2020 01:15:10 -0300 Subject: [PATCH] added __on_player_chooses_recipe and __on_player_switches_slot events --- docs/scarpet/api/Inventories.md | 44 +++++++++++++++++++ ...PlayNetworkHandler_scarpetEventsMixin.java | 29 ++++++++++++ .../java/carpet/script/CarpetEventServer.java | 33 ++++++++++++++ .../assets/carpet/scripts/event_test.sc | 20 +++++++++ 4 files changed, 126 insertions(+) diff --git a/docs/scarpet/api/Inventories.md b/docs/scarpet/api/Inventories.md index 5ef96c7a..fcc1fd53 100644 --- a/docs/scarpet/api/Inventories.md +++ b/docs/scarpet/api/Inventories.md @@ -38,6 +38,50 @@ item_category('ender_pearl') => misc item_category('stone') => building_blocks +### `recipe_data(item, type?)`, `recipe_data(recipe, type?)` + +returns all recipes matching either an `item`, or represent actual `recipe` name. In vanilla datapack, for all items +that have one recipe available, the recipe name is the same as the item name but if an item has multiple recipes, its +direct name can be different. + +Recipe type can take one of the following options: + * `'crafting'` - default, crafting table recipe + * `'smelting'` - furnace recipe + * `'blasting'` - blast furnace recipe + * `'smoking'` - smoker recipe + * `'campfire_cooking'` - campfire recipe + * `'stonecutting'` - stonecutter recipe + + The return value is a list of available recipes (even if there is only one recipe available). Each recipe contains of + an item triple of the crafting result, list of ingredients, each containing a list of possible variants of the + ingredients in this slot, as item triples, or `null` if its a shaped recipe and a given slot in the patterns is left + empty, and recipe specification as another list. Possible recipe specs is: + * `['shaped', width, height]` - shaped crafting. `width` and `height` can be 1, 2 or 3. + * `['shapeless']` - shapeless crafting + * `['smelting', duration, xp]` - smelting/cooking recipes + * `['cutting']` - stonecutter recipe + * `['special']` - special crafting recipe, typically not present in the crafting menu + * `['custom']` - other recipe types + +Note that ingredients are specified as tripes, with count and nbt information. Currently all recipes require always one +of the ingredients, and for some recipes, even if the nbt data for the ingredient is specified (e.g. `dispenser`), it +can accept items of any tags. + +Also note that some recipes leave some products in the crafting window, and these can be determined using + `crafting_remaining_item()` function + + Examples: +
+ recipe_data('iron_ingot_from_nuggets')
+ recipe_data('iron_ingot')
+ recipe_data('glass', 'smelting')
+ 
+ +### `crafting_remaining_item(item)` + +returns `null` if the item has no remaining item in the crafting window when used as a crafting ingredient, or an +item name that serves as a replacement after crafting is done. Currently it can only be buckets and glass bottles. + ### `inventory_size(inventory)` Returns the size of the inventory for the entity or block in question. Returns null if the block or entity don't diff --git a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java index 6128944c..e5ca554a 100644 --- a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java +++ b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_scarpetEventsMixin.java @@ -1,6 +1,9 @@ package carpet.mixins; 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.UpdateSelectedSlotC2SPacket; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.network.packet.c2s.play.ClientCommandC2SPacket; @@ -29,10 +32,12 @@ import static carpet.script.CarpetEventServer.Event.PLAYER_RELEASED_ITEM; import static carpet.script.CarpetEventServer.Event.PLAYER_RIDES; import static carpet.script.CarpetEventServer.Event.PLAYER_JUMPS; import static carpet.script.CarpetEventServer.Event.PLAYER_RIGHT_CLICKS_BLOCK; +import static carpet.script.CarpetEventServer.Event.PLAYER_CHOOSES_RECIPE; import static carpet.script.CarpetEventServer.Event.PLAYER_STARTS_SNEAKING; 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_SWITCHES_SLOT; import static carpet.script.CarpetEventServer.Event.PLAYER_USES_ITEM; import static carpet.script.CarpetEventServer.Event.PLAYER_WAKES_UP; @@ -219,4 +224,28 @@ public class ServerPlayNetworkHandler_scarpetEventsMixin //todo add hit and hand in the future PLAYER_ATTACKS_ENTITY.onEntityAction(player, playerInteractEntityC2SPacket_1.getEntity(player.getServerWorld()), null); } + + @Inject(method = "onButtonClick", at = @At("HEAD")) + private void onItemBeingPickedFromInventory(ButtonClickC2SPacket packet, CallbackInfo ci) + { + // crafts not int the crafting window + //CarpetSettings.LOG.error("Player clicks button "+packet.getButtonId()); + } + @Inject(method = "onCraftRequest", at = @At("HEAD")) + private void onRecipeSelectedInRecipeManager(CraftRequestC2SPacket packet, CallbackInfo ci) + { + if (PLAYER_CHOOSES_RECIPE.isNeeded()) + { + PLAYER_CHOOSES_RECIPE.onRecipeSelected(player, packet.getRecipe(), packet.shouldCraftAll()); + } + } + + @Inject(method = "onUpdateSelectedSlot", at = @At("HEAD")) + private void onUpdatedSelectedSLot(UpdateSelectedSlotC2SPacket packet, CallbackInfo ci) + { + if (PLAYER_SWITCHES_SLOT.isNeeded()) + { + PLAYER_SWITCHES_SLOT.onSlotSwitch(player, player.inventory.selectedSlot, packet.getSelectedSlot()); + } + } } diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java index 2eafcd6d..75171171 100644 --- a/src/main/java/carpet/script/CarpetEventServer.java +++ b/src/main/java/carpet/script/CarpetEventServer.java @@ -488,6 +488,37 @@ public class CarpetEventServer handler.call( () -> Collections.singletonList(((c, t) -> new EntityValue(player))), player::getCommandSource); } }, + PLAYER_CHOOSES_RECIPE("player_chooses_recipe", 3, false) + { + @Override + public void onRecipeSelected(ServerPlayerEntity player, Identifier recipe, boolean fullStack) + { + handler.call( () -> + { + return Arrays.asList( + ((c, t) -> new EntityValue(player)), + ((c, t) -> new StringValue(NBTSerializableValue.nameFromRegistryId(recipe))), + ((c, t) -> new NumericValue(fullStack)) + ); + }, player::getCommandSource); + } + }, + PLAYER_SWITCHES_SLOT("player_switches_slot", 3, false) + { + @Override + public void onSlotSwitch(ServerPlayerEntity player, int from, int to) + { + if (from == to) return; // initial slot update + handler.call( () -> + { + return Arrays.asList( + ((c, t) -> new EntityValue(player)), + ((c, t) -> new NumericValue(from)), + ((c, t) -> new NumericValue(to)) + ); + }, player::getCommandSource); + } + }, PLAYER_TAKES_DAMAGE("player_takes_damage", 4, false) { @Override @@ -647,6 +678,8 @@ public class CarpetEventServer 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 onRecipeSelected(ServerPlayerEntity player, Identifier recipe, boolean fullStack) {} + public void onSlotSwitch(ServerPlayerEntity player, int from, int to) {} public void onWorldEvent(ServerWorld world, BlockPos pos) { } diff --git a/src/main/resources/assets/carpet/scripts/event_test.sc b/src/main/resources/assets/carpet/scripts/event_test.sc index 1659d565..c6934911 100644 --- a/src/main/resources/assets/carpet/scripts/event_test.sc +++ b/src/main/resources/assets/carpet/scripts/event_test.sc @@ -244,3 +244,23 @@ __on_player_disconnects(player, reason) -> print('__on_player_disconnects(player)'); print('Player '+player+' disconnects because: '+reason) ); + +__on_player_chooses_recipe(player, recipe, full_stack) -> +( + print(''); + print('__on_player_chooses_recipe(player, recipe, full_stack)'); + print('player chooses recipe:'); + print(' - player: '+player); + print(' - recipe: '+recipe); + print(' - full stack: '+ full_stack); +); + +__on_player_switches_slot(player, from, to) -> +( + print(''); + print('__on_player_switches_slot(player, from, to)'); + print('player switches inventory slot:'); + print(' - player: '+player); + print(' - from: '+ from); + print(' - to: '+ to); +);