Merge branch 'master' into 1.16

# Conflicts:
#	src/main/java/carpet/network/ServerNetworkHandler.java
#	src/main/java/carpet/script/CarpetExpression.java
This commit is contained in:
gnembon committed 2020-06-14 01:25:58 -03:00
commit 80ca80fe24
22 files changed
+527 -2

No files matched your search

+1
View File
@@ -11,6 +11,7 @@ version = project.minecraft_version+'-'+project.mod_version
group = project.maven_group
minecraft {
accessWidener "src/main/resources/carpet.accesswidener"
}
dependencies {
+46
View File
@@ -2940,6 +2940,50 @@ item_category('ender_pearl') => misc
item_category('stone') => building_blocks
</pre>
### `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:
<pre>
recipe_data('iron_ingot_from_nuggets')
recipe_data('iron_ingot')
recipe_data('glass', 'smelting')
</pre>
### `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
@@ -3055,6 +3099,8 @@ __on_player_right_clicks_block(player, item_tuple, hand, block, face, hitvec) /
__on_player_interacts_with_block(player, hand, block, face, hitvec) //right click on a block resulted in activation of said block
__on_player_places_block(player, item_tuple, hand, block) // player have just placed the block.
__on_player_interacts_with_entity(player, entity, hand)
__on_player_chooses_recipe(player, recipe, full_stack)
__on_player_switches_slot(player, from, to)
__on_player_attacks_entity(player, entity)
__on_player_takes_damage(player, amount, source, source_entity)
__on_player_deals_damage(player, amount, entity)
+2
View File
@@ -32,6 +32,8 @@ __on_player_right_clicks_block(player, item_tuple, hand, block, face, hitvec) /
__on_player_interacts_with_block(player, hand, block, face, hitvec) //right click on a block resulted in activation of said block
__on_player_places_block(player, item_tuple, hand, block) // player have just placed the block.
__on_player_interacts_with_entity(player, entity, hand)
__on_player_chooses_recipe(player, recipe, full_stack)
__on_player_switches_slot(player, from, to)
__on_player_attacks_entity(player, entity)
__on_player_takes_damage(player, amount, source, source_entity)
__on_player_deals_damage(player, amount, entity)
+44
View File
@@ -38,6 +38,50 @@ item_category('ender_pearl') => misc
item_category('stone') => building_blocks
</pre>
### `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:
<pre>
recipe_data('iron_ingot_from_nuggets')
recipe_data('iron_ingot')
recipe_data('glass', 'smelting')
</pre>
### `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
@@ -12,6 +12,7 @@ blocks_daylight
blocks_movement
brightness
chunk_tickets
crafting_remaining_item
create_marker
current_dimension
day_time
@@ -67,6 +68,7 @@ power
property
query
random_tick
recipe_data
rect
reload_chunk
remove_all_markers
@@ -6,6 +6,7 @@ __on_player_attacks_entity
__on_player_breaks_block
__on_player_clicks_block
__on_player_changes_dimension
__on_player_chooses_recipe
__on_player_deploys_elytra
__on_player_drops_item
__on_player_drops_stack
@@ -21,6 +22,7 @@ __on_player_starts_sneaking
__on_player_starts_sprinting
__on_player_stops_sneaking
__on_player_stops_sprinting
__on_player_switches_slot
__on_player_uses_item
__on_player_wakes_up
__on_statistic
@@ -62,7 +62,9 @@
player spawn entity_id entity_list entity_area entity_selector query modify entity_event
stack_limit item_category inventory_size inventory_has_items inventory_get inventory_set inventory_find inventory_remove drop_item
stack_limit item_category recipe_data crafting_remaining_item
inventory_size inventory_has_items inventory_get inventory_set inventory_find inventory_remove drop_item
scan volume neighbours rect diamond
@@ -87,6 +89,7 @@
__on_player_breaks_block
__on_player_clicks_block
__on_player_changes_dimension
__on_player_chooses_recipe
__on_player_deploys_elytra
__on_player_drops_item
__on_player_drops_stack
@@ -102,6 +105,7 @@
__on_player_starts_sprinting
__on_player_stops_sneaking
__on_player_stops_sprinting
__on_player_switches_slot
__on_player_uses_item
__on_player_wakes_up
__on_statistic
@@ -0,0 +1,11 @@
package carpet.fakes;
import net.minecraft.item.ItemStack;
import java.util.Collection;
import java.util.List;
public interface IngredientInterface
{
List<Collection<ItemStack>> getRecipeStacks();
}
@@ -0,0 +1,12 @@
package carpet.fakes;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeType;
import net.minecraft.util.Identifier;
import java.util.List;
public interface RecipeManagerInterface
{
List<Recipe<?>> getAllMatching(RecipeType type, Identifier output);
}
@@ -14,6 +14,11 @@ public class ClientPlayerEntity_clientCommandMixin
@Inject(method = "sendChatMessage", at = @At("HEAD"))
private void inspectMessage(String string, CallbackInfo ci)
{
if (string.startsWith("/call"))
{
String command = string.substring(6);
CarpetClient.sendClientCommand(command);
}
if (CarpetServer.minecraft_server == null && !CarpetClient.isCarpet())
{
ClientPlayerEntity playerSource = (ClientPlayerEntity)(Object) this;
@@ -0,0 +1,26 @@
package carpet.mixins;
import carpet.fakes.IngredientInterface;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Ingredient;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@Mixin(Ingredient.class)
public class Ingredient_scarpetMixin implements IngredientInterface
{
@Shadow @Final private Ingredient.Entry[] entries;
@Override
public List<Collection<ItemStack>> getRecipeStacks()
{
List<Collection<ItemStack>> res = Arrays.stream(entries).map(Ingredient.Entry::getStacks).collect(Collectors.toList());
return res;
}
}
@@ -0,0 +1,32 @@
package carpet.mixins;
import carpet.fakes.RecipeManagerInterface;
import com.google.common.collect.Lists;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeManager;
import net.minecraft.recipe.RecipeType;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Mixin(RecipeManager.class)
public class RecipeManager_scarpetMixin implements RecipeManagerInterface
{
@Shadow private Map<RecipeType<?>, Map<Identifier, Recipe<?>>> recipes;
@Override
public List<Recipe<?>> getAllMatching(RecipeType type, Identifier output)
{
Map<Identifier, Recipe<?>> typeRecipes = recipes.get(type);
if (typeRecipes.containsKey(output)) return Collections.singletonList(typeRecipes.get(output));
return Lists.newArrayList(typeRecipes.values().stream().filter(
r -> Registry.ITEM.getId(r.getOutput().getItem()).equals(output)).collect(Collectors.toList()));
}
}
@@ -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());
}
}
}
@@ -1,8 +1,13 @@
package carpet.network;
import carpet.CarpetServer;
import carpet.CarpetSettings;
import carpet.script.utils.ShapesRenderer;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public class CarpetClient
@@ -51,4 +56,26 @@ public class CarpetClient
{
return isServerCarpet;
}
public static boolean sendClientCommand(String command)
{
if (!isServerCarpet && CarpetServer.minecraft_server == null) return false;
ClientNetworkHandler.clientCommand(command);
return true;
}
public static void onClientCommand(Tag t)
{
CarpetSettings.LOG.info("Server Response:");
CompoundTag tag = (CompoundTag)t;
CarpetSettings.LOG.info(" - id: "+tag.getString("id"));
CarpetSettings.LOG.info(" - code: "+tag.getInt("code"));
if (tag.contains("error")) CarpetSettings.LOG.warn(" - error: "+tag.getString("error"));
if (tag.contains("output"))
{
ListTag outputTag = (ListTag) tag.get("output");
for (int i = 0; i < outputTag.size(); i++)
CarpetSettings.LOG.info(" - response: " + Text.Serializer.fromJson(outputTag.getString(i)).getString());
}
}
}
@@ -44,6 +44,9 @@ public class ClientNetworkHandler
if (CarpetClient.shapes != null)
CarpetClient.shapes.addShapes((ListTag) t);
});
put("clientCommand", (p, t) -> {
CarpetClient.onClientCommand(t);
});
}};
@@ -99,4 +102,17 @@ public class ClientNetworkHandler
CarpetSettings.LOG.error("Unknown carpet data: "+key);
}
}
public static void clientCommand(String command)
{
CompoundTag tag = new CompoundTag();
tag.putString("id", command);
tag.putString("command", command);
CompoundTag outer = new CompoundTag();
outer.put("clientCommand", tag);
CarpetClient.getPlayer().networkHandler.sendPacket(new CustomPayloadC2SPacket(
CarpetClient.CARPET_CHANNEL,
(new PacketByteBuf(Unpooled.buffer())).writeVarInt(CarpetClient.DATA).writeCompoundTag(outer)
));
}
}
@@ -6,22 +6,37 @@ import carpet.helpers.TickSpeed;
import carpet.settings.ParsedRule;
import io.netty.buffer.Unpooled;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
import net.minecraft.util.PacketByteBuf;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
public class ServerNetworkHandler
{
private static Map<ServerPlayerEntity, String> remoteCarpetPlayers = new HashMap<>();
private static Set<ServerPlayerEntity> validCarpetPlayers = new HashSet<>();
private static Map<String, BiConsumer<ServerPlayerEntity, Tag>> dataHandlers = new HashMap<String, BiConsumer<ServerPlayerEntity, Tag>>(){{
put("clientCommand", (p, t) -> {
handleClientCommand(p, (CompoundTag)t);
});
}};
public static void handleData(PacketByteBuf data, ServerPlayerEntity player)
{
if (data != null)
@@ -29,8 +44,13 @@ public class ServerNetworkHandler
int id = data.readVarInt();
if (id == CarpetClient.HELLO)
onHello(player, data);
if (id == CarpetClient.DATA)
onClientData(player, data);
}
}
public static void onPlayerJoin(ServerPlayerEntity playerEntity)
{
if (!playerEntity.networkHandler.connection.isLocal())
@@ -62,6 +82,67 @@ public class ServerNetworkHandler
playerEntity.networkHandler.sendPacket(new CustomPayloadS2CPacket(CarpetClient.CARPET_CHANNEL, data.build() ));
}
private static void handleClientCommand(ServerPlayerEntity player, CompoundTag commandData)
{
String command = commandData.getString("command");
String id = commandData.getString("id");
List<Text> output = new ArrayList<>();
String[] error = {null};
int resultCode = -1;
if (player.getServer() == null)
{
error[0] = "No Server";
}
else
{
resultCode = player.getServer().getCommandManager().execute(
new ServerCommandSource(player, player.getPos(), player.getRotationClient(),
player.world instanceof ServerWorld ? (ServerWorld) player.world : null,
player.server.getPermissionLevel(player.getGameProfile()), player.getName().getString(), player.getDisplayName(),
player.world.getServer(), player)
{
@Override
public void sendError(Text message)
{
error[0] = message.getString();
}
@Override
public void sendFeedback(Text message, boolean broadcastToOps)
{
output.add(message);
}
},
command
);
};
CompoundTag result = new CompoundTag();
result.putString("id", id);
result.putInt("code", resultCode);
if (error[0] != null) result.putString("error", error[0]);
ListTag outputResult = new ListTag();
for (Text line: output) outputResult.add(StringTag.of(Text.Serializer.toJson(line)));
if (!output.isEmpty()) result.put("output", outputResult);
player.networkHandler.sendPacket(new CustomPayloadS2CPacket(
CarpetClient.CARPET_CHANNEL,
DataBuilder.create().withCustomNbt("clientCommand", result).build()
));
// run command plug to command output,
}
private static void onClientData(ServerPlayerEntity player, PacketByteBuf data)
{
CompoundTag compound = data.readCompoundTag();
if (compound == null) return;
for (String key: compound.getKeys())
{
if (dataHandlers.containsKey(key))
dataHandlers.get(key).accept(player, compound.get(key));
else
CarpetSettings.LOG.warn("Unknown carpet client data: "+key);
}
}
public static void updateRuleWithConnectedClients(ParsedRule<?> rule)
{
if (CarpetSettings.superSecretSetting) return;
@@ -494,6 +494,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
@@ -653,6 +684,8 @@ public class CarpetEventServer
public void onEntityAction(ServerPlayerEntity player, Entity entity, Hand enumhand) { }
public void onDimensionChange(ServerPlayerEntity player, Vec3d from, Vec3d to, RegistryKey<World> fromDim, RegistryKey<World> 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) { }
@@ -3,7 +3,10 @@ package carpet.script;
import carpet.CarpetServer;
import carpet.fakes.BiomeArrayInterface;
import carpet.fakes.ChunkTicketManagerInterface;
import carpet.fakes.IngredientInterface;
import carpet.fakes.MinecraftServerInterface;
import carpet.fakes.BiomeArrayInterface;
import carpet.fakes.RecipeManagerInterface;
import carpet.fakes.ServerChunkManagerInterface;
import carpet.fakes.SpawnHelperInnerInterface;
import carpet.fakes.StatTypeInterface;
@@ -83,6 +86,13 @@ import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.recipe.AbstractCookingRecipe;
import net.minecraft.recipe.CuttingRecipe;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeType;
import net.minecraft.recipe.ShapedRecipe;
import net.minecraft.recipe.ShapelessRecipe;
import net.minecraft.recipe.SpecialCraftingRecipe;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.scoreboard.ScoreboardCriterion;
import net.minecraft.scoreboard.ScoreboardObjective;
@@ -135,6 +145,7 @@ import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -1493,6 +1504,121 @@ public class CarpetExpression
return (_c, _t) -> res;
});
this.expr.addLazyFunction("recipe_data", -1, (c, t, lv) ->
{
CarpetContext cc = (CarpetContext)c;
if (lv.size() < 1) throw new InternalExpressionException("'recipe_data' requires at least one argument");
String recipeName = lv.get(0).evalValue(c).getString();
RecipeType type = RecipeType.CRAFTING;
if (lv.size() > 1)
{
String recipeType = lv.get(1).evalValue(c).getString();
try
{
type = Registry.RECIPE_TYPE.get(new Identifier(recipeType));
}
catch (InvalidIdentifierException ignored)
{
throw new InternalExpressionException("Unknown crafting category: " + recipeType);
}
}
List<Recipe<?>> recipes;
try
{
recipes = ((RecipeManagerInterface) cc.s.getMinecraftServer().getRecipeManager()).getAllMatching(type, new Identifier(recipeName));
}
catch (InvalidIdentifierException ignored)
{
return LazyValue.NULL;
}
if (recipes.isEmpty())
return LazyValue.NULL;
List<Value> recipesOutput = new ArrayList<>();
for (Recipe<?> recipe: recipes)
{
ItemStack result = recipe.getOutput();
List<Value> ingredientValue = new ArrayList<>();
CarpetSettings.LOG.error("input size: "+recipe.getPreviewInputs().size());
recipe.getPreviewInputs().forEach(
ingredient ->
{
// I am flattening ingredient lists per slot.
// consider recipe_data('wooden_sword','crafting') and ('iron_nugget', 'blasting') and notice difference
// in depths of lists.
List<Collection<ItemStack>> stacks = ((IngredientInterface) (Object) ingredient).getRecipeStacks();
if (stacks.isEmpty())
{
ingredientValue.add(Value.NULL);
}
else
{
List<Value> alternatives = new ArrayList<>();
stacks.forEach(col -> col.stream().map(ListValue::fromItemStack).forEach(alternatives::add));
ingredientValue.add(ListValue.wrap(alternatives));
}
}
);
Value recipeSpec;
if (recipe instanceof ShapedRecipe)
{
recipeSpec = ListValue.of(
new StringValue("shaped"),
new NumericValue(((ShapedRecipe) recipe).getWidth()),
new NumericValue(((ShapedRecipe) recipe).getHeight())
);
}
else if (recipe instanceof ShapelessRecipe)
{
recipeSpec = ListValue.of(new StringValue("shapeless"));
}
else if (recipe instanceof AbstractCookingRecipe)
{
recipeSpec = ListValue.of(
new StringValue("smelting"),
new NumericValue(((AbstractCookingRecipe) recipe).getCookTime()),
new NumericValue(((AbstractCookingRecipe) recipe).getExperience())
);
}
else if (recipe instanceof CuttingRecipe)
{
recipeSpec = ListValue.of(new StringValue("cutting"));
}
else if (recipe instanceof SpecialCraftingRecipe)
{
recipeSpec = ListValue.of(new StringValue("special"));
}
else
{
recipeSpec = ListValue.of(new StringValue("custom"));
}
recipesOutput.add(ListValue.of(ListValue.fromItemStack(result), ListValue.wrap(ingredientValue), recipeSpec));
}
Value ret = ListValue.wrap(recipesOutput);
return (_c, _t) -> ret;
});
this.expr.addLazyFunction("crafting_remaining_item", 1, (c, t, lv) ->
{
String itemStr = lv.get(0).evalValue(c).getString();
Item item;
try
{
Identifier id = new Identifier(itemStr);
item = Registry.ITEM.get(id);
if (item == Items.AIR && !id.getPath().equalsIgnoreCase("air"))
throw new InvalidIdentifierException("boo");
}
catch (InvalidIdentifierException ignored)
{
throw new InternalExpressionException("Incorrect item: "+itemStr);
}
if (!item.hasRecipeRemainder()) return LazyValue.NULL;
Value ret = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.ITEM.getId(item.getRecipeRemainder())));
return (_c, _t ) -> ret;
});
this.expr.addLazyFunction("inventory_size", -1, (c, t, lv) ->
{
CarpetContext cc = (CarpetContext) c;
@@ -2960,7 +3086,7 @@ public class CarpetExpression
this.expr.addLazyFunction("seed", -1, (c, t, lv) -> {
ServerCommandSource s = ((CarpetContext)c).s;
Value ret = new NumericValue(s.getWorld().getSeed());
Value ret = new StringValue(Long.toString(s.getWorld().getSeed()));
return (cc, tt) -> ret;
});
@@ -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);
);
+2
View File
@@ -0,0 +1,2 @@
accessWidener v1 named
Accessible class net/minecraft/recipe/Ingredient$Entry
+3
View File
@@ -160,6 +160,9 @@
"ServerWorld_scarpetEventMixin",
"HungerManagerMixin_scarpetEventsMixin",
"RecipeManager_scarpetMixin",
"Ingredient_scarpetMixin",
"PistonBlock_movableTEMixin",
"PistonBlockEntity_movableTEMixin",
"World_movableTEMixin",
+1
View File
@@ -24,6 +24,7 @@
"mixins": [
"carpet.mixins.json"
],
"accessWidener" : "carpet.accesswidener",
"depends": {
"minecraft": "1.16.x",