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
+528 -3

No files matched your search

@@ -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())
@@ -61,7 +81,68 @@ public class ServerNetworkHandler
CarpetServer.settingsManager.getRules().forEach(data::withRule);
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;
});