diff --git a/fabric-containers-v0/build.gradle b/fabric-containers-v0/build.gradle index e866ea231..e79c36dac 100644 --- a/fabric-containers-v0/build.gradle +++ b/fabric-containers-v0/build.gradle @@ -1,5 +1,5 @@ archivesBaseName = "fabric-containers-v0" -version = getSubprojectVersion(project, "0.1.7") +version = getSubprojectVersion(project, "0.1.8") dependencies { compile project(path: ':fabric-api-base', configuration: 'dev') diff --git a/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/client/screen/ContainerScreenFactory.java b/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/client/screen/ContainerScreenFactory.java index db4b2d196..163c5a23d 100644 --- a/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/client/screen/ContainerScreenFactory.java +++ b/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/client/screen/ContainerScreenFactory.java @@ -19,6 +19,10 @@ package net.fabricmc.fabric.api.client.screen; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.screen.ScreenHandler; +/** + * @deprecated Use {@link net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry.Factory} instead. + */ +@Deprecated @FunctionalInterface public interface ContainerScreenFactory<C extends ScreenHandler> { HandledScreen create(C container); diff --git a/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/client/screen/ScreenProviderRegistry.java b/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/client/screen/ScreenProviderRegistry.java index a132b746f..7047db7cf 100644 --- a/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/client/screen/ScreenProviderRegistry.java +++ b/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/client/screen/ScreenProviderRegistry.java @@ -24,6 +24,10 @@ import net.fabricmc.fabric.api.container.ContainerFactory; import net.fabricmc.fabric.api.container.ContainerProviderRegistry; import net.fabricmc.fabric.impl.client.container.ScreenProviderRegistryImpl; +/** + * @deprecated Use {@link net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry} instead. + */ +@Deprecated public interface ScreenProviderRegistry { ScreenProviderRegistry INSTANCE = ScreenProviderRegistryImpl.INSTANCE; diff --git a/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerFactory.java b/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerFactory.java index 4a5c0cee1..15daa3dd2 100644 --- a/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerFactory.java +++ b/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerFactory.java @@ -20,6 +20,10 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.Identifier; import net.minecraft.network.PacketByteBuf; +/** + * @deprecated Use {@link net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry.ExtendedClientHandlerFactory} instead. + */ +@Deprecated @FunctionalInterface public interface ContainerFactory<T> { /** diff --git a/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerProviderRegistry.java b/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerProviderRegistry.java index 7d82f98a4..2dd365c6b 100644 --- a/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerProviderRegistry.java +++ b/fabric-containers-v0/src/main/java/net/fabricmc/fabric/api/container/ContainerProviderRegistry.java @@ -27,6 +27,10 @@ import net.minecraft.network.PacketByteBuf; import net.fabricmc.fabric.api.client.screen.ScreenProviderRegistry; import net.fabricmc.fabric.impl.container.ContainerProviderImpl; +/** + * @deprecated Use {@link net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry} instead. + */ +@Deprecated public interface ContainerProviderRegistry { ContainerProviderRegistry INSTANCE = ContainerProviderImpl.INSTANCE; diff --git a/fabric-screen-handler-api-v1/build.gradle b/fabric-screen-handler-api-v1/build.gradle new file mode 100644 index 000000000..1a3f806c1 --- /dev/null +++ b/fabric-screen-handler-api-v1/build.gradle @@ -0,0 +1,12 @@ +archivesBaseName = "fabric-screen-handler-api-v1" +version = getSubprojectVersion(project, "1.0.0") + +minecraft { + accessWidener = file('src/main/resources/fabric-screen-handler-api-v1.accesswidener') +} + +dependencies { + compile(project(path: ':fabric-api-base', configuration: 'dev')) + compile(project(path: ':fabric-networking-v0', configuration: 'dev')) + testmodRuntimeOnly(project(path: ':fabric-resource-loader-v0', configuration: 'dev')) +} diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/client/screenhandler/v1/ScreenRegistry.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/client/screenhandler/v1/ScreenRegistry.java new file mode 100644 index 000000000..725859b59 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/client/screenhandler/v1/ScreenRegistry.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.client.screenhandler.v1; + +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.HandledScreens; +import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.text.Text; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; + +/** + * An API for registering handled screens that represent screen handlers on the client. + * Exposes vanilla's private {@link HandledScreens#register HandledScreens.register()} to modders as {@link #register ScreenRegistry.register()}. + * + * <h2>Example</h2> + * <pre> + * {@code + * // In a client-side initialization method: + * ScreenRegistry.register(MyScreenHandlers.OVEN, OvenScreen::new); + * + * // Screen class + * public class OvenScreen extends HandledScreen<OvenScreenHandler> { + * public OvenScreen(OvenScreenHandler handler, PlayerInventory inventory, Text title) { + * super(handler, inventory, title); + * } + * } + * } + * </pre> + * + * @see net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry registering screen handlers + */ +@Environment(EnvType.CLIENT) +public final class ScreenRegistry { + private ScreenRegistry() { + } + + /** + * Registers a new screen factory for a screen handler type. + * + * @param type the screen handler type object + * @param screenFactory the screen handler factory + * @param <H> the screen handler type + * @param <S> the screen type + */ + public static <H extends ScreenHandler, S extends Screen & ScreenHandlerProvider<H>> void register(ScreenHandlerType<? extends H> type, Factory<? super H, ? extends S> screenFactory) { + // Convert our factory to the vanilla provider here as the vanilla interface won't be available to modders. + HandledScreens.<H, S>register(type, screenFactory::create); + } + + /** + * A factory for handled screens. + * + * @param <H> the screen handler type + * @param <S> the screen type + */ + @FunctionalInterface + public interface Factory<H extends ScreenHandler, S extends Screen & ScreenHandlerProvider<H>> { + /** + * Creates a new handled screen. + * + * @param handler the screen handler + * @param inventory the player inventory + * @param title the title of the screen + * @return the created screen + */ + S create(H handler, PlayerInventory inventory, Text title); + } +} diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/client/screenhandler/v1/package-info.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/client/screenhandler/v1/package-info.java new file mode 100644 index 000000000..47bd0433c --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/client/screenhandler/v1/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * API for working with screen handlers on the client. + */ +package net.fabricmc.fabric.api.client.screenhandler.v1; diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerFactory.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerFactory.java new file mode 100644 index 000000000..e1fb76878 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ExtendedScreenHandlerFactory.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.screenhandler.v1; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.server.network.ServerPlayerEntity; + +/** + * An extension of {@code NamedScreenHandlerFactory} that can write additional data to a screen opening packet. + * + * @see ScreenHandlerRegistry#registerExtended(net.minecraft.util.Identifier, ScreenHandlerRegistry.ExtendedClientHandlerFactory) + */ +public interface ExtendedScreenHandlerFactory extends NamedScreenHandlerFactory { + /** + * Writes additional server -> client screen opening data to the buffer. + * + * @param player the player that is opening the screen + * @param buf the packet buffer + */ + void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf); +} diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ScreenHandlerRegistry.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ScreenHandlerRegistry.java new file mode 100644 index 000000000..2a93d0fed --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/ScreenHandlerRegistry.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.screenhandler.v1; + +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.impl.screenhandler.ExtendedScreenHandlerType; + +/** + * An API for creating and registering {@linkplain ScreenHandlerType screen handler types}. + * + * <p>This class exposes the private {@link ScreenHandlerType} constructor, + * as well as adds support for creating types using Fabric's extended screen handler API. + * + * <p>Screen handlers types are used to synchronize {@linkplain ScreenHandler screen handlers} + * between the server and the client. Screen handlers manage the items and integer properties that are + * needed to show on screens, such as the items in a chest or the progress of a furnace. + * + * <h2>Simple and extended screen handlers</h2> + * Simple screen handlers are the type of screen handlers used in vanilla. + * They can automatically synchronize items and integer properties between the server and the client, + * but they don't support having custom data sent in the opening packet. + * + * <p>This module adds <i>extended screen handlers</i> that can synchronize their own custom data + * when they are opened, which can be useful for defining additional properties of a screen on the server. + * For example, a mod can synchronize text that will show up as a label. + * + * <h2>Example</h2> + * <pre> + * {@code + * // Creating the screen handler type + * public static final ScreenHandlerType<OvenScreenHandler> OVEN = ScreenHandlerRegistry.registerSimple(new Identifier("my_mod", "oven"), OvenScreenHandler::new); + * + * // Screen handler class + * public class OvenScreenHandler extends ScreenHandler { + * public OvenScreenHandler(int syncId) { + * super(MyScreenHandlers.OVEN, syncId); + * } + * } + * + * // Opening the screen + * NamedScreenHandlerFactory factory = ...; + * player.openHandledScreen(factory); // only works on ServerPlayerEntity instances + * } + * </pre> + * + * @see net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry registering screens for screen handlers + */ +public final class ScreenHandlerRegistry { + private ScreenHandlerRegistry() { + } + + /** + * Creates and registers a new {@code ScreenHandlerType} that creates client-sided screen handlers using the factory. + * + * @param id the registry ID + * @param factory the client-sided screen handler factory + * @param <T> the screen handler type + * @return the created type object + */ + public static <T extends ScreenHandler> ScreenHandlerType<T> registerSimple(Identifier id, SimpleClientHandlerFactory<T> factory) { + // Wrap our factory in vanilla's factory; it will not be public for users. + ScreenHandlerType<T> type = new ScreenHandlerType<>(factory::create); + return Registry.register(Registry.SCREEN_HANDLER, id, type); + } + + /** + * Creates and registers a new {@code ScreenHandlerType} that creates client-sided screen handlers with additional + * networked opening data. + * + * <p>These screen handlers must be opened with a {@link ExtendedScreenHandlerFactory}. + * + * @param id the registry ID + * @param factory the client-sided screen handler factory + * @param <T> the screen handler type + * @return the created type object + */ + public static <T extends ScreenHandler> ScreenHandlerType<T> registerExtended(Identifier id, ExtendedClientHandlerFactory<T> factory) { + ScreenHandlerType<T> type = new ExtendedScreenHandlerType<>(factory); + return Registry.register(Registry.SCREEN_HANDLER, id, type); + } + + /** + * A factory for client-sided screen handler instances. + * + * @param <T> the screen handler type + */ + public interface SimpleClientHandlerFactory<T extends ScreenHandler> { + /** + * Creates a new client-sided screen handler. + * + * @param syncId the synchronization ID + * @param inventory the player inventory + * @return the created screen handler + */ + @Environment(EnvType.CLIENT) + T create(int syncId, PlayerInventory inventory); + } + + /** + * A factory for client-sided screen handler instances + * with additional screen opening data. + * + * @param <T> the screen handler type + * @see ExtendedScreenHandlerFactory + */ + public interface ExtendedClientHandlerFactory<T extends ScreenHandler> { + /** + * Creates a new client-sided screen handler with additional screen opening data. + * + * @param syncId the synchronization ID + * @param inventory the player inventory + * @param buf the packet buffer + * @return the created screen handler + */ + @Environment(EnvType.CLIENT) + T create(int syncId, PlayerInventory inventory, PacketByteBuf buf); + } +} diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/package-info.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/package-info.java new file mode 100644 index 000000000..3d1ff2e3d --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/api/screenhandler/v1/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * The Fabric screen handler API for creating screen handlers. + */ +package net.fabricmc.fabric.api.screenhandler.v1; diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/ExtendedScreenHandlerType.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/ExtendedScreenHandlerType.java new file mode 100644 index 000000000..951338f03 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/ExtendedScreenHandlerType.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.screenhandler; + +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerType; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; + +public final class ExtendedScreenHandlerType<T extends ScreenHandler> extends ScreenHandlerType<T> { + private final ScreenHandlerRegistry.ExtendedClientHandlerFactory<T> factory; + + public ExtendedScreenHandlerType(ScreenHandlerRegistry.ExtendedClientHandlerFactory<T> factory) { + super(null); + this.factory = factory; + } + + @Environment(EnvType.CLIENT) + @Override + public T create(int syncId, PlayerInventory inventory) { + throw new UnsupportedOperationException("Use ExtendedScreenHandlerType.create(int, PlayerInventory, PacketByteBuf)!"); + } + + @Environment(EnvType.CLIENT) + public T create(int syncId, PlayerInventory inventory, PacketByteBuf buf) { + return factory.create(syncId, inventory, buf); + } +} diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/Networking.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/Networking.java new file mode 100644 index 000000000..07ab4eb6b --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/Networking.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.screenhandler; + +import java.util.Objects; + +import io.netty.buffer.Unpooled; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; + +public final class Networking { + private static final Logger LOGGER = LogManager.getLogger("fabric-screen-handler-api-v1/server"); + + // [Packet format] + // typeId: identifier + // syncId: varInt + // title: text + // customData: buf + public static final Identifier OPEN_ID = new Identifier("fabric-screen-handler-api-v1", "open_screen"); + + /** + * Opens an extended screen handler by sending a custom packet to the client. + * + * @param player the player + * @param factory the screen handler factory + * @param handler the screen handler instance + * @param syncId the synchronization ID + */ + public static void sendOpenPacket(ServerPlayerEntity player, ExtendedScreenHandlerFactory factory, ScreenHandler handler, int syncId) { + Objects.requireNonNull(player, "player is null"); + Objects.requireNonNull(factory, "factory is null"); + Objects.requireNonNull(handler, "handler is null"); + + Identifier typeId = Registry.SCREEN_HANDLER.getId(handler.getType()); + + if (typeId == null) { + LOGGER.warn("Trying to open unregistered screen handler {}", handler); + return; + } + + PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); + buf.writeIdentifier(typeId); + buf.writeVarInt(syncId); + buf.writeText(factory.getDisplayName()); + factory.writeScreenOpeningData(player, buf); + + ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, OPEN_ID, buf); + } +} diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/client/ClientNetworking.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/client/ClientNetworking.java new file mode 100644 index 000000000..7f4058de0 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/impl/screenhandler/client/ClientNetworking.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.screenhandler.client; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.HandledScreens; +import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; +import net.fabricmc.fabric.impl.screenhandler.ExtendedScreenHandlerType; +import net.fabricmc.fabric.impl.screenhandler.Networking; + +@Environment(EnvType.CLIENT) +public final class ClientNetworking implements ClientModInitializer { + private static final Logger LOGGER = LogManager.getLogger("fabric-screen-handler-api-v1/client"); + + @Override + public void onInitializeClient() { + ClientSidePacketRegistry.INSTANCE.register(Networking.OPEN_ID, (ctx, buf) -> { + Identifier typeId = buf.readIdentifier(); + int syncId = buf.readVarInt(); + Text title = buf.readText(); + buf.retain(); + ctx.getTaskQueue().execute(() -> openScreen(typeId, syncId, title, buf)); + }); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private void openScreen(Identifier typeId, int syncId, Text title, PacketByteBuf buf) { + ScreenHandlerType<?> type = Registry.SCREEN_HANDLER.get(typeId); + + if (type == null) { + LOGGER.warn("Unknown screen handler ID: {}", typeId); + return; + } + + if (!(type instanceof ExtendedScreenHandlerType<?>)) { + LOGGER.warn("Received extended opening packet for non-extended screen handler {}", typeId); + return; + } + + HandledScreens.Provider screenFactory = HandledScreens.getProvider(type); + + if (screenFactory != null) { + MinecraftClient client = MinecraftClient.getInstance(); + PlayerEntity player = client.player; + + Screen screen = screenFactory.create( + ((ExtendedScreenHandlerType<?>) type).create(syncId, player.inventory, buf), + player.inventory, + title + ); + + player.currentScreenHandler = ((ScreenHandlerProvider<?>) screen).getScreenHandler(); + client.openScreen(screen); + } else { + LOGGER.warn("Screen not registered for screen handler {}!", typeId); + } + } +} diff --git a/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/mixin/screenhandler/ServerPlayerEntityMixin.java b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/mixin/screenhandler/ServerPlayerEntityMixin.java new file mode 100644 index 000000000..adcc34e2c --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/java/net/fabricmc/fabric/mixin/screenhandler/ServerPlayerEntityMixin.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.screenhandler; + +import java.util.OptionalInt; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import net.minecraft.network.Packet; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; +import net.fabricmc.fabric.impl.screenhandler.ExtendedScreenHandlerType; +import net.fabricmc.fabric.impl.screenhandler.Networking; + +@Mixin(ServerPlayerEntity.class) +public class ServerPlayerEntityMixin { + @Shadow + private int screenHandlerSyncId; + + @Unique + private final ThreadLocal<ScreenHandler> fabric_openedScreenHandler = new ThreadLocal<>(); + + @Inject(method = "openHandledScreen(Lnet/minecraft/screen/NamedScreenHandlerFactory;)Ljava/util/OptionalInt;", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;sendPacket(Lnet/minecraft/network/Packet;)V"), locals = LocalCapture.CAPTURE_FAILHARD) + private void fabric_storeOpenedScreenHandler(NamedScreenHandlerFactory factory, CallbackInfoReturnable<OptionalInt> info, ScreenHandler handler) { + if (factory instanceof ExtendedScreenHandlerFactory) { + fabric_openedScreenHandler.set(handler); + } else if (handler.getType() instanceof ExtendedScreenHandlerType<?>) { + Identifier id = Registry.SCREEN_HANDLER.getId(handler.getType()); + throw new IllegalArgumentException("[Fabric] Extended screen handler " + id + " must be opened with an ExtendedScreenHandlerFactory!"); + } + } + + @Redirect(method = "openHandledScreen(Lnet/minecraft/screen/NamedScreenHandlerFactory;)Ljava/util/OptionalInt;", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;sendPacket(Lnet/minecraft/network/Packet;)V")) + private void fabric_replaceVanillaScreenPacket(ServerPlayNetworkHandler networkHandler, Packet<?> packet, NamedScreenHandlerFactory factory) { + if (factory instanceof ExtendedScreenHandlerFactory) { + ScreenHandler handler = fabric_openedScreenHandler.get(); + + if (handler.getType() instanceof ExtendedScreenHandlerType<?>) { + Networking.sendOpenPacket((ServerPlayerEntity) (Object) this, (ExtendedScreenHandlerFactory) factory, handler, screenHandlerSyncId); + } else { + Identifier id = Registry.SCREEN_HANDLER.getId(handler.getType()); + throw new IllegalArgumentException("[Fabric] Non-extended screen handler " + id + " must not be opened with an ExtendedScreenHandlerFactory!"); + } + } else { + // Use vanilla logic for non-extended screen handlers + networkHandler.sendPacket(packet); + } + } + + @Inject(method = "openHandledScreen(Lnet/minecraft/screen/NamedScreenHandlerFactory;)Ljava/util/OptionalInt;", at = @At("RETURN")) + private void fabric_clearStoredScreenHandler(NamedScreenHandlerFactory factory, CallbackInfoReturnable<OptionalInt> info) { + fabric_openedScreenHandler.remove(); + } +} diff --git a/fabric-screen-handler-api-v1/src/main/resources/assets/fabric-screen-handler-api-v1/icon.png b/fabric-screen-handler-api-v1/src/main/resources/assets/fabric-screen-handler-api-v1/icon.png new file mode 100644 index 000000000..2931efbf6 Binary files /dev/null and b/fabric-screen-handler-api-v1/src/main/resources/assets/fabric-screen-handler-api-v1/icon.png differ diff --git a/fabric-screen-handler-api-v1/src/main/resources/fabric-screen-handler-api-v1.accesswidener b/fabric-screen-handler-api-v1/src/main/resources/fabric-screen-handler-api-v1.accesswidener new file mode 100644 index 000000000..65704847e --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/resources/fabric-screen-handler-api-v1.accesswidener @@ -0,0 +1,8 @@ +accessWidener v1 named +accessible class net/minecraft/screen/ScreenHandlerType$Factory +accessible method net/minecraft/screen/ScreenHandlerType <init> (Lnet/minecraft/screen/ScreenHandlerType$Factory;)V +extendable method net/minecraft/screen/ScreenHandlerType <init> (Lnet/minecraft/screen/ScreenHandlerType$Factory;)V + +accessible class net/minecraft/client/gui/screen/ingame/HandledScreens$Provider +accessible method net/minecraft/client/gui/screen/ingame/HandledScreens register (Lnet/minecraft/screen/ScreenHandlerType;Lnet/minecraft/client/gui/screen/ingame/HandledScreens$Provider;)V +accessible method net/minecraft/client/gui/screen/ingame/HandledScreens getProvider (Lnet/minecraft/screen/ScreenHandlerType;)Lnet/minecraft/client/gui/screen/ingame/HandledScreens$Provider; diff --git a/fabric-screen-handler-api-v1/src/main/resources/fabric-screen-handler-api-v1.mixins.json b/fabric-screen-handler-api-v1/src/main/resources/fabric-screen-handler-api-v1.mixins.json new file mode 100644 index 000000000..69e30be3d --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/resources/fabric-screen-handler-api-v1.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "package": "net.fabricmc.fabric.mixin.screenhandler", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "ServerPlayerEntityMixin" + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/fabric-screen-handler-api-v1/src/main/resources/fabric.mod.json b/fabric-screen-handler-api-v1/src/main/resources/fabric.mod.json new file mode 100644 index 000000000..6539d01a1 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/main/resources/fabric.mod.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": 1, + "id": "fabric-screen-handler-api-v1", + "name": "Fabric Screen Handler API (v1)", + "version": "${version}", + "environment": "*", + "license": "Apache-2.0", + "icon": "assets/fabric-screen-handler-api-v1/icon.png", + "contact": { + "homepage": "https://fabricmc.net", + "irc": "irc://irc.esper.net:6667/fabric", + "issues": "https://github.com/FabricMC/fabric/issues", + "sources": "https://github.com/FabricMC/fabric" + }, + "authors": [ + "FabricMC" + ], + "depends": { + "fabricloader": ">=0.8.0", + "fabric-api-base": "*", + "fabric-networking-v0": "*" + }, + "entrypoints": { + "client": ["net.fabricmc.fabric.impl.screenhandler.client.ClientNetworking"] + }, + "description": "Hooks and extensions for creating screen handlers.", + "mixins": [ + "fabric-screen-handler-api-v1.mixins.json" + ], + "accessWidener": "fabric-screen-handler-api-v1.accesswidener" +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/ScreenHandlerTest.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/ScreenHandlerTest.java new file mode 100644 index 000000000..c65da0e43 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/ScreenHandlerTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler; + +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.screenhandler.v1.ScreenHandlerRegistry; +import net.fabricmc.fabric.test.screenhandler.block.BoxBlock; +import net.fabricmc.fabric.test.screenhandler.block.BoxBlockEntity; +import net.fabricmc.fabric.test.screenhandler.item.BagItem; +import net.fabricmc.fabric.test.screenhandler.item.PositionedBagItem; +import net.fabricmc.fabric.test.screenhandler.screen.BagScreenHandler; +import net.fabricmc.fabric.test.screenhandler.screen.BoxScreenHandler; +import net.fabricmc.fabric.test.screenhandler.screen.PositionedBagScreenHandler; + +public class ScreenHandlerTest implements ModInitializer { + public static final String ID = "fabric-screen-handler-api-v1-testmod"; + + public static final Item BAG = new BagItem(new Item.Settings().group(ItemGroup.TOOLS).maxCount(1)); + public static final Item POSITIONED_BAG = new PositionedBagItem(new Item.Settings().group(ItemGroup.TOOLS).maxCount(1)); + public static final Block BOX = new BoxBlock(AbstractBlock.Settings.copy(Blocks.OAK_WOOD)); + public static final Item BOX_ITEM = new BlockItem(BOX, new Item.Settings().group(ItemGroup.DECORATIONS)); + public static final BlockEntityType<?> BOX_ENTITY = BlockEntityType.Builder.create(BoxBlockEntity::new, BOX).build(null); + public static final ScreenHandlerType<BagScreenHandler> BAG_SCREEN_HANDLER = ScreenHandlerRegistry.registerSimple(id("bag"), BagScreenHandler::new); + public static final ScreenHandlerType<PositionedBagScreenHandler> POSITIONED_BAG_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(id("positioned_bag"), PositionedBagScreenHandler::new); + public static final ScreenHandlerType<BoxScreenHandler> BOX_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(id("box"), BoxScreenHandler::new); + + public static Identifier id(String path) { + return new Identifier(ID, path); + } + + @Override + public void onInitialize() { + Registry.register(Registry.ITEM, id("bag"), BAG); + Registry.register(Registry.ITEM, id("positioned_bag"), POSITIONED_BAG); + Registry.register(Registry.BLOCK, id("box"), BOX); + Registry.register(Registry.ITEM, id("box"), BOX_ITEM); + Registry.register(Registry.BLOCK_ENTITY_TYPE, id("box"), BOX_ENTITY); + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlock.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlock.java new file mode 100644 index 000000000..280ef3ff5 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlock.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.block; + +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.block.BlockWithEntity; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; + +public class BoxBlock extends BlockWithEntity { + public BoxBlock(Settings settings) { + super(settings); + } + + @Override + public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { + if (!world.isClient) { + NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, pos); + + if (screenHandlerFactory != null) { + player.openHandledScreen(screenHandlerFactory); + } + } + + return ActionResult.SUCCESS; + } + + @Override + public BlockEntity createBlockEntity(BlockView world) { + return new BoxBlockEntity(); + } + + @Override + public BlockRenderType getRenderType(BlockState state) { + return BlockRenderType.MODEL; + } + + @Override + public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + if (state.getBlock() != newState.getBlock()) { + BlockEntity be = world.getBlockEntity(pos); + + if (be instanceof Inventory) { + ItemScatterer.spawn(world, pos, (Inventory) be); + world.updateComparators(pos, this); + } + + super.onStateReplaced(state, world, pos, newState, moved); + } + } + + @Override + public int getComparatorOutput(BlockState state, World world, BlockPos pos) { + return ScreenHandler.calculateComparatorOutput(world.getBlockEntity(pos)); + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlockEntity.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlockEntity.java new file mode 100644 index 000000000..2cab02d23 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/block/BoxBlockEntity.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.block; + +import net.minecraft.block.entity.LootableContainerBlockEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.collection.DefaultedList; + +import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; +import net.fabricmc.fabric.test.screenhandler.ScreenHandlerTest; +import net.fabricmc.fabric.test.screenhandler.screen.BoxScreenHandler; + +public class BoxBlockEntity extends LootableContainerBlockEntity implements ExtendedScreenHandlerFactory { + private DefaultedList<ItemStack> items = DefaultedList.ofSize(size(), ItemStack.EMPTY); + + public BoxBlockEntity() { + super(ScreenHandlerTest.BOX_ENTITY); + } + + @Override + protected DefaultedList<ItemStack> getInvStackList() { + return items; + } + + @Override + protected void setInvStackList(DefaultedList<ItemStack> list) { + this.items = list; + } + + @Override + protected Text getContainerName() { + return new TranslatableText(getCachedState().getBlock().getTranslationKey()); + } + + @Override + protected ScreenHandler createScreenHandler(int syncId, PlayerInventory playerInventory) { + return new BoxScreenHandler(syncId, playerInventory, this); + } + + @Override + public int size() { + return 3 * 3; + } + + @Override + public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) { + buf.writeBlockPos(pos); + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/client/ClientScreenHandlerTest.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/client/ClientScreenHandlerTest.java new file mode 100644 index 000000000..6edce1eaa --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/client/ClientScreenHandlerTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.client; + +import net.minecraft.client.gui.screen.ingame.Generic3x3ContainerScreen; + +import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; +import net.fabricmc.fabric.test.screenhandler.ScreenHandlerTest; +import net.fabricmc.fabric.test.screenhandler.screen.BoxScreenHandler; +import net.fabricmc.fabric.test.screenhandler.screen.PositionedBagScreenHandler; +import net.fabricmc.api.ClientModInitializer; + +public class ClientScreenHandlerTest implements ClientModInitializer { + @Override + public void onInitializeClient() { + ScreenRegistry.register(ScreenHandlerTest.BAG_SCREEN_HANDLER, Generic3x3ContainerScreen::new); + ScreenRegistry.<PositionedBagScreenHandler, PositionedScreen<PositionedBagScreenHandler>>register( + ScreenHandlerTest.POSITIONED_BAG_SCREEN_HANDLER, + PositionedScreen::new + ); + ScreenRegistry.<BoxScreenHandler, PositionedScreen<BoxScreenHandler>>register( + ScreenHandlerTest.BOX_SCREEN_HANDLER, + PositionedScreen::new + ); + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/client/PositionedScreen.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/client/PositionedScreen.java new file mode 100644 index 000000000..631479061 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/client/PositionedScreen.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.client; + +import com.mojang.blaze3d.systems.RenderSystem; + +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; + +import net.fabricmc.fabric.test.screenhandler.screen.PositionedScreenHandler; + +public class PositionedScreen<T extends ScreenHandler & PositionedScreenHandler> extends HandledScreen<T> { + private static final Identifier TEXTURE = new Identifier("minecraft", "textures/gui/container/dispenser.png"); + + public PositionedScreen(T handler, PlayerInventory inventory, Text title) { + super(handler, inventory, title); + } + + @Override + public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { + renderBackground(matrices); + super.render(matrices, mouseX, mouseY, delta); + drawMouseoverTooltip(matrices, mouseX, mouseY); + } + + @Override + protected void drawForeground(MatrixStack matrices, int mouseX, int mouseY) { + BlockPos pos = handler.getPos(); + Text usedTitle = pos != null ? new LiteralText("(" + pos.toShortString() + ")") : title; + textRenderer.draw(matrices, usedTitle, (float) (backgroundWidth / 2 - textRenderer.getWidth(usedTitle) / 2), 6.0F, 0x404040); + textRenderer.draw(matrices, playerInventory.getDisplayName(), 8.0F, backgroundHeight - 96 + 2, 0x404040); + } + + @Override + protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) { + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + client.getTextureManager().bindTexture(TEXTURE); + int x = (width - backgroundWidth) / 2; + int y = (height - backgroundHeight) / 2; + drawTexture(matrices, x, y, 0, 0, backgroundWidth, backgroundHeight); + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/BagInventory.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/BagInventory.java new file mode 100644 index 000000000..aec664e09 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/BagInventory.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.item; + +import net.minecraft.inventory.Inventories; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.collection.DefaultedList; + +final class BagInventory implements ImplementedInventory { + private final ItemStack stack; + private final DefaultedList<ItemStack> items = DefaultedList.ofSize(9, ItemStack.EMPTY); + + BagInventory(ItemStack stack) { + this.stack = stack; + CompoundTag tag = stack.getSubTag("Items"); + + if (tag != null) { + Inventories.fromTag(tag, items); + } + } + + @Override + public DefaultedList<ItemStack> getItems() { + return items; + } + + @Override + public void markDirty() { + CompoundTag tag = stack.getOrCreateSubTag("Items"); + Inventories.toTag(tag, items); + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/BagItem.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/BagItem.java new file mode 100644 index 000000000..fd5b78208 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/BagItem.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.item; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.SimpleNamedScreenHandlerFactory; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.world.World; + +import net.fabricmc.fabric.test.screenhandler.screen.BagScreenHandler; + +public class BagItem extends Item { + public BagItem(Settings settings) { + super(settings); + } + + @Override + public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) { + ItemStack stack = user.getStackInHand(hand); + user.openHandledScreen(createScreenHandlerFactory(stack)); + return TypedActionResult.success(stack); + } + + private NamedScreenHandlerFactory createScreenHandlerFactory(ItemStack stack) { + return new SimpleNamedScreenHandlerFactory((syncId, inventory, player) -> { + return new BagScreenHandler(syncId, inventory, new BagInventory(stack)); + }, stack.getName()); + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/ImplementedInventory.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/ImplementedInventory.java new file mode 100644 index 000000000..a84ce895d --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/ImplementedInventory.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.item; + +import java.util.List; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventories; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.util.math.Direction; + +/** + * A simple {@code SidedInventory} implementation with only default methods + an item list getter. + * + * <h2>Reading and writing to tags</h2> + * Use {@link Inventories#fromTag(CompoundTag, DefaultedList)} and {@link Inventories#toTag(CompoundTag, DefaultedList)} + * on {@linkplain #getItems() the item list}. + * + * @author Juuz + */ +@FunctionalInterface +public interface ImplementedInventory extends SidedInventory { + /** + * Gets the item list of this inventory. + * Must return the same instance every time it's called. + * + * @return the item list + */ + DefaultedList<ItemStack> getItems(); + + // Creation + + /** + * Creates an inventory from the item list. + * + * @param items the item list + * @return a new inventory + */ + static ImplementedInventory of(DefaultedList<ItemStack> items) { + return () -> items; + } + + /** + * Creates a new inventory with the size. + * + * @param size the inventory size + * @return a new inventory + */ + static ImplementedInventory ofSize(int size) { + return of(DefaultedList.ofSize(size, ItemStack.EMPTY)); + } + + // SidedInventory + + /** + * Gets the available slots to automation on the side. + * + * <p>The default implementation returns an array of all slots. + * + * @param side the side + * @return the available slots + */ + @Override + default int[] getAvailableSlots(Direction side) { + int[] result = new int[getItems().size()]; + + for (int i = 0; i < result.length; i++) { + result[i] = i; + } + + return result; + } + + /** + * Returns true if the stack can be inserted in the slot at the side. + * + * <p>The default implementation returns true. + * + * @param slot the slot + * @param stack the stack + * @param side the side + * @return true if the stack can be inserted + */ + @Override + default boolean canInsert(int slot, ItemStack stack, Direction side) { + return true; + } + + /** + * Returns true if the stack can be extracted from the slot at the side. + * + * <p>The default implementation returns true. + * + * @param slot the slot + * @param stack the stack + * @param side the side + * @return true if the stack can be extracted + */ + @Override + default boolean canExtract(int slot, ItemStack stack, Direction side) { + return true; + } + + // Inventory + + /** + * Returns the inventory size. + * + * <p>The default implementation returns the size of {@link #getItems()}. + * + * @return the inventory size + */ + @Override + default int size() { + return getItems().size(); + } + + /** + * @return true if this inventory has only empty stacks, false otherwise + */ + @Override + default boolean isEmpty() { + for (int i = 0; i < size(); i++) { + ItemStack stack = getStack(i); + + if (!stack.isEmpty()) { + return false; + } + } + + return true; + } + + /** + * Gets the item in the slot. + * + * @param slot the slot + * @return the item in the slot + */ + @Override + default ItemStack getStack(int slot) { + return getItems().get(slot); + } + + /** + * Takes a stack of the size from the slot. + * + * <p>(default implementation) If there are less items in the slot than what are requested, + * takes all items in that slot. + * + * @param slot the slot + * @param count the item count + * @return a stack + */ + @Override + default ItemStack removeStack(int slot, int count) { + ItemStack result = Inventories.splitStack(getItems(), slot, count); + + if (!result.isEmpty()) { + markDirty(); + } + + return result; + } + + /** + * Removes the current stack in the {@code slot} and returns it. + * + * <p>The default implementation uses {@link Inventories#removeStack(List, int)} + * + * @param slot the slot + * @return the removed stack + */ + @Override + default ItemStack removeStack(int slot) { + return Inventories.removeStack(getItems(), slot); + } + + /** + * Replaces the current stack in the {@code slot} with the provided stack. + * + * <p>If the stack is too big for this inventory ({@link Inventory#getMaxCountPerStack()} ()}), + * it gets resized to this inventory's maximum amount. + * + * @param slot the slot + * @param stack the stack + */ + @Override + default void setStack(int slot, ItemStack stack) { + getItems().set(slot, stack); + + if (stack.getCount() > getMaxCountPerStack()) { + stack.setCount(getMaxCountPerStack()); + } + } + + /** + * Clears {@linkplain #getItems() the item list}}. + */ + @Override + default void clear() { + getItems().clear(); + } + + @Override + default void markDirty() { + // Override if you want behavior. + } + + @Override + default boolean canPlayerUse(PlayerEntity player) { + return true; + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/PositionedBagItem.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/PositionedBagItem.java new file mode 100644 index 000000000..13373b385 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/item/PositionedBagItem.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.item; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory; +import net.fabricmc.fabric.test.screenhandler.screen.PositionedBagScreenHandler; + +public class PositionedBagItem extends BagItem { + public PositionedBagItem(Settings settings) { + super(settings); + } + + @Override + public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) { + ItemStack stack = user.getStackInHand(hand); + user.openHandledScreen(createScreenHandlerFactory(stack, null)); + return TypedActionResult.success(stack); + } + + @Override + public ActionResult useOnBlock(ItemUsageContext context) { + PlayerEntity user = context.getPlayer(); + ItemStack stack = user.getStackInHand(context.getHand()); + BlockPos pos = context.getBlockPos(); + user.openHandledScreen(createScreenHandlerFactory(stack, pos)); + return ActionResult.SUCCESS; + } + + private ExtendedScreenHandlerFactory createScreenHandlerFactory(ItemStack stack, BlockPos pos) { + return new ExtendedScreenHandlerFactory() { + @Override + public ScreenHandler createMenu(int syncId, PlayerInventory inventory, PlayerEntity player) { + return new PositionedBagScreenHandler(syncId, inventory, new BagInventory(stack), pos); + } + + @Override + public Text getDisplayName() { + return stack.getName(); + } + + @Override + public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) { + buf.writeBoolean(pos != null); + buf.writeBlockPos(pos != null ? pos : BlockPos.ORIGIN); + } + }; + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/BagScreenHandler.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/BagScreenHandler.java new file mode 100644 index 000000000..a1eac6781 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/BagScreenHandler.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.screen; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.Generic3x3ContainerScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.screen.slot.SlotActionType; + +import net.fabricmc.fabric.test.screenhandler.ScreenHandlerTest; +import net.fabricmc.fabric.test.screenhandler.item.BagItem; + +public class BagScreenHandler extends Generic3x3ContainerScreenHandler { + private final ScreenHandlerType<?> type; + + public BagScreenHandler(int syncId, PlayerInventory playerInventory) { + this(syncId, playerInventory, new SimpleInventory(9)); + } + + public BagScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) { + this(ScreenHandlerTest.BAG_SCREEN_HANDLER, syncId, playerInventory, inventory); + } + + protected BagScreenHandler(ScreenHandlerType<?> type, int syncId, PlayerInventory playerInventory, Inventory inventory) { + super(syncId, playerInventory, inventory); + this.type = type; + } + + @Override + public ScreenHandlerType<?> getType() { + return type; + } + + @Override + public ItemStack onSlotClick(int slotId, int clickData, SlotActionType actionType, PlayerEntity playerEntity) { + if (slotId >= 0) { // slotId < 0 are used for networking internals + ItemStack stack = getSlot(slotId).getStack(); + + if (stack.getItem() instanceof BagItem) { + // Prevent moving bags around + return stack; + } + } + + return super.onSlotClick(slotId, clickData, actionType, playerEntity); + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/BoxScreenHandler.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/BoxScreenHandler.java new file mode 100644 index 000000000..6d3dc7e13 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/BoxScreenHandler.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.screen; + +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.screen.Generic3x3ContainerScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.util.math.BlockPos; + +import net.fabricmc.fabric.test.screenhandler.ScreenHandlerTest; + +public class BoxScreenHandler extends Generic3x3ContainerScreenHandler implements PositionedScreenHandler { + private final BlockPos pos; + + public BoxScreenHandler(int syncId, PlayerInventory playerInventory, PacketByteBuf buf) { + super(syncId, playerInventory); + this.pos = buf.readBlockPos(); + } + + public BoxScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) { + super(syncId, playerInventory, inventory); + this.pos = BlockPos.ORIGIN; + } + + @Override + public BlockPos getPos() { + return pos; + } + + @Override + public ScreenHandlerType<?> getType() { + return ScreenHandlerTest.BOX_SCREEN_HANDLER; + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/PositionedBagScreenHandler.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/PositionedBagScreenHandler.java new file mode 100644 index 000000000..2c7102f94 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/PositionedBagScreenHandler.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.screen; + +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.math.BlockPos; + +import net.fabricmc.fabric.test.screenhandler.ScreenHandlerTest; + +public class PositionedBagScreenHandler extends BagScreenHandler implements PositionedScreenHandler { + private final BlockPos pos; + + public PositionedBagScreenHandler(int syncId, PlayerInventory playerInventory, PacketByteBuf buf) { + this(syncId, playerInventory, new SimpleInventory(9), readOptionalPos(buf)); + } + + private static BlockPos readOptionalPos(PacketByteBuf buf) { + boolean hasPos = buf.readBoolean(); + BlockPos pos = buf.readBlockPos(); + return hasPos ? pos : null; + } + + public PositionedBagScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory, BlockPos pos) { + super(ScreenHandlerTest.POSITIONED_BAG_SCREEN_HANDLER, syncId, playerInventory, inventory); + this.pos = pos; + } + + @Override + public BlockPos getPos() { + return pos; + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/PositionedScreenHandler.java b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/PositionedScreenHandler.java new file mode 100644 index 000000000..9432db94a --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/java/net/fabricmc/fabric/test/screenhandler/screen/PositionedScreenHandler.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.test.screenhandler.screen; + +import net.minecraft.util.math.BlockPos; + +public interface PositionedScreenHandler { + BlockPos getPos(); +} diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/blockstates/box.json b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/blockstates/box.json new file mode 100644 index 000000000..861b9b4f8 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/blockstates/box.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "fabric-screen-handler-api-v1-testmod:block/box" } + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/lang/en_us.json b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/lang/en_us.json new file mode 100644 index 000000000..f74eb07c3 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/lang/en_us.json @@ -0,0 +1,5 @@ +{ + "block.fabric-screen-handler-api-v1-testmod.box": "Box", + "item.fabric-screen-handler-api-v1-testmod.bag": "Bag", + "item.fabric-screen-handler-api-v1-testmod.positioned_bag": "Positioned Bag" +} diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/block/box.json b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/block/box.json new file mode 100644 index 000000000..7307a9c37 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/block/box.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "fabric-screen-handler-api-v1-testmod:block/box" + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/item/bag.json b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/item/bag.json new file mode 100644 index 000000000..e9479a5ec --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/item/bag.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "fabric-screen-handler-api-v1-testmod:item/bag" + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/item/box.json b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/item/box.json new file mode 100644 index 000000000..ff03794e4 --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/item/box.json @@ -0,0 +1,3 @@ +{ + "parent": "fabric-screen-handler-api-v1-testmod:block/box" +} diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/item/positioned_bag.json b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/item/positioned_bag.json new file mode 100644 index 000000000..2b7938cbd --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/models/item/positioned_bag.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "fabric-screen-handler-api-v1-testmod:item/positioned_bag" + } +} diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/textures/block/box.png b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/textures/block/box.png new file mode 100644 index 000000000..b57b82765 Binary files /dev/null and b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/textures/block/box.png differ diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/textures/item/bag.png b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/textures/item/bag.png new file mode 100644 index 000000000..1a474f87a Binary files /dev/null and b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/textures/item/bag.png differ diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/textures/item/positioned_bag.png b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/textures/item/positioned_bag.png new file mode 100644 index 000000000..542e1607f Binary files /dev/null and b/fabric-screen-handler-api-v1/src/testmod/resources/assets/fabric-screen-handler-api-v1-testmod/textures/item/positioned_bag.png differ diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/data/fabric-screen-handler-api-v1-testmod/loot_tables/blocks/box.json b/fabric-screen-handler-api-v1/src/testmod/resources/data/fabric-screen-handler-api-v1-testmod/loot_tables/blocks/box.json new file mode 100644 index 000000000..f8a3e07dd --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/resources/data/fabric-screen-handler-api-v1-testmod/loot_tables/blocks/box.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "fabric-screen-handler-api-v1-testmod:box" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} diff --git a/fabric-screen-handler-api-v1/src/testmod/resources/fabric.mod.json b/fabric-screen-handler-api-v1/src/testmod/resources/fabric.mod.json new file mode 100644 index 000000000..f3d6f8bad --- /dev/null +++ b/fabric-screen-handler-api-v1/src/testmod/resources/fabric.mod.json @@ -0,0 +1,20 @@ +{ + "schemaVersion": 1, + "id": "fabric-screen-handler-api-v1-testmod", + "name": "Fabric Screen Handler API (v1) Test Mod", + "version": "1.0.0", + "environment": "*", + "license": "Apache-2.0", + "depends": { + "fabric-resource-loader-v0": "*", + "fabric-screen-handler-api-v1": "*" + }, + "entrypoints": { + "main": [ + "net.fabricmc.fabric.test.screenhandler.ScreenHandlerTest" + ], + "client": [ + "net.fabricmc.fabric.test.screenhandler.client.ClientScreenHandlerTest" + ] + } +} diff --git a/settings.gradle b/settings.gradle index b6faf41d5..4dcd34a31 100644 --- a/settings.gradle +++ b/settings.gradle @@ -44,6 +44,7 @@ include 'fabric-rendering-v1' include 'fabric-rendering-data-attachment-v1' include 'fabric-rendering-fluids-v1' include 'fabric-resource-loader-v0' +include 'fabric-screen-handler-api-v1' include 'fabric-tag-extensions-v0' include 'fabric-textures-v0' include 'fabric-tool-attribute-api-v1'