From d1d2e36143de43bfe99a2bab8baa5a7076197f0f Mon Sep 17 00:00:00 2001 From: Des Herriott Date: Wed, 17 Jul 2024 22:52:33 +0100 Subject: [PATCH] Total overhaul of the remote widget system Remote widgets are now immutable objects in a registry with no client code All client code moved to RemoteClientRegistry Remote widgets are fully codec'd and saved in data component on the remote Exported Json format much cleaner now; support for legacy import --- build.gradle | 2 +- gradle.properties | 8 +- .../api/drone/ProgWidgetType.java | 6 +- .../api/misc/IGlobalVariableHelper.java | 95 ++++++ .../pneumaticcraft/api/misc/IMiscHelpers.java | 7 + .../api/misc/IPlayerFilter.java | 6 + .../api/misc}/IVariableProvider.java | 6 +- .../api/registry/PNCRegistries.java | 7 +- .../api/remote/BaseSettings.java | 30 ++ .../api/remote/IRemoteVariableWidget.java | 17 + .../api/remote/IRemoteWidget.java | 113 +++++++ .../api/remote/RemoteWidgetType.java | 23 ++ .../api/remote/WidgetSettings.java | 55 ++++ .../PneumaticCraftRepressurized.java | 2 + .../pneumaticcraft/client/ClientSetup.java | 4 + .../client/gui/GPSAreaToolScreen.java | 10 +- .../client/gui/GPSToolScreen.java | 6 +- .../client/gui/PastebinScreen.java | 2 +- .../client/gui/RemoteEditorScreen.java | 272 ---------------- .../client/gui/RemoteScreen.java | 100 ------ .../gui/remote/AbstractRemoteScreen.java | 77 +++++ .../gui/remote/BasicRemoteOptionScreen.java | 151 --------- .../gui/remote/RemoteClientRegistry.java | 64 ++++ .../remote/RemoteDropdownOptionScreen.java | 72 ----- .../client/gui/remote/RemoteEditorScreen.java | 304 ++++++++++++++++++ .../client/gui/remote/RemoteLayout.java | 119 ------- .../client/gui/remote/RemoteScreen.java | 60 ++++ .../gui/remote/actionwidget/ActionWidget.java | 171 ---------- .../actionwidget/ActionWidgetButton.java | 116 ------- .../actionwidget/ActionWidgetCheckBox.java | 90 ------ .../actionwidget/ActionWidgetDropdown.java | 156 --------- .../actionwidget/ActionWidgetLabel.java | 76 ----- .../actionwidget/ActionWidgetVariable.java | 72 ----- .../remote/actionwidget/ActionWidgets.java | 25 -- .../actionwidget/IActionWidgetLabeled.java | 26 -- .../actionwidget/WidgetLabelVariable.java | 54 ---- .../remote/actionwidget/WidgetSettings.java | 126 -------- .../config/AbstractRemoteConfigScreen.java | 212 ++++++++++++ .../AbstractRemoteVariableConfigScreen.java} | 31 +- .../RemoteButtonOptionScreen.java | 63 +++- .../config/RemoteCheckboxOptionScreen.java | 55 ++++ .../config/RemoteDropdownOptionScreen.java | 120 +++++++ .../config/RemoteLabelOptionScreen.java | 40 +++ .../pneumaticcraft/common/MiscAPIHandler.java | 8 +- .../common/commands/ModCommands.java | 24 +- .../common/drone/ai/DroneAIManager.java | 10 +- .../drone/progwidgets/ProgWidgetArea.java | 2 +- .../semiblock/AbstractSemiblockEntity.java | 12 +- .../common/inventory/RemoteMenu.java | 42 ++- .../common/item/GPSAreaToolItem.java | 15 +- .../common/item/GPSToolItem.java | 10 +- .../common/item/RemoteItem.java | 30 +- .../network/PacketSetGlobalVariable.java | 13 +- .../network/PacketUpdateRemoteLayout.java | 17 +- .../common/registry/ModDataComponents.java | 5 +- .../common/registry/ModRemoteWidgetTypes.java | 36 +++ .../common/remote/RemoteWidgetButton.java | 53 +++ .../common/remote/RemoteWidgetCheckbox.java | 48 +++ .../common/remote/RemoteWidgetDropdown.java | 69 ++++ .../common/remote/RemoteWidgetLabel.java | 46 +++ .../common/remote/SavedRemoteLayout.java | 89 +++++ .../WorldGlobalVariableAnalogSensor.java | 2 +- .../WorldGlobalVariableSensor.java | 2 +- .../legacyconv/ActionWidgetLegacyConv.java | 9 +- .../util/playerfilter/PlayerFilter.java | 4 - .../variables/GlobalVariableHelper.java | 126 +++----- .../common/variables/TextVariableParser.java | 4 +- .../assets/pneumaticcraft/lang/en_us.json | 18 +- 68 files changed, 1864 insertions(+), 1881 deletions(-) create mode 100644 src/api/java/me/desht/pneumaticcraft/api/misc/IGlobalVariableHelper.java rename src/{main/java/me/desht/pneumaticcraft/common/drone/progwidgets => api/java/me/desht/pneumaticcraft/api/misc}/IVariableProvider.java (87%) create mode 100644 src/api/java/me/desht/pneumaticcraft/api/remote/BaseSettings.java create mode 100644 src/api/java/me/desht/pneumaticcraft/api/remote/IRemoteVariableWidget.java create mode 100644 src/api/java/me/desht/pneumaticcraft/api/remote/IRemoteWidget.java create mode 100644 src/api/java/me/desht/pneumaticcraft/api/remote/RemoteWidgetType.java create mode 100644 src/api/java/me/desht/pneumaticcraft/api/remote/WidgetSettings.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/RemoteEditorScreen.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/RemoteScreen.java create mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/AbstractRemoteScreen.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/BasicRemoteOptionScreen.java create mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteClientRegistry.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteDropdownOptionScreen.java create mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteEditorScreen.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteLayout.java create mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteScreen.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidget.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetButton.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetCheckBox.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetDropdown.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetLabel.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetVariable.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgets.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/IActionWidgetLabeled.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/WidgetLabelVariable.java delete mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/WidgetSettings.java create mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/AbstractRemoteConfigScreen.java rename src/main/java/me/desht/pneumaticcraft/client/gui/remote/{RemoteVariableOptionScreen.java => config/AbstractRemoteVariableConfigScreen.java} (63%) rename src/main/java/me/desht/pneumaticcraft/client/gui/remote/{ => config}/RemoteButtonOptionScreen.java (55%) create mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteCheckboxOptionScreen.java create mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteDropdownOptionScreen.java create mode 100644 src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteLabelOptionScreen.java create mode 100644 src/main/java/me/desht/pneumaticcraft/common/registry/ModRemoteWidgetTypes.java create mode 100644 src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetButton.java create mode 100644 src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetCheckbox.java create mode 100644 src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetDropdown.java create mode 100644 src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetLabel.java create mode 100644 src/main/java/me/desht/pneumaticcraft/common/remote/SavedRemoteLayout.java diff --git a/build.gradle b/build.gradle index 62db69397..c278e6468 100644 --- a/build.gradle +++ b/build.gradle @@ -170,7 +170,7 @@ dependencies { //runtimeOnly("vazkii.patchouli:Patchouli:${patchouli_version}") compileOnly("cc.tweaked:cc-tweaked-1.21-forge-api:${cc_tweaked_version}") - runtimeOnly("cc.tweaked:cc-tweaked-1.21-forge:${cc_tweaked_version}") +// runtimeOnly("cc.tweaked:cc-tweaked-1.21-forge:${cc_tweaked_version}") compileOnly("dev.ftb.mods:ftb-filter-system-neoforge:${ffs_version}") { transitive = false } diff --git a/gradle.properties b/gradle.properties index 383d702bf..ac8f6b55d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,8 +9,8 @@ org.gradle.daemon=false ######################################################### minecraft_version=1.21 minecraft_version_range=[1.21,) -neo_version=21.0.76-beta -neo_version_range=[21.0.40-beta,) +neo_version=21.0.98-beta +neo_version_range=[21.0.98-beta,) loader_version_range=[4,) mappings_version=1.20.6-2024.06.02 pack_format_number=18 @@ -34,14 +34,14 @@ curse_project_id=281849 ######################################################### # API versions ######################################################### -jei_version=19.1.0.17 +jei_version=19.5.0.35 curios_version=8.0.0-beta+1.20.6 top_version=1.21_neo-12.0.0-1 ffs_version=3.0.0 jade_curse_id = 5493270 crafttweaker_version=20.0.4 cc_tweaked_version=1.111.0 -mekanism_version=1.21-10.6.4.50 +mekanism_version=1.21-10.6.5.52 # TODO update deps when available immersive_engineering_version=1.20.4-11.1.0-172.110 diff --git a/src/api/java/me/desht/pneumaticcraft/api/drone/ProgWidgetType.java b/src/api/java/me/desht/pneumaticcraft/api/drone/ProgWidgetType.java index 2ee19983f..5c9c0fb8d 100644 --- a/src/api/java/me/desht/pneumaticcraft/api/drone/ProgWidgetType.java +++ b/src/api/java/me/desht/pneumaticcraft/api/drone/ProgWidgetType.java @@ -27,9 +27,9 @@ * Handles serialization of progwidgets, as well as default instance creation. */ public class ProgWidgetType

{ - private final Supplier defaultSupplier; - private final MapCodec codec; - private final StreamCodec streamCodec; + private final Supplier

defaultSupplier; + private final MapCodec

codec; + private final StreamCodec streamCodec; private String descriptionId; private ProgWidgetType(Supplier

defaultSupplier, MapCodec

codec, StreamCodec streamCodec) { diff --git a/src/api/java/me/desht/pneumaticcraft/api/misc/IGlobalVariableHelper.java b/src/api/java/me/desht/pneumaticcraft/api/misc/IGlobalVariableHelper.java new file mode 100644 index 000000000..1939dafb0 --- /dev/null +++ b/src/api/java/me/desht/pneumaticcraft/api/misc/IGlobalVariableHelper.java @@ -0,0 +1,95 @@ +package me.desht.pneumaticcraft.api.misc; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.ItemStack; + +import javax.annotation.Nullable; +import java.util.Set; +import java.util.UUID; + +public interface IGlobalVariableHelper { + /** + * Retrieve a blockpos variable from the GVM. The variable may start with "#" or "%" to indicate player-global + * or global respectively. Missing prefix defaults to player-global. + * @param id the ID of the owning player (ignored for "%" global variables) + * @param varName the variable name, optionally prefixed with "%" or "#" + * @param def default value if not present in the GVM + * @return the variable's value + */ + BlockPos getPos(@Nullable UUID id, String varName, BlockPos def); + + /** + * Retrieve a blockpos variable from the GVM. The variable may start with "#" or "%" to indicate player-global + * or global respectively. Missing prefix defaults to player-global. + * @param id the ID of the owning player (ignored for "%" global variables, must be a valid player UUID otherwise) + * @param varName the variable name, optionally prefixed with "%" or "#" + * @return the variable's value + */ + BlockPos getPos(@Nullable UUID id, String varName); + + /** + * Retrieve an itemstack variable from the GVM. The variable may start with "#" or "%" to indicate player-global + * or global respectively. Missing prefix defaults to player-global "#". + * @param id the ID of the owning player (ignored for "%" global variables, must be a valid player UUID otherwise) + * @param varName the variable name, optionally prefixed with "%" or "#" + * @param def default value if not present in the GVM + * @return the variable's value + */ + ItemStack getStack(@Nullable UUID id, String varName, ItemStack def); + + /** + * Retrieve an itemstack variable from the GVM. The variable may start with "#" or "%" to indicate player-global + * or global respectively. Missing prefix defaults to player-global. + * @param id the ID of the owning player (ignored for "%" global variables, must be a valid player UUID otherwise) + * @param varName the variable name, optionally prefixed with "%" or "#" + * @return the variable's value + */ + ItemStack getStack(@Nullable UUID id, String varName); + + int getInt(UUID id, String varName); + + void setPos(UUID id, String varName, BlockPos pos); + + void setStack(UUID id, String varName, ItemStack stack); + + boolean getBool(UUID id, String varName); + + /** + * Given a plain variable name, add the "#" or "%" prefix as appropriate + * @param varName the variable + * @param playerGlobal true if a player-global, false if a server-global + * @return the prefixed var name + */ + String getPrefixedVar(String varName, boolean playerGlobal); + + /** + * Get the correct var prefix + * @param playerGlobal true if a player-global, false if a server-global + * @return the var prefix + */ + String getVarPrefix(boolean playerGlobal); + + /** + * Strip the prefix character from a var name + * @param varName the var name + * @return the var name without a prefix + */ + String stripVarPrefix(String varName); + + /** + * Check if this varname has a prefix character + * @param varName the var name + * @return true if prefixed, false otherwise + */ + boolean hasPrefix(String varName); + + /** + * Parse a string, and extract a set of global variables (both player-global and server-global) referred to in the + * string via {@code ${varname}} notation. + * + * @param string the string to parse + * @param playerId UUID of the player + * @return a set of global variable names + */ + Set getRelevantVariables(String string, UUID playerId); +} diff --git a/src/api/java/me/desht/pneumaticcraft/api/misc/IMiscHelpers.java b/src/api/java/me/desht/pneumaticcraft/api/misc/IMiscHelpers.java index 9fca57dc7..1ff5e44d3 100644 --- a/src/api/java/me/desht/pneumaticcraft/api/misc/IMiscHelpers.java +++ b/src/api/java/me/desht/pneumaticcraft/api/misc/IMiscHelpers.java @@ -107,4 +107,11 @@ public interface IMiscHelpers { */ Optional getHackingForEntity(Entity entity, boolean create); + /** + * Get the global variable helper; this helper allows querying and modifying global variables, as used by drones, + * the Universal Sensor, and the Remote item. + * + * @return the global variable helper + */ + IGlobalVariableHelper getGlobalVariableHelper(); } diff --git a/src/api/java/me/desht/pneumaticcraft/api/misc/IPlayerFilter.java b/src/api/java/me/desht/pneumaticcraft/api/misc/IPlayerFilter.java index 23ef97f4c..8a3e9e0a1 100644 --- a/src/api/java/me/desht/pneumaticcraft/api/misc/IPlayerFilter.java +++ b/src/api/java/me/desht/pneumaticcraft/api/misc/IPlayerFilter.java @@ -2,10 +2,16 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Player; +import org.jetbrains.annotations.ApiStatus; import java.util.List; import java.util.function.Predicate; +/** + * A player filter is a collection of individual matcher objects with either match-any or match-all behaviour. + * Custom matcher objects can be registered and have full codec/stream-codec support, so can be used in recipes etc. + */ +@ApiStatus.NonExtendable public interface IPlayerFilter extends Predicate { boolean isReal(); diff --git a/src/main/java/me/desht/pneumaticcraft/common/drone/progwidgets/IVariableProvider.java b/src/api/java/me/desht/pneumaticcraft/api/misc/IVariableProvider.java similarity index 87% rename from src/main/java/me/desht/pneumaticcraft/common/drone/progwidgets/IVariableProvider.java rename to src/api/java/me/desht/pneumaticcraft/api/misc/IVariableProvider.java index 3bbe6625c..5fc36eaf9 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/drone/progwidgets/IVariableProvider.java +++ b/src/api/java/me/desht/pneumaticcraft/api/misc/IVariableProvider.java @@ -15,16 +15,18 @@ * along with pnc-repressurized. If not, see . */ -package me.desht.pneumaticcraft.common.drone.progwidgets; +package me.desht.pneumaticcraft.api.misc; import net.minecraft.core.BlockPos; import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.ApiStatus; import javax.annotation.Nonnull; import java.util.Optional; import java.util.UUID; -public interface IVariableProvider{ +@ApiStatus.NonExtendable +public interface IVariableProvider { Optional getCoordinate(UUID id, String varName); @Nonnull diff --git a/src/api/java/me/desht/pneumaticcraft/api/registry/PNCRegistries.java b/src/api/java/me/desht/pneumaticcraft/api/registry/PNCRegistries.java index d6024b2de..5a3e85b3d 100644 --- a/src/api/java/me/desht/pneumaticcraft/api/registry/PNCRegistries.java +++ b/src/api/java/me/desht/pneumaticcraft/api/registry/PNCRegistries.java @@ -1,11 +1,12 @@ package me.desht.pneumaticcraft.api.registry; +import me.desht.pneumaticcraft.api.drone.ProgWidgetType; import me.desht.pneumaticcraft.api.drone.area.AreaType; import me.desht.pneumaticcraft.api.drone.area.AreaTypeSerializer; -import me.desht.pneumaticcraft.api.drone.ProgWidgetType; import me.desht.pneumaticcraft.api.harvesting.HarvestHandler; import me.desht.pneumaticcraft.api.harvesting.HoeHandler; import me.desht.pneumaticcraft.api.misc.IPlayerMatcher; +import me.desht.pneumaticcraft.api.remote.RemoteWidgetType; import net.minecraft.core.Registry; import net.minecraft.resources.ResourceKey; import net.neoforged.neoforge.registries.RegistryBuilder; @@ -24,6 +25,8 @@ public class PNCRegistries { = ResourceKey.createRegistryKey(RL("player_matchers")); public static final ResourceKey>> PROG_WIDGETS_KEY = ResourceKey.createRegistryKey(RL("prog_widgets")); + public static final ResourceKey>> REMOTE_WIDGETS_KEY + = ResourceKey.createRegistryKey(RL("remote_widgets")); // Registries public static final Registry> AREA_TYPE_SERIALIZER_REGISTRY @@ -36,4 +39,6 @@ public class PNCRegistries { = new RegistryBuilder<>(PLAYER_MATCHER_KEY).create(); public static final Registry> PROG_WIDGETS_REGISTRY = new RegistryBuilder<>(PROG_WIDGETS_KEY).sync(true).create(); + public static final Registry> REMOTE_WIDGETS_REGISTRY + = new RegistryBuilder<>(REMOTE_WIDGETS_KEY).sync(true).create(); } diff --git a/src/api/java/me/desht/pneumaticcraft/api/remote/BaseSettings.java b/src/api/java/me/desht/pneumaticcraft/api/remote/BaseSettings.java new file mode 100644 index 000000000..4bec530e8 --- /dev/null +++ b/src/api/java/me/desht/pneumaticcraft/api/remote/BaseSettings.java @@ -0,0 +1,30 @@ +package me.desht.pneumaticcraft.api.remote; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; + +public record BaseSettings(String enableVariable, BlockPos enablingValue) { + public static final Codec CODEC = RecordCodecBuilder.create(builder -> builder.group( + Codec.STRING.optionalFieldOf("enable_var", "").forGetter(BaseSettings::enableVariable), + BlockPos.CODEC.optionalFieldOf("enable_pos", BlockPos.ZERO).forGetter(BaseSettings::enablingValue) + ).apply(builder, BaseSettings::new)); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.STRING_UTF8, BaseSettings::enableVariable, + BlockPos.STREAM_CODEC, BaseSettings::enablingValue, + BaseSettings::new + ); + + public static final BaseSettings DEFAULT = new BaseSettings("", BlockPos.ZERO); + + public BaseSettings withVariable(String var) { + return new BaseSettings(var, enablingValue); + } + + public BaseSettings withEnablingValue(BlockPos value) { + return new BaseSettings(enableVariable, value); + } +} diff --git a/src/api/java/me/desht/pneumaticcraft/api/remote/IRemoteVariableWidget.java b/src/api/java/me/desht/pneumaticcraft/api/remote/IRemoteVariableWidget.java new file mode 100644 index 000000000..bc3f8afe8 --- /dev/null +++ b/src/api/java/me/desht/pneumaticcraft/api/remote/IRemoteVariableWidget.java @@ -0,0 +1,17 @@ +package me.desht.pneumaticcraft.api.remote; + +import java.util.Set; +import java.util.UUID; + +public interface IRemoteVariableWidget extends IRemoteWidget { + String varName(); + + @Override + default void discoverVariables(Set variables, UUID playerId) { + IRemoteWidget.super.discoverVariables(variables, playerId); + + if (!varName().isEmpty()) { + variables.add(varName()); + } + } +} diff --git a/src/api/java/me/desht/pneumaticcraft/api/remote/IRemoteWidget.java b/src/api/java/me/desht/pneumaticcraft/api/remote/IRemoteWidget.java new file mode 100644 index 000000000..015737612 --- /dev/null +++ b/src/api/java/me/desht/pneumaticcraft/api/remote/IRemoteWidget.java @@ -0,0 +1,113 @@ +package me.desht.pneumaticcraft.api.remote; + +import com.mojang.serialization.Codec; +import me.desht.pneumaticcraft.api.PneumaticRegistry; +import me.desht.pneumaticcraft.api.misc.IGlobalVariableHelper; +import me.desht.pneumaticcraft.api.registry.PNCRegistries; +import net.minecraft.core.BlockPos; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.entity.player.Player; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +/** + * Represents a template for a widget to be added to the Remote GUI. This is an immutable object, is used in itemstack + * data components, and does not contain any client-only methods; see {@link xxx} for that. + */ +public interface IRemoteWidget { + int TRAY_WIDGET_X = 200; + + Codec CODEC = PNCRegistries.REMOTE_WIDGETS_REGISTRY.byNameCodec().dispatch( + IRemoteWidget::getType, + RemoteWidgetType::codec + ); + + StreamCodec STREAM_CODEC + = ByteBufCodecs.registry(PNCRegistries.REMOTE_WIDGETS_KEY) + .dispatch(IRemoteWidget::getType, RemoteWidgetType::streamCodec); + + /** + * {@return Base settings, common to all remote widgets} + */ + BaseSettings baseSettings(); + + /** + * {@return Settings for the physical Minecraft widget, common to all remote widgets} + */ + WidgetSettings widgetSettings(); + + /** + * {@return an exact copy of this remote widget} + */ + @ApiStatus.NonExtendable + default IRemoteWidget copy() { + return copyToPos(widgetSettings().x(), widgetSettings().y()); + } + + /** + * Make a copy of this remote widget, at the new X/Y physical widget position + * @param x X + * @param y Y + * @return the copied remote widget + */ + IRemoteWidget copyToPos(int x, int y); + + /** + * Does this widget allow configuration of its title and tooltip? + * @return true if configurable, false if not + */ + default boolean hasConfigurableText() { + return true; + } + + /** + * {@return the widget type, which handles serialization} + */ + RemoteWidgetType getType(); + + default String getTranslationKey() { + return getTranslationKey(getType()); + } + + static String getTranslationKey(RemoteWidgetType type) { + String id = PNCRegistries.REMOTE_WIDGETS_REGISTRY.getResourceKey(type) + .map(key -> key.location().toLanguageKey()) + .orElse("unknown"); + return "pneumaticcraft.gui.remote.tray." + id + ".name"; + } + + static String getTooltipTranslationKey(RemoteWidgetType type) { + String id = PNCRegistries.REMOTE_WIDGETS_REGISTRY.getResourceKey(type) + .map(key -> key.location().toLanguageKey()) + .orElse("unknown"); + return "pneumaticcraft.gui.remote.tray." + id + ".tooltip"; + } + + default void discoverVariables(Set variables, UUID playerId) { + if (!baseSettings().enableVariable().isEmpty()) { + variables.add(baseSettings().enableVariable()); + } + if (this instanceof IRemoteVariableWidget v && !v.varName().isEmpty()) { + variables.add(v.varName()); + } + IGlobalVariableHelper helper = PneumaticRegistry.getInstance().getMiscHelpers().getGlobalVariableHelper(); + widgetSettings().title().visit(string -> { + variables.addAll(helper.getRelevantVariables(string, playerId)); + return Optional.empty(); + }); + } + + default boolean isEnabled(Player player) { + if (baseSettings().enableVariable().isEmpty()) { + return true; + } + BlockPos pos = PneumaticRegistry.getInstance().getMiscHelpers().getGlobalVariableHelper() + .getPos(player.getUUID(), baseSettings().enableVariable(), BlockPos.ZERO); + return pos.equals(baseSettings().enablingValue()); + } +} diff --git a/src/api/java/me/desht/pneumaticcraft/api/remote/RemoteWidgetType.java b/src/api/java/me/desht/pneumaticcraft/api/remote/RemoteWidgetType.java new file mode 100644 index 000000000..3da90fac5 --- /dev/null +++ b/src/api/java/me/desht/pneumaticcraft/api/remote/RemoteWidgetType.java @@ -0,0 +1,23 @@ +package me.desht.pneumaticcraft.api.remote; + +import com.mojang.serialization.MapCodec; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; + +public class RemoteWidgetType { + private final MapCodec codec; + private final StreamCodec streamCodec; + + public RemoteWidgetType(MapCodec codec, StreamCodec streamCodec) { + this.codec = codec; + this.streamCodec = streamCodec; + } + + public MapCodec codec() { + return codec; + } + + public StreamCodec streamCodec() { + return streamCodec; + } +} diff --git a/src/api/java/me/desht/pneumaticcraft/api/remote/WidgetSettings.java b/src/api/java/me/desht/pneumaticcraft/api/remote/WidgetSettings.java new file mode 100644 index 000000000..63af8dbb7 --- /dev/null +++ b/src/api/java/me/desht/pneumaticcraft/api/remote/WidgetSettings.java @@ -0,0 +1,55 @@ +package me.desht.pneumaticcraft.api.remote; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import org.jetbrains.annotations.NotNull; + +public record WidgetSettings(int x, int y, int width, int height, Component title, Component tooltip) { + public static final Codec CODEC = RecordCodecBuilder.create(builder -> builder.group( + Codec.INT.fieldOf("x").forGetter(WidgetSettings::x), + Codec.INT.fieldOf("y").forGetter(WidgetSettings::y), + Codec.INT.optionalFieldOf("width", 0).forGetter(WidgetSettings::width), + Codec.INT.optionalFieldOf("height", 0).forGetter(WidgetSettings::height), + ComponentSerialization.CODEC.fieldOf("title").forGetter(WidgetSettings::title), + ComponentSerialization.CODEC.optionalFieldOf("tooltip", Component.empty()).forGetter(WidgetSettings::tooltip) + ).apply(builder, WidgetSettings::new)); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.INT, WidgetSettings::x, + ByteBufCodecs.INT, WidgetSettings::y, + ByteBufCodecs.VAR_INT, WidgetSettings::width, + ByteBufCodecs.VAR_INT, WidgetSettings::height, + ComponentSerialization.STREAM_CODEC, WidgetSettings::title, + ComponentSerialization.STREAM_CODEC, WidgetSettings::tooltip, + WidgetSettings::new + ); + + public WidgetSettings(int x, int y, int width, int height, @NotNull Component title, @NotNull Component tooltip) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.title = title; + this.tooltip = tooltip; + } + + public WidgetSettings copy() { + return new WidgetSettings(x, y, width, height, title.copy(), tooltip.copy()); + } + + public WidgetSettings copyToPos(int newX, int newY) { + return new WidgetSettings(newX, newY, width, height, title.copy(), tooltip.copy()); + } + + public WidgetSettings resize(int newWidth, int newHeight) { + return new WidgetSettings(x, y, newWidth, newHeight, title.copy(), tooltip.copy()); + } + + public WidgetSettings withText(Component title, Component tooltip) { + return new WidgetSettings(x, y, width, height, title, tooltip); + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/PneumaticCraftRepressurized.java b/src/main/java/me/desht/pneumaticcraft/PneumaticCraftRepressurized.java index 2f4f5a95a..6af573dd0 100644 --- a/src/main/java/me/desht/pneumaticcraft/PneumaticCraftRepressurized.java +++ b/src/main/java/me/desht/pneumaticcraft/PneumaticCraftRepressurized.java @@ -107,6 +107,7 @@ private void newRegistries(NewRegistryEvent event) { event.register(PNCRegistries.PROG_WIDGETS_REGISTRY); event.register(PNCRegistries.PLAYER_MATCHER_REGISTRY); event.register(PNCRegistries.AREA_TYPE_SERIALIZER_REGISTRY); + event.register(PNCRegistries.REMOTE_WIDGETS_REGISTRY); } private void registerAllDeferredRegistryObjects(IEventBus modBus) { @@ -139,6 +140,7 @@ private void registerAllDeferredRegistryObjects(IEventBus modBus) { ModProgWidgetTypes.PROG_WIDGETS_DEFERRED.register(modBus); ModProgWidgetAreaTypes.PROG_WIDGET_AREA_SERIALIZER_DEFERRED.register(modBus); ModPlayerMatchers.PLAYER_MATCHERS_DEFERRED.register(modBus); + ModRemoteWidgetTypes.REMOTE_WIDGETS.register(modBus); ModCreativeModeTab.TABS.register(modBus); } diff --git a/src/main/java/me/desht/pneumaticcraft/client/ClientSetup.java b/src/main/java/me/desht/pneumaticcraft/client/ClientSetup.java index 49f13c889..14ddb9859 100644 --- a/src/main/java/me/desht/pneumaticcraft/client/ClientSetup.java +++ b/src/main/java/me/desht/pneumaticcraft/client/ClientSetup.java @@ -5,6 +5,9 @@ import me.desht.pneumaticcraft.api.lib.Names; import me.desht.pneumaticcraft.client.gui.*; import me.desht.pneumaticcraft.client.gui.programmer.*; +import me.desht.pneumaticcraft.client.gui.remote.RemoteClientRegistry; +import me.desht.pneumaticcraft.client.gui.remote.RemoteEditorScreen; +import me.desht.pneumaticcraft.client.gui.remote.RemoteScreen; import me.desht.pneumaticcraft.client.gui.semiblock.LogisticsProviderScreen; import me.desht.pneumaticcraft.client.gui.semiblock.LogisticsRequesterScreen; import me.desht.pneumaticcraft.client.gui.semiblock.LogisticsStorageScreen; @@ -102,6 +105,7 @@ static void onClientSetup(FMLClientSetupEvent event) { registerProgWidgetScreenFactories(); registerTubeModuleFactories(); registerArmorClientUpgradeHandlers(); + RemoteClientRegistry.INSTANCE.registerClientFactories(); event.enqueueWork(ClientSetup::initLate); } diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/GPSAreaToolScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/GPSAreaToolScreen.java index 6d33f2987..4a9beac07 100644 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/GPSAreaToolScreen.java +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/GPSAreaToolScreen.java @@ -56,7 +56,7 @@ private GPSAreaToolScreen(ItemStack stack, InteractionHand hand, int index) { p1p2Pos[i] = GPSAreaToolItem.getGPSLocation(Minecraft.getInstance().player, stack, i).orElse(ClientUtils.getClientPlayer().blockPosition()); vars[i] = GPSAreaToolItem.getVariable(Minecraft.getInstance().player, stack, i); playerGlobals[i] = !vars[i].startsWith("%"); - vars[i] = GlobalVariableHelper.stripVarPrefix(vars[i]); + vars[i] = GlobalVariableHelper.getInstance().stripVarPrefix(vars[i]); } } @@ -94,7 +94,7 @@ protected void syncToServer() { vars[index] = variableField.getValue(); for (int i = 0; i <= 1; i++) { if (changed(i)) { - String varName = GlobalVariableHelper.getPrefixedVar(vars[i], playerGlobals[i]); + String varName = GlobalVariableHelper.getInstance().getPrefixedVar(vars[i], playerGlobals[i]); NetworkHandler.sendToServer(new PacketChangeGPSToolCoordinate(p1p2Pos[i], hand, varName, i)); } } @@ -104,14 +104,14 @@ private boolean changed(int index) { ItemStack stack = ClientUtils.getClientPlayer().getItemInHand(hand); BlockPos p = GPSAreaToolItem.getGPSLocation(ClientUtils.getClientPlayer(), stack, index).orElse(PneumaticCraftUtils.invalidPos()); String var = GPSAreaToolItem.getVariable(ClientUtils.getClientPlayer(), stack, index); - String var2 = GlobalVariableHelper.getPrefixedVar(vars[index], playerGlobals[index]); + String var2 = GlobalVariableHelper.getInstance().getPrefixedVar(vars[index], playerGlobals[index]); return !p.equals(p1p2Pos[index]) || !var.equals(var2); } @Override protected void toggleVarType() { playerGlobals[index] = !playerGlobals[index]; - varTypeButton.setMessage(Component.literal(GlobalVariableHelper.getVarPrefix(playerGlobals[index]))); + varTypeButton.setMessage(Component.literal(GlobalVariableHelper.getInstance().getVarPrefix(playerGlobals[index]))); } private void toggleP1P2(Button b) { @@ -127,7 +127,7 @@ private void toggleP1P2(Button b) { textFields[1].setValue(p1p2Pos[index].getY()); textFields[2].setValue(p1p2Pos[index].getZ()); variableField.setValue(vars[index]); - varTypeButton.setMessage(Component.literal(GlobalVariableHelper.getVarPrefix(playerGlobals[index]))); + varTypeButton.setMessage(Component.literal(GlobalVariableHelper.getInstance().getVarPrefix(playerGlobals[index]))); if (teleportButton != null) { BlockPos pos = getBlockPos(); teleportButton.setTooltipText(Component.literal(String.format("/tp %d %d %d", pos.getX(), pos.getY(), pos.getZ())).withStyle(ChatFormatting.YELLOW)); diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/GPSToolScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/GPSToolScreen.java index a065c59bc..14522d6d9 100644 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/GPSToolScreen.java +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/GPSToolScreen.java @@ -106,7 +106,7 @@ public void init() { if (variableField != null) oldVarName = variableField.getValue(); variableField = new WidgetTextField(font, xMiddle - 50, yMiddle + 59, 100, font.lineHeight + 3); playerGlobal = !oldVarName.startsWith("%"); - oldVarName = GlobalVariableHelper.stripVarPrefix(oldVarName); + oldVarName = GlobalVariableHelper.getInstance().stripVarPrefix(oldVarName); variableField.setFilter(s -> VAR_PATTERN.matcher(s).matches()); variableField.setValue(oldVarName); addRenderableWidget(variableField); @@ -134,7 +134,7 @@ protected BlockPos getBlockPos() { protected void toggleVarType() { playerGlobal = !playerGlobal; - varTypeButton.setMessage(Component.literal(GlobalVariableHelper.getVarPrefix(playerGlobal))); + varTypeButton.setMessage(Component.literal(GlobalVariableHelper.getInstance().getVarPrefix(playerGlobal))); } private void updateTextField(int idx, int amount) { @@ -162,7 +162,7 @@ public void removed() { } protected void syncToServer() { - String varName = GlobalVariableHelper.getPrefixedVar(GlobalVariableHelper.stripVarPrefix(variableField.getValue()), playerGlobal); + String varName = GlobalVariableHelper.getInstance().getPrefixedVar(GlobalVariableHelper.getInstance().stripVarPrefix(variableField.getValue()), playerGlobal); NetworkHandler.sendToServer(new PacketChangeGPSToolCoordinate(getBlockPos(), hand, varName, getIndex())); } diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/PastebinScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/PastebinScreen.java index 7d3596a4e..cbbe0779f 100644 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/PastebinScreen.java +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/PastebinScreen.java @@ -55,7 +55,7 @@ private enum EnumState { NONE, GETTING, PUTTING, LOGIN, LOGOUT } - PastebinScreen(Screen parentScreen, JsonElement input, ConversionType conversionType) { + public PastebinScreen(Screen parentScreen, JsonElement input, ConversionType conversionType) { super(Component.literal("Pastebin")); xSize = 183; diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/RemoteEditorScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/RemoteEditorScreen.java deleted file mode 100644 index 8690b78f9..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/RemoteEditorScreen.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui; - -import com.google.gson.JsonElement; -import com.mojang.serialization.JsonOps; -import me.desht.pneumaticcraft.client.gui.remote.RemoteLayout; -import me.desht.pneumaticcraft.client.gui.remote.actionwidget.*; -import me.desht.pneumaticcraft.client.gui.widget.WidgetButtonExtended; -import me.desht.pneumaticcraft.client.gui.widget.WidgetCheckBox; -import me.desht.pneumaticcraft.client.gui.widget.WidgetComboBox; -import me.desht.pneumaticcraft.client.gui.widget.WidgetLabel; -import me.desht.pneumaticcraft.client.util.ClientUtils; -import me.desht.pneumaticcraft.client.util.PointXY; -import me.desht.pneumaticcraft.common.config.ConfigHelper; -import me.desht.pneumaticcraft.common.inventory.RemoteMenu; -import me.desht.pneumaticcraft.common.item.RemoteItem; -import me.desht.pneumaticcraft.common.network.NetworkHandler; -import me.desht.pneumaticcraft.common.network.PacketUpdateRemoteLayout; -import me.desht.pneumaticcraft.common.registry.ModDataComponents; -import me.desht.pneumaticcraft.common.registry.ModItems; -import me.desht.pneumaticcraft.common.registry.ModMenuTypes; -import me.desht.pneumaticcraft.common.util.legacyconv.ConversionType; -import me.desht.pneumaticcraft.lib.Textures; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.AbstractWidget; -import net.minecraft.client.gui.components.Tooltip; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.component.CustomData; - -import java.util.ArrayList; -import java.util.List; - -import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; - -public class RemoteEditorScreen extends RemoteScreen { - private InventorySearcherScreen invSearchGui; - private PastebinScreen pastebinGui; - private final List> widgetTray = new ArrayList<>(); - private ActionWidget draggingWidget; - private int dragMouseStartX, dragMouseStartY; - private int dragWidgetStartX, dragWidgetStartY; - private int oldGuiLeft, oldGuiTop; - - public RemoteEditorScreen(RemoteMenu container, Inventory inv, Component displayString) { - super(container, inv, displayString); - - imageWidth = 283; - } - - @Override - protected ResourceLocation getGuiTexture() { - return Textures.GUI_REMOTE_EDITOR; - } - - @Override - public void init() { - if (pastebinGui != null && pastebinGui.getOutput() != null) { - RemoteLayout layout = RemoteLayout.fromJson(registryAccess(), pastebinGui.getOutput()); - RemoteItem.setSavedLayout(remote, layout.toNBT(registryAccess())); - } else if (remoteLayout != null) { - RemoteItem.setSavedLayout(remote, remoteLayout.toNBT(registryAccess())); - } - - if (invSearchGui != null && invSearchGui.getSearchStack().getItem() == ModItems.REMOTE.get()) { - if (RemoteItem.hasSameSecuritySettings(remote, invSearchGui.getSearchStack())) { - CustomData data = invSearchGui.getSearchStack().getOrDefault(ModDataComponents.REMOTE_LAYOUT, CustomData.EMPTY); - remoteLayout = RemoteLayout.fromNBT(registryAccess(), data.copyTag()); - } else { - ClientUtils.getClientPlayer().displayClientMessage(Component.literal("pneumaticcraft.gui.remote.differentSecuritySettings"), false); - } - } - - super.init(); - - oldGuiLeft = leftPos; - oldGuiTop = topPos; - - widgetTray.clear(); - widgetTray.add(new ActionWidgetCheckBox(this, new WidgetCheckBox(leftPos + 200, topPos + 23, 0xFF404040, xlate("pneumaticcraft.gui.remote.tray.checkbox.name")))); - widgetTray.add(new ActionWidgetLabel(this, new WidgetLabelVariable(leftPos + 200, topPos + 38, xlate("pneumaticcraft.gui.remote.tray.label.name")))); - widgetTray.add(new ActionWidgetButton(this, new WidgetButtonExtended(leftPos + 200, topPos + 53, 50, 20, xlate("pneumaticcraft.gui.remote.tray.button.name")))); - widgetTray.add(new ActionWidgetDropdown(this, new WidgetComboBox(font, leftPos + 200, topPos + 79, 70, font.lineHeight + 3).setFixedOptions(true))); - - for (ActionWidget actionWidget : widgetTray) { - addRenderableWidget(actionWidget.getOrCreateMinecraftWidget(this)); - } - - var importBtn = new WidgetButtonExtended(leftPos - 24, topPos, 20, 20, Component.empty(), b -> doImport()) - .setRenderStacks(new ItemStack(ModItems.REMOTE.get())); - importBtn.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.button.importRemoteButton"))); - addRenderableWidget(importBtn); - - var pastebinBtn = new WidgetButtonExtended(leftPos - 24, topPos + 22, 20, 20, Component.empty(), b -> doPastebin()) - .setRenderedIcon(Textures.GUI_PASTEBIN_ICON_LOCATION); - pastebinBtn.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.button.pastebinButton"))); - addRenderableWidget(pastebinBtn); - - WidgetCheckBox snapCheck = new WidgetCheckBox(leftPos + 194, topPos + 105, 0xFF404040, xlate("pneumaticcraft.gui.misc.snapToGrid"), - b -> ConfigHelper.setGuiRemoteGridSnap(b.checked)); - snapCheck.checked = ConfigHelper.client().general.guiRemoteGridSnap.get(); - addRenderableWidget(snapCheck); - - addRenderableWidget(new WidgetLabel(leftPos + 234, topPos + 7, xlate("pneumaticcraft.gui.remote.widgetTray").withStyle(ChatFormatting.DARK_BLUE)).setAlignment(WidgetLabel.Alignment.CENTRE)); - } - - private void doImport() { - ClientUtils.openContainerGui(ModMenuTypes.INVENTORY_SEARCHER.get(), Component.translatable("pneumaticcraft.gui.amadron.addTrade.invSearch")); - if (minecraft.screen instanceof InventorySearcherScreen) { - invSearchGui = (InventorySearcherScreen) minecraft.screen; - invSearchGui.setStackPredicate(s -> s.getItem() == ModItems.REMOTE.get()); - } - } - - private void doPastebin() { - JsonElement json = remoteLayout.toJson(registryAccess()); - minecraft.setScreen(pastebinGui = new PastebinScreen(this, json, ConversionType.ACTION_WIDGET)); - } - - @Override - protected boolean shouldDrawBackground() { - return false; - } - - @Override - protected void renderBg(GuiGraphics graphics, float partialTicks, int x, int y) { - graphics.blit(getGuiTexture(), leftPos, topPos, 0, 0, imageWidth, imageHeight, 320, 256); - } - - @Override - protected PointXY getInvNameOffset() { - return new PointXY(-50, 0); - } - - private boolean isOutsideProgrammingArea(ActionWidget actionWidget) { - AbstractWidget w = actionWidget.getOrCreateMinecraftWidget(this); - return w.getX() < leftPos || w.getY() < topPos || w.getX() + w.getWidth() > leftPos + 183 || w.getY() + w.getHeight() > topPos + imageHeight; - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) { - int x = (int) mouseX; - int y = (int) mouseY; - - switch (mouseButton) { - case 0 -> { - // left click - drag widget - for (ActionWidget actionWidget : widgetTray) { - if (actionWidget.getOrCreateMinecraftWidget(this).isHoveredOrFocused()) { - // create new widget from tray - startDrag(actionWidget.copy(registryAccess()), x, y); - remoteLayout.addActionWidget(draggingWidget); - addRenderableWidget(draggingWidget.getOrCreateMinecraftWidget(this)); - return true; - } - } - if (draggingWidget == null) { - for (ActionWidget actionWidget : remoteLayout.getActionWidgets()) { - if (actionWidget.getOrCreateMinecraftWidget(this).isHoveredOrFocused()) { - // move existing widget - startDrag(actionWidget, x, y); - return true; - } - } - } - } - case 1 -> { - // right click - configure widget - for (ActionWidget actionWidget : remoteLayout.getActionWidgets()) { - if (!isOutsideProgrammingArea(actionWidget)) { - if (actionWidget.getOrCreateMinecraftWidget(this).isHoveredOrFocused()) { - Screen screen = actionWidget.createConfigurationGui(this); - if (screen != null) minecraft.setScreen(screen); - return true; - } - } - } - } - case 2 -> { - // middle click - copy existing widget - for (ActionWidget actionWidget : remoteLayout.getActionWidgets()) { - if (actionWidget.getOrCreateMinecraftWidget(this).isHoveredOrFocused()) { - startDrag(actionWidget.copy(registryAccess()), x, y); - remoteLayout.addActionWidget(draggingWidget); - addRenderableWidget(draggingWidget.getOrCreateMinecraftWidget(this)); - return true; - } - } - } - } - return super.mouseClicked(mouseX, mouseY, mouseButton); - } - - private void startDrag(ActionWidget widget, int x, int y) { - draggingWidget = widget; - dragMouseStartX = x; - dragMouseStartY = y; - dragWidgetStartX = widget.getOrCreateMinecraftWidget(this).getX(); - dragWidgetStartY = widget.getOrCreateMinecraftWidget(this).getY(); - } - - @Override - public boolean mouseReleased(double mouseX, double mouseY, int button) { - if (draggingWidget != null && isOutsideProgrammingArea(draggingWidget)) { - remoteLayout.removeActionWidget(draggingWidget); -// remoteLayout.getActionWidgets().remove(draggingWidget); - removeWidget(draggingWidget.getOrCreateMinecraftWidget(this)); - } - draggingWidget = null; - - return super.mouseReleased(mouseX, mouseY, button); - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int mouseButton, double dragX, double dragY) { - if (draggingWidget != null) { - int x = (int) mouseX; - int y = (int) mouseY; - int x1 = x - dragMouseStartX + dragWidgetStartX; - int y1 = y - dragMouseStartY + dragWidgetStartY; - if (ConfigHelper.client().general.guiRemoteGridSnap.get()) { - x1 = (x1 / 4) * 4; - y1 = (y1 / 4) * 4; - } - draggingWidget.setWidgetPos(this,x1, y1); - return true; - } - return super.mouseDragged(mouseX, mouseY, mouseButton, dragX, dragY); - } - - @Override - public void onGlobalVariableChange(String variable) { - } - - @Override - public boolean shouldCloseOnEsc() { - return true; - } - - @Override - public void removed() { - ItemStack stack = ClientUtils.getClientPlayer().getItemInHand(menu.getHand()); - if (stack.getItem() == ModItems.REMOTE.get()) { - CompoundTag tag = remoteLayout.toNBT(registryAccess()); - RemoteItem.setSavedLayout(stack, tag); - NetworkHandler.sendToServer(new PacketUpdateRemoteLayout(tag, menu.getHand())); - } - - super.removed(); - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/RemoteScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/RemoteScreen.java deleted file mode 100644 index a84362685..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/RemoteScreen.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui; - -import me.desht.pneumaticcraft.client.gui.remote.RemoteLayout; -import me.desht.pneumaticcraft.client.gui.remote.actionwidget.ActionWidgetVariable; -import me.desht.pneumaticcraft.client.util.PointXY; -import me.desht.pneumaticcraft.common.block.entity.AbstractPneumaticCraftBlockEntity; -import me.desht.pneumaticcraft.common.inventory.RemoteMenu; -import me.desht.pneumaticcraft.common.registry.ModDataComponents; -import me.desht.pneumaticcraft.lib.Textures; -import net.minecraft.client.Minecraft; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.component.CustomData; - -public class RemoteScreen extends AbstractPneumaticCraftContainerScreen { - - RemoteLayout remoteLayout; - protected final ItemStack remote; - - public RemoteScreen(RemoteMenu container, Inventory inv, Component displayString) { - super(container, inv, displayString); - - imageWidth = 183; - imageHeight = 202; - this.remote = inv.player.getItemInHand(container.getHand()); - } - - /** - * Client has received a PacketSetGlobalVariable message; update the remote GUI, if it's open. - * @param varName variable that changed - */ - public static void handleVariableChangeIfOpen(String varName) { - if (Minecraft.getInstance().screen instanceof RemoteScreen r) { - r.onGlobalVariableChange(varName); - } - } - - @Override - public void init() { - remoteLayout = null; - - super.init(); - - if (remoteLayout == null) { - CompoundTag tag = remote.getOrDefault(ModDataComponents.REMOTE_LAYOUT, CustomData.EMPTY).copyTag(); - remoteLayout = RemoteLayout.fromNBT(registryAccess(), tag); - } - remoteLayout.getOrCreateMinecraftWidgets(this, !(this instanceof RemoteEditorScreen)) - .forEach(this::addRenderableWidget); - } - - @Override - protected PointXY getInvTextOffset() { - return null; - } - - @Override - protected boolean shouldAddProblemTab() { - return false; - } - - @Override - protected ResourceLocation getGuiTexture() { - return Textures.GUI_WIDGET_OPTIONS; - } - - public void onGlobalVariableChange(String variable) { - clearWidgets(); - init(); - - remoteLayout.getActionWidgets().stream() - .filter(actionWidget -> actionWidget instanceof ActionWidgetVariable) - .forEach(actionWidget -> ((ActionWidgetVariable) actionWidget).onVariableChange()); - } - - @Override - protected boolean shouldParseVariablesInTooltips() { - return true; - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/AbstractRemoteScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/AbstractRemoteScreen.java new file mode 100644 index 000000000..f47704f8f --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/AbstractRemoteScreen.java @@ -0,0 +1,77 @@ +package me.desht.pneumaticcraft.client.gui.remote; + +import me.desht.pneumaticcraft.api.remote.IRemoteWidget; +import me.desht.pneumaticcraft.client.gui.AbstractPneumaticCraftContainerScreen; +import me.desht.pneumaticcraft.client.util.PointXY; +import me.desht.pneumaticcraft.common.block.entity.AbstractPneumaticCraftBlockEntity; +import me.desht.pneumaticcraft.common.inventory.RemoteMenu; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public abstract class AbstractRemoteScreen extends AbstractPneumaticCraftContainerScreen { + protected final ItemStack remoteItem; + protected final Map widgetMap = new LinkedHashMap<>(); + + public AbstractRemoteScreen(RemoteMenu container, Inventory inv, Component displayString) { + super(container, inv, displayString); + + remoteItem = inv.player.getItemInHand(container.getHand()); + } + + protected void addRemoteWidget(AbstractWidget mcWidget, IRemoteWidget remoteWidget) { + widgetMap.put(mcWidget, remoteWidget); + addRenderableWidget(mcWidget); + } + + /** + * Client has received a PacketSetGlobalVariable message; update the remote GUI, if it's open. + * @param varName variable that changed + */ + public static void handleVariableChangeIfOpen(String varName) { + if (Minecraft.getInstance().screen instanceof RemoteScreen r) { + r.onGlobalVariableChanged(varName); + } + } + + /** + * Given a list of remote widgets, build an identity hash map of minecraft widget -> remote widget. + * + * @param remoteWidgets the remote widgets + * @param screen the screen on which the minecraft widgets will be placed + * @param filterWidgets if true, make invisible any widgets which have a non-matching enable variable + * @return the widget map + */ + static Map buildMinecraftWidgetList(List remoteWidgets, AbstractRemoteScreen screen, boolean filterWidgets) { + // Subclasses of AbstractWidget don't override hashCode() and equals(), which is fine for our purposes here + // We basically want an identity map of mc widget -> remote widget, and linked is nice to preserve widget order + Map map = new LinkedHashMap<>(); + remoteWidgets.forEach(remoteWidget -> { + AbstractWidget mcWidget = RemoteClientRegistry.INSTANCE.createMinecraftWidget(remoteWidget, screen); + mcWidget.visible = !filterWidgets || remoteWidget.isEnabled(Minecraft.getInstance().player); + map.put(mcWidget, remoteWidget); + }); + return map; + } + + @Override + protected PointXY getInvTextOffset() { + return null; + } + + @Override + protected boolean shouldAddProblemTab() { + return false; + } + + @Override + protected boolean shouldParseVariablesInTooltips() { + return true; + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/BasicRemoteOptionScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/BasicRemoteOptionScreen.java deleted file mode 100644 index 3da50031e..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/BasicRemoteOptionScreen.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote; - -import me.desht.pneumaticcraft.client.gui.AbstractPneumaticCraftScreen; -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.client.gui.remote.actionwidget.ActionWidget; -import me.desht.pneumaticcraft.client.gui.remote.actionwidget.IActionWidgetLabeled; -import me.desht.pneumaticcraft.client.gui.widget.*; -import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; -import me.desht.pneumaticcraft.lib.Textures; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.Tooltip; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; - -import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; - -public class BasicRemoteOptionScreen> extends AbstractPneumaticCraftScreen { - protected final A actionWidget; - final RemoteEditorScreen guiRemote; - private WidgetTextField labelField, tooltipField; - private WidgetComboBox enableField; - private WidgetTextFieldNumber xValueField, yValueField, zValueField; - private WidgetButtonExtended enableVarTypeButton; - private boolean playerGlobalEnableVar; - - public BasicRemoteOptionScreen(A actionWidget, RemoteEditorScreen guiRemote) { - super(Component.translatable("pneumaticcraft.gui.remote.tray." + actionWidget.getId() + ".name")); - - this.actionWidget = actionWidget; - this.guiRemote = guiRemote; - xSize = 183; - ySize = 202; - } - - @Override - public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { - renderBackground(graphics, mouseX, mouseY, partialTicks); - super.render(graphics, mouseX, mouseY, partialTicks); - } - - @Override - protected ResourceLocation getTexture() { - return Textures.GUI_WIDGET_OPTIONS; - } - - @Override - public boolean isPauseScreen() { - return false; - } - - @Override - public void init() { - super.init(); - - int textFieldHeight = font.lineHeight + 3; - - playerGlobalEnableVar = actionWidget.getEnableVariable().isEmpty() || actionWidget.getEnableVariable().startsWith("#"); - - addLabel(xlate("pneumaticcraft.gui.remote.enable"), guiLeft + 10, guiTop + 150); - addLabel(title, width / 2, guiTop + 5, WidgetLabel.Alignment.CENTRE); - enableVarTypeButton = new WidgetButtonExtended(guiLeft + 10, guiTop + 158, 12, 14, GlobalVariableHelper.getVarPrefix(playerGlobalEnableVar), - b -> togglePlayerGlobalEnable()).setTooltipKey("pneumaticcraft.gui.remote.varType.tooltip"); - addRenderableWidget(enableVarTypeButton); - - if (actionWidget instanceof IActionWidgetLabeled) { - addLabel(xlate("pneumaticcraft.gui.remote.text"), guiLeft + 10, guiTop + 20); - addLabel(xlate("pneumaticcraft.gui.remote.tooltip"), guiLeft + 10, guiTop + 46); - } - - addLabel(xlate("pneumaticcraft.gui.remote.enableValue"), guiLeft + 10, guiTop + 175); - addLabel(Component.literal("X:"), guiLeft + 10, guiTop + 186); - addLabel(Component.literal("Y:"), guiLeft + 67, guiTop + 186); - addLabel(Component.literal("Z:"), guiLeft + 124, guiTop + 186); - - enableField = new WidgetComboBox(font, guiLeft + 23, guiTop + 159, 147, textFieldHeight); - enableField.setElements(GlobalVariableHelper.extractVarnames(guiRemote.getMenu().variables, playerGlobalEnableVar)); - enableField.setValue(GlobalVariableHelper.stripVarPrefix(actionWidget.getEnableVariable())); - enableField.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.enable.tooltip"))); - addRenderableWidget(enableField); - - Component valueTooltip = xlate("pneumaticcraft.gui.remote.enableValue.tooltip"); - - xValueField = new WidgetTextFieldNumber(font, guiLeft + 20, guiTop + 184, 38, textFieldHeight); - xValueField.setValue(actionWidget.getEnablingValue().getX()); - xValueField.setTooltip(Tooltip.create(valueTooltip)); - addRenderableWidget(xValueField); - - yValueField = new WidgetTextFieldNumber(font, guiLeft + 78, guiTop + 184, 38, textFieldHeight); - yValueField.setValue(actionWidget.getEnablingValue().getY()); - yValueField.setTooltip(Tooltip.create(valueTooltip)); - addRenderableWidget(yValueField); - - zValueField = new WidgetTextFieldNumber(font, guiLeft + 136, guiTop + 184, 38, textFieldHeight); - zValueField.setValue(actionWidget.getEnablingValue().getZ()); - zValueField.setTooltip(Tooltip.create(valueTooltip)); - addRenderableWidget(zValueField); - - if (actionWidget instanceof IActionWidgetLabeled) { - labelField = new WidgetTextField(font, guiLeft + 10, guiTop + 29, 160, textFieldHeight); - labelField.setValue(((IActionWidgetLabeled) actionWidget).getText().getString()); - labelField.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.label.tooltip"))); - labelField.setMaxLength(1000); - addRenderableWidget(labelField); - - tooltipField = new WidgetTextField(font, guiLeft + 10, guiTop + 55, 160, textFieldHeight); - tooltipField.setValue(actionWidget.getTooltipMessage(guiRemote).getString()); - addRenderableWidget(tooltipField); - } - } - - @Override - public void removed() { - actionWidget.setEnableVariable(GlobalVariableHelper.getPrefixedVar(enableField.getValue(), playerGlobalEnableVar)); - actionWidget.setEnablingValue(xValueField.getIntValue(), yValueField.getIntValue(), zValueField.getIntValue()); - if (actionWidget instanceof IActionWidgetLabeled labeled) { - labeled.setText(Component.literal(labelField.getValue())); - if (tooltipField.getValue().isEmpty()) { - actionWidget.setTooltip(null); - } else { - actionWidget.setTooltip(Tooltip.create(Component.literal(tooltipField.getValue()))); - } - } - } - private void togglePlayerGlobalEnable() { - playerGlobalEnableVar = !playerGlobalEnableVar; - enableVarTypeButton.setMessage(Component.literal(GlobalVariableHelper.getVarPrefix(playerGlobalEnableVar))); - enableField.setElements(GlobalVariableHelper.extractVarnames(guiRemote.getMenu().variables, playerGlobalEnableVar)); - } - - @Override - public void onClose() { - minecraft.setScreen(guiRemote); - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteClientRegistry.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteClientRegistry.java new file mode 100644 index 000000000..2fc522e95 --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteClientRegistry.java @@ -0,0 +1,64 @@ +package me.desht.pneumaticcraft.client.gui.remote; + +import me.desht.pneumaticcraft.api.registry.PNCRegistries; +import me.desht.pneumaticcraft.api.remote.IRemoteVariableWidget; +import me.desht.pneumaticcraft.api.remote.IRemoteWidget; +import me.desht.pneumaticcraft.api.remote.RemoteWidgetType; +import me.desht.pneumaticcraft.client.gui.remote.config.RemoteButtonOptionScreen; +import me.desht.pneumaticcraft.client.gui.remote.config.RemoteCheckboxOptionScreen; +import me.desht.pneumaticcraft.client.gui.remote.config.RemoteDropdownOptionScreen; +import me.desht.pneumaticcraft.client.gui.remote.config.RemoteLabelOptionScreen; +import me.desht.pneumaticcraft.common.registry.ModRemoteWidgetTypes; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +public enum RemoteClientRegistry { + INSTANCE; + + private final Map> factoryMap = new ConcurrentHashMap<>(); + + public void registerClientFactories() { + register(ModRemoteWidgetTypes.BUTTON.get(), RemoteButtonOptionScreen.Factory.INSTANCE); + register(ModRemoteWidgetTypes.CHECKBOX.get(), RemoteCheckboxOptionScreen.Factory.INSTANCE); + register(ModRemoteWidgetTypes.DROPDOWN.get(), RemoteDropdownOptionScreen.Factory.INSTANCE); + register(ModRemoteWidgetTypes.LABEL.get(), RemoteLabelOptionScreen.Factory.INSTANCE); + } + + public void register(RemoteWidgetType type, Factory factory) { + factoryMap.put(PNCRegistries.REMOTE_WIDGETS_REGISTRY.getKey(type), factory); + } + + public MCW createMinecraftWidget(RW remoteWidget, AbstractRemoteScreen screen) { + @SuppressWarnings("unchecked") Factory factory = (Factory) factoryMap.get(getKey(remoteWidget)); + return factory.createMinecraftWidget(remoteWidget, screen); + } + + public Screen createConfigurationScreen(RW remoteWidget, RemoteEditorScreen screen) { + @SuppressWarnings("unchecked") Factory factory = (Factory) factoryMap.get(getKey(remoteWidget)); + return factory.createConfigurationScreen(remoteWidget, screen); + } + + public void handleGlobalVariableChange(RW remoteWidget, MCW mcWidget, String varName) { + @SuppressWarnings("unchecked") Factory factory = (Factory) factoryMap.get(getKey(remoteWidget)); + factory.handleGlobalVariableChange(remoteWidget, mcWidget, varName); + } + + private static @NotNull ResourceLocation getKey(IRemoteWidget remoteWidget) { + return Objects.requireNonNull(PNCRegistries.REMOTE_WIDGETS_REGISTRY.getKey(remoteWidget.getType())); + } + + public interface Factory { + MCW createMinecraftWidget(RW remoteWidget, AbstractRemoteScreen screen); + + Screen createConfigurationScreen(RW remoteWidget, RemoteEditorScreen screen); + + default void handleGlobalVariableChange(RW remoteWidget, MCW mcWidget, String varName) { + } + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteDropdownOptionScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteDropdownOptionScreen.java deleted file mode 100644 index d370b8cf3..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteDropdownOptionScreen.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote; - -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.client.gui.remote.actionwidget.ActionWidgetDropdown; -import me.desht.pneumaticcraft.client.gui.widget.WidgetCheckBox; -import me.desht.pneumaticcraft.client.gui.widget.WidgetTextField; -import me.desht.pneumaticcraft.client.gui.widget.WidgetTextFieldNumber; -import net.minecraft.client.gui.components.Tooltip; - -import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; - -public class RemoteDropdownOptionScreen extends RemoteVariableOptionScreen { - private WidgetTextField dropDownElementsField; - private WidgetTextFieldNumber widthField; - private WidgetCheckBox sortCheckBox; - - public RemoteDropdownOptionScreen(ActionWidgetDropdown widget, RemoteEditorScreen guiRemote) { - super(widget, guiRemote); - } - - @Override - public void init() { - super.init(); - - int textFieldHeight = font.lineHeight + 3; - - addLabel(xlate("pneumaticcraft.gui.remote.button.width"), guiLeft + 10, guiTop + 100); - addLabel(xlate("pneumaticcraft.gui.remote.dropdown.dropDownElements"), guiLeft + 10, guiTop + 40); - - dropDownElementsField = new WidgetTextField(font, guiLeft + 10, guiTop + 49, 160, textFieldHeight); - dropDownElementsField.setMaxLength(1024); - dropDownElementsField.setValue(String.join(",", actionWidget.getDropDownElements())); - dropDownElementsField.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.dropdown.dropDownElements.tooltip"))); - addRenderableWidget(dropDownElementsField); - - widthField = new WidgetTextFieldNumber(font, guiLeft + 49, guiTop + 99, 30, textFieldHeight).setRange(10, Integer.MAX_VALUE); - widthField.setValue(actionWidget.getWidth()); - widthField.minValue = 10; - addRenderableWidget(widthField); - - sortCheckBox = new WidgetCheckBox(guiLeft + 10, guiTop + 120, 0x404040, xlate("pneumaticcraft.gui.remote.dropdown.sort")) - .setChecked(actionWidget.getSorted()); - sortCheckBox.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.dropdown.sort.tooltip"))); - addRenderableWidget(sortCheckBox); - } - - @Override - public void removed() { - actionWidget.setDropDownElements(dropDownElementsField.getValue().split(",")); - actionWidget.setWidth(widthField.getIntValue()); - actionWidget.setSorted(sortCheckBox.checked); - - super.removed(); - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteEditorScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteEditorScreen.java new file mode 100644 index 000000000..c0b1c9cdb --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteEditorScreen.java @@ -0,0 +1,304 @@ +/* + * This file is part of pnc-repressurized. + * + * pnc-repressurized 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. + * + * pnc-repressurized 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 pnc-repressurized. If not, see . + */ + +package me.desht.pneumaticcraft.client.gui.remote; + +import com.google.gson.JsonElement; +import me.desht.pneumaticcraft.api.remote.IRemoteWidget; +import me.desht.pneumaticcraft.client.gui.InventorySearcherScreen; +import me.desht.pneumaticcraft.client.gui.PastebinScreen; +import me.desht.pneumaticcraft.client.gui.widget.WidgetButtonExtended; +import me.desht.pneumaticcraft.client.gui.widget.WidgetCheckBox; +import me.desht.pneumaticcraft.client.gui.widget.WidgetLabel; +import me.desht.pneumaticcraft.client.util.ClientUtils; +import me.desht.pneumaticcraft.client.util.PointXY; +import me.desht.pneumaticcraft.common.config.ConfigHelper; +import me.desht.pneumaticcraft.common.inventory.RemoteMenu; +import me.desht.pneumaticcraft.common.item.RemoteItem; +import me.desht.pneumaticcraft.common.network.NetworkHandler; +import me.desht.pneumaticcraft.common.network.PacketUpdateRemoteLayout; +import me.desht.pneumaticcraft.common.registry.ModItems; +import me.desht.pneumaticcraft.common.registry.ModMenuTypes; +import me.desht.pneumaticcraft.common.remote.*; +import me.desht.pneumaticcraft.common.util.legacyconv.ConversionType; +import me.desht.pneumaticcraft.lib.Textures; +import net.minecraft.ChatFormatting; +import net.minecraft.Util; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.renderer.Rect2i; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; + +public class RemoteEditorScreen extends AbstractRemoteScreen { + private static final List TRAY_WIDGETS = List.of( + RemoteWidgetCheckbox.TRAY.get(), + RemoteWidgetLabel.TRAY.get(), + RemoteWidgetButton.TRAY.get(), + RemoteWidgetDropdown.TRAY.get() + ); + private static final int PROGRAMMING_AREA_WIDTH = 183; + private static final Rect2i PROGRAMMING_AREA = new Rect2i(3, 18, 177, 181); + private static final Rect2i TRAY_AREA = new Rect2i(195, 18, 80, 78); + + private InventorySearcherScreen invSearchGui; + private PastebinScreen pastebinGui; + private IRemoteWidget draggingRemoteWidget; + private AbstractWidget draggingMCWidget; + private AbstractWidget configuringMCWidget; + + public RemoteEditorScreen(RemoteMenu container, Inventory inv, Component displayString) { + super(container, inv, displayString); + + imageWidth = 283; + imageHeight = 202; + } + + @Override + public void init() { + super.init(); + + if (pastebinGui != null && pastebinGui.getOutput() != null) { + // returning from the pastebin gui; load widgets from retrieved Json + addWidgetsFromLayout(SavedRemoteLayout.fromJson(registryAccess(), pastebinGui.getOutput())); + } else if (invSearchGui != null && invSearchGui.getSearchStack().getItem() == ModItems.REMOTE.get()) { + // return from item selection GUI; copy widgets from other remote + if (RemoteItem.hasSameSecuritySettings(remoteItem, invSearchGui.getSearchStack())) { + addWidgetsFromLayout(SavedRemoteLayout.fromItem(invSearchGui.getSearchStack())); + } else { + ClientUtils.getClientPlayer().displayClientMessage(Component.literal("pneumaticcraft.gui.remote.differentSecuritySettings"), false); + } + } else if (widgetMap.isEmpty()) { + // initial opening of the editor screen; load saved widgets from the remote item data component + addWidgetsFromLayout(SavedRemoteLayout.fromItem(remoteItem)); + } else { + // doing a widget rebuild; re-create the mc widgets and update the mapping for the new mc widgets + Map newMap = new LinkedHashMap<>(); + widgetMap.values().forEach(remoteWidget -> { + AbstractWidget newMCWidget = RemoteClientRegistry.INSTANCE.createMinecraftWidget(remoteWidget, this); + newMap.put(newMCWidget, remoteWidget); + addRenderableWidget(newMCWidget); + }); + widgetMap.clear(); + widgetMap.putAll(newMap); + } + + var importBtn = new WidgetButtonExtended(leftPos - 24, topPos, 20, 20, Component.empty(), b -> openImportScreen()) + .setRenderStacks(new ItemStack(ModItems.REMOTE.get())); + importBtn.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.button.importRemoteButton"))); + addRenderableWidget(importBtn); + + var pastebinBtn = new WidgetButtonExtended(leftPos - 24, topPos + 22, 20, 20, Component.empty(), b -> openPastebinScreen()) + .setRenderedIcon(Textures.GUI_PASTEBIN_ICON_LOCATION); + pastebinBtn.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.button.pastebinButton"))); + addRenderableWidget(pastebinBtn); + + WidgetCheckBox snapCheck = new WidgetCheckBox(leftPos + 194, topPos + 105, 0xFF404040, xlate("pneumaticcraft.gui.misc.snapToGrid"), + b -> ConfigHelper.setGuiRemoteGridSnap(b.checked)); + snapCheck.checked = ConfigHelper.client().general.guiRemoteGridSnap.get(); + addRenderableWidget(snapCheck); + + addRenderableWidget(new WidgetLabel(leftPos + 234, topPos + 7, xlate("pneumaticcraft.gui.remote.widgetTray").withStyle(ChatFormatting.DARK_BLUE)).setAlignment(WidgetLabel.Alignment.CENTRE)); + } + + private void addWidgetsFromLayout(SavedRemoteLayout layout) { + widgetMap.clear(); + + buildMinecraftWidgetList(layout.getWidgets(), this, false) + .forEach(this::addRemoteWidget); + + for (IRemoteWidget remoteWidget : TRAY_WIDGETS) { + addRemoteWidget(RemoteClientRegistry.INSTANCE.createMinecraftWidget(remoteWidget, this), remoteWidget); + } + } + + private void openImportScreen() { + ClientUtils.openContainerGui(ModMenuTypes.INVENTORY_SEARCHER.get(), Component.translatable("pneumaticcraft.gui.amadron.addTrade.invSearch")); + if (minecraft.screen instanceof InventorySearcherScreen) { + invSearchGui = (InventorySearcherScreen) minecraft.screen; + invSearchGui.setStackPredicate(s -> s.getItem() == ModItems.REMOTE.get()); + } + } + + private void openPastebinScreen() { + JsonElement json = makeNewLayout().toJson(registryAccess()); + minecraft.setScreen(pastebinGui = new PastebinScreen(this, json, ConversionType.ACTION_WIDGET)); + } + + private SavedRemoteLayout makeNewLayout() { + List list = Util.make(new ArrayList<>(), l -> widgetMap.forEach((mcWidget, remoteWidget) -> { + if (isInProgrammingArea(mcWidget)) { + l.add(remoteWidget); + } + })); + return new SavedRemoteLayout(list); + } + + @Override + protected ResourceLocation getGuiTexture() { + return Textures.GUI_REMOTE_EDITOR; + } + + @Override + protected boolean shouldDrawBackground() { + return false; + } + + @Override + protected void renderBg(GuiGraphics graphics, float partialTicks, int x, int y) { + graphics.blit(getGuiTexture(), leftPos, topPos, 0, 0, imageWidth, imageHeight, 320, 256); + } + + @Override + protected PointXY getInvNameOffset() { + return new PointXY(-50, 0); + } + + private boolean isInTrayArea(AbstractWidget widget) { + return TRAY_AREA.contains(widget.getX() - getGuiLeft(), widget.getY() - getGuiTop()); + } + + private boolean isInProgrammingArea(AbstractWidget widget) { + return PROGRAMMING_AREA.contains(widget.getX() - getGuiLeft(), widget.getY() - getGuiTop()); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) { + switch (mouseButton) { + case 0 -> { + // left click - drag widget (with copy if it's a tray widget) + for (Map.Entry entry : widgetMap.entrySet()) { + AbstractWidget mcWidget = entry.getKey(); + boolean trayWidget = isInTrayArea(mcWidget); + if (mcWidget.isHovered() && (isInProgrammingArea(mcWidget) || trayWidget)) { + IRemoteWidget remoteWidget = entry.getValue(); + AbstractWidget mcDrag = trayWidget ? + RemoteClientRegistry.INSTANCE.createMinecraftWidget(remoteWidget, this) : + mcWidget; + startDrag(remoteWidget.copy(), mcDrag, trayWidget); + return true; + } + } + } + case 1 -> { + // right click - configure widget + for (Map.Entry entry : widgetMap.entrySet()) { + AbstractWidget mcWidget = entry.getKey(); + if (mcWidget.isHovered() && isInProgrammingArea(mcWidget)) { + IRemoteWidget remoteWidget = entry.getValue(); + Screen screen = RemoteClientRegistry.INSTANCE.createConfigurationScreen(remoteWidget, this); + if (screen != null) { + configuringMCWidget = mcWidget; + minecraft.setScreen(screen); + return true; + } + } + } + } + case 2 -> { + // middle click - copy & drag widget + for (Map.Entry entry : widgetMap.entrySet()) { + AbstractWidget mcWidget = entry.getKey(); + if (mcWidget.isHovered() && isInProgrammingArea(mcWidget)) { + IRemoteWidget remoteWidget = entry.getValue(); + AbstractWidget newMCWidget = RemoteClientRegistry.INSTANCE.createMinecraftWidget(remoteWidget, this); + startDrag(remoteWidget.copy(), newMCWidget, true); + return true; + } + } + } + } + return super.mouseClicked(mouseX, mouseY, mouseButton); + } + + private void startDrag(IRemoteWidget remoteWidget, AbstractWidget mcWidget, boolean copying) { + draggingRemoteWidget = remoteWidget; + draggingMCWidget = mcWidget; + + if (copying) { + addRenderableWidget(draggingMCWidget); + } + } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int button) { + if (draggingRemoteWidget != null && draggingMCWidget != null) { + if (!isInProgrammingArea(draggingMCWidget)) { + // dragged off the screen - delete it + removeWidget(draggingMCWidget); + widgetMap.remove(draggingMCWidget); + } else { + // dragged to a new position + widgetMap.put(draggingMCWidget, draggingRemoteWidget.copyToPos(draggingMCWidget.getX() - getGuiLeft(), draggingMCWidget.getY() - getGuiTop())); + } + draggingRemoteWidget = null; + draggingMCWidget = null; + return true; + } + + return super.mouseReleased(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int mouseButton, double dragX, double dragY) { + if (draggingMCWidget != null) { + int x1 = (int) mouseX; + int y1 = (int) mouseY; + if (ConfigHelper.client().general.guiRemoteGridSnap.get()) { + x1 = (x1 / 4) * 4; + y1 = (y1 / 4) * 4; + } + draggingMCWidget.setPosition(x1, y1); + return true; + } + return super.mouseDragged(mouseX, mouseY, mouseButton, dragX, dragY); + } + + @Override + public void onClose() { + ItemStack stack = ClientUtils.getClientPlayer().getItemInHand(menu.getHand()); + if (stack.getItem() == ModItems.REMOTE.get()) { + SavedRemoteLayout layout = makeNewLayout(); + RemoteItem.saveToItem(stack, layout); + NetworkHandler.sendToServer(new PacketUpdateRemoteLayout(layout, menu.getHand())); + } + + super.onClose(); + } + + public void updateWidgetFromConfigScreen(IRemoteWidget newWidget) { + if (configuringMCWidget != null) { + IRemoteWidget current = widgetMap.get(configuringMCWidget); + if (current != null && !current.equals(newWidget)) { + widgetMap.put(configuringMCWidget, newWidget); + configuringMCWidget = null; + rebuildWidgets(); + } + } + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteLayout.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteLayout.java deleted file mode 100644 index 01165351e..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteLayout.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote; - -import com.google.gson.JsonElement; -import com.mojang.serialization.Codec; -import com.mojang.serialization.JsonOps; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import me.desht.pneumaticcraft.client.gui.RemoteScreen; -import me.desht.pneumaticcraft.client.gui.remote.actionwidget.ActionWidget; -import me.desht.pneumaticcraft.client.gui.remote.actionwidget.ActionWidgets; -import me.desht.pneumaticcraft.lib.Log; -import net.minecraft.client.gui.components.AbstractWidget; -import net.minecraft.core.HolderLookup; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtOps; -import net.minecraft.nbt.Tag; -import net.minecraft.resources.RegistryOps; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -public class RemoteLayout { - public static final int JSON_VERSION = 2; - - public static final Codec VERSIONED_SAVE_CODEC = RecordCodecBuilder.create(builder -> builder.group( - Codec.INT.fieldOf("version").forGetter(RemoteLayout.Versioned::version), - ActionWidgets.LIST_CODEC.fieldOf("action_widgets").forGetter(RemoteLayout.Versioned::widgets) - ).apply(builder, RemoteLayout.Versioned::new)); - - // Note: this is a mutable list - private final List> actionWidgets; - - private RemoteLayout(List> list) { - actionWidgets = new ArrayList<>(list); - } - - public static RemoteLayout createEmpty() { - return new RemoteLayout(List.of()); - } - - public static RemoteLayout fromNBT(HolderLookup.Provider provider, CompoundTag tag) { - if (tag.isEmpty()) { - return new RemoteLayout(List.of()); - } - - RegistryOps ops = provider.createSerializationContext(NbtOps.INSTANCE); - var saved = Saved.CODEC.parse(ops, tag) - .resultOrPartial(err -> Log.warning("can't parse remote layout NBT: " + err)) - .orElse(Saved.EMPTY); - return new RemoteLayout(saved.widgets()); - } - - public static RemoteLayout fromJson(HolderLookup.Provider provider, JsonElement json) { - RegistryOps ops = provider.createSerializationContext(JsonOps.INSTANCE); - return VERSIONED_SAVE_CODEC.parse(ops, json) - .resultOrPartial(err -> Log.warning("can't parse remote layout JSON: " + err)) - .map(v -> new RemoteLayout(v.widgets)) - .orElse(createEmpty()); - } - - public CompoundTag toNBT(HolderLookup.Provider provider) { - RegistryOps ops = provider.createSerializationContext(NbtOps.INSTANCE); - Tag tag = Saved.CODEC.encodeStart(ops, new Saved(actionWidgets)).result().orElseThrow(); - return tag instanceof CompoundTag c ? c : new CompoundTag(); - } - - public JsonElement toJson(HolderLookup.Provider provider) { - RegistryOps ops = provider.createSerializationContext(JsonOps.INSTANCE); - return VERSIONED_SAVE_CODEC.encodeStart(ops, new Versioned(JSON_VERSION, actionWidgets)).result().orElseThrow(); - } - - public void addActionWidget(ActionWidget actionWidget) { - actionWidgets.add(actionWidget); - } - - public void removeActionWidget(ActionWidget actionWidget) { - actionWidgets.remove(actionWidget); - } - - public List> getActionWidgets() { - return Collections.unmodifiableList(actionWidgets); - } - - public List getOrCreateMinecraftWidgets(RemoteScreen screen, boolean filterDisabledWidgets) { - return actionWidgets.stream() - .filter(actionWidget -> !filterDisabledWidgets || actionWidget.isEnabled()) - .map(actionWidget -> actionWidget.getOrCreateMinecraftWidget(screen)) - .collect(Collectors.toList()); - } - - public record Saved(List> widgets) { - public static final Codec CODEC = RecordCodecBuilder.create(builder -> builder.group( - ActionWidgets.CODEC.listOf().fieldOf("widgets").forGetter(Saved::widgets) - ).apply(builder, Saved::new)); - - public static Saved EMPTY = new Saved(List.of()); - } - - public record Versioned(int version, List> widgets) { - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteScreen.java new file mode 100644 index 000000000..ab687c787 --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteScreen.java @@ -0,0 +1,60 @@ +/* + * This file is part of pnc-repressurized. + * + * pnc-repressurized 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. + * + * pnc-repressurized 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 pnc-repressurized. If not, see . + */ + +package me.desht.pneumaticcraft.client.gui.remote; + +import me.desht.pneumaticcraft.api.remote.IRemoteVariableWidget; +import me.desht.pneumaticcraft.common.inventory.RemoteMenu; +import me.desht.pneumaticcraft.common.remote.SavedRemoteLayout; +import me.desht.pneumaticcraft.lib.Textures; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; + +public class RemoteScreen extends AbstractRemoteScreen { + public RemoteScreen(RemoteMenu container, Inventory inv, Component displayString) { + super(container, inv, displayString); + + imageWidth = 183; + imageHeight = 202; + } + + @Override + public void init() { + super.init(); + + SavedRemoteLayout remoteLayout = SavedRemoteLayout.fromItem(remoteItem); + + buildMinecraftWidgetList(remoteLayout.getWidgets(), this, true) + .forEach(this::addRemoteWidget); + } + + @Override + protected ResourceLocation getGuiTexture() { + return Textures.GUI_WIDGET_OPTIONS; + } + + public void onGlobalVariableChanged(String varName) { + widgetMap.forEach((mcWidget, remoteWidget) -> { + if (remoteWidget instanceof IRemoteVariableWidget rv && varName.equals(rv.varName())) { + RemoteClientRegistry.INSTANCE.handleGlobalVariableChange(rv, mcWidget, varName); + } + mcWidget.visible = remoteWidget.isEnabled(Minecraft.getInstance().player); + }); + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidget.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidget.java deleted file mode 100644 index 50718a251..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidget.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote.actionwidget; - -import com.mojang.datafixers.Products; -import com.mojang.serialization.Codec; -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.client.gui.RemoteScreen; -import me.desht.pneumaticcraft.client.util.ClientUtils; -import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; -import me.desht.pneumaticcraft.common.variables.TextVariableParser; -import me.desht.pneumaticcraft.lib.Log; -import me.desht.pneumaticcraft.mixin.accessors.TooltipAccess; -import net.minecraft.client.gui.components.AbstractWidget; -import net.minecraft.client.gui.components.Tooltip; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.core.BlockPos; -import net.minecraft.core.HolderLookup; -import net.minecraft.nbt.NbtOps; -import net.minecraft.nbt.Tag; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.RegistryOps; - -import java.util.Optional; -import java.util.Set; -import java.util.UUID; - -public abstract class ActionWidget { - protected W widget; - protected BaseSettings baseSettings; - protected final WidgetSettings widgetSettings; - - protected static

> Products.P2, BaseSettings, WidgetSettings> baseParts(RecordCodecBuilder.Instance

pInstance) { - return pInstance.group( - BaseSettings.CODEC.optionalFieldOf("base", BaseSettings.DEFAULT).forGetter(a -> a.baseSettings), - WidgetSettings.CODEC.fieldOf("widget").forGetter(a -> a.widgetSettings) - ); - } - - protected ActionWidget(BaseSettings baseSettings, WidgetSettings widgetSettings) { - this.baseSettings = baseSettings; - this.widgetSettings = widgetSettings; - } - - protected ActionWidget(WidgetSettings widgetSettings) { - this(BaseSettings.DEFAULT, widgetSettings); - } - - public abstract MapCodec> codec(); - - public abstract String getId(); - - public ActionWidget copy(HolderLookup.Provider provider) { - try { - RegistryOps ops = provider.createSerializationContext(NbtOps.INSTANCE); - Tag tag = ActionWidgets.CODEC.encodeStart(ops, this).getOrThrow(); - return ActionWidgets.CODEC.parse(ops, tag).getOrThrow(); - } catch (Exception e) { - Log.error("Error occurred when trying to copy a {} action widget: {}", getId(), e.getMessage()); - return null; - } - } - - public final W getOrCreateMinecraftWidget(RemoteScreen screen) { - if (widget == null) { - widget = createMinecraftWidget(screen); - } - return widget; - } - - protected abstract W createMinecraftWidget(RemoteScreen screen); - - public abstract Screen createConfigurationGui(RemoteEditorScreen guiRemote); - - public final void setWidgetPos(RemoteEditorScreen screen, int absX, int absY) { - // widget X/Y are stored relative to screen left/top - widgetSettings.setX(absX - screen.getGuiLeft()); - widgetSettings.setY(absY - screen.getGuiTop()); - - if (widget != null) { - widget.setPosition(absX, absY); - } - } - - public void setEnableVariable(String varName) { - baseSettings = baseSettings.withVariable(varName); - } - - public String getEnableVariable() { - return baseSettings.enableVariable; - } - - public boolean isEnabled() { - if (getEnableVariable().isEmpty()) { - return true; - } - BlockPos pos = GlobalVariableHelper.getPos(ClientUtils.getClientPlayer().getUUID(), getEnableVariable(), BlockPos.ZERO); - return pos.equals(getEnablingValue()); - } - - public void setEnablingValue(int x, int y, int z) { - baseSettings = baseSettings.withEnablingValue(new BlockPos(x, y, z)); - } - - public BlockPos getEnablingValue() { - return baseSettings.enablingValue; - } - - public Component getTitle() { - return widgetSettings.getTitle(); - } - - public void setTooltip(Tooltip tooltip) { - widget.setTooltip(tooltip); - } - - public Tooltip getTooltip() { - return widget.getTooltip(); - } - - public Component getTooltipMessage(RemoteScreen screen) { - Tooltip tooltip = getOrCreateMinecraftWidget(screen).getTooltip(); - return tooltip == null ? Component.empty() : ((TooltipAccess) tooltip).getMessage(); - } - - public void discoverVariables(Set variables, UUID playerId) { - if (!getEnableVariable().isEmpty()) { - variables.add(getEnableVariable()); - } - getTitle().visit(string -> { - TextVariableParser parser = new TextVariableParser(string, playerId); - parser.parse(); - variables.addAll(parser.getRelevantVariables()); - return Optional.empty(); - }); - } - - protected record BaseSettings(String enableVariable, BlockPos enablingValue) { - public static final Codec CODEC = RecordCodecBuilder.create(builder -> builder.group( - Codec.STRING.optionalFieldOf("enable_var", "").forGetter(BaseSettings::enableVariable), - BlockPos.CODEC.optionalFieldOf("enable_pos", BlockPos.ZERO).forGetter(BaseSettings::enablingValue) - ).apply(builder, BaseSettings::new)); - - public static final BaseSettings DEFAULT = new BaseSettings("", BlockPos.ZERO); - - public BaseSettings withVariable(String var) { - return new BaseSettings(var, enablingValue); - } - - public BaseSettings withEnablingValue(BlockPos value) { - return new BaseSettings(enableVariable, value); - } - } -} \ No newline at end of file diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetButton.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetButton.java deleted file mode 100644 index b38bc043d..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetButton.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote.actionwidget; - -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.client.gui.RemoteScreen; -import me.desht.pneumaticcraft.client.gui.remote.RemoteButtonOptionScreen; -import me.desht.pneumaticcraft.client.gui.widget.WidgetButtonExtended; -import me.desht.pneumaticcraft.common.network.NetworkHandler; -import me.desht.pneumaticcraft.common.network.PacketSetGlobalVariable; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; - -public class ActionWidgetButton extends ActionWidgetVariable implements IActionWidgetLabeled { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(builder -> - varParts(builder).and( - BlockPos.CODEC.fieldOf("set_pos").forGetter(a -> a.settingPos) - ).apply(builder, ActionWidgetButton::new)); - public static final String ID = "button"; - - public BlockPos settingPos = BlockPos.ZERO; // The coordinate the variable is set to when the button is pressed. - - public ActionWidgetButton(RemoteEditorScreen screen, WidgetButtonExtended widget) { - super(BaseSettings.DEFAULT, WidgetSettings.forWidget(screen, widget), ""); - } - - public ActionWidgetButton(BaseSettings baseSettings, WidgetSettings widgetSettings, String s, BlockPos settingPos) { - super(baseSettings, widgetSettings, s); - - this.settingPos = settingPos; - } - - @Override - public MapCodec> codec() { - return CODEC; - } - - @Override - public String getId() { - return ID; - } - - @Override - public void setText(Component text) { - widgetSettings.setTitle(text); - widget.setMessage(text); - } - - @Override - public Component getText() { - return widget.getMessage(); - } - - @Override - public void onActionPerformed() { - if (!getVariableName().isEmpty()) { - NetworkHandler.sendToServer(PacketSetGlobalVariable.forPos(getVariableName(), settingPos)); - } - } - - @Override - public void onVariableChange() { - // no action needed - } - - @Override - public Screen createConfigurationGui(RemoteEditorScreen guiRemote) { - return new RemoteButtonOptionScreen(this, guiRemote); - } - - @Override - protected WidgetButtonExtended createMinecraftWidget(RemoteScreen screen) { - return new WidgetButtonExtended( - widgetSettings.getX() + screen.getGuiLeft(), - widgetSettings.getY() + screen.getGuiTop(), - widgetSettings.getWidth(), - widgetSettings.getHeight(), - widgetSettings.getTitle(), - b -> onActionPerformed() - ); - } - - public void setWidth(int width) { - widget.setWidth(width); - } - - public int getWidth() { - return widget.getWidth(); - } - - public void setHeight(int height) { - widget.setHeight(height); - } - - public int getHeight() { - return widget.getHeight(); - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetCheckBox.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetCheckBox.java deleted file mode 100644 index 211f6afea..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetCheckBox.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote.actionwidget; - -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.client.gui.RemoteScreen; -import me.desht.pneumaticcraft.client.gui.widget.WidgetCheckBox; -import me.desht.pneumaticcraft.client.util.ClientUtils; -import me.desht.pneumaticcraft.common.network.NetworkHandler; -import me.desht.pneumaticcraft.common.network.PacketSetGlobalVariable; -import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; -import net.minecraft.network.chat.Component; - -public class ActionWidgetCheckBox extends ActionWidgetVariable implements IActionWidgetLabeled { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(builder -> - varParts(builder).apply(builder, ActionWidgetCheckBox::new)); - public static final String ID = "checkbox"; - - public ActionWidgetCheckBox(RemoteEditorScreen screen, WidgetCheckBox widget) { - super(BaseSettings.DEFAULT, WidgetSettings.forWidget(screen, widget), ""); - } - - public ActionWidgetCheckBox(BaseSettings baseSettings, WidgetSettings widgetSettings, String variableName) { - super(baseSettings, widgetSettings, variableName); - } - - @Override - public MapCodec> codec() { - return CODEC; - } - - @Override - protected WidgetCheckBox createMinecraftWidget(RemoteScreen screen) { - return new WidgetCheckBox( - widgetSettings.getX() + screen.getGuiLeft(), - widgetSettings.getY() + screen.getGuiTop(), - 0xFF404040, widgetSettings.getTitle(), - b -> onActionPerformed() - ); - } - - @Override - public String getId() { - return ID; - } - - @Override - public void setText(Component text) { - widgetSettings.setTitle(text); - if (widget != null) { - widget.setMessage(text); - } - } - - @Override - public Component getText() { - return widget.getMessage(); - } - - @Override - public void onActionPerformed() { - if (!getVariableName().isEmpty()) { - NetworkHandler.sendToServer(PacketSetGlobalVariable.forBool(getVariableName(), widget.checked)); - } - } - - @Override - public void onVariableChange() { - if (widget != null) { - widget.checked = GlobalVariableHelper.getBool(ClientUtils.getClientPlayer().getUUID(), getVariableName()); - } - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetDropdown.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetDropdown.java deleted file mode 100644 index d23531771..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetDropdown.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote.actionwidget; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.client.gui.RemoteScreen; -import me.desht.pneumaticcraft.client.gui.remote.RemoteDropdownOptionScreen; -import me.desht.pneumaticcraft.client.gui.widget.WidgetComboBox; -import me.desht.pneumaticcraft.client.util.ClientUtils; -import me.desht.pneumaticcraft.common.network.NetworkHandler; -import me.desht.pneumaticcraft.common.network.PacketSetGlobalVariable; -import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.util.Mth; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.List; - -public class ActionWidgetDropdown extends ActionWidgetVariable { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(builder -> - varParts(builder).and(builder.group( - Codec.STRING.listOf().fieldOf("elements").forGetter(ActionWidgetDropdown::getDropDownElements), - Codec.BOOL.optionalFieldOf("sorted", false).forGetter(ActionWidgetDropdown::getSorted) - )).apply(builder, ActionWidgetDropdown::new)); - public static final String ID = "dropdown"; - - private List dropDownElements = List.of(); - private boolean sorted; - - public ActionWidgetDropdown(RemoteEditorScreen remoteEditorScreen, WidgetComboBox widgetComboBox) { - super(BaseSettings.DEFAULT, WidgetSettings.forWidget(remoteEditorScreen, widgetComboBox), ""); - } - - public ActionWidgetDropdown(BaseSettings baseSettings, WidgetSettings widgetSettings, String variableName, List elements, boolean sorted) { - super(baseSettings, widgetSettings, variableName); - - this.dropDownElements = elements; - this.sorted = sorted; - } - - @Override - public MapCodec> codec() { - return CODEC; - } - - @Override - public String getId() { - return ID; - } - - @Override - public void onKeyTyped() { - if (!getVariableName().isEmpty()) NetworkHandler.sendToServer(PacketSetGlobalVariable.forInt(getVariableName(), widget.getSelectedElementIndex())); - } - - @Override - public void onVariableChange() { - if (widget != null) { - widget.setValue(getSelectedElement()); - } - } - - @Override - protected WidgetComboBox createMinecraftWidget(RemoteScreen screen) { - WidgetComboBox res = new WidgetComboBox(Minecraft.getInstance().font, - widgetSettings.getX() + screen.getGuiLeft(), - widgetSettings.getY() + screen.getGuiTop(), - widgetSettings.getWidth(), widgetSettings.getHeight(), - this::onPressed - ); - res.setElements(dropDownElements); - res.setFixedOptions(true); - res.setShouldSort(sorted); - res.setValue(getSelectedElement()); - return res; - } - - private void onPressed(WidgetComboBox comboBox) { - if (comboBox.getSelectedElementIndex() >= 0 && !getVariableName().isEmpty()) { - NetworkHandler.sendToServer(PacketSetGlobalVariable.forInt(getVariableName(), comboBox.getSelectedElementIndex())); - } - } - - private String getSelectedElement() { - if (dropDownElements.isEmpty()) { - return ""; - } else { - int idx = GlobalVariableHelper.getInt(ClientUtils.getClientPlayer().getUUID(), getVariableName()); - return dropDownElements.get(Mth.clamp(idx, 0, dropDownElements.size() - 1)); - } - } - - @Override - public void onActionPerformed() { - // nothing - } - - public void setDropDownElements(@NotNull String[] dropDownElements) { - this.dropDownElements = Arrays.asList(dropDownElements); - if (widget != null) { - widget.setElements(dropDownElements); - widget.setValue(getSelectedElement()); - } - } - - public List getDropDownElements() { - return dropDownElements; - } - - public boolean getSorted() { - return sorted; - } - - public void setSorted(boolean sorted) { - this.sorted = sorted; - if (widget != null) { - widget.setShouldSort(sorted); - } - } - - public void setWidth(int width) { - widgetSettings.setWidth(width); - if (widget != null) { - widget.setWidth(width); - } - } - - public int getWidth() { - return widgetSettings.getWidth(); - } - - @Override - public Screen createConfigurationGui(RemoteEditorScreen guiRemote) { - return new RemoteDropdownOptionScreen(this, guiRemote); - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetLabel.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetLabel.java deleted file mode 100644 index 821f50324..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetLabel.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote.actionwidget; - -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.client.gui.RemoteScreen; -import me.desht.pneumaticcraft.client.gui.remote.BasicRemoteOptionScreen; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; - -public class ActionWidgetLabel extends ActionWidget implements IActionWidgetLabeled { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(builder -> - baseParts(builder).apply(builder, ActionWidgetLabel::new) - ); - public static final String ID = "label"; - - public ActionWidgetLabel(RemoteEditorScreen remoteEditorScreen, WidgetLabelVariable widget) { - super(WidgetSettings.forWidget(remoteEditorScreen, widget)); - } - - public ActionWidgetLabel(BaseSettings baseSettings, WidgetSettings widgetSettings) { - super(baseSettings, widgetSettings); - } - - @Override - public MapCodec> codec() { - return CODEC; - } - - @Override - protected WidgetLabelVariable createMinecraftWidget(RemoteScreen screen) { - return new WidgetLabelVariable( - widgetSettings.getX() + screen.getGuiLeft(), - widgetSettings.getY() + screen.getGuiTop(), - widgetSettings.getTitle() - ); - } - - @Override - public String getId() { - return ID; - } - - @Override - public void setText(Component text) { - widgetSettings.setTitle(text); - widget.setMessage(text); - } - - @Override - public Component getText() { - return widget.getMessage(); - } - - @Override - public Screen createConfigurationGui(RemoteEditorScreen guiRemote) { - return new BasicRemoteOptionScreen<>(this, guiRemote); - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetVariable.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetVariable.java deleted file mode 100644 index 5db9146e4..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgetVariable.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote.actionwidget; - -import com.mojang.datafixers.Products; -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.client.gui.remote.RemoteVariableOptionScreen; -import net.minecraft.client.gui.components.AbstractWidget; -import net.minecraft.client.gui.screens.Screen; - -import java.util.Set; -import java.util.UUID; - -public abstract class ActionWidgetVariable extends ActionWidget { - protected static

> Products.P3, BaseSettings, WidgetSettings, String> varParts(RecordCodecBuilder.Instance

pInstance) { - return baseParts(pInstance).and(Codec.STRING.fieldOf("var_name").forGetter(p -> p.variableName)); - } - - protected String variableName = ""; - - public ActionWidgetVariable(BaseSettings baseSettings, WidgetSettings widgetSettings, String variableName) { - super(baseSettings, widgetSettings); - - this.variableName = variableName; - } - - public String getVariableName() { - return variableName; - } - - public void setVariableName(String variableName) { - this.variableName = variableName; - } - - @Override - public Screen createConfigurationGui(RemoteEditorScreen guiRemote) { - return new RemoteVariableOptionScreen<>(this, guiRemote); - } - - public abstract void onActionPerformed(); - - public void onKeyTyped() { - } - - public abstract void onVariableChange(); - - @Override - public void discoverVariables(Set variables, UUID playerId) { - super.discoverVariables(variables, playerId); - - if (!getVariableName().isEmpty()) { - variables.add(getVariableName()); - } - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgets.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgets.java deleted file mode 100644 index 809b11541..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/ActionWidgets.java +++ /dev/null @@ -1,25 +0,0 @@ -package me.desht.pneumaticcraft.client.gui.remote.actionwidget; - -import com.google.common.collect.BiMap; -import com.google.common.collect.ImmutableBiMap; -import com.mojang.serialization.Codec; -import com.mojang.serialization.MapCodec; -import me.desht.pneumaticcraft.common.util.CodecUtil; - -import java.util.List; -import java.util.function.Function; - -public class ActionWidgets { - private static final BiMap>> registeredWidgets = ImmutableBiMap.of( - ActionWidgetCheckBox.ID, ActionWidgetCheckBox.CODEC, - ActionWidgetLabel.ID, ActionWidgetLabel.CODEC, - ActionWidgetButton.ID, ActionWidgetButton.CODEC, - ActionWidgetDropdown.ID, ActionWidgetDropdown.CODEC - ); - - private static final Codec>> DISPATCH = CodecUtil.simpleDispatchCodec(Codec.STRING, registeredWidgets); - - public static final Codec> CODEC = DISPATCH.dispatch(ActionWidget::codec, Function.identity()); - - public static final Codec>> LIST_CODEC = CODEC.listOf(); -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/IActionWidgetLabeled.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/IActionWidgetLabeled.java deleted file mode 100644 index 4d4f069d1..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/IActionWidgetLabeled.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote.actionwidget; - -import net.minecraft.network.chat.Component; - -public interface IActionWidgetLabeled { - void setText(Component text); - - Component getText(); -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/WidgetLabelVariable.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/WidgetLabelVariable.java deleted file mode 100644 index cca7bcf5d..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/WidgetLabelVariable.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of pnc-repressurized. - * - * pnc-repressurized 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. - * - * pnc-repressurized 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 pnc-repressurized. If not, see . - */ - -package me.desht.pneumaticcraft.client.gui.remote.actionwidget; - -import me.desht.pneumaticcraft.client.gui.widget.WidgetLabel; -import me.desht.pneumaticcraft.client.util.ClientUtils; -import me.desht.pneumaticcraft.common.variables.TextVariableParser; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.FormattedText; -import net.minecraft.network.chat.MutableComponent; - -import java.util.Optional; -import java.util.UUID; - -public class WidgetLabelVariable extends WidgetLabel { - private final MutableComponent displayedMessage; - - public WidgetLabelVariable(int x, int y, Component text) { - super(x, y, text); - - displayedMessage = Component.empty(); - UUID uuid = ClientUtils.getClientPlayer().getUUID(); - text.visit((style, string) -> { - TextVariableParser p = new TextVariableParser(string, uuid); - displayedMessage.append(Component.literal(p.parse()).withStyle(style)); - return Optional.empty(); - }, text.getStyle()); - } - - @Override - public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) { - Component origText = getMessage(); - setMessage(displayedMessage); - super.renderWidget(graphics, mouseX, mouseY, partialTick); - setMessage(origText); - } -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/WidgetSettings.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/WidgetSettings.java deleted file mode 100644 index 7089050f9..000000000 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/actionwidget/WidgetSettings.java +++ /dev/null @@ -1,126 +0,0 @@ -package me.desht.pneumaticcraft.client.gui.remote.actionwidget; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.mixin.accessors.TooltipAccess; -import net.minecraft.client.gui.components.AbstractWidget; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.ComponentSerialization; -import org.jetbrains.annotations.NotNull; - -import java.util.Objects; - -public final class WidgetSettings { - public static final Codec CODEC = RecordCodecBuilder.create(builder -> builder.group( - Codec.INT.fieldOf("x").forGetter(WidgetSettings::getX), - Codec.INT.fieldOf("y").forGetter(WidgetSettings::getY), - Codec.INT.optionalFieldOf("width", 0).forGetter(WidgetSettings::getWidth), - Codec.INT.optionalFieldOf("height", 0).forGetter(WidgetSettings::getHeight), - ComponentSerialization.CODEC.fieldOf("title").forGetter(WidgetSettings::getTitle), - ComponentSerialization.CODEC.optionalFieldOf("tooltip", Component.empty()).forGetter(WidgetSettings::getTooltip) - ).apply(builder, WidgetSettings::new)); - - private int x; - private int y; - private int width; - private int height; - private Component title; - private Component tooltip; - - public WidgetSettings(int x, int y, int width, int height, @NotNull Component title, @NotNull Component tooltip) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.title = title; - this.tooltip = tooltip; - } - - public static WidgetSettings forWidget(RemoteEditorScreen screen, AbstractWidget widget) { - return new WidgetSettings(widget.getX() - screen.getGuiLeft(), widget.getY() - screen.getGuiTop(), widget.getWidth(), widget.getHeight(), widget.getMessage(), getTooltip(widget)); - } - - @NotNull - private static Component getTooltip(AbstractWidget widget) { - return widget.getTooltip() == null ? Component.empty() : ((TooltipAccess) widget.getTooltip()).getMessage(); - } - - public int getX() { - return x; - } - - public void setX(int x) { - this.x = x; - } - - public int getY() { - return y; - } - - public void setY(int y) { - this.y = y; - } - - public int getWidth() { - return width; - } - - public void setWidth(int width) { - this.width = width; - } - - public int getHeight() { - return height; - } - - public void setHeight(int height) { - this.height = height; - } - - public Component getTitle() { - return title; - } - - public void setTitle(@NotNull Component title) { - this.title = title; - } - - public Component getTooltip() { - return tooltip; - } - - public void setTooltip(@NotNull Component tooltip) { - this.tooltip = tooltip; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (WidgetSettings) obj; - return this.x == that.x && - this.y == that.y && - this.width == that.width && - this.height == that.height && - Objects.equals(this.title, that.title) && - Objects.equals(this.tooltip, that.tooltip); - } - - @Override - public int hashCode() { - return Objects.hash(x, y, width, height, title, tooltip); - } - - @Override - public String toString() { - return "WidgetSettings[" + - "x=" + x + ", " + - "y=" + y + ", " + - "width=" + width + ", " + - "height=" + height + ", " + - "title=" + title.getString() + ", " + - "tooltip=" + tooltip.getString() + ']'; - } - -} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/AbstractRemoteConfigScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/AbstractRemoteConfigScreen.java new file mode 100644 index 000000000..d080fc291 --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/AbstractRemoteConfigScreen.java @@ -0,0 +1,212 @@ +/* + * This file is part of pnc-repressurized. + * + * pnc-repressurized 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. + * + * pnc-repressurized 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 pnc-repressurized. If not, see . + */ + +package me.desht.pneumaticcraft.client.gui.remote.config; + +import com.google.gson.*; +import com.mojang.serialization.JsonOps; +import me.desht.pneumaticcraft.api.remote.BaseSettings; +import me.desht.pneumaticcraft.api.remote.IRemoteWidget; +import me.desht.pneumaticcraft.api.remote.WidgetSettings; +import me.desht.pneumaticcraft.client.gui.AbstractPneumaticCraftScreen; +import me.desht.pneumaticcraft.client.gui.remote.RemoteEditorScreen; +import me.desht.pneumaticcraft.client.gui.widget.*; +import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; +import me.desht.pneumaticcraft.lib.Textures; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.resources.ResourceLocation; + +import java.util.List; + +import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; + +public abstract class AbstractRemoteConfigScreen extends AbstractPneumaticCraftScreen { + protected final R remoteWidget; + final RemoteEditorScreen guiRemote; + protected WidgetTextField labelField, tooltipField; + protected WidgetComboBox enableField; + protected WidgetTextFieldNumber xValueField, yValueField, zValueField; + protected WidgetButtonExtended enableVarTypeButton; + private boolean playerGlobalEnableVar; + + public AbstractRemoteConfigScreen(R remoteWidget, RemoteEditorScreen guiRemote) { + super(Component.translatable(remoteWidget.getTranslationKey())); + + this.remoteWidget = remoteWidget; + this.guiRemote = guiRemote; + xSize = 183; + ySize = 202; + } + + @Override + public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + renderBackground(graphics, mouseX, mouseY, partialTicks); + super.render(graphics, mouseX, mouseY, partialTicks); + } + + @Override + protected ResourceLocation getTexture() { + return Textures.GUI_WIDGET_OPTIONS; + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override + public void init() { + super.init(); + + int textFieldHeight = font.lineHeight + 3; + + GlobalVariableHelper variableHelper = GlobalVariableHelper.getInstance(); + + BaseSettings baseSettings = remoteWidget.baseSettings(); + playerGlobalEnableVar = baseSettings.enableVariable().isEmpty() || baseSettings.enableVariable().startsWith("#"); + + addLabel(xlate("pneumaticcraft.gui.remote.enable"), guiLeft + 10, guiTop + 150); + addLabel(title, width / 2, guiTop + 5, WidgetLabel.Alignment.CENTRE); + enableVarTypeButton = new WidgetButtonExtended(guiLeft + 10, guiTop + 158, 12, 14, variableHelper.getVarPrefix(playerGlobalEnableVar), + b -> togglePlayerGlobalEnable()).setTooltipKey("pneumaticcraft.gui.remote.varType.tooltip"); + addRenderableWidget(enableVarTypeButton); + + if (remoteWidget.hasConfigurableText()) { + addLabel(xlate("pneumaticcraft.gui.remote.text"), guiLeft + 10, guiTop + 20); + addLabel(xlate("pneumaticcraft.gui.remote.tooltip"), guiLeft + 10, guiTop + 46); + } + + addLabel(xlate("pneumaticcraft.gui.remote.enableValue"), guiLeft + 10, guiTop + 175); + addLabel(Component.literal("X:"), guiLeft + 10, guiTop + 186); + addLabel(Component.literal("Y:"), guiLeft + 67, guiTop + 186); + addLabel(Component.literal("Z:"), guiLeft + 124, guiTop + 186); + + enableField = new WidgetComboBox(font, guiLeft + 23, guiTop + 159, 147, textFieldHeight); + enableField.setElements(extractVarnames(playerGlobalEnableVar)); + enableField.setValue(variableHelper.stripVarPrefix(baseSettings.enableVariable())); + enableField.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.enable.tooltip"))); + addRenderableWidget(enableField); + + Component valueTooltip = xlate("pneumaticcraft.gui.remote.enableValue.tooltip"); + + xValueField = new WidgetTextFieldNumber(font, guiLeft + 20, guiTop + 184, 38, textFieldHeight); + xValueField.setValue(baseSettings.enablingValue().getX()); + xValueField.setTooltip(Tooltip.create(valueTooltip)); + addRenderableWidget(xValueField); + + yValueField = new WidgetTextFieldNumber(font, guiLeft + 78, guiTop + 184, 38, textFieldHeight); + yValueField.setValue(baseSettings.enablingValue().getY()); + yValueField.setTooltip(Tooltip.create(valueTooltip)); + addRenderableWidget(yValueField); + + zValueField = new WidgetTextFieldNumber(font, guiLeft + 136, guiTop + 184, 38, textFieldHeight); + zValueField.setValue(baseSettings.enablingValue().getZ()); + zValueField.setTooltip(Tooltip.create(valueTooltip)); + addRenderableWidget(zValueField); + + if (remoteWidget.hasConfigurableText()) { + labelField = new WidgetTextField(font, guiLeft + 10, guiTop + 29, 160, textFieldHeight); + labelField.setMaxLength(2048); + labelField.setValue(toJsonString(remoteWidget.widgetSettings().title())); + labelField.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.label.tooltip"))); + addRenderableWidget(labelField); + + tooltipField = new WidgetTextField(font, guiLeft + 10, guiTop + 55, 160, textFieldHeight); + tooltipField.setMaxLength(2048); + tooltipField.setValue(toJsonString(remoteWidget.widgetSettings().tooltip())); + addRenderableWidget(tooltipField); + } + } + + private void togglePlayerGlobalEnable() { + playerGlobalEnableVar = !playerGlobalEnableVar; + enableVarTypeButton.setMessage(Component.literal(GlobalVariableHelper.getInstance().getVarPrefix(playerGlobalEnableVar))); + enableField.setElements(extractVarnames(playerGlobalEnableVar)); + } + + @Override + public void onClose() { + IRemoteWidget newWidget = makeUpdatedRemoteWidget(); + if (newWidget != null) { + guiRemote.updateWidgetFromConfigScreen(newWidget); + } + + minecraft.setScreen(guiRemote); + } + + protected R makeUpdatedRemoteWidget() { + return null; + } + + protected BaseSettings makeBaseSettings() { + return new BaseSettings( + GlobalVariableHelper.getInstance().getPrefixedVar(enableField.getValue(), playerGlobalEnableVar), + new BlockPos(xValueField.getIntValue(), yValueField.getIntValue(), zValueField.getIntValue()) + ); + } + + protected WidgetSettings makeWidgetSettings() { + WidgetSettings res = remoteWidget.widgetSettings(); + if (remoteWidget.hasConfigurableText()) { + res = res.withText(fromJson(labelField.getValue()), fromJson(tooltipField.getValue())); + } + return res; + } + + private Component fromJson(String text) { + try { + if (!text.startsWith("\"") && !text.startsWith("{") && !text.startsWith("[")) { + text = "\"" + text + "\""; + } + JsonElement json = JsonParser.parseString(text); + return ComponentSerialization.CODEC + .parse(JsonOps.INSTANCE, json) + .getOrThrow(JsonSyntaxException::new); + } catch (JsonParseException e) { + return Component.literal(": " + e.getMessage()); + } + } + + private String toJsonString(Component component) { + JsonElement element = ComponentSerialization.CODEC + .encodeStart(JsonOps.INSTANCE, component) + .result() + .orElse(new JsonPrimitive("")); + String str = element.toString(); + if (str.startsWith("\"") && str.endsWith("\"")) { + return str.substring(1, str.length() - 1); + } else { + return str; + } + } + + /** + * Given an array of prefixed var names, return a corresponding list of var names with a matching prefix character + * @param playerGlobal true to extract player-global, false for server-global + * @return a list of unprefixed var names + */ + protected List extractVarnames(boolean playerGlobal) { + return guiRemote.getMenu().allKnownGlobalVars().stream() + .filter(v -> playerGlobal && v.startsWith("#") || !playerGlobal && v.startsWith("%")) + .map(v -> v.substring(1)) + .toList(); + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteVariableOptionScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/AbstractRemoteVariableConfigScreen.java similarity index 63% rename from src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteVariableOptionScreen.java rename to src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/AbstractRemoteVariableConfigScreen.java index 67b9c3b72..a66de22b8 100644 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteVariableOptionScreen.java +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/AbstractRemoteVariableConfigScreen.java @@ -15,10 +15,10 @@ * along with pnc-repressurized. If not, see . */ -package me.desht.pneumaticcraft.client.gui.remote; +package me.desht.pneumaticcraft.client.gui.remote.config; -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.client.gui.remote.actionwidget.ActionWidgetVariable; +import me.desht.pneumaticcraft.api.remote.IRemoteVariableWidget; +import me.desht.pneumaticcraft.client.gui.remote.RemoteEditorScreen; import me.desht.pneumaticcraft.client.gui.widget.WidgetButtonExtended; import me.desht.pneumaticcraft.client.gui.widget.WidgetComboBox; import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; @@ -27,13 +27,13 @@ import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; -public class RemoteVariableOptionScreen> extends BasicRemoteOptionScreen { +public abstract class AbstractRemoteVariableConfigScreen extends AbstractRemoteConfigScreen { private boolean playerGlobal; private WidgetButtonExtended varTypeButton; private WidgetComboBox variableField; - public RemoteVariableOptionScreen(A actionWidget, RemoteEditorScreen guiRemote) { - super(actionWidget, guiRemote); + public AbstractRemoteVariableConfigScreen(A widget, RemoteEditorScreen guiRemote) { + super(widget, guiRemote); } @Override @@ -42,30 +42,27 @@ public void init() { addLabel(xlate("pneumaticcraft.gui.progWidget.coordinate.variableName"), guiLeft + 10, guiTop + 70); - playerGlobal = actionWidget.getVariableName().isEmpty() || actionWidget.getVariableName().startsWith("#"); + playerGlobal = remoteWidget.varName().isEmpty() || remoteWidget.varName().startsWith("#"); - varTypeButton = new WidgetButtonExtended(guiLeft + 10, guiTop + 78, 12, 14, GlobalVariableHelper.getVarPrefix(playerGlobal), + varTypeButton = new WidgetButtonExtended(guiLeft + 10, guiTop + 78, 12, 14, GlobalVariableHelper.getInstance().getVarPrefix(playerGlobal), b -> togglePlayerGlobal()) .setTooltipKey("pneumaticcraft.gui.remote.varType.tooltip"); addRenderableWidget(varTypeButton); variableField = new WidgetComboBox(font, guiLeft + 23, guiTop + 79, 147, font.lineHeight + 3); - variableField.setElements(GlobalVariableHelper.extractVarnames(guiRemote.getMenu().variables, playerGlobal)); - variableField.setValue(GlobalVariableHelper.stripVarPrefix(actionWidget.getVariableName())); + variableField.setElements(extractVarnames(playerGlobal)); + variableField.setValue(GlobalVariableHelper.getInstance().stripVarPrefix(remoteWidget.varName())); variableField.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.variable.tooltip"))); addRenderableWidget(variableField); } - @Override - public void removed() { - actionWidget.setVariableName(GlobalVariableHelper.getPrefixedVar(variableField.getValue(), playerGlobal)); - - super.removed(); + protected String makeVarName() { + return GlobalVariableHelper.getInstance().getPrefixedVar(variableField.getValue(), playerGlobal); } private void togglePlayerGlobal() { playerGlobal = !playerGlobal; - variableField.setElements(GlobalVariableHelper.extractVarnames(guiRemote.getMenu().variables, playerGlobal)); - varTypeButton.setMessage(Component.literal(GlobalVariableHelper.getVarPrefix(playerGlobal))); + variableField.setElements(extractVarnames(playerGlobal)); + varTypeButton.setMessage(Component.literal(GlobalVariableHelper.getInstance().getVarPrefix(playerGlobal))); } } diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteButtonOptionScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteButtonOptionScreen.java similarity index 55% rename from src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteButtonOptionScreen.java rename to src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteButtonOptionScreen.java index 35fbe8374..b58f388f8 100644 --- a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/RemoteButtonOptionScreen.java +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteButtonOptionScreen.java @@ -15,24 +15,31 @@ * along with pnc-repressurized. If not, see . */ -package me.desht.pneumaticcraft.client.gui.remote; +package me.desht.pneumaticcraft.client.gui.remote.config; -import me.desht.pneumaticcraft.client.gui.RemoteEditorScreen; -import me.desht.pneumaticcraft.client.gui.remote.actionwidget.ActionWidgetButton; +import me.desht.pneumaticcraft.api.remote.WidgetSettings; +import me.desht.pneumaticcraft.client.gui.remote.AbstractRemoteScreen; +import me.desht.pneumaticcraft.client.gui.remote.RemoteClientRegistry; +import me.desht.pneumaticcraft.client.gui.remote.RemoteEditorScreen; +import me.desht.pneumaticcraft.client.gui.widget.WidgetButtonExtended; import me.desht.pneumaticcraft.client.gui.widget.WidgetLabel; import me.desht.pneumaticcraft.client.gui.widget.WidgetTextFieldNumber; +import me.desht.pneumaticcraft.common.network.NetworkHandler; +import me.desht.pneumaticcraft.common.network.PacketSetGlobalVariable; +import me.desht.pneumaticcraft.common.remote.RemoteWidgetButton; import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; -public class RemoteButtonOptionScreen extends RemoteVariableOptionScreen { +public class RemoteButtonOptionScreen extends AbstractRemoteVariableConfigScreen { private WidgetTextFieldNumber widthField; private WidgetTextFieldNumber heightField; private WidgetTextFieldNumber xValueField, yValueField, zValueField; - public RemoteButtonOptionScreen(ActionWidgetButton widget, RemoteEditorScreen guiRemote) { + public RemoteButtonOptionScreen(RemoteWidgetButton widget, RemoteEditorScreen guiRemote) { super(widget, guiRemote); } @@ -55,41 +62,65 @@ public void init() { Component valueTooltip = xlate("pneumaticcraft.gui.remote.button.value.tooltip"); xValueField = new WidgetTextFieldNumber(font, guiLeft + 20, guiTop + 104, 38, textFieldHeight); - xValueField.setValue(actionWidget.settingPos.getX()); + xValueField.setValue(remoteWidget.settingPos().getX()); xValueField.setTooltip(Tooltip.create(valueTooltip)); addRenderableWidget(xValueField); yValueField = new WidgetTextFieldNumber(font, guiLeft + 78, guiTop + 104, 38, textFieldHeight); - yValueField.setValue(actionWidget.settingPos.getY()); + yValueField.setValue(remoteWidget.settingPos().getY()); yValueField.setTooltip(Tooltip.create(valueTooltip)); addRenderableWidget(yValueField); zValueField = new WidgetTextFieldNumber(font, guiLeft + 136, guiTop + 104, 38, textFieldHeight); - zValueField.setValue(actionWidget.settingPos.getZ()); + zValueField.setValue(remoteWidget.settingPos().getZ()); zValueField.setTooltip(Tooltip.create(valueTooltip)); addRenderableWidget(zValueField); widthField = new WidgetTextFieldNumber(font, xOff, guiTop + 121, 35, textFieldHeight) .setRange(10, Integer.MAX_VALUE).setAdjustments(1, 10); - widthField.setValue(actionWidget.getWidth()); + widthField.setValue(remoteWidget.widgetSettings().width()); widthField.minValue = 10; addRenderableWidget(widthField); heightField = new WidgetTextFieldNumber(font, xOff, guiTop + 134, 35, textFieldHeight) .setRange(10, Integer.MAX_VALUE).setAdjustments(1, 10); - heightField.setValue(actionWidget.getHeight()); + heightField.setValue(remoteWidget.widgetSettings().height()); heightField.minValue = 10; heightField.maxValue = 20; addRenderableWidget(heightField); - } @Override - public void removed() { - actionWidget.settingPos = new BlockPos(xValueField.getIntValue(), yValueField.getIntValue(), zValueField.getIntValue()); - actionWidget.setWidth(widthField.getIntValue()); - actionWidget.setHeight(heightField.getIntValue()); + protected RemoteWidgetButton makeUpdatedRemoteWidget() { + return new RemoteWidgetButton( + makeBaseSettings(), + makeWidgetSettings().resize(widthField.getIntValue(), heightField.getIntValue()), + makeVarName(), + new BlockPos(xValueField.getIntValue(), yValueField.getIntValue(), zValueField.getIntValue()) + ); + } - super.removed(); + public enum Factory implements RemoteClientRegistry.Factory { + INSTANCE; + + @Override + public WidgetButtonExtended createMinecraftWidget(RemoteWidgetButton remoteWidget, AbstractRemoteScreen screen) { + WidgetSettings widgetSettings = remoteWidget.widgetSettings(); + return new WidgetButtonExtended( + widgetSettings.x() + screen.getGuiLeft(), widgetSettings.y() + screen.getGuiTop(), + widgetSettings.width(), widgetSettings.height(), + widgetSettings.title(), + btn -> { + if (!remoteWidget.varName().isEmpty()) { + NetworkHandler.sendToServer(PacketSetGlobalVariable.forPos(remoteWidget.varName(), remoteWidget.settingPos())); + } + } + ).setTooltipText(remoteWidget.widgetSettings().tooltip()); + } + + @Override + public Screen createConfigurationScreen(RemoteWidgetButton remoteWidget, RemoteEditorScreen screen) { + return new RemoteButtonOptionScreen(remoteWidget, screen); + } } } diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteCheckboxOptionScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteCheckboxOptionScreen.java new file mode 100644 index 000000000..98ba15c04 --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteCheckboxOptionScreen.java @@ -0,0 +1,55 @@ +package me.desht.pneumaticcraft.client.gui.remote.config; + +import me.desht.pneumaticcraft.client.gui.remote.AbstractRemoteScreen; +import me.desht.pneumaticcraft.client.gui.remote.RemoteClientRegistry; +import me.desht.pneumaticcraft.client.gui.remote.RemoteEditorScreen; +import me.desht.pneumaticcraft.client.gui.widget.WidgetCheckBox; +import me.desht.pneumaticcraft.client.util.ClientUtils; +import me.desht.pneumaticcraft.common.network.NetworkHandler; +import me.desht.pneumaticcraft.common.network.PacketSetGlobalVariable; +import me.desht.pneumaticcraft.common.remote.RemoteWidgetCheckbox; +import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; +import net.minecraft.client.gui.screens.Screen; + +public class RemoteCheckboxOptionScreen extends AbstractRemoteVariableConfigScreen { + public RemoteCheckboxOptionScreen(RemoteWidgetCheckbox widget, RemoteEditorScreen guiRemote) { + super(widget, guiRemote); + } + + @Override + protected RemoteWidgetCheckbox makeUpdatedRemoteWidget() { + return new RemoteWidgetCheckbox( + makeBaseSettings(), + makeWidgetSettings(), + makeVarName() + ); + } + + public enum Factory implements RemoteClientRegistry.Factory { + INSTANCE; + + @Override + public WidgetCheckBox createMinecraftWidget(RemoteWidgetCheckbox remoteWidget, AbstractRemoteScreen screen) { + return new WidgetCheckBox( + remoteWidget.widgetSettings().x() + screen.getGuiLeft(), + remoteWidget.widgetSettings().y() + screen.getGuiTop(), + 0xFF404040, remoteWidget.widgetSettings().title(), + btn -> { + if (!remoteWidget.varName().isEmpty()) { + NetworkHandler.sendToServer(PacketSetGlobalVariable.forBool(remoteWidget.varName(), btn.checked)); + } + } + ).setTooltipText(remoteWidget.widgetSettings().tooltip()); + } + + @Override + public Screen createConfigurationScreen(RemoteWidgetCheckbox remoteWidget, RemoteEditorScreen screen) { + return new RemoteCheckboxOptionScreen(remoteWidget, screen); + } + + @Override + public void handleGlobalVariableChange(RemoteWidgetCheckbox remoteWidget, WidgetCheckBox mcWidget, String varName) { + mcWidget.setChecked(GlobalVariableHelper.getInstance().getBool(ClientUtils.getClientPlayer().getUUID(), varName)); + } + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteDropdownOptionScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteDropdownOptionScreen.java new file mode 100644 index 000000000..3f868671b --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteDropdownOptionScreen.java @@ -0,0 +1,120 @@ +/* + * This file is part of pnc-repressurized. + * + * pnc-repressurized 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. + * + * pnc-repressurized 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 pnc-repressurized. If not, see . + */ + +package me.desht.pneumaticcraft.client.gui.remote.config; + +import me.desht.pneumaticcraft.client.gui.remote.AbstractRemoteScreen; +import me.desht.pneumaticcraft.client.gui.remote.RemoteClientRegistry; +import me.desht.pneumaticcraft.client.gui.remote.RemoteEditorScreen; +import me.desht.pneumaticcraft.client.gui.widget.WidgetCheckBox; +import me.desht.pneumaticcraft.client.gui.widget.WidgetComboBox; +import me.desht.pneumaticcraft.client.gui.widget.WidgetTextField; +import me.desht.pneumaticcraft.client.gui.widget.WidgetTextFieldNumber; +import me.desht.pneumaticcraft.client.util.ClientUtils; +import me.desht.pneumaticcraft.common.network.NetworkHandler; +import me.desht.pneumaticcraft.common.network.PacketSetGlobalVariable; +import me.desht.pneumaticcraft.common.remote.RemoteWidgetDropdown; +import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.client.gui.screens.Screen; + +import java.util.List; + +import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; + +public class RemoteDropdownOptionScreen extends AbstractRemoteVariableConfigScreen { + private WidgetTextField dropDownElementsField; + private WidgetTextFieldNumber widthField; + private WidgetCheckBox sortCheckBox; + + public RemoteDropdownOptionScreen(RemoteWidgetDropdown widget, RemoteEditorScreen guiRemote) { + super(widget, guiRemote); + } + + @Override + public void init() { + super.init(); + + int textFieldHeight = font.lineHeight + 3; + + addLabel(xlate("pneumaticcraft.gui.remote.button.width"), guiLeft + 10, guiTop + 100); + addLabel(xlate("pneumaticcraft.gui.remote.dropdown.dropDownElements"), guiLeft + 10, guiTop + 40); + + dropDownElementsField = new WidgetTextField(font, guiLeft + 10, guiTop + 49, 160, textFieldHeight); + dropDownElementsField.setMaxLength(1024); + dropDownElementsField.setValue(String.join(",", remoteWidget.elements())); + dropDownElementsField.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.dropdown.dropDownElements.tooltip"))); + addRenderableWidget(dropDownElementsField); + + widthField = new WidgetTextFieldNumber(font, guiLeft + 49, guiTop + 99, 30, textFieldHeight).setRange(10, Integer.MAX_VALUE); + widthField.setValue(remoteWidget.widgetSettings().width()); + widthField.minValue = 10; + addRenderableWidget(widthField); + + sortCheckBox = new WidgetCheckBox(guiLeft + 10, guiTop + 120, 0x404040, xlate("pneumaticcraft.gui.remote.dropdown.sort")) + .setChecked(remoteWidget.sorted()); + sortCheckBox.setTooltip(Tooltip.create(xlate("pneumaticcraft.gui.remote.dropdown.sort.tooltip"))); + addRenderableWidget(sortCheckBox); + } + + @Override + protected RemoteWidgetDropdown makeUpdatedRemoteWidget() { + return new RemoteWidgetDropdown( + makeBaseSettings(), + makeWidgetSettings().resize(widthField.getIntValue(), Minecraft.getInstance().font.lineHeight + 3), + makeVarName(), + List.of(dropDownElementsField.getValue().split(",")), + sortCheckBox.isChecked() + ); + } + + public enum Factory implements RemoteClientRegistry.Factory { + INSTANCE; + + @Override + public WidgetComboBox createMinecraftWidget(RemoteWidgetDropdown remoteWidget, AbstractRemoteScreen screen) { + WidgetComboBox res = new WidgetComboBox(Minecraft.getInstance().font, + remoteWidget.widgetSettings().x() + screen.getGuiLeft(), + remoteWidget.widgetSettings().y() + screen.getGuiTop(), + remoteWidget.widgetSettings().width(), Minecraft.getInstance().font.lineHeight + 3, + btn -> { + if (btn.getSelectedElementIndex() >= 0 && !remoteWidget.varName().isEmpty()) { + NetworkHandler.sendToServer(PacketSetGlobalVariable.forInt(remoteWidget.varName(), btn.getSelectedElementIndex())); + } + } + ); + res.setElements(remoteWidget.elements()); + res.setFixedOptions(true); + res.setShouldSort(remoteWidget.sorted()); + res.setValue(remoteWidget.getSelectedElement()); + res.setTooltip(Tooltip.create(remoteWidget.widgetSettings().tooltip())); + return res; + } + + @Override + public Screen createConfigurationScreen(RemoteWidgetDropdown remoteWidget, RemoteEditorScreen screen) { + return new RemoteDropdownOptionScreen(remoteWidget, screen); + } + + @Override + public void handleGlobalVariableChange(RemoteWidgetDropdown remoteWidget, WidgetComboBox mcWidget, String varName) { + int idx = GlobalVariableHelper.getInstance().getInt(ClientUtils.getClientPlayer().getUUID(), varName); + mcWidget.selectElement(idx); + } + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteLabelOptionScreen.java b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteLabelOptionScreen.java new file mode 100644 index 000000000..d58ad4bf4 --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/client/gui/remote/config/RemoteLabelOptionScreen.java @@ -0,0 +1,40 @@ +package me.desht.pneumaticcraft.client.gui.remote.config; + +import me.desht.pneumaticcraft.client.gui.remote.AbstractRemoteScreen; +import me.desht.pneumaticcraft.client.gui.remote.RemoteClientRegistry; +import me.desht.pneumaticcraft.client.gui.remote.RemoteEditorScreen; +import me.desht.pneumaticcraft.client.gui.widget.WidgetLabel; +import me.desht.pneumaticcraft.common.remote.RemoteWidgetLabel; +import net.minecraft.client.gui.screens.Screen; + +public class RemoteLabelOptionScreen extends AbstractRemoteConfigScreen { + public RemoteLabelOptionScreen(RemoteWidgetLabel widget, RemoteEditorScreen guiRemote) { + super(widget, guiRemote); + } + + @Override + protected RemoteWidgetLabel makeUpdatedRemoteWidget() { + return new RemoteWidgetLabel( + makeBaseSettings(), + makeWidgetSettings() + ); + } + + public enum Factory implements RemoteClientRegistry.Factory { + INSTANCE; + + @Override + public WidgetLabel createMinecraftWidget(RemoteWidgetLabel remoteWidget, AbstractRemoteScreen screen) { + return new WidgetLabel( + remoteWidget.widgetSettings().x() + screen.getGuiLeft(), + remoteWidget.widgetSettings().y() + screen.getGuiTop(), + remoteWidget.widgetSettings().title() + ).setTooltipText(remoteWidget.widgetSettings().tooltip()); + } + + @Override + public Screen createConfigurationScreen(RemoteWidgetLabel remoteWidget, RemoteEditorScreen screen) { + return new RemoteLabelOptionScreen(remoteWidget, screen); + } + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/common/MiscAPIHandler.java b/src/main/java/me/desht/pneumaticcraft/common/MiscAPIHandler.java index 3c02afc15..da49fa186 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/MiscAPIHandler.java +++ b/src/main/java/me/desht/pneumaticcraft/common/MiscAPIHandler.java @@ -1,6 +1,7 @@ package me.desht.pneumaticcraft.common; import me.desht.pneumaticcraft.api.PNCCapabilities; +import me.desht.pneumaticcraft.api.misc.IGlobalVariableHelper; import me.desht.pneumaticcraft.api.misc.IMiscHelpers; import me.desht.pneumaticcraft.api.pneumatic_armor.hacking.IActiveEntityHacks; import me.desht.pneumaticcraft.common.block.entity.utility.SecurityStationBlockEntity; @@ -54,7 +55,7 @@ public void registerXPFluid(FluidIngredient tag, int liquidToPointRatio) { @Override public void syncGlobalVariable(ServerPlayer player, String varName) { - BlockPos pos = GlobalVariableHelper.getPos(player.getUUID(), varName); + BlockPos pos = getGlobalVariableHelper().getPos(player.getUUID(), varName); NetworkHandler.sendToPlayer(PacketSetGlobalVariable.forPos(varName, pos), player); // TODO should we sync item variables too? // right now there isn't really a need for it, so it would just be extra network chatter @@ -98,4 +99,9 @@ public ParticleOptions airParticle() { public Optional getHackingForEntity(Entity entity, boolean create) { return create ? HackManager.getOrCreateActiveHacks(entity) : HackManager.getActiveHacks(entity); } + + @Override + public IGlobalVariableHelper getGlobalVariableHelper() { + return GlobalVariableHelper.getInstance(); + } } diff --git a/src/main/java/me/desht/pneumaticcraft/common/commands/ModCommands.java b/src/main/java/me/desht/pneumaticcraft/common/commands/ModCommands.java index 3409885ad..c0a759bf2 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/commands/ModCommands.java +++ b/src/main/java/me/desht/pneumaticcraft/common/commands/ModCommands.java @@ -241,8 +241,8 @@ private static int listGlobalVars(CommandContext ctx) { Collection varNames = GlobalVariableManager.getInstance().getAllActiveVariableNames(playerEntity); source.sendSuccess(() -> Component.literal(varNames.size() + " vars").withStyle(ChatFormatting.GREEN, ChatFormatting.UNDERLINE), false); varNames.stream().sorted().forEach(var -> { - BlockPos pos = GlobalVariableHelper.getPos(id, var); - ItemStack stack = GlobalVariableHelper.getStack(id, var); + BlockPos pos = GlobalVariableHelper.getInstance().getPos(id, var); + ItemStack stack = GlobalVariableHelper.getInstance().getStack(id, var); String val = PneumaticCraftUtils.posToString(pos) + (stack.isEmpty() ? "" : " / " + PneumaticCraftUtils.getRegistryName(stack.getItem()).orElse(UNKNOWN_ITEM)); source.sendSuccess(() -> Component.literal(var).append(" = [").append(val).append("]"), false); }); @@ -252,15 +252,15 @@ private static int listGlobalVars(CommandContext ctx) { private static int getGlobalVar(CommandContext ctx, String varName0) { CommandSourceStack source = ctx.getSource(); String varName; - if (!GlobalVariableHelper.hasPrefix(varName0)) { + if (!GlobalVariableHelper.getInstance().hasPrefix(varName0)) { source.sendSuccess(() -> xlate("pneumaticcraft.command.globalVariable.prefixReminder", varName0).withStyle(ChatFormatting.GOLD), false); varName = "#" + varName0; } else { varName = varName0; } UUID id = varName.startsWith("%") || !(ctx.getSource().getEntity() instanceof Player player) ? null : player.getUUID(); - BlockPos pos = GlobalVariableHelper.getPos(id, varName); - ItemStack stack = GlobalVariableHelper.getStack(id, varName); + BlockPos pos = GlobalVariableHelper.getInstance().getPos(id, varName); + ItemStack stack = GlobalVariableHelper.getInstance().getStack(id, varName); String val = PneumaticCraftUtils.posToString(pos) + (stack.isEmpty() ? "" : " / " + PneumaticCraftUtils.getRegistryName(stack.getItem()).orElse(UNKNOWN_ITEM)); if (pos == null && stack.isEmpty()) { source.sendFailure(xlate("pneumaticcraft.command.globalVariable.missing", varName)); @@ -275,7 +275,7 @@ private static int setGlobalVar(CommandContext ctx, String v CommandSourceStack source = ctx.getSource(); String varName; - if (!GlobalVariableHelper.hasPrefix(varName0)) { + if (!GlobalVariableHelper.getInstance().hasPrefix(varName0)) { source.sendSuccess(() -> xlate("pneumaticcraft.command.globalVariable.prefixReminder", varName0).withStyle(ChatFormatting.GOLD), false); varName = "#" + varName0; } else { @@ -286,11 +286,11 @@ private static int setGlobalVar(CommandContext ctx, String v UUID id = varName.startsWith("%") ? null : ctx.getSource().getPlayerOrException().getUUID(); final String v = varName; posOrItem.ifLeft(pos -> { - GlobalVariableHelper.setPos(id, v, pos); + GlobalVariableHelper.getInstance().setPos(id, v, pos); source.sendSuccess(() -> xlate("pneumaticcraft.command.globalVariable.output", v, PneumaticCraftUtils.posToString(pos)), true); }).ifRight(item -> { ItemStack stack = new ItemStack(item.getItem()); - GlobalVariableHelper.setStack(id, v, stack); + GlobalVariableHelper.getInstance().setStack(id, v, stack); source.sendSuccess(() -> xlate("pneumaticcraft.command.globalVariable.output", v, PneumaticCraftUtils.getRegistryName(stack.getItem()).orElse(UNKNOWN_ITEM)), true); }); } catch (CommandSyntaxException e) { @@ -304,7 +304,7 @@ private static int delGlobalVar(CommandContext ctx, String v CommandSourceStack source = ctx.getSource(); String varName; - if (!GlobalVariableHelper.hasPrefix(varName0)) { + if (!GlobalVariableHelper.getInstance().hasPrefix(varName0)) { source.sendSuccess(() -> xlate("pneumaticcraft.command.globalVariable.prefixReminder", varName0).withStyle(ChatFormatting.GOLD), false); varName = "#" + varName0; } else { @@ -313,11 +313,11 @@ private static int delGlobalVar(CommandContext ctx, String v try { UUID id = varName.startsWith("%") ? null : ctx.getSource().getPlayerOrException().getUUID(); - if (GlobalVariableHelper.getPos(id, varName) == null && GlobalVariableHelper.getStack(id, varName).isEmpty()) { + if (GlobalVariableHelper.getInstance().getPos(id, varName) == null && GlobalVariableHelper.getInstance().getStack(id, varName).isEmpty()) { source.sendFailure(xlate("pneumaticcraft.command.globalVariable.missing", varName)); } else { - GlobalVariableHelper.setPos(id, varName, null); - GlobalVariableHelper.setStack(id, varName, ItemStack.EMPTY); + GlobalVariableHelper.getInstance().setPos(id, varName, null); + GlobalVariableHelper.getInstance().setStack(id, varName, ItemStack.EMPTY); // global var deletions need to get sync'd to players; syncing normally happens when remote/gps tool/etc GUI's // are opened, but deleted vars won't get sync'd there, so could wrongly hang around on the client if (id != null) { diff --git a/src/main/java/me/desht/pneumaticcraft/common/drone/ai/DroneAIManager.java b/src/main/java/me/desht/pneumaticcraft/common/drone/ai/DroneAIManager.java index d7cd7bf66..24e1fcc25 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/drone/ai/DroneAIManager.java +++ b/src/main/java/me/desht/pneumaticcraft/common/drone/ai/DroneAIManager.java @@ -21,10 +21,10 @@ import me.desht.pneumaticcraft.api.drone.IDrone; import me.desht.pneumaticcraft.api.drone.IProgWidget; import me.desht.pneumaticcraft.api.drone.SpecialVariableRetrievalEvent; +import me.desht.pneumaticcraft.api.misc.IVariableProvider; import me.desht.pneumaticcraft.common.config.ConfigHelper; import me.desht.pneumaticcraft.common.drone.IDroneBase; import me.desht.pneumaticcraft.common.drone.progwidgets.IJumpBackWidget; -import me.desht.pneumaticcraft.common.drone.progwidgets.IVariableProvider; import me.desht.pneumaticcraft.common.drone.progwidgets.IVariableWidget; import me.desht.pneumaticcraft.common.drone.progwidgets.ProgWidgetStart; import me.desht.pneumaticcraft.common.item.ItemRegistry; @@ -187,7 +187,7 @@ public Optional getCoordinate(UUID id, String varName) { NeoForge.EVENT_BUS.post(event); return Optional.ofNullable(event.getCoordinate()); } else if (varName.startsWith("%") || varName.startsWith("#")) { - return Optional.ofNullable(GlobalVariableHelper.getPos(drone.getOwnerUUID(), varName)); + return Optional.ofNullable(GlobalVariableHelper.getInstance().getPos(drone.getOwnerUUID(), varName)); } else { return Optional.ofNullable(coordinateVariables.get(varName)); } @@ -201,7 +201,7 @@ public ItemStack getStack(UUID id, String varName) { NeoForge.EVENT_BUS.post(event); item = event.getItem(); } else if (varName.startsWith("#") || varName.startsWith("%")) { - item = GlobalVariableHelper.getStack(drone.getOwnerUUID(), varName); + item = GlobalVariableHelper.getInstance().getStack(drone.getOwnerUUID(), varName); } else { item = itemVariables.getOrDefault(varName, ItemStack.EMPTY); } @@ -210,7 +210,7 @@ public ItemStack getStack(UUID id, String varName) { public void setCoordinate(String variable, BlockPos coord) { if (variable.startsWith("%") || variable.startsWith("#")) { - GlobalVariableHelper.setPos(drone.getOwnerUUID(), variable, coord); + GlobalVariableHelper.getInstance().setPos(drone.getOwnerUUID(), variable, coord); } else if (!variable.startsWith("$")) { coordinateVariables.put(variable, coord); drone.onVariableChanged(variable, true); @@ -219,7 +219,7 @@ public void setCoordinate(String variable, BlockPos coord) { public void setItemStack(String varName, @Nonnull ItemStack item) { if (varName.startsWith("#")) { - GlobalVariableHelper.setStack(drone.getOwnerUUID(), varName, item); + GlobalVariableHelper.getInstance().setStack(drone.getOwnerUUID(), varName, item); } else if (!varName.startsWith("$")) { itemVariables.put(varName, item); drone.onVariableChanged(varName, false); diff --git a/src/main/java/me/desht/pneumaticcraft/common/drone/progwidgets/ProgWidgetArea.java b/src/main/java/me/desht/pneumaticcraft/common/drone/progwidgets/ProgWidgetArea.java index 9c501cbee..808465d7d 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/drone/progwidgets/ProgWidgetArea.java +++ b/src/main/java/me/desht/pneumaticcraft/common/drone/progwidgets/ProgWidgetArea.java @@ -27,6 +27,7 @@ import me.desht.pneumaticcraft.api.drone.area.AreaType; import me.desht.pneumaticcraft.api.drone.area.AreaTypeSerializer; import me.desht.pneumaticcraft.api.drone.area.AreaTypeWidget; +import me.desht.pneumaticcraft.api.misc.IVariableProvider; import me.desht.pneumaticcraft.api.registry.PNCRegistries; import me.desht.pneumaticcraft.common.config.ConfigHelper; import me.desht.pneumaticcraft.common.drone.ai.DroneAIManager; @@ -38,7 +39,6 @@ import me.desht.pneumaticcraft.lib.Textures; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; diff --git a/src/main/java/me/desht/pneumaticcraft/common/entity/semiblock/AbstractSemiblockEntity.java b/src/main/java/me/desht/pneumaticcraft/common/entity/semiblock/AbstractSemiblockEntity.java index 52325ab40..4f623a637 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/entity/semiblock/AbstractSemiblockEntity.java +++ b/src/main/java/me/desht/pneumaticcraft/common/entity/semiblock/AbstractSemiblockEntity.java @@ -194,7 +194,7 @@ public BlockPos getBlockPos() { @Override public void setPos(double x, double y, double z) { // a semiblock is positioned when added to world, and not again - if (!isAddedToWorld()) { + if (!isAddedToLevel()) { super.setPos(x, y, z); this.blockPos = BlockPos.containing(x, y, z); } @@ -323,8 +323,8 @@ public boolean isValid() { } @Override - public void onAddedToWorld() { - super.onAddedToWorld(); + public void onAddedToLevel() { + super.onAddedToLevel(); Level level = level(); if (!level.isClientSide) { @@ -339,7 +339,7 @@ public void onAddedToWorld() { } @Override - public void onRemovedFromWorld() { + public void onRemovedFromLevel() { Level level = level(); if (!level.isClientSide) { Direction dir = this instanceof IDirectionalSemiblock d ? d.getSide() : null; @@ -358,7 +358,7 @@ public void onRemovedFromWorld() { doExtraCleanupTasks(beingRemoved); - super.onRemovedFromWorld(); + super.onRemovedFromLevel(); } /** @@ -380,7 +380,7 @@ public boolean isPickable() { @Override public int getTrackingId() { - return isAddedToWorld() ? getId() : -1; + return isAddedToLevel() ? getId() : -1; } @Override diff --git a/src/main/java/me/desht/pneumaticcraft/common/inventory/RemoteMenu.java b/src/main/java/me/desht/pneumaticcraft/common/inventory/RemoteMenu.java index bed694cb3..ba527c5d2 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/inventory/RemoteMenu.java +++ b/src/main/java/me/desht/pneumaticcraft/common/inventory/RemoteMenu.java @@ -17,22 +17,16 @@ package me.desht.pneumaticcraft.common.inventory; -import me.desht.pneumaticcraft.client.gui.remote.RemoteLayout; -import me.desht.pneumaticcraft.client.gui.remote.actionwidget.ActionWidgetVariable; import me.desht.pneumaticcraft.common.block.entity.AbstractPneumaticCraftBlockEntity; -import me.desht.pneumaticcraft.common.item.RemoteItem; import me.desht.pneumaticcraft.common.network.NetworkHandler; import me.desht.pneumaticcraft.common.network.PacketSetGlobalVariable; import me.desht.pneumaticcraft.common.registry.ModItems; import me.desht.pneumaticcraft.common.registry.ModMenuTypes; +import me.desht.pneumaticcraft.common.remote.SavedRemoteLayout; import me.desht.pneumaticcraft.common.util.PneumaticCraftUtils; import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; -import me.desht.pneumaticcraft.common.variables.TextVariableParser; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; @@ -42,7 +36,10 @@ import net.minecraft.world.item.ItemStack; import javax.annotation.Nonnull; -import java.util.*; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; @@ -50,31 +47,28 @@ public class RemoteMenu extends AbstractPneumaticCraftMenu syncedVars; private final BlockPos[] lastValues; private final InteractionHand hand; - public final String[] variables; + private final List allKnownGlobalVars; private final UUID playerId; public RemoteMenu(MenuType type, int windowId, Inventory playerInventory, InteractionHand hand) { super(type, windowId, playerInventory); this.hand = hand; - this.variables = new String[0]; + this.allKnownGlobalVars = List.of(); this.playerId = playerInventory.player.getUUID(); - this.syncedVars = new ArrayList<>(getRelevantVariableNames(playerInventory.player, playerInventory.player.getItemInHand(hand))); + this.syncedVars = List.copyOf(getRelevantVariableNames(playerInventory.player, playerInventory.player.getItemInHand(hand))); this.lastValues = new BlockPos[syncedVars.size()]; } private RemoteMenu(MenuType type, int windowId, Inventory playerInventory, FriendlyByteBuf buffer) { super(type, windowId, playerInventory); - this.hand = buffer.readBoolean() ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; - - this.variables = new String[buffer.readVarInt()]; - for (int i = 0; i < variables.length; i++) { - variables[i] = buffer.readUtf(); - } + // see RemoteItem#toBytes for corresponding serialization + this.hand = buffer.readEnum(InteractionHand.class); + this.allKnownGlobalVars = buffer.readList(FriendlyByteBuf::readUtf); this.playerId = playerInventory.player.getUUID(); - this.syncedVars = new ArrayList<>(getRelevantVariableNames(playerInventory.player, playerInventory.player.getItemInHand(hand))); + this.syncedVars = List.copyOf(getRelevantVariableNames(playerInventory.player, playerInventory.player.getItemInHand(hand))); this.lastValues = new BlockPos[syncedVars.size()]; } @@ -87,15 +81,15 @@ public static RemoteMenu createRemoteEditorContainer(int windowId, Inventory pla } private Set getRelevantVariableNames(Player player, @Nonnull ItemStack remote) { - RemoteLayout layout = RemoteLayout.fromNBT(player.registryAccess(), RemoteItem.getSavedLayout(remote)); + SavedRemoteLayout layout = SavedRemoteLayout.fromItem(remote); Set variables = new HashSet<>(); - layout.getActionWidgets().forEach(w -> w.discoverVariables(variables, playerId)); + layout.getWidgets().forEach(w -> w.discoverVariables(variables, playerId)); Set result = new HashSet<>(); variables.forEach(varName -> { if (!varName.isEmpty()) { - if (!GlobalVariableHelper.hasPrefix(varName)) { + if (!GlobalVariableHelper.getInstance().hasPrefix(varName)) { if (!player.level().isClientSide) { player.displayClientMessage(xlate("pneumaticcraft.command.globalVariable.prefixReminder", varName).withStyle(ChatFormatting.GOLD), false); } @@ -114,7 +108,7 @@ public void broadcastChanges() { for (int i = 0; i < lastValues.length; i++) { String varName = syncedVars.get(i); if (varName.isEmpty()) continue; - BlockPos newValue = GlobalVariableHelper.getPos(playerId, varName); + BlockPos newValue = GlobalVariableHelper.getInstance().getPos(playerId, varName); if (newValue != null && !newValue.equals(lastValues[i])) { lastValues[i] = newValue; ServerPlayer serverPlayer = PneumaticCraftUtils.getPlayerFromId(playerId); @@ -133,4 +127,8 @@ public boolean stillValid(Player player) { public InteractionHand getHand() { return hand; } + + public List allKnownGlobalVars() { + return allKnownGlobalVars; + } } diff --git a/src/main/java/me/desht/pneumaticcraft/common/item/GPSAreaToolItem.java b/src/main/java/me/desht/pneumaticcraft/common/item/GPSAreaToolItem.java index b16d742bb..2b2139b7f 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/item/GPSAreaToolItem.java +++ b/src/main/java/me/desht/pneumaticcraft/common/item/GPSAreaToolItem.java @@ -23,7 +23,6 @@ import me.desht.pneumaticcraft.client.gui.GPSAreaToolScreen; import me.desht.pneumaticcraft.client.util.ClientUtils; import me.desht.pneumaticcraft.common.drone.progwidgets.ProgWidgetArea; -import me.desht.pneumaticcraft.common.drone.progwidgets.SavedDroneProgram; import me.desht.pneumaticcraft.common.registry.ModDataComponents; import me.desht.pneumaticcraft.common.registry.ModItems; import me.desht.pneumaticcraft.common.registry.ModSounds; @@ -127,7 +126,7 @@ public void inventoryTick(ItemStack stack, Level world, Entity entity, int slot, String varName = area.getVarName(index); if (!varName.isEmpty()) { BlockPos curPos = area.getPos(index).orElse(PneumaticCraftUtils.invalidPos()); - BlockPos pos = GlobalVariableHelper.getPos(entity.getUUID(), varName, PneumaticCraftUtils.invalidPos()); + BlockPos pos = GlobalVariableHelper.getInstance().getPos(entity.getUUID(), varName, PneumaticCraftUtils.invalidPos()); if (!curPos.equals(pos)) { setGPSLocation(p, stack, pos, area, index, false); } @@ -141,7 +140,7 @@ public static ProgWidgetArea getArea(UUID playerId, ItemStack stack) { Validate.isTrue(stack.getItem() instanceof GPSAreaToolItem); ProgWidgetArea area = stack.getOrDefault(ModDataComponents.AREA_WIDGET, ProgWidgetArea.Immutable.DEFAULT).toMutable(); - area.setVariableProvider(GlobalVariableHelper.getVariableProvider(), playerId); // allows client to read vars for rendering purposes + area.setVariableProvider(GlobalVariableHelper.getInstance().getVariableProvider(), playerId); // allows client to read vars for rendering purposes return area; } @@ -157,7 +156,7 @@ public static Optional getGPSLocation(Player player, ItemStack gpsTool // if there's a variable set for this index, use its value instead (and update the stored position) String var = area.getVarName(index); if (!var.isEmpty() && !player.level().isClientSide) { - BlockPos newPos = GlobalVariableHelper.getPos(player.getUUID(), var); + BlockPos newPos = GlobalVariableHelper.getInstance().getPos(player.getUUID(), var); if (pos.isEmpty() || !pos.get().equals(newPos)) { area.setPos(index, newPos); setArea(gpsTool, area); @@ -176,7 +175,7 @@ private static void setGPSLocation(Player player, ItemStack gpsTool, BlockPos po if (updateVar) { String varName = area.getVarName(index); if (!varName.isEmpty()) { - GlobalVariableHelper.setPos(player.getUUID(), varName, pos); + GlobalVariableHelper.getInstance().setPos(player.getUUID(), varName, pos); } } } @@ -200,8 +199,8 @@ public void syncVariables(ServerPlayer player, ItemStack stack) { ProgWidgetArea area = getArea(player, stack); String v1 = area.getVarName(0); String v2 = area.getVarName(1); - if (GlobalVariableHelper.hasPrefix(v1)) PneumaticRegistry.getInstance().getMiscHelpers().syncGlobalVariable(player, v1); - if (GlobalVariableHelper.hasPrefix(v2)) PneumaticRegistry.getInstance().getMiscHelpers().syncGlobalVariable(player, v2); + if (GlobalVariableHelper.getInstance().hasPrefix(v1)) PneumaticRegistry.getInstance().getMiscHelpers().syncGlobalVariable(player, v1); + if (GlobalVariableHelper.getInstance().hasPrefix(v2)) PneumaticRegistry.getInstance().getMiscHelpers().syncGlobalVariable(player, v2); } @Override @@ -232,7 +231,7 @@ public void syncFromClient(Player player, ItemStack stack, int index, BlockPos p GPSAreaToolItem.setVariable(player, stack, varName, index); GPSAreaToolItem.setGPSPosAndNotify(player, stack, pos, index); if (!varName.isEmpty()) { - GlobalVariableHelper.setPos(player.getUUID(), varName, pos); + GlobalVariableHelper.getInstance().setPos(player.getUUID(), varName, pos); } } diff --git a/src/main/java/me/desht/pneumaticcraft/common/item/GPSToolItem.java b/src/main/java/me/desht/pneumaticcraft/common/item/GPSToolItem.java index 664cf8d10..55814480f 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/item/GPSToolItem.java +++ b/src/main/java/me/desht/pneumaticcraft/common/item/GPSToolItem.java @@ -104,7 +104,7 @@ public void inventoryTick(ItemStack stack, Level world, Entity entity, int slot, String var = getVariable(stack); if (!var.isEmpty() && !world.isClientSide && entity instanceof Player) { getGPSLocation(entity.getUUID(), stack).ifPresent(curPos -> { - BlockPos varPos = GlobalVariableHelper.getPos(entity.getUUID(), var, PneumaticCraftUtils.invalidPos()); + BlockPos varPos = GlobalVariableHelper.getInstance().getPos(entity.getUUID(), var, PneumaticCraftUtils.invalidPos()); if (!varPos.equals(curPos)) { setGPSLocation(entity.getUUID(), stack, varPos, false); } @@ -123,7 +123,7 @@ public static Optional getGPSLocation(UUID playerId, ItemStack gpsTool if (gpsTool.getItem() == ModItems.GPS_TOOL.get() && curPos != null) { String var = getVariable(gpsTool); if (!var.isEmpty()) { - BlockPos pos = GlobalVariableHelper.getPos(playerId, var); + BlockPos pos = GlobalVariableHelper.getInstance().getPos(playerId, var); if (pos != null && !curPos.equals(pos)) { curPos = pos; setGPSLocation(playerId, gpsTool, pos, false); @@ -144,7 +144,7 @@ public static void setGPSLocation(UUID playerId, ItemStack gpsTool, BlockPos pos if (updateVarManager) { String var = getVariable(gpsTool); if (!var.isEmpty()) { - GlobalVariableHelper.setPos(playerId, var, pos); + GlobalVariableHelper.getInstance().setPos(playerId, var, pos); } } } @@ -170,7 +170,7 @@ public int getRenderColor(int index) { @Override public void syncVariables(ServerPlayer player, ItemStack stack) { String varName = getVariable(stack); - if (GlobalVariableHelper.hasPrefix(varName)) PneumaticRegistry.getInstance().getMiscHelpers().syncGlobalVariable(player, varName); + if (GlobalVariableHelper.getInstance().hasPrefix(varName)) PneumaticRegistry.getInstance().getMiscHelpers().syncGlobalVariable(player, varName); } @Override @@ -178,7 +178,7 @@ public void syncFromClient(Player player, ItemStack stack, int index, BlockPos p GPSToolItem.setVariable(stack, varName); GPSToolItem.setGPSLocation(player.getUUID(), stack, pos); if (!varName.isEmpty()) { - GlobalVariableHelper.setPos(player.getUUID(), varName, pos); + GlobalVariableHelper.getInstance().setPos(player.getUUID(), varName, pos); } } } diff --git a/src/main/java/me/desht/pneumaticcraft/common/item/RemoteItem.java b/src/main/java/me/desht/pneumaticcraft/common/item/RemoteItem.java index 5358dc300..fa7ccee29 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/item/RemoteItem.java +++ b/src/main/java/me/desht/pneumaticcraft/common/item/RemoteItem.java @@ -22,13 +22,12 @@ import me.desht.pneumaticcraft.common.registry.ModDataComponents; import me.desht.pneumaticcraft.common.registry.ModItems; import me.desht.pneumaticcraft.common.registry.ModMenuTypes; +import me.desht.pneumaticcraft.common.remote.SavedRemoteLayout; import me.desht.pneumaticcraft.common.util.GlobalPosHelper; import me.desht.pneumaticcraft.common.variables.GlobalVariableManager; import net.minecraft.ChatFormatting; import net.minecraft.core.BlockPos; import net.minecraft.core.GlobalPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; @@ -44,13 +43,11 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import javax.annotation.Nullable; -import java.util.Collection; import java.util.List; import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; @@ -70,24 +67,27 @@ public InteractionResultHolder use(Level world, Player player, Intera } @Override - public InteractionResult onItemUseFirst(ItemStack remote, UseOnContext ctx) { + public InteractionResult useOn(UseOnContext ctx) { Player player = ctx.getPlayer(); Level world = ctx.getLevel(); BlockPos pos = ctx.getClickedPos(); BlockEntity te = world.getBlockEntity(pos); + ItemStack remote = ctx.getItemInHand(); if (te instanceof SecurityStationBlockEntity teSS && player instanceof ServerPlayer && player.isCrouching() && isAllowedToEdit(player, remote)) { if (teSS.doesAllowPlayer(player)) { GlobalPos gPos = GlobalPosHelper.makeGlobalPos(world, pos); setSecurityStationPos(remote, gPos); - player.displayClientMessage(xlate("pneumaticcraft.gui.remote.boundSecurityStation", GlobalPosHelper.prettyPrint(gPos)), false); - return InteractionResult.SUCCESS; + Component posComp = Component.literal(GlobalPosHelper.prettyPrint(gPos)).withStyle(ChatFormatting.YELLOW); + player.displayClientMessage(xlate("pneumaticcraft.gui.remote.boundSecurityStation", posComp), false); + return InteractionResult.CONSUME; } else { player.displayClientMessage(xlate("pneumaticcraft.gui.remote.cantBindSecurityStation"), true); return InteractionResult.FAIL; } } else if (player instanceof ServerPlayer sp) { openGui(sp, remote, ctx.getHand()); + return InteractionResult.CONSUME; } return InteractionResult.SUCCESS; @@ -120,12 +120,10 @@ private void openGui(ServerPlayer player, ItemStack remote, InteractionHand hand } private void toBytes(FriendlyByteBuf buf, Player player, InteractionHand hand, boolean syncGlobals) { - // see RemoteMenu constructor for corresponding deserialisation - buf.writeBoolean(hand == InteractionHand.MAIN_HAND); + // see RemoteMenu constructor for corresponding deserialization + buf.writeEnum(hand); if (syncGlobals) { - Collection variables = GlobalVariableManager.getInstance().getAllActiveVariableNames(player); - buf.writeVarInt(variables.size()); - variables.forEach(buf::writeUtf); + buf.writeCollection(GlobalVariableManager.getInstance().getAllActiveVariableNames(player), FriendlyByteBuf::writeUtf); } else { buf.writeVarInt(0); } @@ -174,12 +172,8 @@ public void inventoryTick(ItemStack remote, Level world, Entity entity, int slot } } - public static CompoundTag getSavedLayout(ItemStack remote) { - return remote.getOrDefault(ModDataComponents.REMOTE_LAYOUT, CustomData.EMPTY).copyTag(); - } - - public static void setSavedLayout(ItemStack remote, CompoundTag layout) { - remote.set(ModDataComponents.REMOTE_LAYOUT, CustomData.of(layout)); + public static void saveToItem(ItemStack remote, SavedRemoteLayout layout) { + remote.set(ModDataComponents.REMOTE_LAYOUT, layout); } static class RemoteContainerProvider implements MenuProvider { diff --git a/src/main/java/me/desht/pneumaticcraft/common/network/PacketSetGlobalVariable.java b/src/main/java/me/desht/pneumaticcraft/common/network/PacketSetGlobalVariable.java index 0eda6b75c..3c6922ecd 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/network/PacketSetGlobalVariable.java +++ b/src/main/java/me/desht/pneumaticcraft/common/network/PacketSetGlobalVariable.java @@ -18,7 +18,7 @@ package me.desht.pneumaticcraft.common.network; import com.mojang.datafixers.util.Either; -import me.desht.pneumaticcraft.client.gui.RemoteScreen; +import me.desht.pneumaticcraft.client.gui.remote.AbstractRemoteScreen; import me.desht.pneumaticcraft.client.render.area.AreaRenderManager; import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; import net.minecraft.core.BlockPos; @@ -49,14 +49,13 @@ public record PacketSetGlobalVariable(String varName, Either GlobalVariableHelper.setPos(player.getUUID(), message.varName(), pos)) - .ifRight(stack -> GlobalVariableHelper.setStack(player.getUUID(), message.varName(), stack)); + .ifLeft(pos -> GlobalVariableHelper.getInstance().setPos(player.getUUID(), message.varName(), pos)) + .ifRight(stack -> GlobalVariableHelper.getInstance().setStack(player.getUUID(), message.varName(), stack)); if (ctx.flow().isClientbound()) { - RemoteScreen.handleVariableChangeIfOpen(message.varName()); + AbstractRemoteScreen.handleVariableChangeIfOpen(message.varName()); AreaRenderManager.getInstance().clearPosProviderCache(); } } diff --git a/src/main/java/me/desht/pneumaticcraft/common/network/PacketUpdateRemoteLayout.java b/src/main/java/me/desht/pneumaticcraft/common/network/PacketUpdateRemoteLayout.java index d1fbe4a30..1ef76732b 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/network/PacketUpdateRemoteLayout.java +++ b/src/main/java/me/desht/pneumaticcraft/common/network/PacketUpdateRemoteLayout.java @@ -18,31 +18,26 @@ package me.desht.pneumaticcraft.common.network; import me.desht.pneumaticcraft.common.item.RemoteItem; -import me.desht.pneumaticcraft.common.registry.ModDataComponents; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.codec.ByteBufCodecs; +import me.desht.pneumaticcraft.common.remote.SavedRemoteLayout; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.world.InteractionHand; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.component.CustomData; import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs; import net.neoforged.neoforge.network.handling.IPayloadContext; -import java.rmi.Remote; - import static me.desht.pneumaticcraft.api.PneumaticRegistry.RL; /** * Received on: SERVER * Sent by client to update the layout of a Remote item from the Remote GUI */ -public record PacketUpdateRemoteLayout(CompoundTag layout, InteractionHand hand) implements CustomPacketPayload { +public record PacketUpdateRemoteLayout(SavedRemoteLayout layout, InteractionHand hand) implements CustomPacketPayload { public static final Type TYPE = new Type<>(RL("update_remote_layout")); - public static final StreamCodec STREAM_CODEC = StreamCodec.composite( - ByteBufCodecs.COMPOUND_TAG, PacketUpdateRemoteLayout::layout, + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + SavedRemoteLayout.STREAM_CODEC, PacketUpdateRemoteLayout::layout, NeoForgeStreamCodecs.enumCodec(InteractionHand.class), PacketUpdateRemoteLayout::hand, PacketUpdateRemoteLayout::new ); @@ -55,7 +50,7 @@ public Type type() { public static void handle(PacketUpdateRemoteLayout message, IPayloadContext ctx) { ItemStack remote = ctx.player().getItemInHand(message.hand); if (remote.getItem() instanceof RemoteItem) { - RemoteItem.setSavedLayout(remote, message.layout); + RemoteItem.saveToItem(remote, message.layout); } } } diff --git a/src/main/java/me/desht/pneumaticcraft/common/registry/ModDataComponents.java b/src/main/java/me/desht/pneumaticcraft/common/registry/ModDataComponents.java index 3d174dc52..60569a092 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/registry/ModDataComponents.java +++ b/src/main/java/me/desht/pneumaticcraft/common/registry/ModDataComponents.java @@ -13,6 +13,7 @@ import me.desht.pneumaticcraft.common.item.MicromissilesItem; import me.desht.pneumaticcraft.common.item.SpawnerCoreItem; import me.desht.pneumaticcraft.common.network.DronePacket; +import me.desht.pneumaticcraft.common.remote.SavedRemoteLayout; import me.desht.pneumaticcraft.common.upgrades.SavedUpgrades; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -142,8 +143,8 @@ private static Supplier> register(String name, Codec = register("micromissile_settings", MicromissilesItem.Settings.CODEC, MicromissilesItem.Settings.STREAM_CODEC); // Remote Layout - public static final Supplier> REMOTE_LAYOUT - = register("remote_layout", CustomData.CODEC, CustomData.STREAM_CODEC); + public static final Supplier> REMOTE_LAYOUT + = register("remote_layout", SavedRemoteLayout.CODEC, SavedRemoteLayout.STREAM_CODEC); // Remote security station position public static final Supplier> REMOTE_SECSTATION_POS = register("remote_secstation_pos", GlobalPos.CODEC, GlobalPos.STREAM_CODEC); diff --git a/src/main/java/me/desht/pneumaticcraft/common/registry/ModRemoteWidgetTypes.java b/src/main/java/me/desht/pneumaticcraft/common/registry/ModRemoteWidgetTypes.java new file mode 100644 index 000000000..2e7c14ae1 --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/common/registry/ModRemoteWidgetTypes.java @@ -0,0 +1,36 @@ +package me.desht.pneumaticcraft.common.registry; + +import com.mojang.serialization.MapCodec; +import me.desht.pneumaticcraft.api.lib.Names; +import me.desht.pneumaticcraft.api.registry.PNCRegistries; +import me.desht.pneumaticcraft.api.remote.IRemoteWidget; +import me.desht.pneumaticcraft.api.remote.RemoteWidgetType; +import me.desht.pneumaticcraft.common.remote.RemoteWidgetButton; +import me.desht.pneumaticcraft.common.remote.RemoteWidgetCheckbox; +import me.desht.pneumaticcraft.common.remote.RemoteWidgetDropdown; +import me.desht.pneumaticcraft.common.remote.RemoteWidgetLabel; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.neoforged.neoforge.registries.DeferredRegister; + +import java.util.function.Supplier; + +public class ModRemoteWidgetTypes { + public static final DeferredRegister> REMOTE_WIDGETS + = DeferredRegister.create(PNCRegistries.REMOTE_WIDGETS_REGISTRY, Names.MOD_ID); + + public static final Supplier> BUTTON + = register("button", RemoteWidgetButton.CODEC, RemoteWidgetButton.STREAM_CODEC); + public static final Supplier> CHECKBOX + = register("checkbox", RemoteWidgetCheckbox.CODEC, RemoteWidgetCheckbox.STREAM_CODEC); + public static final Supplier> DROPDOWN + = register("dropdown", RemoteWidgetDropdown.CODEC, RemoteWidgetDropdown.STREAM_CODEC); + public static final Supplier> LABEL + = register("label", RemoteWidgetLabel.CODEC, RemoteWidgetLabel.STREAM_CODEC); + + + private static

> Supplier register(String name, MapCodec

codec, StreamCodec streamCodec) { + //noinspection unchecked + return REMOTE_WIDGETS.register(name, () -> (T) new RemoteWidgetType<>(codec, streamCodec)); + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetButton.java b/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetButton.java new file mode 100644 index 000000000..316304f04 --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetButton.java @@ -0,0 +1,53 @@ +package me.desht.pneumaticcraft.common.remote; + +import com.google.common.base.Suppliers; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.desht.pneumaticcraft.api.remote.*; +import me.desht.pneumaticcraft.common.registry.ModRemoteWidgetTypes; +import net.minecraft.core.BlockPos; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; + +import java.util.function.Supplier; + +import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; + +public record RemoteWidgetButton(BaseSettings baseSettings, WidgetSettings widgetSettings, String varName, BlockPos settingPos) implements IRemoteVariableWidget { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(builder -> builder.group( + BaseSettings.CODEC.optionalFieldOf("base", BaseSettings.DEFAULT).forGetter(RemoteWidgetButton::baseSettings), + WidgetSettings.CODEC.fieldOf("widget").forGetter(RemoteWidgetButton::widgetSettings), + Codec.STRING.optionalFieldOf("var_name", "").forGetter(RemoteWidgetButton::varName), + BlockPos.CODEC.optionalFieldOf("set_pos", BlockPos.ZERO).forGetter(RemoteWidgetButton::settingPos) + ).apply(builder, RemoteWidgetButton::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BaseSettings.STREAM_CODEC, RemoteWidgetButton::baseSettings, + WidgetSettings.STREAM_CODEC, RemoteWidgetButton::widgetSettings, + ByteBufCodecs.STRING_UTF8, RemoteWidgetButton::varName, + BlockPos.STREAM_CODEC, RemoteWidgetButton::settingPos, + RemoteWidgetButton::new + ); + public static final Supplier TRAY = Suppliers.memoize(() -> new RemoteWidgetButton( + BaseSettings.DEFAULT, + new WidgetSettings(TRAY_WIDGET_X, 53, 50, 20, + xlate(IRemoteWidget.getTranslationKey(ModRemoteWidgetTypes.BUTTON.get())), + xlate(IRemoteWidget.getTooltipTranslationKey(ModRemoteWidgetTypes.BUTTON.get())) + ), + "", + BlockPos.ZERO + )); + + @Override + public RemoteWidgetButton copyToPos(int x, int y) { + return new RemoteWidgetButton(baseSettings, widgetSettings.copyToPos(x, y), varName, settingPos); + } + + @Override + public RemoteWidgetType getType() { + return ModRemoteWidgetTypes.BUTTON.get(); + } + +} diff --git a/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetCheckbox.java b/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetCheckbox.java new file mode 100644 index 000000000..14732ce52 --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetCheckbox.java @@ -0,0 +1,48 @@ +package me.desht.pneumaticcraft.common.remote; + +import com.google.common.base.Suppliers; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.desht.pneumaticcraft.api.remote.*; +import me.desht.pneumaticcraft.common.registry.ModRemoteWidgetTypes; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; + +import java.util.function.Supplier; + +import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; + +public record RemoteWidgetCheckbox(BaseSettings baseSettings, WidgetSettings widgetSettings, String varName) implements IRemoteVariableWidget { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(builder -> builder.group( + BaseSettings.CODEC.optionalFieldOf("base", BaseSettings.DEFAULT).forGetter(RemoteWidgetCheckbox::baseSettings), + WidgetSettings.CODEC.fieldOf("widget").forGetter(RemoteWidgetCheckbox::widgetSettings), + Codec.STRING.optionalFieldOf("var_name", "").forGetter(RemoteWidgetCheckbox::varName) + ).apply(builder, RemoteWidgetCheckbox::new)); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BaseSettings.STREAM_CODEC, RemoteWidgetCheckbox::baseSettings, + WidgetSettings.STREAM_CODEC, RemoteWidgetCheckbox::widgetSettings, + ByteBufCodecs.STRING_UTF8, RemoteWidgetCheckbox::varName, + RemoteWidgetCheckbox::new + ); + public static final Supplier TRAY = Suppliers.memoize(() -> new RemoteWidgetCheckbox( + BaseSettings.DEFAULT, + new WidgetSettings(TRAY_WIDGET_X, 23, 50, 20, + xlate(IRemoteWidget.getTranslationKey(ModRemoteWidgetTypes.CHECKBOX.get())), + xlate(IRemoteWidget.getTooltipTranslationKey(ModRemoteWidgetTypes.CHECKBOX.get())) + ), + "" + )); + + @Override + public RemoteWidgetCheckbox copyToPos(int x, int y) { + return new RemoteWidgetCheckbox(baseSettings, widgetSettings.copyToPos(x, y), varName); + } + + @Override + public RemoteWidgetType getType() { + return ModRemoteWidgetTypes.CHECKBOX.get(); + } + +} diff --git a/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetDropdown.java b/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetDropdown.java new file mode 100644 index 000000000..30aa7f97e --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetDropdown.java @@ -0,0 +1,69 @@ +package me.desht.pneumaticcraft.common.remote; + +import com.google.common.base.Suppliers; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.desht.pneumaticcraft.api.remote.*; +import me.desht.pneumaticcraft.client.util.ClientUtils; +import me.desht.pneumaticcraft.common.registry.ModRemoteWidgetTypes; +import me.desht.pneumaticcraft.common.variables.GlobalVariableHelper; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.util.Mth; + +import java.util.List; +import java.util.function.Supplier; + +import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; + +public record RemoteWidgetDropdown(BaseSettings baseSettings, WidgetSettings widgetSettings, String varName, List elements, boolean sorted) implements IRemoteVariableWidget { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(builder -> builder.group( + BaseSettings.CODEC.optionalFieldOf("base", BaseSettings.DEFAULT).forGetter(RemoteWidgetDropdown::baseSettings), + WidgetSettings.CODEC.fieldOf("widget").forGetter(RemoteWidgetDropdown::widgetSettings), + Codec.STRING.optionalFieldOf("var_name", "").forGetter(RemoteWidgetDropdown::varName), + Codec.STRING.listOf().fieldOf("elements").forGetter(RemoteWidgetDropdown::elements), + Codec.BOOL.optionalFieldOf("sorted", false).forGetter(RemoteWidgetDropdown::sorted) + ).apply(builder, RemoteWidgetDropdown::new)); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BaseSettings.STREAM_CODEC, RemoteWidgetDropdown::baseSettings, + WidgetSettings.STREAM_CODEC, RemoteWidgetDropdown::widgetSettings, + ByteBufCodecs.STRING_UTF8, RemoteWidgetDropdown::varName, + ByteBufCodecs.STRING_UTF8.apply(ByteBufCodecs.list()), RemoteWidgetDropdown::elements, + ByteBufCodecs.BOOL, RemoteWidgetDropdown::sorted, + RemoteWidgetDropdown::new + ); + public static final Supplier TRAY = Suppliers.memoize(() -> new RemoteWidgetDropdown( + BaseSettings.DEFAULT, + new WidgetSettings(TRAY_WIDGET_X, 79, 70, 20, + xlate(IRemoteWidget.getTranslationKey(ModRemoteWidgetTypes.CHECKBOX.get())), + xlate(IRemoteWidget.getTooltipTranslationKey(ModRemoteWidgetTypes.DROPDOWN.get())) + ), + "", List.of(), false + )); + + @Override + public boolean hasConfigurableText() { + return false; + } + + @Override + public RemoteWidgetDropdown copyToPos(int x, int y) { + return new RemoteWidgetDropdown(baseSettings, widgetSettings.copyToPos(x, y), varName, List.copyOf(elements), sorted); + } + + @Override + public RemoteWidgetType getType() { + return ModRemoteWidgetTypes.DROPDOWN.get(); + } + + public String getSelectedElement() { + if (elements.isEmpty()) { + return ""; + } else { + int idx = GlobalVariableHelper.INSTANCE.getInt(ClientUtils.getClientPlayer().getUUID(), varName); + return elements.get(Mth.clamp(idx, 0, elements.size() - 1)); + } + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetLabel.java b/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetLabel.java new file mode 100644 index 000000000..cdaa05059 --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/common/remote/RemoteWidgetLabel.java @@ -0,0 +1,46 @@ +package me.desht.pneumaticcraft.common.remote; + +import com.google.common.base.Suppliers; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.desht.pneumaticcraft.api.remote.BaseSettings; +import me.desht.pneumaticcraft.api.remote.IRemoteWidget; +import me.desht.pneumaticcraft.api.remote.RemoteWidgetType; +import me.desht.pneumaticcraft.api.remote.WidgetSettings; +import me.desht.pneumaticcraft.common.registry.ModRemoteWidgetTypes; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; + +import java.util.function.Supplier; + +import static me.desht.pneumaticcraft.common.util.PneumaticCraftUtils.xlate; + +public record RemoteWidgetLabel(BaseSettings baseSettings, WidgetSettings widgetSettings) implements IRemoteWidget { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(builder -> builder.group( + BaseSettings.CODEC.optionalFieldOf("base", BaseSettings.DEFAULT).forGetter(RemoteWidgetLabel::baseSettings), + WidgetSettings.CODEC.fieldOf("widget").forGetter(RemoteWidgetLabel::widgetSettings) + ).apply(builder, RemoteWidgetLabel::new)); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BaseSettings.STREAM_CODEC, RemoteWidgetLabel::baseSettings, + WidgetSettings.STREAM_CODEC, RemoteWidgetLabel::widgetSettings, + RemoteWidgetLabel::new + ); + public static final Supplier TRAY = Suppliers.memoize(() -> new RemoteWidgetLabel( + BaseSettings.DEFAULT, + new WidgetSettings(TRAY_WIDGET_X, 38, 50, 20, + xlate(IRemoteWidget.getTranslationKey(ModRemoteWidgetTypes.LABEL.get())), + xlate(IRemoteWidget.getTooltipTranslationKey(ModRemoteWidgetTypes.LABEL.get())) + ) + )); + + @Override + public RemoteWidgetLabel copyToPos(int x, int y) { + return new RemoteWidgetLabel(baseSettings, widgetSettings.copyToPos(x, y)); + } + + @Override + public RemoteWidgetType getType() { + return ModRemoteWidgetTypes.LABEL.get(); + } + +} diff --git a/src/main/java/me/desht/pneumaticcraft/common/remote/SavedRemoteLayout.java b/src/main/java/me/desht/pneumaticcraft/common/remote/SavedRemoteLayout.java new file mode 100644 index 000000000..8f4bf9439 --- /dev/null +++ b/src/main/java/me/desht/pneumaticcraft/common/remote/SavedRemoteLayout.java @@ -0,0 +1,89 @@ +package me.desht.pneumaticcraft.common.remote; + +import com.google.gson.JsonElement; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.desht.pneumaticcraft.api.remote.IRemoteWidget; +import me.desht.pneumaticcraft.common.registry.ModDataComponents; +import me.desht.pneumaticcraft.lib.Log; +import net.minecraft.core.HolderLookup; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.RegistryOps; +import net.minecraft.world.item.ItemStack; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +public class SavedRemoteLayout { + public static final int JSON_VERSION = 2; + + public static final Codec CODEC = RecordCodecBuilder.create(builder -> builder.group( + IRemoteWidget.CODEC.listOf().fieldOf("widgets").forGetter(s -> s.widgets) + ).apply(builder, SavedRemoteLayout::new)); + + public static final Codec VERSIONED_CODEC = RecordCodecBuilder.create(builder -> builder.group( + Codec.INT.fieldOf("version").forGetter(Versioned::version), + IRemoteWidget.CODEC.listOf().fieldOf("widgets").forGetter(Versioned::widgets) + ).apply(builder, Versioned::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + IRemoteWidget.STREAM_CODEC.apply(ByteBufCodecs.list()), s -> s.widgets, + SavedRemoteLayout::new + ); + + public static final SavedRemoteLayout EMPTY = new SavedRemoteLayout(List.of()); + + private final List widgets; // note: immutable! + + public SavedRemoteLayout(Collection widgets) { + this.widgets = List.copyOf(widgets); + } + + public static SavedRemoteLayout fromJson(HolderLookup.Provider provider, JsonElement json) { + RegistryOps ops = provider.createSerializationContext(JsonOps.INSTANCE); + return VERSIONED_CODEC.parse(ops, json) + .resultOrPartial(err -> Log.warning("can't parse remote layout JSON: " + err)) + .map(v -> new SavedRemoteLayout(v.widgets())) + .orElse(EMPTY); + } + + public JsonElement toJson(HolderLookup.Provider provider) { + RegistryOps ops = provider.createSerializationContext(JsonOps.INSTANCE); + SavedRemoteLayout.Versioned saved = new SavedRemoteLayout.Versioned(JSON_VERSION, widgets); + + return SavedRemoteLayout.VERSIONED_CODEC.encodeStart(ops, saved).result().orElseThrow(); + } + + public static SavedRemoteLayout fromItem(ItemStack stack) { + return stack.getOrDefault(ModDataComponents.REMOTE_LAYOUT, SavedRemoteLayout.EMPTY); + } + + public List getWidgets() { + return widgets; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (SavedRemoteLayout) obj; + return Objects.equals(this.widgets, that.widgets); + } + + @Override + public int hashCode() { + return Objects.hash(widgets); + } + + @Override + public String toString() { + return "Saved[" + "widgets=" + widgets + ']'; + } + + public record Versioned(int version, List widgets) { + } +} diff --git a/src/main/java/me/desht/pneumaticcraft/common/sensor/pollSensors/WorldGlobalVariableAnalogSensor.java b/src/main/java/me/desht/pneumaticcraft/common/sensor/pollSensors/WorldGlobalVariableAnalogSensor.java index e9f196762..7c78bd001 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/sensor/pollSensors/WorldGlobalVariableAnalogSensor.java +++ b/src/main/java/me/desht/pneumaticcraft/common/sensor/pollSensors/WorldGlobalVariableAnalogSensor.java @@ -30,6 +30,6 @@ public String getSensorPath() { @Override public int getRedstoneValue(Level level, BlockPos pos, int sensorRange, String textBoxText) { - return Mth.clamp(GlobalVariableHelper.getInt(playerID, textBoxText), 0, 15); + return Mth.clamp(GlobalVariableHelper.getInstance().getInt(playerID, textBoxText), 0, 15); } } diff --git a/src/main/java/me/desht/pneumaticcraft/common/sensor/pollSensors/WorldGlobalVariableSensor.java b/src/main/java/me/desht/pneumaticcraft/common/sensor/pollSensors/WorldGlobalVariableSensor.java index 5cb526c46..d7dfebb46 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/sensor/pollSensors/WorldGlobalVariableSensor.java +++ b/src/main/java/me/desht/pneumaticcraft/common/sensor/pollSensors/WorldGlobalVariableSensor.java @@ -58,7 +58,7 @@ public int getPollFrequency(BlockEntity te) { @Override public int getRedstoneValue(Level level, BlockPos pos, int sensorRange, String textBoxText) { - return GlobalVariableHelper.getBool(playerID, textBoxText) ? 15 : 0; + return GlobalVariableHelper.getInstance().getBool(playerID, textBoxText) ? 15 : 0; } @Override diff --git a/src/main/java/me/desht/pneumaticcraft/common/util/legacyconv/ActionWidgetLegacyConv.java b/src/main/java/me/desht/pneumaticcraft/common/util/legacyconv/ActionWidgetLegacyConv.java index a14b5cc3a..caf5c9af0 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/util/legacyconv/ActionWidgetLegacyConv.java +++ b/src/main/java/me/desht/pneumaticcraft/common/util/legacyconv/ActionWidgetLegacyConv.java @@ -4,7 +4,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; -import me.desht.pneumaticcraft.client.gui.remote.RemoteLayout; +import me.desht.pneumaticcraft.api.lib.Names; +import me.desht.pneumaticcraft.common.remote.SavedRemoteLayout; import me.desht.pneumaticcraft.lib.Log; import static me.desht.pneumaticcraft.common.util.legacyconv.ConversionUtil.*; @@ -52,7 +53,7 @@ private static void convertFromV1(JsonObject json) { newEntry.add("base", base); newEntry.add("widget", widget); - getString(oldEntry, "id").ifPresent(val -> newEntry.addProperty("type", val)); + getString(oldEntry, "id").ifPresent(val -> newEntry.addProperty("type", Names.MOD_ID + ":" + val)); getString(oldEntry, "variableName").ifPresent(val -> newEntry.addProperty("var_name", prefixVar(val))); convXYZ(oldEntry, newEntry, "setting", "set_pos"); getString(oldEntry, "dropDownElements").ifPresent(val -> newEntry.addProperty("elements", val)); @@ -61,9 +62,9 @@ private static void convertFromV1(JsonObject json) { newDoc.add(newEntry); } - json.add("action_widgets", newDoc); + json.add("widgets", newDoc); json.remove("main"); - json.addProperty("version", RemoteLayout.JSON_VERSION); + json.addProperty("version", SavedRemoteLayout.JSON_VERSION); Log.info("Pastebin Remote import (V1 -> V2): converted {} legacy widgets", newDoc.size()); } diff --git a/src/main/java/me/desht/pneumaticcraft/common/util/playerfilter/PlayerFilter.java b/src/main/java/me/desht/pneumaticcraft/common/util/playerfilter/PlayerFilter.java index d821f62d8..855be08bb 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/util/playerfilter/PlayerFilter.java +++ b/src/main/java/me/desht/pneumaticcraft/common/util/playerfilter/PlayerFilter.java @@ -32,10 +32,6 @@ import java.util.List; import java.util.stream.Collectors; -/** - * A player filter is a collection of individual matcher objects with either match-any or match-all behaviour. - * Custom matcher objects can be registered and have full codec/stream-codec support, so can be used in recipes etc. - */ public record PlayerFilter(Op op, List matchers) implements IPlayerFilter { public static final Codec CODEC = RecordCodecBuilder.create(inst -> inst.group( StringRepresentable.fromEnum(Op::values).fieldOf("op").forGetter(PlayerFilter::op), diff --git a/src/main/java/me/desht/pneumaticcraft/common/variables/GlobalVariableHelper.java b/src/main/java/me/desht/pneumaticcraft/common/variables/GlobalVariableHelper.java index a7a314e10..20a5668cc 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/variables/GlobalVariableHelper.java +++ b/src/main/java/me/desht/pneumaticcraft/common/variables/GlobalVariableHelper.java @@ -1,28 +1,26 @@ package me.desht.pneumaticcraft.common.variables; -import me.desht.pneumaticcraft.common.drone.progwidgets.IVariableProvider; +import me.desht.pneumaticcraft.api.misc.IGlobalVariableHelper; +import me.desht.pneumaticcraft.api.misc.IVariableProvider; import me.desht.pneumaticcraft.lib.Log; import net.minecraft.core.BlockPos; import net.minecraft.world.item.ItemStack; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; - -public class GlobalVariableHelper { - /** - * Retrieve a blockpos variable from the GVM. The variable may start with "#" or "%" to indicate player-global - * or global respectively. Missing prefix defaults to player-global. - * @param id the ID of the owning player (ignored for "%" global variables) - * @param varName the variable name, optionally prefixed with "%" or "#" - * @param def default value if not present in the GVM - * @return the variable's value - */ - public static BlockPos getPos(@Nullable UUID id, String varName, BlockPos def) { + +public enum GlobalVariableHelper implements IGlobalVariableHelper { + INSTANCE; + + public static GlobalVariableHelper getInstance() { + return INSTANCE; + } + + @Override + public BlockPos getPos(@Nullable UUID id, String varName, BlockPos def) { GlobalVariableManager gvm = GlobalVariableManager.getInstance(); if (varName.startsWith("%")) { return gvm.hasPos(varName.substring(1)) ? gvm.getPos(varName.substring(1)) : def; @@ -37,26 +35,13 @@ public static BlockPos getPos(@Nullable UUID id, String varName, BlockPos def) { return gvm.hasPos(id, varName) ? gvm.getPos(id, varName) : def; } - /** - * Retrieve a blockpos variable from the GVM. The variable may start with "#" or "%" to indicate player-global - * or global respectively. Missing prefix defaults to player-global. - * @param id the ID of the owning player (ignored for "%" global variables, must be a valid player UUID otherwise) - * @param varName the variable name, optionally prefixed with "%" or "#" - * @return the variable's value - */ - public static BlockPos getPos(@Nullable UUID id, String varName) { + @Override + public BlockPos getPos(@Nullable UUID id, String varName) { return getPos(id, varName, null); } - /** - * Retrieve an itemstack variable from the GVM. The variable may start with "#" or "%" to indicate player-global - * or global respectively. Missing prefix defaults to player-global "#". - * @param id the ID of the owning player (ignored for "%" global variables, must be a valid player UUID otherwise) - * @param varName the variable name, optionally prefixed with "%" or "#" - * @param def default value if not present in the GVM - * @return the variable's value - */ - public static ItemStack getStack(@Nullable UUID id, String varName, ItemStack def) { + @Override + public ItemStack getStack(@Nullable UUID id, String varName, ItemStack def) { GlobalVariableManager gvm = GlobalVariableManager.getInstance(); if (varName.startsWith("%")) { return gvm.hasStack(varName.substring(1)) ? gvm.getStack(varName.substring(1)) : def; @@ -71,18 +56,13 @@ public static ItemStack getStack(@Nullable UUID id, String varName, ItemStack de return gvm.hasStack(id, varName) ? gvm.getStack(id, varName) : def; } - /** - * Retrieve an itemstack variable from the GVM. The variable may start with "#" or "%" to indicate player-global - * or global respectively. Missing prefix defaults to player-global. - * @param id the ID of the owning player (ignored for "%" global variables, must be a valid player UUID otherwise) - * @param varName the variable name, optionally prefixed with "%" or "#" - * @return the variable's value - */ - public static ItemStack getStack(@Nullable UUID id, String varName) { + @Override + public ItemStack getStack(@Nullable UUID id, String varName) { return getStack(id, varName, ItemStack.EMPTY); } - public static void setPos(UUID id, String varName, BlockPos pos) { + @Override + public void setPos(UUID id, String varName, BlockPos pos) { GlobalVariableManager gvm = GlobalVariableManager.getInstance(); if (varName.startsWith("#") && id != null) { gvm.setPos(id, varName.substring(1), pos); @@ -93,7 +73,8 @@ public static void setPos(UUID id, String varName, BlockPos pos) { } } - public static void setStack(UUID id, String varName, ItemStack stack) { + @Override + public void setStack(UUID id, String varName, ItemStack stack) { GlobalVariableManager gvm = GlobalVariableManager.getInstance(); if (varName.startsWith("#") && id != null) { gvm.setStack(id, varName.substring(1), stack); @@ -104,65 +85,44 @@ public static void setStack(UUID id, String varName, ItemStack stack) { } } - public static boolean getBool(UUID id, String varName) { + @Override + public boolean getBool(UUID id, String varName) { return getInt(id, varName) != 0; } - public static int getInt(UUID id, String varName) { + @Override + public int getInt(UUID id, String varName) { return getPos(id, varName, BlockPos.ZERO).getX(); } - /** - * Given a plain variable name, add the "#" or "%" prefix as appropriate - * @param varName the variable - * @param playerGlobal true if a player-global, false if a server-global - * @return the prefixed var name - */ - public static String getPrefixedVar(String varName, boolean playerGlobal) { + @Override + public String getPrefixedVar(String varName, boolean playerGlobal) { return varName.isEmpty() ? "" : getVarPrefix(playerGlobal) + varName; } - /** - * Get the correct var prefix - * @param playerGlobal true if a player-global, false if a server-global - * @return the var prefix - */ - public static String getVarPrefix(boolean playerGlobal) { + @Override + public String getVarPrefix(boolean playerGlobal) { return playerGlobal ? "#" : "%"; } - /** - * Strip the prefix character from a var name - * @param varName the var name - * @return the var name without a prefix - */ - public static String stripVarPrefix(String varName) { + @Override + public String stripVarPrefix(String varName) { return hasPrefix(varName) ? varName.substring(1) : varName; } - /** - * Check if this varname has a prefix character - * @param varName the var name - * @return true if prefixed, false otherwise - */ - public static boolean hasPrefix(String varName) { + @Override + public boolean hasPrefix(String varName) { return varName.length() > 1 && (varName.startsWith("#") || varName.startsWith("%")); } - /** - * Given a list of prefixed var names, return a corresponding list of var names with a matching prefix character - * @param varnames the var names - * @param playerGlobal true to extract player-global, false for server-global - * @return a list of unprefixed var names - */ - public static List extractVarnames(String[] varnames, boolean playerGlobal) { - return Arrays.stream(varnames) - .filter(v -> playerGlobal && v.startsWith("#") || !playerGlobal && v.startsWith("%")) - .map(v -> v.substring(1)) - .collect(Collectors.toList()); + @Override + public Set getRelevantVariables(String string, UUID playerId) { + TextVariableParser parser = new TextVariableParser(string, playerId); + parser.parse(); + return parser.getRelevantVariables(); } - public static IVariableProvider getVariableProvider() { + public IVariableProvider getVariableProvider() { return VariableProviderWrapper.INSTANCE; } @@ -171,13 +131,13 @@ private enum VariableProviderWrapper implements IVariableProvider { @Override public Optional getCoordinate(UUID id, String varName) { - return Optional.ofNullable(GlobalVariableHelper.getPos(id, varName)); + return Optional.ofNullable(GlobalVariableHelper.INSTANCE.getPos(id, varName)); } @Nonnull @Override public ItemStack getStack(UUID id, String varName) { - return GlobalVariableHelper.getStack(id, varName); + return GlobalVariableHelper.INSTANCE.getStack(id, varName); } } } diff --git a/src/main/java/me/desht/pneumaticcraft/common/variables/TextVariableParser.java b/src/main/java/me/desht/pneumaticcraft/common/variables/TextVariableParser.java index 79b9feffd..46defdffd 100644 --- a/src/main/java/me/desht/pneumaticcraft/common/variables/TextVariableParser.java +++ b/src/main/java/me/desht/pneumaticcraft/common/variables/TextVariableParser.java @@ -17,8 +17,8 @@ package me.desht.pneumaticcraft.common.variables; +import me.desht.pneumaticcraft.api.misc.IVariableProvider; import me.desht.pneumaticcraft.common.drone.ai.DroneAIManager; -import me.desht.pneumaticcraft.common.drone.progwidgets.IVariableProvider; import me.desht.pneumaticcraft.common.util.PneumaticCraftUtils; import net.minecraft.core.BlockPos; import net.minecraft.world.item.ItemStack; @@ -44,7 +44,7 @@ public class TextVariableParser { public TextVariableParser(String str, UUID playerID) { this.orig = str; - this.variableProvider = GlobalVariableHelper.getVariableProvider(); + this.variableProvider = GlobalVariableHelper.getInstance().getVariableProvider(); this.playerID = playerID; } diff --git a/src/main/resources/assets/pneumaticcraft/lang/en_us.json b/src/main/resources/assets/pneumaticcraft/lang/en_us.json index f3f9dfa94..88e8d09ab 100644 --- a/src/main/resources/assets/pneumaticcraft/lang/en_us.json +++ b/src/main/resources/assets/pneumaticcraft/lang/en_us.json @@ -1272,7 +1272,7 @@ "pneumaticcraft.gui.redstone" : "Redstone", "pneumaticcraft.gui.regulatorTube.hudMessage.inverted" : "§cA Regulator Tube Module only regulates air in the direction of the arrow.", "pneumaticcraft.gui.regulatorTube.hudMessage.notInLine" : "§cA Regulator Tube Module only regulates air in line of the module.", - "pneumaticcraft.gui.remote.boundSecurityStation" : "Remote bound to Security Station @ %s. Only players with access to this Station can modify it.", + "pneumaticcraft.gui.remote.boundSecurityStation" : "Remote bound to Security Station @ %s.\nOnly players with access to this Station can modify it.", "pneumaticcraft.gui.remote.button.height" : "Height:", "pneumaticcraft.gui.remote.button.importRemoteButton" : "Import an existing Remote lay-out from another Remote.", "pneumaticcraft.gui.remote.button.pastebinButton" : "Import/Export layout from/to Pastebin.", @@ -1296,14 +1296,14 @@ "pneumaticcraft.gui.remote.tooltip.rightClickToBind" : "If you bind this remote to a Security Station, only players allowed by that Station can edit the Remote.", "pneumaticcraft.gui.remote.tooltip.sneakRightClickToEdit" : "§aSneak right click to edit", "pneumaticcraft.gui.remote.tooltip" : "Tooltip:", - "pneumaticcraft.gui.remote.tray.button.name" : "Button", - "pneumaticcraft.gui.remote.tray.button.tooltip" : "A simple push button which directly assigns it values to the linked variable when clicked.", - "pneumaticcraft.gui.remote.tray.checkbox.name" : "CheckBox", - "pneumaticcraft.gui.remote.tray.checkbox.tooltip" : "A toggleable button which assigns 1 to the linked variable's X value when checked, and 0 when not checked.", - "pneumaticcraft.gui.remote.tray.dropdown.name" : "Drop-down", - "pneumaticcraft.gui.remote.tray.dropdown.tooltip" : "A set of text elements which the user can choose from. The linked variable's X value is set to the (0-based) index of the selected element.", - "pneumaticcraft.gui.remote.tray.label.name" : "Label", - "pneumaticcraft.gui.remote.tray.label.tooltip" : "A text label with an optional tooltip. For informational purposes only; does not have a linked variable.", + "pneumaticcraft.gui.remote.tray.pneumaticcraft.button.name" : "Button", + "pneumaticcraft.gui.remote.tray.pneumaticcraft.button.tooltip" : "A simple push button which directly assigns it values to the linked variable when clicked.", + "pneumaticcraft.gui.remote.tray.pneumaticcraft.checkbox.name" : "CheckBox", + "pneumaticcraft.gui.remote.tray.pneumaticcraft.checkbox.tooltip" : "A toggleable button which assigns 1 to the linked variable's X value when checked, and 0 when not checked.", + "pneumaticcraft.gui.remote.tray.pneumaticcraft.dropdown.name" : "Drop-down", + "pneumaticcraft.gui.remote.tray.pneumaticcraft.dropdown.tooltip" : "A set of text elements which the user can choose from. The linked variable's X value is set to the (0-based) index of the selected element.", + "pneumaticcraft.gui.remote.tray.pneumaticcraft.label.name" : "Label", + "pneumaticcraft.gui.remote.tray.pneumaticcraft.label.tooltip" : "A text label with an optional tooltip. For informational purposes only; does not have a linked variable.", "pneumaticcraft.gui.remote.variable.tooltip" : "The variable modified by this widget.", "pneumaticcraft.gui.remote.varType.tooltip" : "'#': player-global variable, private to you\n'%%': global variable, shared between all players", "pneumaticcraft.gui.remote.widgetTray" : "Widget Tray",