Skip to content

Commit

Permalink
Total overhaul of the remote widget system
Browse files Browse the repository at this point in the history
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
  • Loading branch information
desht committed Jul 17, 2024
1 parent 74b3d4f commit d1d2e36
Show file tree
Hide file tree
Showing 68 changed files with 1,864 additions and 1,881 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
8 changes: 4 additions & 4 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
* Handles serialization of progwidgets, as well as default instance creation.
*/
public class ProgWidgetType<P extends IProgWidget> {
private final Supplier<? extends P> defaultSupplier;
private final MapCodec<? extends IProgWidget> codec;
private final StreamCodec<RegistryFriendlyByteBuf,? extends IProgWidget> streamCodec;
private final Supplier<P> defaultSupplier;
private final MapCodec<P> codec;
private final StreamCodec<RegistryFriendlyByteBuf,P> streamCodec;
private String descriptionId;

private ProgWidgetType(Supplier<P> defaultSupplier, MapCodec<P> codec, StreamCodec<RegistryFriendlyByteBuf,P> streamCodec) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> getRelevantVariables(String string, UUID playerId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,11 @@ public interface IMiscHelpers {
*/
Optional<? extends IActiveEntityHacks> 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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Player> {
boolean isReal();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@
* along with pnc-repressurized. If not, see <https://www.gnu.org/licenses/>.
*/

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<BlockPos> getCoordinate(UUID id, String varName);

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -24,6 +25,8 @@ public class PNCRegistries {
= ResourceKey.createRegistryKey(RL("player_matchers"));
public static final ResourceKey<Registry<ProgWidgetType<?>>> PROG_WIDGETS_KEY
= ResourceKey.createRegistryKey(RL("prog_widgets"));
public static final ResourceKey<Registry<RemoteWidgetType<?>>> REMOTE_WIDGETS_KEY
= ResourceKey.createRegistryKey(RL("remote_widgets"));

// Registries
public static final Registry<AreaTypeSerializer<? extends AreaType>> AREA_TYPE_SERIALIZER_REGISTRY
Expand All @@ -36,4 +39,6 @@ public class PNCRegistries {
= new RegistryBuilder<>(PLAYER_MATCHER_KEY).create();
public static final Registry<ProgWidgetType<?>> PROG_WIDGETS_REGISTRY
= new RegistryBuilder<>(PROG_WIDGETS_KEY).sync(true).create();
public static final Registry<RemoteWidgetType<?>> REMOTE_WIDGETS_REGISTRY
= new RegistryBuilder<>(REMOTE_WIDGETS_KEY).sync(true).create();
}
30 changes: 30 additions & 0 deletions src/api/java/me/desht/pneumaticcraft/api/remote/BaseSettings.java
Original file line number Diff line number Diff line change
@@ -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<BaseSettings> 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<FriendlyByteBuf, BaseSettings> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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<String> variables, UUID playerId) {
IRemoteWidget.super.discoverVariables(variables, playerId);

if (!varName().isEmpty()) {
variables.add(varName());
}
}
}
113 changes: 113 additions & 0 deletions src/api/java/me/desht/pneumaticcraft/api/remote/IRemoteWidget.java
Original file line number Diff line number Diff line change
@@ -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<IRemoteWidget> CODEC = PNCRegistries.REMOTE_WIDGETS_REGISTRY.byNameCodec().dispatch(
IRemoteWidget::getType,
RemoteWidgetType::codec
);

StreamCodec<RegistryFriendlyByteBuf,IRemoteWidget> 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<? extends IRemoteWidget> 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<String> 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());
}
}
Loading

0 comments on commit d1d2e36

Please sign in to comment.