FlorianMichael 2023-07-06 14:40:14 +02:00
parent 6e9d5a4d05
commit b39e8013a0
No known key found for this signature in database
GPG Key ID: C2FB87E71C425126
9 changed files with 383 additions and 70 deletions

View File

@ -1,66 +0,0 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.definition;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement;
import de.florianmichael.viafabricplus.ViaFabricPlus;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.resource.featuretoggle.FeatureFlags;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.text.Text;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;
public class ScreenHandlerEmulator1_13_2 {
public final static Consumer<PacketByteBuf> OLD_PACKET_HANDLER = data -> {
final var byteBuf = data.asByteBuf();
try {
ScreenHandlerEmulator1_13_2.handle(Type.SHORT.readPrimitive(byteBuf), Type.COMPONENT.read(byteBuf), Type.SHORT.readPrimitive(byteBuf));
} catch (Exception e) {
ViaFabricPlus.LOGGER.error("Failed to open custom ScreenHandler with dimension 9xN", e);
}
};
private final static Map<Integer, ScreenHandlerType<GenericContainerScreenHandler>> fakeHandlers = new LinkedHashMap<>();
static {
for (int i = 0; i < 1000; i++) {
int finalI = i;
fakeHandlers.put(i, new ScreenHandlerType<>((syncId, playerInventory) -> new GenericContainerScreenHandler(fakeHandlers.get(finalI), syncId, playerInventory, finalI), FeatureFlags.VANILLA_FEATURES));
}
}
public static void handle(final short windowID, final JsonElement title, final short slots) {
int n = slots / 9;
final int modulo = slots % 9;
if (modulo > 0) n++;
HandledScreens.open(ScreenHandlerEmulator1_13_2.fakeHandlers.get(n), MinecraftClient.getInstance(), windowID, Text.Serializer.fromJson(title.toString()));
}
public static boolean isFakeHandler(final ScreenHandlerType<?> screenHandlerType) {
return fakeHandlers.containsValue(screenHandlerType);
}
}

View File

@ -0,0 +1,83 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.definition.screen;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.libs.gson.JsonElement;
import de.florianmichael.viafabricplus.ViaFabricPlus;
import de.florianmichael.viafabricplus.definition.screen.netminecraft.LegacySmithingScreenHandler;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.resource.featuretoggle.FeatureFlags;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.text.Text;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Consumer;
public class CustomScreenHandler {
public final static Consumer<PacketByteBuf> TRIPLE_CHEST_HANDLER = data -> {
final var byteBuf = data.asByteBuf();
try {
CustomScreenHandler.handleTripleChestHandler(Type.SHORT.readPrimitive(byteBuf), Type.COMPONENT.read(byteBuf), Type.SHORT.readPrimitive(byteBuf));
} catch (Exception e) {
ViaFabricPlus.LOGGER.error("Failed to open custom ScreenHandler with dimension 9xN", e);
}
};
public final static Consumer<PacketByteBuf> LEGACY_SMITHING_HANDLER = data -> {
final var byteBuf = data.asByteBuf();
try {
CustomScreenHandler.openLegacySmithingScreen(Type.VAR_INT.readPrimitive(byteBuf), Type.COMPONENT.read(byteBuf));
} catch (Exception e) {
ViaFabricPlus.LOGGER.error("Failed to open legacy smithing table", e);
}
};
public final static ScreenHandlerType<LegacySmithingScreenHandler> LEGACY_SMITHING = new ScreenHandlerType<>(LegacySmithingScreenHandler::new, FeatureFlags.VANILLA_FEATURES);
private final static Map<Integer, ScreenHandlerType<ScreenHandler>> TRIPLE_CHEST_HANDLERS = new LinkedHashMap<>();
static {
for (int i = 0; i < 1000; i++) {
int finalI = i;
TRIPLE_CHEST_HANDLERS.put(i, new ScreenHandlerType<>((syncId, playerInventory) -> new GenericContainerScreenHandler(TRIPLE_CHEST_HANDLERS.get(finalI), syncId, playerInventory, finalI), FeatureFlags.VANILLA_FEATURES));
}
}
public static void openLegacySmithingScreen(final int windowID, final JsonElement title) {
HandledScreens.open(CustomScreenHandler.LEGACY_SMITHING, MinecraftClient.getInstance(), windowID, Text.Serializer.fromJson(title.toString()));
}
public static void handleTripleChestHandler(final short windowID, final JsonElement title, final short slots) {
int n = slots / 9;
final int modulo = slots % 9;
if (modulo > 0) n++;
HandledScreens.open(CustomScreenHandler.TRIPLE_CHEST_HANDLERS.get(n), MinecraftClient.getInstance(), windowID, Text.Serializer.fromJson(title.toString()));
}
public static boolean isTripleChestHandler(final ScreenHandlerType<?> screenHandlerType) {
return TRIPLE_CHEST_HANDLERS.containsValue(screenHandlerType);
}
}

View File

@ -0,0 +1,102 @@
package de.florianmichael.viafabricplus.definition.screen.netminecraft;
import com.google.gson.JsonObject;
import java.util.stream.Stream;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.recipe.Ingredient;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.ShapedRecipe;
import net.minecraft.recipe.SmithingRecipe;
import net.minecraft.registry.DynamicRegistryManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.world.World;
public class LegacySmithingRecipe implements SmithingRecipe {
public final static Serializer SERIALIZER = new Serializer();
final Ingredient base;
final Ingredient addition;
final ItemStack result;
private final Identifier id;
public LegacySmithingRecipe(Identifier id, Ingredient base, Ingredient addition, ItemStack result) {
this.id = id;
this.base = base;
this.addition = addition;
this.result = result;
}
public boolean matches(Inventory inventory, World world) {
return this.base.test(inventory.getStack(0)) && this.addition.test(inventory.getStack(1));
}
public ItemStack craft(Inventory inventory, DynamicRegistryManager registryManager) {
ItemStack itemStack = this.result.copy();
NbtCompound nbtCompound = inventory.getStack(0).getNbt();
if (nbtCompound != null) {
itemStack.setNbt(nbtCompound.copy());
}
return itemStack;
}
public boolean fits(int width, int height) {
return width * height >= 2;
}
public ItemStack getOutput(DynamicRegistryManager registryManager) {
return this.result;
}
public boolean testTemplate(ItemStack stack) {
return false;
}
public boolean testBase(ItemStack stack) {
return this.base.test(stack);
}
public boolean testAddition(ItemStack stack) {
return this.addition.test(stack);
}
public Identifier getId() {
return this.id;
}
public RecipeSerializer<?> getSerializer() {
return SERIALIZER;
}
public boolean isEmpty() {
return Stream.of(this.base, this.addition).anyMatch((ingredient) -> ingredient.getMatchingStacks().length == 0);
}
public static class Serializer implements RecipeSerializer<LegacySmithingRecipe> {
public Serializer() {
}
public LegacySmithingRecipe read(Identifier identifier, JsonObject jsonObject) {
Ingredient ingredient = Ingredient.fromJson(JsonHelper.getObject(jsonObject, "base"));
Ingredient ingredient2 = Ingredient.fromJson(JsonHelper.getObject(jsonObject, "addition"));
ItemStack itemStack = ShapedRecipe.outputFromJson(JsonHelper.getObject(jsonObject, "result"));
return new LegacySmithingRecipe(identifier, ingredient, ingredient2, itemStack);
}
public LegacySmithingRecipe read(Identifier identifier, PacketByteBuf packetByteBuf) {
Ingredient ingredient = Ingredient.fromPacket(packetByteBuf);
Ingredient ingredient2 = Ingredient.fromPacket(packetByteBuf);
ItemStack itemStack = packetByteBuf.readItemStack();
return new LegacySmithingRecipe(identifier, ingredient, ingredient2, itemStack);
}
public void write(PacketByteBuf packetByteBuf, LegacySmithingRecipe legacySmithingRecipe) {
legacySmithingRecipe.base.write(packetByteBuf);
legacySmithingRecipe.addition.write(packetByteBuf);
packetByteBuf.writeItemStack(legacySmithingRecipe.result);
}
}
}

View File

@ -0,0 +1,24 @@
package de.florianmichael.viafabricplus.definition.screen.netminecraft;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ingame.ForgingScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public class LegacySmithingScreen extends ForgingScreen<LegacySmithingScreenHandler> {
private static final Identifier TEXTURE = new Identifier("textures/gui/container/legacy_smithing.png");
public LegacySmithingScreen(LegacySmithingScreenHandler handler, PlayerInventory playerInventory, Text title) {
super(handler, playerInventory, title, TEXTURE);
this.titleX = 60;
this.titleY = 18;
}
@Override
protected void drawInvalidRecipeArrow(DrawContext context, int x, int y) {
if ((this.handler.getSlot(0).hasStack() || this.handler.getSlot(1).hasStack()) && !this.handler.getSlot(this.handler.getResultSlotIndex()).hasStack()) {
context.drawTexture(TEXTURE, x + 99, y + 45, this.backgroundWidth, 0, 28, 21);
}
}
}

View File

@ -0,0 +1,106 @@
package de.florianmichael.viafabricplus.definition.screen.netminecraft;
import de.florianmichael.viafabricplus.definition.screen.CustomScreenHandler;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.RecipeType;
import net.minecraft.screen.ForgingScreenHandler;
import net.minecraft.screen.ScreenHandlerContext;
import net.minecraft.screen.slot.ForgingSlotsManager;
import net.minecraft.screen.slot.Slot;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
public class LegacySmithingScreenHandler extends ForgingScreenHandler {
private final World world;
@Nullable
private LegacySmithingRecipe currentRecipe;
private final List<LegacySmithingRecipe> recipes;
public LegacySmithingScreenHandler(int syncId, PlayerInventory playerInventory) {
this(syncId, playerInventory, ScreenHandlerContext.EMPTY);
}
public LegacySmithingScreenHandler(int syncId, PlayerInventory playerInventory, ScreenHandlerContext context) {
super(CustomScreenHandler.LEGACY_SMITHING, syncId, playerInventory, context);
this.world = playerInventory.player.getWorld();
this.recipes = this.world.getRecipeManager().listAllOfType(RecipeType.SMITHING).stream().filter((recipe) -> {
return recipe instanceof LegacySmithingRecipe;
}).map((recipe) -> {
return (LegacySmithingRecipe)recipe;
}).toList();
}
protected ForgingSlotsManager getForgingSlotsManager() {
return ForgingSlotsManager.create().input(0, 27, 47, (stack) -> {
return true;
}).input(1, 76, 47, (stack) -> {
return true;
}).output(2, 134, 47).build();
}
protected boolean canUse(BlockState state) {
return state.isOf(Blocks.SMITHING_TABLE);
}
protected boolean canTakeOutput(PlayerEntity player, boolean present) {
return this.currentRecipe != null && this.currentRecipe.matches(this.input, this.world);
}
protected void onTakeOutput(PlayerEntity player, ItemStack stack) {
stack.onCraft(player.getWorld(), player, stack.getCount());
this.output.unlockLastRecipe(player, Collections.emptyList());
this.decrementStack(0);
this.decrementStack(1);
this.context.run((world, pos) -> {
world.syncWorldEvent(1044, pos, 0);
});
}
private void decrementStack(int slot) {
ItemStack itemStack = this.input.getStack(slot);
itemStack.decrement(1);
this.input.setStack(slot, itemStack);
}
public void updateResult() {
List<LegacySmithingRecipe> list = this.world.getRecipeManager().getAllMatches(RecipeType.SMITHING, this.input, this.world).stream().filter((recipe) -> {
return recipe instanceof LegacySmithingRecipe;
}).map((recipe) -> {
return (LegacySmithingRecipe)recipe;
}).toList();
if (list.isEmpty()) {
this.output.setStack(0, ItemStack.EMPTY);
} else {
LegacySmithingRecipe legacySmithingRecipe = (LegacySmithingRecipe)list.get(0);
ItemStack itemStack = legacySmithingRecipe.craft(this.input, this.world.getRegistryManager());
if (itemStack.isItemEnabled(this.world.getEnabledFeatures())) {
this.currentRecipe = legacySmithingRecipe;
this.output.setLastRecipe(legacySmithingRecipe);
this.output.setStack(0, itemStack);
}
}
}
public int getSlotFor(ItemStack stack) {
return this.testAddition(stack) ? 1 : 0;
}
protected boolean testAddition(ItemStack stack) {
return this.recipes.stream().anyMatch((recipe) -> {
return recipe.testAddition(stack);
});
}
public boolean canInsertIntoSlot(ItemStack stack, Slot slot) {
return slot.inventory != this.output && super.canInsertIntoSlot(stack, slot);
}
}

View File

@ -17,7 +17,9 @@
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.minecraft;
import de.florianmichael.viafabricplus.definition.ScreenHandlerEmulator1_13_2;
import de.florianmichael.viafabricplus.definition.screen.netminecraft.LegacySmithingScreen;
import de.florianmichael.viafabricplus.definition.screen.netminecraft.LegacySmithingScreenHandler;
import de.florianmichael.viafabricplus.definition.screen.CustomScreenHandler;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
import net.minecraft.client.gui.screen.ingame.HandledScreens;
@ -36,7 +38,10 @@ public class MixinHandledScreens {
@Inject(method = "getProvider", at = @At("HEAD"), cancellable = true)
private static <T extends ScreenHandler> void returnFakeProvider(ScreenHandlerType<T> type, CallbackInfoReturnable<HandledScreens.@Nullable Provider> cir) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2) && ScreenHandlerEmulator1_13_2.isFakeHandler(type)) {
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_20tor1_20_1) && type == CustomScreenHandler.LEGACY_SMITHING) {
cir.setReturnValue((handler, playerInventory, title) -> new LegacySmithingScreen((LegacySmithingScreenHandler) handler, playerInventory, title));
}
if (ProtocolHack.getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_13_2) && CustomScreenHandler.isTripleChestHandler(type)) {
cir.setReturnValue((handler, playerInventory, title) -> new GenericContainerScreen((GenericContainerScreenHandler) handler, playerInventory, title));
}
}

View File

@ -28,7 +28,7 @@ import com.viaversion.viaversion.libs.gson.JsonElement;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.ClientboundPackets1_14;
import com.viaversion.viaversion.protocols.protocol1_14to1_13_2.packets.InventoryPackets;
import de.florianmichael.viafabricplus.definition.PacketSyncBase;
import de.florianmichael.viafabricplus.definition.ScreenHandlerEmulator1_13_2;
import de.florianmichael.viafabricplus.definition.screen.CustomScreenHandler;
import de.florianmichael.viafabricplus.protocolhack.ProtocolHack;
import io.netty.buffer.Unpooled;
import net.minecraft.SharedConstants;
@ -64,7 +64,7 @@ public class MixinInventoryPackets {
fakeOpenWindow.read(Type.VAR_INT);
fakeOpenWindow.read(Type.VAR_INT);
final String uuid = PacketSyncBase.track(ScreenHandlerEmulator1_13_2.OLD_PACKET_HANDLER);
final String uuid = PacketSyncBase.track(CustomScreenHandler.TRIPLE_CHEST_HANDLER);
wrapper.write(Type.STRING, uuid);
wrapper.write(Type.SHORT, windowId);

View File

@ -0,0 +1,58 @@
/*
* This file is part of ViaFabricPlus - https://github.com/FlorianMichael/ViaFabricPlus
* Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.florianmichael.viafabricplus.injection.mixin.fixes.viaversion.protocol1_20to1_19_4;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ServerboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_20to1_19_4.Protocol1_20To1_19_4;
import com.viaversion.viaversion.protocols.protocol1_20to1_19_4.packets.InventoryPackets;
import com.viaversion.viaversion.rewriter.ItemRewriter;
import de.florianmichael.viafabricplus.definition.PacketSyncBase;
import de.florianmichael.viafabricplus.definition.screen.CustomScreenHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = InventoryPackets.class, remap = false)
public class MixinInventoryPackets extends ItemRewriter<ClientboundPackets1_19_4, ServerboundPackets1_19_4, Protocol1_20To1_19_4> {
public MixinInventoryPackets(Protocol1_20To1_19_4 protocol) {
super(protocol);
}
@Inject(method = "registerPackets", at = @At("RETURN"))
public void handleLegacySmithingScreen(CallbackInfo ci) {
protocol.registerClientbound(ClientboundPackets1_19_4.OPEN_WINDOW, wrapper -> {
final var windowId = wrapper.read(Type.VAR_INT);
final int typeId = wrapper.read(Type.VAR_INT);
var title = wrapper.read(Type.COMPONENT);
if (typeId == 20) {
wrapper.clearPacket();
wrapper.setPacketType(ClientboundPackets1_19_4.PLUGIN_MESSAGE);
wrapper.write(Type.STRING, PacketSyncBase.PACKET_SYNC_IDENTIFIER);
wrapper.write(Type.STRING, PacketSyncBase.track(CustomScreenHandler.LEGACY_SMITHING_HANDLER));
wrapper.write(Type.VAR_INT, windowId);
wrapper.write(Type.COMPONENT, title);
}
});
}
}

View File

@ -160,6 +160,7 @@
"fixes.viaversion.protocol1_19_1to1_19.MixinProtocol1_19_1To1_19",
"fixes.viaversion.protocol1_19_3to1_19_1.MixinProtocol1_19_3To1_19_1",
"fixes.viaversion.protocol1_19to1_18_2.MixinWorldPackets",
"fixes.viaversion.protocol1_20to1_19_4.MixinInventoryPackets",
"fixes.viaversion.protocol1_9_1to1_9.MixinProtocol1_9_1To1_9",
"fixes.viaversion.protocol1_9to1_8.MixinChunk1_8Type",
"fixes.viaversion.protocol1_9to1_8.MixinCommandBlockProvider",