Pondering Alone, Part II

-move some theme keys to a new ponder specific theme
-move config gui to catnip
-fix some client/server siding issues
-move some icons to catnip/ponder
-move some commands to catnip/ponder
-refactor SConfigureConfigPacket and move it to catnip
-add PonderPlugin to bundle all ponder extension points
This commit is contained in:
zelophed 2022-08-31 13:52:28 +02:00
parent bce234ec50
commit 57dc43e398
43 changed files with 284 additions and 3078 deletions

View file

@ -99,6 +99,11 @@ minecraft {
server {
workingDirectory project.file('run/server')
if (inMultiModWorkspace)
ideaModule "createmod.Create.main"
else
ideaModule "Create.main"
arg '-mixin.config=create.mixins.json'
property 'forge.logging.console.level', 'info'
mods {
@ -124,6 +129,11 @@ minecraft {
data {
workingDirectory project.file('run')
if (inMultiModWorkspace)
ideaModule "createmod.Create.main"
else
ideaModule "Create.main"
property 'forge.logging.markers', 'REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
args '--mod', 'create', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources')

View file

@ -20,10 +20,8 @@ import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler;
import com.simibubi.create.content.schematics.client.SchematicHandler;
import com.simibubi.create.foundation.ClientResourceReloadListener;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.ponder.CreatePonderIndex;
import com.simibubi.create.foundation.ponder.CreatePonderTag;
import com.simibubi.create.foundation.ponder.CreatePonderPlugin;
import com.simibubi.create.foundation.ponder.CreateSharedPonderText;
import com.simibubi.create.foundation.ponder.PonderWorldTileFix;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.CreateContexts;
import com.simibubi.create.foundation.render.SuperByteBufferCache;
@ -31,7 +29,6 @@ import com.simibubi.create.foundation.utility.ModelSwapper;
import com.simibubi.create.foundation.utility.ShippedResourcePacks;
import net.createmod.ponder.foundation.PonderIndex;
import net.createmod.ponder.foundation.PonderWorld;
import net.minecraft.ChatFormatting;
import net.minecraft.client.GraphicsStatus;
import net.minecraft.client.Minecraft;
@ -93,11 +90,7 @@ public class CreateClient {
AllBlockPartials.init();
AllStitchedTextures.init();
CreatePonderIndex.register();
CreatePonderIndex.registerTags();
PonderIndex.addIndex(CreatePonderIndex::register);
PonderIndex.addIndex(CreatePonderTag::register);
PonderWorld.onRestore(PonderWorldTileFix::fixControllerTiles);
PonderIndex.addPlugin(new CreatePonderPlugin());
registerOverlays();
}

View file

@ -12,7 +12,7 @@ import com.simibubi.create.foundation.utility.ControlsUtil;
import net.createmod.catnip.utility.animation.LerpedFloat;
import net.createmod.catnip.utility.animation.LerpedFloat.Chaser;
import net.createmod.catnip.utility.math.AngleHelper;
import net.createmod.catnip.utility.placement.PlacementHelpers;
import net.createmod.catnip.utility.placement.PlacementClient;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiComponent;
@ -203,7 +203,7 @@ public class TrainHUD {
poseStack.translate(91, -9, 0);
poseStack.scale(0.925f, 0.925f, 1);
PlacementHelpers.textured(poseStack, 0, 0, 1, snappedAngle);
PlacementClient.textured(poseStack, 0, 0, 1, snappedAngle);
poseStack.popPose();
}

View file

@ -15,6 +15,7 @@ import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.model.BakedModelWrapper;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.client.model.data.ModelProperty;
@ -29,8 +30,9 @@ public class BracketedKineticBlockModel extends BakedModelWrapper<BakedModel> {
@Override
public IModelData getModelData(BlockAndTintGetter world, BlockPos pos, BlockState state, IModelData tileData) {
if (VirtualEmptyModelData.is(tileData))
if (VirtualEmptyModelData.is(tileData) || tileData.equals(EmptyModelData.INSTANCE))
return tileData;
BracketedModelData data = new BracketedModelData();
BracketedTileEntityBehaviour attachmentBehaviour =
TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE);
@ -42,16 +44,18 @@ public class BracketedKineticBlockModel extends BakedModelWrapper<BakedModel> {
@Override
public List<BakedQuad> getQuads(BlockState state, Direction side, Random rand, IModelData data) {
if (!VirtualEmptyModelData.is(data)) {
if (data.hasProperty(BRACKET_PROPERTY)) {
BracketedModelData pipeData = data.getData(BRACKET_PROPERTY);
BakedModel bracket = pipeData.getBracket();
if (bracket != null)
return bracket.getQuads(state, side, rand, data);
}
return Collections.emptyList();
if (VirtualEmptyModelData.is(data) || data.equals(EmptyModelData.INSTANCE)) {
return super.getQuads(state, side, rand, data);
}
return super.getQuads(state, side, rand, data);
if (data.hasProperty(BRACKET_PROPERTY)) {
BracketedModelData pipeData = data.getData(BRACKET_PROPERTY);
BakedModel bracket = pipeData.getBracket();
if (bracket != null)
return bracket.getQuads(state, side, rand, data);
}
return Collections.emptyList();
}
private static class BracketedModelData {

View file

@ -5,6 +5,7 @@ import java.util.List;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllFluids;
import com.simibubi.create.AllItems;
import com.simibubi.create.Create;
@ -25,6 +26,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.tra
import com.simibubi.create.content.contraptions.components.turntable.TurntableHandler;
import com.simibubi.create.content.contraptions.itemAssembly.SequencedAssemblyRecipe;
import com.simibubi.create.content.contraptions.relays.belt.item.BeltConnectorHandler;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.content.curiosities.armor.CopperBacktankArmorLayer;
import com.simibubi.create.content.curiosities.girder.GirderWrenchBehavior;
import com.simibubi.create.content.curiosities.toolbox.ToolboxHandlerClient;
@ -46,7 +48,6 @@ import com.simibubi.create.content.logistics.trains.track.CurvedTrackInteraction
import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline;
import com.simibubi.create.content.logistics.trains.track.TrackPlacement;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.config.ui.BaseConfigScreen;
import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.foundation.item.ItemDescription;
import com.simibubi.create.foundation.item.TooltipHelper;
@ -61,16 +62,18 @@ import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollVal
import com.simibubi.create.foundation.utility.CameraAngleAnimationService;
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import net.createmod.catnip.config.ui.BaseConfigScreen;
import net.createmod.catnip.config.ui.ConfigScreen;
import net.createmod.catnip.render.DefaultSuperRenderTypeBufferImpl;
import net.createmod.catnip.render.SuperRenderTypeBuffer;
import net.createmod.catnip.utility.AnimationTickHolder;
import net.createmod.catnip.utility.placement.PlacementHelpers;
import net.createmod.catnip.utility.worldWrappers.WrappedClientWorld;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.item.BlockItem;
@ -121,7 +124,6 @@ public class ClientEvents {
}
SoundScapes.tick();
AnimationTickHolder.tick();
ScrollValueHandler.tick();
CreateClient.SCHEMATIC_SENDER.tick();
@ -137,7 +139,6 @@ public class ClientEvents {
CapabilityMinecartController.tick(world);
CouplingPhysics.tick(world);
// ScreenOpener.tick();
ServerSpeedProvider.clientTick();
BeltConnectorHandler.tick();
// BeltSlicer.tickHoveringInformation();
@ -155,8 +156,6 @@ public class ClientEvents {
// CollisionDebugger.tick();
ArmInteractionPointHandler.tick();
EjectorTargetHandler.tick();
PlacementHelpers.tick();
//CreateClient.OUTLINER.tickOutlines();
ContraptionRenderDispatcher.tick(world);
BlueprintOverlayRenderer.tick();
ToolboxHandlerClient.clientTick();
@ -188,7 +187,6 @@ public class ClientEvents {
LevelAccessor world = event.getWorld();
if (world.isClientSide() && world instanceof ClientLevel && !(world instanceof WrappedClientWorld)) {
CreateClient.invalidateRenderers();
AnimationTickHolder.reset();
}
}
@ -199,7 +197,6 @@ public class ClientEvents {
return;
CreateClient.invalidateRenderers();
CreateClient.SOUL_PULSE_EFFECT_HANDLER.refresh();
AnimationTickHolder.reset();
ControlsHandler.levelUnloaded(event.getWorld());
}
@ -219,7 +216,6 @@ public class ClientEvents {
CarriageCouplingRenderer.renderAll(ms, buffer);
CreateClient.SCHEMATIC_HANDLER.render(ms, buffer);
//CreateClient.OUTLINER.renderOutlines(ms, buffer, pt);
buffer.draw();
RenderSystem.enableCull();
@ -392,7 +388,15 @@ public class ClientEvents {
.orElseThrow(() -> new IllegalStateException("Create Mod Container missing after loadCompleted"));
createContainer.registerExtensionPoint(ConfigGuiHandler.ConfigGuiFactory.class,
() -> new ConfigGuiHandler.ConfigGuiFactory(
(mc, previousScreen) -> BaseConfigScreen.forCreate(previousScreen)));
(mc, previousScreen) -> new BaseConfigScreen(previousScreen, Create.ID)));
BaseConfigScreen.setDefaultActionFor(Create.ID, base -> base
.withTitles("Client Settings", "World Generation Settings", "Gameplay Settings")
.withSpecs(AllConfigs.CLIENT.specification, AllConfigs.COMMON.specification, AllConfigs.SERVER.specification)
);
ConfigScreen.shadowState = AllBlocks.LARGE_COGWHEEL.getDefaultState().setValue(CogWheelBlock.AXIS, Direction.Axis.Y);
}
}

View file

@ -1,13 +1,11 @@
package com.simibubi.create.foundation.command;
import java.util.Collections;
import java.util.function.Predicate;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.LiteralCommandNode;
import net.createmod.catnip.command.CatnipCommands;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.world.entity.player.Player;
@ -32,8 +30,6 @@ public class AllCommands {
.then(KillTrainCommand.register())
.then(PassengerCommand.register())
.then(CouplingCommand.register())
.then(ConfigCommand.register())
.then(PonderCommand.register())
.then(CloneCommand.register())
.then(GlueCommand.register())
@ -41,15 +37,10 @@ public class AllCommands {
.then(util)
);
createRoot.addChild(buildRedirect("u", util));
CommandNode<CommandSourceStack> c = dispatcher.findNode(Collections.singleton("c"));
if (c != null)
return;
dispatcher.getRoot()
.addChild(buildRedirect("c", createRoot));
createRoot.addChild(CatnipCommands.buildRedirect("u", util));
//add all of Create's commands to /c if it already exists, otherwise create the shortcut
CatnipCommands.createOrAddToShortcut(dispatcher, "c", createRoot);
}
private static LiteralCommandNode<CommandSourceStack> buildUtilityCommands() {
@ -59,38 +50,9 @@ public class AllCommands {
.then(ClearBufferCacheCommand.register())
.then(CameraDistanceCommand.register())
.then(CameraAngleCommand.register())
.then(FlySpeedCommand.register())
//.then(KillTPSCommand.register())
.build();
}
/**
* *****
* https://github.com/VelocityPowered/Velocity/blob/8abc9c80a69158ebae0121fda78b55c865c0abad/proxy/src/main/java/com/velocitypowered/proxy/util/BrigadierUtils.java#L38
* *****
* <p>
* Returns a literal node that redirects its execution to
* the given destination node.
*
* @param alias the command alias
* @param destination the destination node
*
* @return the built node
*/
public static LiteralCommandNode<CommandSourceStack> buildRedirect(final String alias, final LiteralCommandNode<CommandSourceStack> destination) {
// Redirects only work for nodes with children, but break the top argument-less command.
// Manually adding the root command after setting the redirect doesn't fix it.
// See https://github.com/Mojang/brigadier/issues/46). Manually clone the node instead.
LiteralArgumentBuilder<CommandSourceStack> builder = LiteralArgumentBuilder
.<CommandSourceStack>literal(alias)
.requires(destination.getRequirement())
.forward(destination.getRedirect(), destination.getRedirectModifier(), destination.isFork())
.executes(destination.getCommand());
for (CommandNode<CommandSourceStack> child : destination.getChildren()) {
builder.then(child);
}
return builder.build();
}
}

View file

@ -7,14 +7,14 @@ import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.CameraAngleAnimationService;
import net.createmod.catnip.net.ClientboundSimpleActionPacket;
import net.createmod.catnip.platform.CatnipServices;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.PacketDistributor;
public class CameraAngleCommand {
@ -50,13 +50,12 @@ public class CameraAngleCommand {
AtomicInteger targets = new AtomicInteger(0);
float angleTarget = FloatArgumentType.getFloat(ctx, "degrees");
String optionName = (yaw ? SConfigureConfigPacket.Actions.camAngleYawTarget : SConfigureConfigPacket.Actions.camAnglePitchTarget).name();
String optionName = yaw ? "camAngleYawTarget" : "camAnglePitchTarget";
getPlayersFromContext(ctx).forEach(player -> {
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket(optionName, String.valueOf(angleTarget))
);
CatnipServices.NETWORK.sendToPlayer(
player,
new ClientboundSimpleActionPacket(optionName, String.valueOf(angleTarget)));
targets.incrementAndGet();
});
@ -67,9 +66,9 @@ public class CameraAngleCommand {
AtomicInteger targets = new AtomicInteger(0);
getPlayersFromContext(ctx).forEach(player -> {
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.camAngleFunction.name(), value)
CatnipServices.NETWORK.sendToPlayer(
player,
new ClientboundSimpleActionPacket("camAngleFunction", value)
);
targets.incrementAndGet();
});
@ -81,9 +80,9 @@ public class CameraAngleCommand {
AtomicInteger targets = new AtomicInteger(0);
getPlayersFromContext(ctx).forEach(player -> {
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.camAngleFunction.name(), value + ":" + speed)
CatnipServices.NETWORK.sendToPlayer(
player,
new ClientboundSimpleActionPacket("camAngleFunction", value + ":" + speed)
);
targets.incrementAndGet();
});

View file

@ -3,12 +3,12 @@ package com.simibubi.create.foundation.command;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.simibubi.create.foundation.networking.AllPackets;
import net.createmod.catnip.net.ClientboundSimpleActionPacket;
import net.createmod.catnip.platform.CatnipServices;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.PacketDistributor;
public class CameraDistanceCommand {
@ -17,10 +17,9 @@ public class CameraDistanceCommand {
.then(Commands.literal("reset")
.executes(ctx -> {
ServerPlayer player = ctx.getSource().getPlayerOrException();
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.zoomMultiplier.name(), "1")
);
CatnipServices.NETWORK.sendToPlayer(
player,
new ClientboundSimpleActionPacket("zoomMultiplier", ""));
return Command.SINGLE_SUCCESS;
})
@ -28,10 +27,9 @@ public class CameraDistanceCommand {
.executes(ctx -> {
float multiplier = FloatArgumentType.getFloat(ctx, "multiplier");
ServerPlayer player = ctx.getSource().getPlayerOrException();
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.zoomMultiplier.name(), String.valueOf(multiplier))
);
CatnipServices.NETWORK.sendToPlayer(
player,
new ClientboundSimpleActionPacket("zoomMultiplier", String.valueOf(multiplier)));
return Command.SINGLE_SUCCESS;
})

View file

@ -1,90 +0,0 @@
package com.simibubi.create.foundation.command;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.config.ui.ConfigHelper;
import com.simibubi.create.foundation.networking.AllPackets;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.network.PacketDistributor;
/**
* Examples:
* /create config client - to open Create's ConfigGui with the client config already selected
* /create config "botania:common" - to open Create's ConfigGui with Botania's common config already selected
* /create config "create:client.client.rainbowDebug" set false - to disable Create's rainbow debug for the sender
*/
public class ConfigCommand {
public static ArgumentBuilder<CommandSourceStack, ?> register() {
return Commands.literal("config")
.executes(ctx -> {
ServerPlayer player = ctx.getSource().getPlayerOrException();
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.configScreen.name(), "")
);
return Command.SINGLE_SUCCESS;
})
.then(Commands.argument("path", StringArgumentType.string())
.executes(ctx -> {
ServerPlayer player = ctx.getSource().getPlayerOrException();
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.configScreen.name(), StringArgumentType.getString(ctx, "path"))
);
return Command.SINGLE_SUCCESS;
})
.then(Commands.literal("set")
.requires(cs -> cs.hasPermission(2))
.then(Commands.argument("value", StringArgumentType.string())
.executes(ctx -> {
String path = StringArgumentType.getString(ctx, "path");
String value = StringArgumentType.getString(ctx, "value");
ConfigHelper.ConfigPath configPath;
try {
configPath = ConfigHelper.ConfigPath.parse(path);
} catch (IllegalArgumentException e) {
ctx.getSource().sendFailure(new TextComponent(e.getMessage()));
return 0;
}
if (configPath.getType() == ModConfig.Type.CLIENT) {
ServerPlayer player = ctx.getSource().getPlayerOrException();
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket("SET" + path, value)
);
return Command.SINGLE_SUCCESS;
}
try {
ConfigHelper.setConfigValue(configPath, value);
ctx.getSource().sendSuccess(new TextComponent("Great Success!"), false);
return Command.SINGLE_SUCCESS;
} catch (ConfigHelper.InvalidValueException e) {
ctx.getSource().sendFailure(new TextComponent("Config could not be set the the specified value!"));
return 0;
} catch (Exception e) {
ctx.getSource().sendFailure(new TextComponent("Something went wrong while trying to set config value. Check the server logs for more information"));
Create.LOGGER.warn("Exception during server-side config value set:", e);
return 0;
}
})
)
)
);
}
}

View file

@ -2,12 +2,12 @@ package com.simibubi.create.foundation.command;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.simibubi.create.foundation.networking.AllPackets;
import net.createmod.catnip.net.ClientboundSimpleActionPacket;
import net.createmod.catnip.platform.CatnipServices;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.PacketDistributor;
public class FabulousWarningCommand {
@ -18,10 +18,9 @@ public class FabulousWarningCommand {
ServerPlayer player = ctx.getSource()
.getPlayerOrException();
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.fabulousWarning.name(), "")
);
CatnipServices.NETWORK.sendToPlayer(
player,
new ClientboundSimpleActionPacket("fabulousWarning", ""));
return Command.SINGLE_SUCCESS;
});

View file

@ -1,13 +1,12 @@
package com.simibubi.create.foundation.command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.simibubi.create.foundation.networking.AllPackets;
import net.createmod.catnip.net.ClientboundSimpleActionPacket;
import net.createmod.catnip.platform.CatnipServices;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.PacketDistributor;
public class FixLightingCommand {
@ -15,9 +14,9 @@ public class FixLightingCommand {
return Commands.literal("fixLighting")
.requires(cs -> cs.hasPermission(0))
.executes(ctx -> {
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) ctx.getSource()
.getEntity()),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.fixLighting.name(), String.valueOf(true)));
CatnipServices.NETWORK.sendToPlayer(
ctx.getSource().getPlayerOrException(),
new ClientboundSimpleActionPacket("fixLighting", String.valueOf(true)));
ctx.getSource()
.sendSuccess(

View file

@ -1,47 +0,0 @@
package com.simibubi.create.foundation.command;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket;
import net.minecraft.server.level.ServerPlayer;
public class FlySpeedCommand {
public static ArgumentBuilder<CommandSourceStack, ?> register() {
return Commands.literal("flySpeed")
.requires(cs -> cs.hasPermission(2))
.then(Commands.argument("speed", FloatArgumentType.floatArg(0))
.then(Commands.argument("target", EntityArgument.player())
.executes(ctx -> sendFlySpeedUpdate(ctx, EntityArgument.getPlayer(ctx, "target"),
FloatArgumentType.getFloat(ctx, "speed"))))
.executes(ctx -> sendFlySpeedUpdate(ctx, ctx.getSource()
.getPlayerOrException(), FloatArgumentType.getFloat(ctx, "speed"))))
.then(Commands.literal("reset")
.then(Commands.argument("target", EntityArgument.player())
.executes(ctx -> sendFlySpeedUpdate(ctx, EntityArgument.getPlayer(ctx, "target"), 0.05f)))
.executes(ctx -> sendFlySpeedUpdate(ctx, ctx.getSource()
.getPlayerOrException(), 0.05f))
);
}
private static int sendFlySpeedUpdate(CommandContext<CommandSourceStack> ctx, ServerPlayer player, float speed) {
ClientboundPlayerAbilitiesPacket packet = new ClientboundPlayerAbilitiesPacket(player.getAbilities());
packet.flyingSpeed = speed;
player.connection.send(packet);
ctx.getSource()
.sendSuccess(new TextComponent("Temporarily set " + player.getName()
.getString() + "'s Flying Speed to: " + speed), true);
return Command.SINGLE_SUCCESS;
}
}

View file

@ -1,15 +1,16 @@
package com.simibubi.create.foundation.command;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.simibubi.create.foundation.networking.AllPackets;
import net.createmod.catnip.net.ClientboundSimpleActionPacket;
import net.createmod.catnip.platform.CatnipServices;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.network.PacketDistributor;
public class OverlayConfigCommand {
@ -18,12 +19,12 @@ public class OverlayConfigCommand {
.requires(cs -> cs.hasPermission(0))
.then(Commands.literal("reset")
.executes(ctx -> {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> SConfigureConfigPacket.Actions.overlayReset.performAction(""));
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> SimpleCreateActions.overlayReset(""));
DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () ->
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> (ServerPlayer) ctx.getSource().getEntity()),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.overlayReset.name(), "")));
CatnipServices.NETWORK.sendToPlayer(
(Player) ctx.getSource().getEntity(),
new ClientboundSimpleActionPacket("overlayReset", "")));
ctx.getSource()
.sendSuccess(new TextComponent("reset overlay offset"), true);
@ -32,17 +33,17 @@ public class OverlayConfigCommand {
})
)
.executes(ctx -> {
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> SConfigureConfigPacket.Actions.overlayScreen.performAction(""));
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> SimpleCreateActions.overlayScreen(""));
DistExecutor.unsafeRunWhenOn(Dist.DEDICATED_SERVER, () -> () ->
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> (ServerPlayer) ctx.getSource().getEntity()),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.overlayScreen.name(), "")));
CatnipServices.NETWORK.sendToPlayer(
(Player) ctx.getSource().getEntity(),
new ClientboundSimpleActionPacket("overlayScreen", "")));
ctx.getSource()
.sendSuccess(new TextComponent("window opened"), true);
return 1;
return Command.SINGLE_SUCCESS;
});
}

View file

@ -1,56 +0,0 @@
package com.simibubi.create.foundation.command;
import java.util.Collection;
import com.google.common.collect.ImmutableList;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.simibubi.create.foundation.networking.AllPackets;
import net.createmod.ponder.foundation.PonderRegistry;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.commands.arguments.ResourceLocationArgument;
import net.minecraft.commands.synchronization.SuggestionProviders;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.network.PacketDistributor;
public class PonderCommand {
public static final SuggestionProvider<CommandSourceStack> ITEM_PONDERS = SuggestionProviders.register(new ResourceLocation("all_ponders"), (iSuggestionProviderCommandContext, builder) -> SharedSuggestionProvider.suggestResource(PonderRegistry.ALL.keySet().stream(), builder));
static ArgumentBuilder<CommandSourceStack, ?> register() {
return Commands.literal("ponder")
.requires(cs -> cs.hasPermission(0))
.executes(ctx -> openScene("index", ctx.getSource().getPlayerOrException()))
.then(Commands.argument("scene", ResourceLocationArgument.id())
.suggests(ITEM_PONDERS)
.executes(ctx -> openScene(ResourceLocationArgument.getId(ctx, "scene").toString(), ctx.getSource().getPlayerOrException()))
.then(Commands.argument("targets", EntityArgument.players())
.requires(cs -> cs.hasPermission(2))
.executes(ctx -> openScene(ResourceLocationArgument.getId(ctx, "scene").toString(), EntityArgument.getPlayers(ctx, "targets")))
)
);
}
private static int openScene(String sceneId, ServerPlayer player) {
return openScene(sceneId, ImmutableList.of(player));
}
private static int openScene(String sceneId, Collection<? extends ServerPlayer> players) {
for (ServerPlayer player : players) {
if (player instanceof FakePlayer)
continue;
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.openPonder.name(), sceneId));
}
return Command.SINGLE_SUCCESS;
}
}

View file

@ -1,275 +0,0 @@
package com.simibubi.create.foundation.command;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.apache.logging.log4j.LogManager;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.goggles.GoggleConfigScreen;
import com.simibubi.create.content.logistics.trains.CameraDistanceModifier;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.config.ui.BaseConfigScreen;
import com.simibubi.create.foundation.config.ui.ConfigHelper;
import com.simibubi.create.foundation.config.ui.SubMenuConfigScreen;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import com.simibubi.create.foundation.utility.CameraAngleAnimationService;
import net.createmod.catnip.gui.ScreenOpener;
import net.createmod.ponder.foundation.PonderRegistry;
import net.createmod.ponder.foundation.ui.PonderIndexScreen;
import net.createmod.ponder.foundation.ui.PonderUI;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.ForgeConfig;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.network.NetworkEvent;
public class SConfigureConfigPacket extends SimplePacketBase {
private final String option;
private final String value;
public SConfigureConfigPacket(String option, String value) {
this.option = option;
this.value = value;
}
public SConfigureConfigPacket(FriendlyByteBuf buffer) {
this.option = buffer.readUtf(32767);
this.value = buffer.readUtf(32767);
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeUtf(option);
buffer.writeUtf(value);
}
@Override
public void handle(Supplier<NetworkEvent.Context> ctx) {
ctx.get()
.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
if (option.startsWith("SET")) {
trySetConfig(option.substring(3), value);
return;
}
try {
Actions.valueOf(option)
.performAction(value);
} catch (IllegalArgumentException e) {
LogManager.getLogger()
.warn("Received ConfigureConfigPacket with invalid Option: " + option);
}
}));
ctx.get()
.setPacketHandled(true);
}
private static void trySetConfig(String option, String value) {
LocalPlayer player = Minecraft.getInstance().player;
if (player == null)
return;
ConfigHelper.ConfigPath configPath;
try {
configPath = ConfigHelper.ConfigPath.parse(option);
} catch (IllegalArgumentException e) {
player.displayClientMessage(new TextComponent(e.getMessage()), false);
return;
}
if (configPath.getType() != ModConfig.Type.CLIENT) {
Create.LOGGER.warn("Received type-mismatched config packet on client");
return;
}
try {
ConfigHelper.setConfigValue(configPath, value);
player.displayClientMessage(new TextComponent("Great Success!"), false);
} catch (ConfigHelper.InvalidValueException e) {
player.displayClientMessage(new TextComponent("Config could not be set the the specified value!"), false);
} catch (Exception e) {
player.displayClientMessage(new TextComponent("Something went wrong while trying to set config value. Check the client logs for more information"), false);
Create.LOGGER.warn("Exception during client-side config value set:", e);
}
}
public enum Actions {
configScreen(() -> Actions::configScreen),
rainbowDebug(() -> Actions::rainbowDebug),
overlayScreen(() -> Actions::overlayScreen),
fixLighting(() -> Actions::experimentalLighting),
overlayReset(() -> Actions::overlayReset),
openPonder(() -> Actions::openPonder),
fabulousWarning(() -> Actions::fabulousWarning),
zoomMultiplier(() -> Actions::zoomMultiplier),
camAngleYawTarget(() -> value -> camAngleTarget(value, true)),
camAnglePitchTarget(() -> value -> camAngleTarget(value, false)),
camAngleFunction(() -> Actions::camAngleFunction)
;
private final Supplier<Consumer<String>> consumer;
Actions(Supplier<Consumer<String>> action) {
this.consumer = action;
}
void performAction(String value) {
consumer.get()
.accept(value);
}
@OnlyIn(Dist.CLIENT)
private static void configScreen(String value) {
if (value.equals("")) {
ScreenOpener.open(BaseConfigScreen.forCreate(null));
return;
}
LocalPlayer player = Minecraft.getInstance().player;
ConfigHelper.ConfigPath configPath;
try {
configPath = ConfigHelper.ConfigPath.parse(value);
} catch (IllegalArgumentException e) {
player.displayClientMessage(new TextComponent(e.getMessage()), false);
return;
}
try {
ScreenOpener.open(SubMenuConfigScreen.find(configPath));
} catch (Exception e) {
player.displayClientMessage(new TextComponent("Unable to find the specified config"), false);
}
}
@OnlyIn(Dist.CLIENT)
private static void rainbowDebug(String value) {
LocalPlayer player = Minecraft.getInstance().player;
if (player == null || "".equals(value))
return;
if (value.equals("info")) {
Component text = new TextComponent("Rainbow Debug Utility is currently: ")
.append(boolToText(AllConfigs.CLIENT.rainbowDebug.get()));
player.displayClientMessage(text, false);
return;
}
AllConfigs.CLIENT.rainbowDebug.set(Boolean.parseBoolean(value));
Component text = boolToText(AllConfigs.CLIENT.rainbowDebug.get())
.append(new TextComponent(" Rainbow Debug Utility").withStyle(ChatFormatting.WHITE));
player.displayClientMessage(text, false);
}
@OnlyIn(Dist.CLIENT)
private static void overlayReset(String value) {
AllConfigs.CLIENT.overlayOffsetX.set(0);
AllConfigs.CLIENT.overlayOffsetY.set(0);
}
@OnlyIn(Dist.CLIENT)
private static void overlayScreen(String value) {
ScreenOpener.open(new GoggleConfigScreen());
}
@OnlyIn(Dist.CLIENT)
private static void experimentalLighting(String value) {
ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.set(true);
Minecraft.getInstance().levelRenderer.allChanged();
}
@OnlyIn(Dist.CLIENT)
private static void openPonder(String value) {
if (value.equals("index")) {
ScreenOpener.transitionTo(new PonderIndexScreen());
return;
}
ResourceLocation id = new ResourceLocation(value);
if (!PonderRegistry.ALL.containsKey(id)) {
Create.LOGGER.error("Could not find ponder scenes for item: " + id);
return;
}
ScreenOpener.transitionTo(PonderUI.of(id));
}
@OnlyIn(Dist.CLIENT)
private static void fabulousWarning(String value) {
AllConfigs.CLIENT.ignoreFabulousWarning.set(true);
Minecraft.getInstance().gui.handleChat(ChatType.CHAT,
new TextComponent("Disabled Fabulous graphics warning"),
Minecraft.getInstance().player.getUUID());
}
@OnlyIn(Dist.CLIENT)
private static void zoomMultiplier(String value) {
try {
float v = Float.parseFloat(value);
if (v <= 0)
return;
CameraDistanceModifier.zoomOut(v);
} catch (NumberFormatException ignored) {
Create.LOGGER.debug("Received non-float value {} in zoom packet, ignoring", value);
}
}
@OnlyIn(Dist.CLIENT)
private static void camAngleTarget(String value, boolean yaw) {
try {
float v = Float.parseFloat(value);
if (yaw) {
CameraAngleAnimationService.setYawTarget(v);
} else {
CameraAngleAnimationService.setPitchTarget(v);
}
} catch (NumberFormatException ignored) {
Create.LOGGER.debug("Received non-float value {} in camAngle packet, ignoring", value);
}
}
@OnlyIn(Dist.CLIENT)
private static void camAngleFunction(String value) {
CameraAngleAnimationService.Mode mode = CameraAngleAnimationService.Mode.LINEAR;
String modeString = value;
float speed = -1;
String[] split = value.split(":");
if (split.length > 1) {
modeString = split[0];
try {
speed = Float.parseFloat(split[1]);
} catch (NumberFormatException ignored) {}
}
try {
mode = CameraAngleAnimationService.Mode.valueOf(modeString);
} catch (IllegalArgumentException ignored) {}
CameraAngleAnimationService.setAnimationMode(mode);
CameraAngleAnimationService.setAnimationSpeed(speed);
}
private static MutableComponent boolToText(boolean b) {
return b ? new TextComponent("enabled").withStyle(ChatFormatting.DARK_GREEN)
: new TextComponent("disabled").withStyle(ChatFormatting.RED);
}
}
}

View file

@ -0,0 +1,111 @@
package com.simibubi.create.foundation.command;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.goggles.GoggleConfigScreen;
import com.simibubi.create.content.logistics.trains.CameraDistanceModifier;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.CameraAngleAnimationService;
import net.createmod.catnip.gui.ScreenOpener;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.chat.ChatType;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
import net.minecraftforge.common.ForgeConfig;
public class SimpleCreateActions {
public static void rainbowDebug(String value) {
LocalPlayer player = Minecraft.getInstance().player;
if (player == null || "".equals(value))
return;
if (value.equals("info")) {
Component text = new TextComponent("Rainbow Debug Utility is currently: ")
.append(boolToText(AllConfigs.CLIENT.rainbowDebug.get()));
player.displayClientMessage(text, false);
return;
}
AllConfigs.CLIENT.rainbowDebug.set(Boolean.parseBoolean(value));
Component text = boolToText(AllConfigs.CLIENT.rainbowDebug.get())
.append(new TextComponent(" Rainbow Debug Utility").withStyle(ChatFormatting.WHITE));
player.displayClientMessage(text, false);
}
public static void overlayReset(String value) {
AllConfigs.CLIENT.overlayOffsetX.set(0);
AllConfigs.CLIENT.overlayOffsetY.set(0);
}
public static void overlayScreen(String value) {
ScreenOpener.open(new GoggleConfigScreen());
}
public static void experimentalLighting(String value) {
ForgeConfig.CLIENT.experimentalForgeLightPipelineEnabled.set(true);
Minecraft.getInstance().levelRenderer.allChanged();
}
public static void fabulousWarning(String value) {
AllConfigs.CLIENT.ignoreFabulousWarning.set(true);
Minecraft.getInstance().gui.handleChat(ChatType.CHAT,
new TextComponent("Disabled Fabulous graphics warning"),
Minecraft.getInstance().player.getUUID());
}
public static void zoomMultiplier(String value) {
try {
float v = Float.parseFloat(value);
if (v <= 0)
return;
CameraDistanceModifier.zoomOut(v);
} catch (NumberFormatException ignored) {
Create.LOGGER.debug("Received non-float value {} in zoom packet, ignoring", value);
}
}
public static void camAngleTarget(String value, boolean yaw) {
try {
float v = Float.parseFloat(value);
if (yaw) {
CameraAngleAnimationService.setYawTarget(v);
} else {
CameraAngleAnimationService.setPitchTarget(v);
}
} catch (NumberFormatException ignored) {
Create.LOGGER.debug("Received non-float value {} in camAngle packet, ignoring", value);
}
}
public static void camAngleFunction(String value) {
CameraAngleAnimationService.Mode mode = CameraAngleAnimationService.Mode.LINEAR;
String modeString = value;
float speed = -1;
String[] split = value.split(":");
if (split.length > 1) {
modeString = split[0];
try {
speed = Float.parseFloat(split[1]);
} catch (NumberFormatException ignored) {}
}
try {
mode = CameraAngleAnimationService.Mode.valueOf(modeString);
} catch (IllegalArgumentException ignored) {}
CameraAngleAnimationService.setAnimationMode(mode);
CameraAngleAnimationService.setAnimationSpeed(speed);
}
private static MutableComponent boolToText(boolean b) {
return b ? new TextComponent("enabled").withStyle(ChatFormatting.DARK_GREEN)
: new TextComponent("disabled").withStyle(ChatFormatting.RED);
}
}

View file

@ -1,9 +1,8 @@
package com.simibubi.create.foundation.command;
import com.simibubi.create.foundation.networking.AllPackets;
import net.createmod.catnip.net.ClientboundSimpleActionPacket;
import net.createmod.catnip.platform.CatnipServices;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.PacketDistributor;
public class ToggleDebugCommand extends ConfigureConfigCommand {
@ -13,9 +12,9 @@ public class ToggleDebugCommand extends ConfigureConfigCommand {
@Override
protected void sendPacket(ServerPlayer player, String option) {
AllPackets.channel.send(
PacketDistributor.PLAYER.with(() -> player),
new SConfigureConfigPacket(SConfigureConfigPacket.Actions.rainbowDebug.name(), option)
CatnipServices.NETWORK.sendToPlayer(
player,
new ClientboundSimpleActionPacket("rainbowDebug", option)
);
}
}

View file

@ -2,9 +2,8 @@ package com.simibubi.create.foundation.config;
import javax.annotation.Nonnull;
import com.simibubi.create.foundation.config.ui.ConfigAnnotations;
import net.createmod.catnip.config.ConfigBase;
import net.createmod.catnip.config.ui.ConfigAnnotations;
public class CClient extends ConfigBase {

View file

@ -1,8 +1,7 @@
package com.simibubi.create.foundation.config;
import com.simibubi.create.foundation.config.ui.ConfigAnnotations;
import net.createmod.catnip.config.ConfigBase;
import net.createmod.catnip.config.ui.ConfigAnnotations;
public class CKinetics extends ConfigBase {

View file

@ -1,252 +0,0 @@
package com.simibubi.create.foundation.config.ui;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.function.UnaryOperator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.lwjgl.glfw.GLFW;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.gui.AllIcons;
import net.createmod.catnip.gui.ScreenOpener;
import net.createmod.catnip.gui.element.FadableScreenElement;
import net.createmod.catnip.utility.FontHelper;
import net.createmod.catnip.utility.theme.Theme;
import net.createmod.catnip.gui.UIRenderHelper;
import net.createmod.catnip.gui.element.TextStencilElement;
import net.createmod.catnip.gui.widget.BoxWidget;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.TextComponent;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.config.ModConfig;
public class BaseConfigScreen extends ConfigScreen {
public static final FadableScreenElement DISABLED_RENDERER = (ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, height, width, Theme.Key.BUTTON_DISABLE.p());
private static final Map<String, UnaryOperator<BaseConfigScreen>> DEFAULTS = new HashMap<>();
static {
DEFAULTS.put(Create.ID, (base) -> base
.withTitles("Client Settings", "World Generation Settings", "Gameplay Settings")
.withSpecs(AllConfigs.CLIENT.specification, AllConfigs.COMMON.specification, AllConfigs.SERVER.specification)
);
}
/**
* If you are a Create Addon dev and want to change the config labels,
* add a default action here.
*
* Make sure you call either {@link #withSpecs(ForgeConfigSpec, ForgeConfigSpec, ForgeConfigSpec)}
* or {@link #searchForSpecsInModContainer()}
*
* @param modID the modID of your addon/mod
*/
public static void setDefaultActionFor(String modID, UnaryOperator<BaseConfigScreen> transform) {
if (modID.equals(Create.ID))
return;
DEFAULTS.put(modID, transform);
}
public static BaseConfigScreen forCreate(Screen parent) {
return new BaseConfigScreen(parent);
}
BoxWidget clientConfigWidget;
BoxWidget commonConfigWidget;
BoxWidget serverConfigWidget;
BoxWidget goBack;
BoxWidget others;
BoxWidget title;
ForgeConfigSpec clientSpec;
ForgeConfigSpec commonSpec;
ForgeConfigSpec serverSpec;
String clientTile = "Client Config";
String commonTile = "Common Config";
String serverTile = "Server Config";
String modID;
protected boolean returnOnClose;
public BaseConfigScreen(Screen parent, @Nonnull String modID) {
super(parent);
this.modID = modID;
if (DEFAULTS.containsKey(modID))
DEFAULTS.get(modID).apply(this);
else {
this.searchForSpecsInModContainer();
}
}
private BaseConfigScreen(Screen parent) {
this(parent, Create.ID);
}
/**
* If you have static references to your Configs or ConfigSpecs (like Create does in {@link AllConfigs}),
* please use {@link #withSpecs(ForgeConfigSpec, ForgeConfigSpec, ForgeConfigSpec)} instead
*/
public BaseConfigScreen searchForSpecsInModContainer() {
if (!ConfigHelper.hasAnyForgeConfig(this.modID)){
return this;
}
try {
clientSpec = ConfigHelper.findForgeConfigSpecFor(ModConfig.Type.CLIENT, this.modID);
} catch (Exception e) {
Create.LOGGER.debug("Unable to find ClientConfigSpec for mod: " + this.modID);
}
try {
commonSpec = ConfigHelper.findForgeConfigSpecFor(ModConfig.Type.COMMON, this.modID);
} catch (Exception e) {
Create.LOGGER.debug("Unable to find CommonConfigSpec for mod: " + this.modID);
}
try {
serverSpec = ConfigHelper.findForgeConfigSpecFor(ModConfig.Type.SERVER, this.modID);
} catch (Exception e) {
Create.LOGGER.debug("Unable to find ServerConfigSpec for mod: " + this.modID);
}
return this;
}
public BaseConfigScreen withSpecs(@Nullable ForgeConfigSpec client, @Nullable ForgeConfigSpec common, @Nullable ForgeConfigSpec server) {
clientSpec = client;
commonSpec = common;
serverSpec = server;
return this;
}
public BaseConfigScreen withTitles(@Nullable String client, @Nullable String common, @Nullable String server) {
if (client != null)
clientTile = client;
if (common != null)
commonTile = common;
if (server != null)
serverTile = server;
return this;
}
@Override
protected void init() {
super.init();
returnOnClose = true;
TextStencilElement clientText = new TextStencilElement(font, new TextComponent(clientTile)).centered(true, true);
addRenderableWidget(clientConfigWidget = new BoxWidget(width / 2 - 100, height / 2 - 15 - 30, 200, 16).showingElement(clientText));
if (clientSpec != null) {
clientConfigWidget.withCallback(() -> linkTo(new SubMenuConfigScreen(this, ModConfig.Type.CLIENT, clientSpec)));
clientText.withElementRenderer(BoxWidget.gradientFactory.apply(clientConfigWidget));
} else {
clientConfigWidget.active = false;
clientConfigWidget.updateColorsFromState();
clientText.withElementRenderer(DISABLED_RENDERER);
}
TextStencilElement commonText = new TextStencilElement(font, new TextComponent(commonTile)).centered(true, true);
addRenderableWidget(commonConfigWidget = new BoxWidget(width / 2 - 100, height / 2 - 15, 200, 16).showingElement(commonText));
if (commonSpec != null) {
commonConfigWidget.withCallback(() -> linkTo(new SubMenuConfigScreen(this, ModConfig.Type.COMMON, commonSpec)));
commonText.withElementRenderer(BoxWidget.gradientFactory.apply(commonConfigWidget));
} else {
commonConfigWidget.active = false;
commonConfigWidget.updateColorsFromState();
commonText.withElementRenderer(DISABLED_RENDERER);
}
TextStencilElement serverText = new TextStencilElement(font, new TextComponent(serverTile)).centered(true, true);
addRenderableWidget(serverConfigWidget = new BoxWidget(width / 2 - 100, height / 2 - 15 + 30, 200, 16).showingElement(serverText));
if (serverSpec == null) {
serverConfigWidget.active = false;
serverConfigWidget.updateColorsFromState();
serverText.withElementRenderer(DISABLED_RENDERER);
} else if (minecraft.level == null) {
serverText.withElementRenderer(DISABLED_RENDERER);
serverConfigWidget.getToolTip()
.add(new TextComponent("Stored individually per World"));
serverConfigWidget.getToolTip()
.addAll(FontHelper.cutTextComponent(
new TextComponent(
"Gameplay settings can only be accessed from the in-game menu after joining a World or Server."),
ChatFormatting.GRAY, ChatFormatting.GRAY));
} else {
serverConfigWidget.withCallback(() -> linkTo(new SubMenuConfigScreen(this, ModConfig.Type.SERVER, serverSpec)));
serverText.withElementRenderer(BoxWidget.gradientFactory.apply(serverConfigWidget));
}
TextStencilElement titleText = new TextStencilElement(font, modID.toUpperCase(Locale.ROOT))
.centered(true, true)
.withElementRenderer((ms, w, h, alpha) -> {
UIRenderHelper.angledGradient(ms, 0, 0, h / 2, h, w / 2, Theme.Key.CONFIG_TITLE_A.p());
UIRenderHelper.angledGradient(ms, 0, w / 2, h / 2, h, w / 2, Theme.Key.CONFIG_TITLE_B.p());
});
int boxWidth = width + 10;
int boxHeight = 39;
int boxPadding = 4;
title = new BoxWidget(-5, height / 2 - 110, boxWidth, boxHeight)
//.withCustomBackground(new Color(0x20_000000, true))
.withBorderColors(Theme.Key.BUTTON_IDLE.p())
.withPadding(0, boxPadding)
.rescaleElement(boxWidth / 2f, (boxHeight - 2 * boxPadding) / 2f)//double the text size by telling it the element is only half as big as the available space
.showingElement(titleText.at(0, 7));
title.active = false;
addRenderableWidget(title);
ConfigScreen.modID = this.modID;
goBack = new BoxWidget(width / 2 - 134, height / 2, 20, 20).withPadding(2, 2)
.withCallback(() -> linkTo(parent));
goBack.showingElement(AllIcons.I_CONFIG_BACK.asStencil()
.withElementRenderer(BoxWidget.gradientFactory.apply(goBack)));
goBack.getToolTip()
.add(new TextComponent("Go Back"));
addRenderableWidget(goBack);
TextStencilElement othersText = new TextStencilElement(font, new TextComponent("Access Configs of other Mods")).centered(true, true);
others = new BoxWidget(width / 2 - 100, height / 2 - 15 + 90, 200, 16).showingElement(othersText);
othersText.withElementRenderer(BoxWidget.gradientFactory.apply(others));
others.withCallback(() -> linkTo(new ConfigModListScreen(this)));
addRenderableWidget(others);
}
@Override
protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
drawCenteredString(ms, font, "Access Configs for Mod:", width / 2, height / 2 - 105, Theme.Key.TEXT_ACCENT_STRONG.i());
}
private void linkTo(Screen screen) {
returnOnClose = false;
ScreenOpener.open(screen);
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (super.keyPressed(keyCode, scanCode, modifiers))
return true;
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
linkTo(parent);
}
return false;
}
}

View file

@ -1,96 +0,0 @@
package com.simibubi.create.foundation.config.ui;
import java.util.Objects;
import java.util.function.Supplier;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.network.NetworkEvent;
public class CConfigureConfigPacket<T> extends SimplePacketBase {
private String modID;
private String path;
private String value;
public CConfigureConfigPacket(String modID, String path, T value) {
this.modID = Objects.requireNonNull(modID);
this.path = path;
this.value = serialize(value);
}
public CConfigureConfigPacket(FriendlyByteBuf buffer) {
this.modID = buffer.readUtf(32767);
this.path = buffer.readUtf(32767);
this.value = buffer.readUtf(32767);
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeUtf(modID);
buffer.writeUtf(path);
buffer.writeUtf(value);
}
@Override
public void handle(Supplier<NetworkEvent.Context> context) {
context.get().enqueueWork(() -> {
try {
ServerPlayer sender = context.get().getSender();
if (sender == null || !sender.hasPermissions(2))
return;
ForgeConfigSpec spec = ConfigHelper.findForgeConfigSpecFor(ModConfig.Type.SERVER, modID);
if (spec == null)
return;
ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw(path);
ForgeConfigSpec.ConfigValue<T> configValue = spec.getValues().get(path);
T v = (T) deserialize(configValue.get(), value);
if (!valueSpec.test(v))
return;
configValue.set(v);
} catch (Exception e) {
Create.LOGGER.warn("Unable to handle ConfigureConfig Packet. ", e);
}
});
context.get().setPacketHandled(true);
}
public String serialize(T value) {
if (value instanceof Boolean)
return Boolean.toString((Boolean) value);
if (value instanceof Enum<?>)
return ((Enum<?>) value).name();
if (value instanceof Integer)
return Integer.toString((Integer) value);
if (value instanceof Float)
return Float.toString((Float) value);
if (value instanceof Double)
return Double.toString((Double) value);
throw new IllegalArgumentException("unknown type " + value + ": " + value.getClass().getSimpleName());
}
public static Object deserialize(Object type, String sValue) {
if (type instanceof Boolean)
return Boolean.parseBoolean(sValue);
if (type instanceof Enum<?>)
return Enum.valueOf(((Enum<?>) type).getClass(), sValue);
if (type instanceof Integer)
return Integer.parseInt(sValue);
if (type instanceof Float)
return Float.parseFloat(sValue);
if (type instanceof Double)
return Double.parseDouble(sValue);
throw new IllegalArgumentException("unknown type " + type + ": " + type.getClass().getSimpleName());
}
}

View file

@ -1,112 +0,0 @@
package com.simibubi.create.foundation.config.ui;
public class ConfigAnnotations {
/**
* Changes the way the Integer value is display.
*/
public enum IntDisplay implements ConfigAnnotation {
HEX("#"),
ZERO_X("0x"),
ZERO_B("0b");
private final String value;
IntDisplay(String value) {
this.value = value;
}
@Override
public String getName() {
return "IntDisplay";
}
@Override
public String getValue() {
return value;
}
}
/**
* Indicates to the player that changing this value will require a restart to take full effect
*/
public enum RequiresRestart implements ConfigAnnotation {
CLIENT("client"),
SERVER("server"),
BOTH("both");
private final String value;
RequiresRestart(String value) {
this.value = value;
}
@Override
public String getName() {
return "RequiresReload";
}
@Override
public String getValue() {
return value;
}
}
/**
* Indicates to the player that changing this value will require them to relog to take full effect
*/
public enum RequiresRelog implements ConfigAnnotation {
TRUE;
@Override
public String getName() {
return "RequiresRelog";
}
}
/**
* Changing a value that is annotated with Execute will cause the player to run the given command automatically.
*/
public static class Execute implements ConfigAnnotation {
private final String command;
public static Execute run(String command) {
return new Execute(command);
}
private Execute(String command) {
this.command = command;
}
@Override
public String getName() {
return "Execute";
}
@Override
public String getValue() {
return command;
}
}
public interface ConfigAnnotation {
String getName();
default String getValue() {
return null;
}
default String asComment() {
String comment = "[@cui:" + getName();
String value = getValue();
if (value != null) {
comment = comment + ":" + value;
}
comment = comment + "]";
return comment;
}
}
}

View file

@ -1,232 +0,0 @@
package com.simibubi.create.foundation.config.ui;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.config.AllConfigs;
import net.createmod.catnip.utility.Pair;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.config.IConfigSpec;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.util.ObfuscationReflectionHelper;
public class ConfigHelper {
public static final Pattern unitPattern = Pattern.compile("\\[(in .*)]");
public static final Pattern annotationPattern = Pattern.compile("\\[@cui:([^:]*)(?::(.*))?]");
public static final Map<String, ConfigChange> changes = new HashMap<>();
private static final LoadingCache<String, EnumMap<ModConfig.Type, ModConfig>> configCache =
CacheBuilder.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.build(new CacheLoader<String, EnumMap<ModConfig.Type, ModConfig>>() {
@Override
public EnumMap<ModConfig.Type, ModConfig> load(@Nonnull String key) {
return findModConfigsUncached(key);
}
});
private static EnumMap<ModConfig.Type, ModConfig> findModConfigsUncached(String modID) {
ModContainer modContainer = ModList.get()
.getModContainerById(modID)
.orElseThrow(() -> new IllegalArgumentException("Unable to find ModContainer for id: " + modID));
EnumMap<ModConfig.Type, ModConfig> configs =
ObfuscationReflectionHelper.getPrivateValue(ModContainer.class, modContainer, "configs");
return Objects.requireNonNull(configs);
}
public static IConfigSpec<?> findConfigSpecFor(ModConfig.Type type, String modID) {
if (!modID.equals(Create.ID))
return configCache.getUnchecked(modID)
.get(type)
.getSpec();
return AllConfigs.byType(type).specification;
}
@Nullable
public static ForgeConfigSpec findForgeConfigSpecFor(ModConfig.Type type, String modID) {
IConfigSpec<?> spec = findConfigSpecFor(type, modID);
if (spec instanceof ForgeConfigSpec) {
return (ForgeConfigSpec) spec;
}
return null;
}
public static boolean hasAnyConfig(String modID) {
if (!modID.equals(Create.ID))
return !configCache.getUnchecked(modID)
.isEmpty();
return true;
}
public static boolean hasAnyForgeConfig(String modID) {
if (!modID.equals(Create.ID))
return configCache.getUnchecked(modID)
.values()
.stream()
.anyMatch(config -> config.getSpec() instanceof ForgeConfigSpec);
return true;
}
// Directly set a value
public static <T> void setConfigValue(ConfigPath path, String value) throws InvalidValueException {
ForgeConfigSpec spec = findForgeConfigSpecFor(path.getType(), path.getModID());
if (spec == null)
return;
List<String> pathList = Arrays.asList(path.getPath());
ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw(pathList);
ForgeConfigSpec.ConfigValue<T> configValue = spec.getValues()
.get(pathList);
T v = (T) CConfigureConfigPacket.deserialize(configValue.get(), value);
if (!valueSpec.test(v))
throw new InvalidValueException();
configValue.set(v);
}
// Add a value to the current UI's changes list
public static <T> void setValue(String path, ForgeConfigSpec.ConfigValue<T> configValue, T value,
@Nullable Map<String, String> annotations) {
if (value.equals(configValue.get())) {
changes.remove(path);
} else {
changes.put(path, annotations == null ? new ConfigChange(value) : new ConfigChange(value, annotations));
}
}
// Get a value from the current UI's changes list or the config value, if its
// unchanged
public static <T> T getValue(String path, ForgeConfigSpec.ConfigValue<T> configValue) {
ConfigChange configChange = changes.get(path);
if (configChange != null)
// noinspection unchecked
return (T) configChange.value;
else
return configValue.get();
}
public static Pair<String, Map<String, String>> readMetadataFromComment(List<String> commentLines) {
AtomicReference<String> unit = new AtomicReference<>();
Map<String, String> annotations = new HashMap<>();
commentLines.removeIf(line -> {
if (line.trim()
.isEmpty()) {
return true;
}
Matcher matcher = annotationPattern.matcher(line);
if (matcher.matches()) {
String annotation = matcher.group(1);
String aValue = matcher.group(2);
annotations.putIfAbsent(annotation, aValue);
return true;
}
matcher = unitPattern.matcher(line);
if (matcher.matches()) {
unit.set(matcher.group(1));
}
return false;
});
return Pair.of(unit.get(), annotations);
}
public static class ConfigPath {
private String modID = Create.ID;
private ModConfig.Type type = ModConfig.Type.CLIENT;
private String[] path;
public static ConfigPath parse(String string) {
ConfigPath cp = new ConfigPath();
String p = string;
int index = string.indexOf(":");
if (index >= 0) {
p = string.substring(index + 1);
if (index >= 1) {
cp.modID = string.substring(0, index);
}
}
String[] split = p.split("\\.");
try {
cp.type = ModConfig.Type.valueOf(split[0].toUpperCase(Locale.ROOT));
} catch (Exception e) {
throw new IllegalArgumentException("path must start with either 'client.', 'common.' or 'server.'");
}
cp.path = new String[split.length - 1];
System.arraycopy(split, 1, cp.path, 0, cp.path.length);
return cp;
}
public ConfigPath setID(String modID) {
this.modID = modID;
return this;
}
public ConfigPath setType(ModConfig.Type type) {
this.type = type;
return this;
}
public ConfigPath setPath(String[] path) {
this.path = path;
return this;
}
public String getModID() {
return modID;
}
public ModConfig.Type getType() {
return type;
}
public String[] getPath() {
return path;
}
}
public static class ConfigChange {
Object value;
Map<String, String> annotations;
ConfigChange(Object value) {
this.value = value;
}
ConfigChange(Object value, Map<String, String> annotations) {
this(value);
this.annotations = new HashMap<>();
this.annotations.putAll(annotations);
}
}
public static class InvalidValueException extends Exception {
private static final long serialVersionUID = 1L;
}
}

View file

@ -1,147 +0,0 @@
package com.simibubi.create.foundation.config.ui;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.lwjgl.glfw.GLFW;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.foundation.gui.AllIcons;
import net.createmod.catnip.gui.ScreenOpener;
import net.createmod.catnip.gui.element.DelegatedStencilElement;
import net.createmod.catnip.gui.widget.BoxWidget;
import net.createmod.catnip.utility.FontHelper;
import net.createmod.catnip.utility.theme.Theme;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.TextComponent;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.forgespi.language.IModInfo;
public class ConfigModListScreen extends ConfigScreen {
ConfigScreenList list;
HintableTextFieldWidget search;
BoxWidget goBack;
List<ModEntry> allEntries;
public ConfigModListScreen(Screen parent) {
super(parent);
}
@Override
protected void init() {
super.init();
int listWidth = Math.min(width - 80, 300);
list = new ConfigScreenList(minecraft, listWidth, height - 60, 15, height - 45, 40);
list.setLeftPos(this.width / 2 - list.getWidth() / 2);
addRenderableWidget(list);
allEntries = new ArrayList<>();
ModList.get().getMods().stream().map(IModInfo::getModId).forEach(id -> allEntries.add(new ModEntry(id, this)));
allEntries.sort((e1, e2) -> {
int empty = (e2.button.active ? 1 : 0) - (e1.button.active ? 1 : 0);
if (empty != 0)
return empty;
return e1.id.compareToIgnoreCase(e2.id);
});
list.children().clear();
list.children().addAll(allEntries);
goBack = new BoxWidget(width / 2 - listWidth / 2 - 30, height / 2 + 65, 20, 20).withPadding(2, 2)
.withCallback(() -> ScreenOpener.open(parent));
goBack.showingElement(AllIcons.I_CONFIG_BACK.asStencil()
.withElementRenderer(BoxWidget.gradientFactory.apply(goBack)));
goBack.getToolTip()
.add(new TextComponent("Go Back"));
addRenderableWidget(goBack);
search = new HintableTextFieldWidget(font, width / 2 - listWidth / 2, height - 35, listWidth, 20);
search.setResponder(this::updateFilter);
search.setHint("Search...");
search.moveCursorToStart();
addRenderableWidget(search);
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (super.keyPressed(keyCode, scanCode, modifiers))
return true;
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
ScreenOpener.open(parent);
}
return false;
}
private void updateFilter(String search) {
list.children().clear();
allEntries
.stream()
.filter(modEntry -> modEntry.id.contains(search.toLowerCase(Locale.ROOT)))
.forEach(list.children()::add);
list.setScrollAmount(list.getScrollAmount());
if (list.children().size() > 0) {
this.search.setTextColor(Theme.Key.TEXT.i());
} else {
this.search.setTextColor(Theme.Key.BUTTON_FAIL.i());
}
}
public static class ModEntry extends ConfigScreenList.LabeledEntry {
protected BoxWidget button;
protected String id;
public ModEntry(String id, Screen parent) {
super(toHumanReadable(id));
this.id = id;
button = new BoxWidget(0, 0, 35, 16)
.showingElement(AllIcons.I_CONFIG_OPEN.asStencil().at(10, 0));
button.modifyElement(e -> ((DelegatedStencilElement) e).withElementRenderer(BoxWidget.gradientFactory.apply(button)));
if (ConfigHelper.hasAnyForgeConfig(id)) {
button.withCallback(() -> ScreenOpener.open(new BaseConfigScreen(parent, id)));
} else {
button.active = false;
button.updateColorsFromState();
button.modifyElement(e -> ((DelegatedStencilElement) e).withElementRenderer(BaseConfigScreen.DISABLED_RENDERER));
labelTooltip.add(new TextComponent(toHumanReadable(id)));
labelTooltip.addAll(FontHelper.cutTextComponent(new TextComponent("This Mod does not have any configs registered or is not using Forge's config system"), ChatFormatting.GRAY, ChatFormatting.GRAY));
}
listeners.add(button);
}
public String getId() {
return id;
}
@Override
public void tick() {
super.tick();
button.tick();
}
@Override
public void render(PoseStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) {
super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks);
button.x = x + width - 108;
button.y = y + 10;
button.setHeight(height - 20);
button.render(ms, mouseX, mouseY, partialTicks);
}
@Override
protected int getLabelWidth(int totalWidth) {
return (int) (totalWidth * labelWidthMult) + 30;
}
}
}

View file

@ -1,168 +0,0 @@
package com.simibubi.create.foundation.config.ui;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.TriConsumer;
import org.lwjgl.opengl.GL30;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.relays.elementary.CogWheelBlock;
import com.simibubi.create.foundation.gui.CreateMainMenuScreen;
import net.createmod.catnip.gui.AbstractSimiScreen;
import net.createmod.catnip.gui.UIRenderHelper;
import net.createmod.catnip.gui.element.DelegatedStencilElement;
import net.createmod.catnip.gui.element.GuiGameElement;
import net.createmod.catnip.utility.animation.Force;
import net.createmod.catnip.utility.animation.PhysicalFloat;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.client.event.ScreenEvent;
public abstract class ConfigScreen extends AbstractSimiScreen {
/*
*
* TODO
*
* reduce number of packets sent to the server when saving a bunch of values
*
* FIXME
*
* tooltips are hidden underneath the scrollbar, if the bar is near the middle
*
*/
public static final Map<String, TriConsumer<Screen, PoseStack, Float>> backgrounds = new HashMap<>();
public static final PhysicalFloat cogSpin = PhysicalFloat.create().withLimit(10f).withDrag(0.3).addForce(new Force.Static(.2f));
public static final BlockState cogwheelState = AllBlocks.LARGE_COGWHEEL.getDefaultState().setValue(CogWheelBlock.AXIS, Direction.Axis.Y);
public static String modID = null;
protected final Screen parent;
public ConfigScreen(Screen parent) {
this.parent = parent;
}
@Override
public void tick() {
super.tick();
cogSpin.tick();
}
@Override
public void renderBackground(@Nonnull PoseStack ms) {
net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new ScreenEvent.BackgroundDrawnEvent(this, ms));
}
@Override
protected void renderWindowBackground(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
if (this.minecraft != null && this.minecraft.level != null) {
//in game
fill(ms, 0, 0, this.width, this.height, 0xb0_282c34);
} else {
//in menus
renderMenuBackground(ms, partialTicks);
}
/*new StencilElement() {
@Override
protected void renderStencil(PoseStack ms) {
renderCog(ms, partialTicks);
}
@Override
protected void renderElement(PoseStack ms) {
fill(ms, -200, -200, 200, 200, 0x60_000000);
}
}*/
new DelegatedStencilElement(
(ps, x, y, alpha) -> renderCog(ps, partialTicks),
(ps, x, y, alpha) -> fill(ms, -200, -200, 200, 200, 0x60_000000)
).at(width * 0.5f, height * 0.5f, 0).render(ms);
super.renderWindowBackground(ms, mouseX, mouseY, partialTicks);
}
@Override
protected void prepareFrame() {
UIRenderHelper.swapAndBlitColor(minecraft.getMainRenderTarget(), UIRenderHelper.framebuffer);
RenderSystem.clear(GL30.GL_STENCIL_BUFFER_BIT | GL30.GL_DEPTH_BUFFER_BIT, Minecraft.ON_OSX);
}
@Override
protected void endFrame() {
UIRenderHelper.swapAndBlitColor(UIRenderHelper.framebuffer, minecraft.getMainRenderTarget());
}
@Override
protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
}
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
cogSpin.bump(3, -delta * 5);
return super.mouseScrolled(mouseX, mouseY, delta);
}
@Override
public boolean isPauseScreen() {
return true;
}
public static String toHumanReadable(String key) {
String s = key.replaceAll("_", " ");
s = Arrays.stream(StringUtils.splitByCharacterTypeCamelCase(s)).map(StringUtils::capitalize).collect(Collectors.joining(" "));
s = StringUtils.normalizeSpace(s);
return s;
}
/**
* By default ConfigScreens will render the Create Panorama as
* their background when opened from the Main- or ModList-Menu.
* If your addon wants to render something else, please add to the
* backgrounds Map in this Class with your modID as the key.
*/
protected void renderMenuBackground(PoseStack ms, float partialTicks) {
TriConsumer<Screen, PoseStack, Float> customBackground = backgrounds.get(modID);
if (customBackground != null) {
customBackground.accept(this, ms, partialTicks);
return;
}
float elapsedPartials = minecraft.getDeltaFrameTime();
CreateMainMenuScreen.PANORAMA.render(elapsedPartials, 1);
RenderSystem.setShaderTexture(0, CreateMainMenuScreen.PANORAMA_OVERLAY_TEXTURES);
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
blit(ms, 0, 0, this.width, this.height, 0.0F, 0.0F, 16, 128, 16, 128);
fill(ms, 0, 0, this.width, this.height, 0x90_282c34);
}
protected void renderCog(PoseStack ms, float partialTicks) {
ms.pushPose();
ms.translate(-100, 100, -100);
ms.scale(200, 200, 1);
GuiGameElement.of(cogwheelState)
.rotateBlock(22.5, cogSpin.getValue(partialTicks), 22.5)
.render(ms);
ms.popPose();
}
}

View file

@ -1,278 +0,0 @@
package com.simibubi.create.foundation.config.ui;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.platform.Window;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.foundation.config.ui.entries.NumberEntry;
import com.simibubi.create.foundation.gui.RemovedGuiUtils;
import net.createmod.catnip.gui.TickableGuiEventListener;
import net.createmod.catnip.gui.UIRenderHelper;
import net.createmod.catnip.gui.element.TextStencilElement;
import net.createmod.catnip.utility.animation.LerpedFloat;
import net.createmod.catnip.utility.theme.Color;
import net.createmod.catnip.utility.theme.Theme;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.components.ObjectSelectionList;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
public class ConfigScreenList extends ObjectSelectionList<ConfigScreenList.Entry> implements TickableGuiEventListener {
public static EditBox currentText;
public ConfigScreenList(Minecraft client, int width, int height, int top, int bottom, int elementHeight) {
super(client, width, height, top, bottom, elementHeight);
setRenderBackground(false);
setRenderTopAndBottom(false);
setRenderSelection(false);
currentText = null;
headerHeight = 3;
}
@Override
public void render(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
Color c = new Color(0x60_000000);
UIRenderHelper.angledGradient(ms, 90, x0 + width / 2, y0, width, 5, c, Color.TRANSPARENT_BLACK);
UIRenderHelper.angledGradient(ms, -90, x0 + width / 2, y1, width, 5, c, Color.TRANSPARENT_BLACK);
UIRenderHelper.angledGradient(ms, 0, x0, y0 + height / 2, height, 5, c, Color.TRANSPARENT_BLACK);
UIRenderHelper.angledGradient(ms, 180, x1, y0 + height / 2, height, 5, c, Color.TRANSPARENT_BLACK);
super.render(ms, mouseX, mouseY, partialTicks);
}
@Override
protected void renderList(PoseStack p_238478_1_, int p_238478_2_, int p_238478_3_, int p_238478_4_, int p_238478_5_, float p_238478_6_) {
Window window = minecraft.getWindow();
double d0 = window.getGuiScale();
RenderSystem.enableScissor((int) (this.x0 * d0), (int) (window.getHeight() - (this.y1 * d0)), (int) (this.width * d0), (int) (this.height * d0));
super.renderList(p_238478_1_, p_238478_2_, p_238478_3_, p_238478_4_, p_238478_5_, p_238478_6_);
RenderSystem.disableScissor();
}
@Override
public boolean mouseClicked(double x, double y, int button) {
children().stream().filter(e -> e instanceof NumberEntry<?>).forEach(e -> e.mouseClicked(x, y, button));
return super.mouseClicked(x, y, button);
}
@Override
public int getRowWidth() {
return width - 16;
}
@Override
protected int getScrollbarPosition() {
return x0 + this.width - 6;
}
@Override
public void tick() {
/*for(int i = 0; i < getItemCount(); ++i) {
int top = this.getRowTop(i);
int bot = top + itemHeight;
if (bot >= this.y0 && top <= this.y1)
this.getEntry(i).tick();
}*/
children().forEach(Entry::tick);
}
public boolean search(String query) {
if (query == null || query.isEmpty()) {
setScrollAmount(0);
return true;
}
String q = query.toLowerCase(Locale.ROOT);
Optional<Entry> first = children().stream().filter(entry -> {
if (entry.path == null)
return false;
String[] split = entry.path.split("\\.");
String key = split[split.length - 1].toLowerCase(Locale.ROOT);
return key.contains(q);
}).findFirst();
if (!first.isPresent()) {
setScrollAmount(0);
return false;
}
Entry e = first.get();
e.annotations.put("highlight", "(:");
centerScrollOn(e);
return true;
}
public void bumpCog(float force) {
ConfigScreen.cogSpin.bump(3, force);
}
public static abstract class Entry extends ObjectSelectionList.Entry<Entry> implements TickableGuiEventListener {
protected List<GuiEventListener> listeners;
protected Map<String, String> annotations;
protected String path;
protected Entry() {
listeners = new ArrayList<>();
annotations = new HashMap<>();
}
@Override
public boolean mouseClicked(double x, double y, int button) {
return getGuiListeners().stream().anyMatch(l -> l.mouseClicked(x, y, button));
}
@Override
public boolean keyPressed(int code, int keyPressed_2_, int keyPressed_3_) {
return getGuiListeners().stream().anyMatch(l -> l.keyPressed(code, keyPressed_2_, keyPressed_3_));
}
@Override
public boolean charTyped(char ch, int code) {
return getGuiListeners().stream().anyMatch(l -> l.charTyped(ch, code));
}
@Override
public void tick() {}
public List<GuiEventListener> getGuiListeners() {
return listeners;
}
protected void setEditable(boolean b) {}
protected boolean isCurrentValueChanged() {
if (path == null) {
return false;
}
return ConfigHelper.changes.containsKey(path);
}
}
public static class LabeledEntry extends Entry {
protected static final float labelWidthMult = 0.4f;
protected TextStencilElement label;
protected List<Component> labelTooltip;
protected String unit = null;
protected LerpedFloat differenceAnimation = LerpedFloat.linear().startWithValue(0);
protected LerpedFloat highlightAnimation = LerpedFloat.linear().startWithValue(0);
public LabeledEntry(String label) {
this.label = new TextStencilElement(Minecraft.getInstance().font, label);
this.label.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, height, width, Theme.Key.TEXT_ACCENT_STRONG.p()));
labelTooltip = new ArrayList<>();
}
public LabeledEntry(String label, String path) {
this(label);
this.path = path;
}
@Override
public void tick() {
differenceAnimation.tickChaser();
highlightAnimation.tickChaser();
super.tick();
}
@Override
public void render(PoseStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) {
if (isCurrentValueChanged()) {
if (differenceAnimation.getChaseTarget() != 1)
differenceAnimation.chase(1, .5f, LerpedFloat.Chaser.EXP);
} else {
if (differenceAnimation.getChaseTarget() != 0)
differenceAnimation.chase(0, .6f, LerpedFloat.Chaser.EXP);
}
float animation = differenceAnimation.getValue(partialTicks);
if (animation > .1f) {
int offset = (int) (30 * (1 - animation));
if (annotations.containsKey(ConfigAnnotations.RequiresRestart.CLIENT.getName())) {
UIRenderHelper.streak(ms, 180, x + width + 10 + offset, y + height / 2, height - 6, 110, new Color(0x50_601010));
} else if (annotations.containsKey(ConfigAnnotations.RequiresRelog.TRUE.getName())) {
UIRenderHelper.streak(ms, 180, x + width + 10 + offset, y + height / 2, height - 6, 110, new Color(0x40_eefb17));
}
UIRenderHelper.breadcrumbArrow(ms, x - 10 - offset, y + 6, 0, -20, 24, -18, new Color(0x70_ffffff), Color.TRANSPARENT_BLACK);
}
UIRenderHelper.streak(ms, 0, x - 10, y + height / 2, height - 6, width / 8 * 7, new Color(0xdd_000000));
UIRenderHelper.streak(ms, 180, x + (int) (width * 1.35f) + 10, y + height / 2, height - 6, width / 8 * 7, new Color(0xdd_000000));
MutableComponent component = label.getComponent();
Font font = Minecraft.getInstance().font;
if (font.width(component) > getLabelWidth(width) - 10) {
label.withText(font.substrByWidth(component, getLabelWidth(width) - 15).getString() + "...");
}
if (unit != null) {
int unitWidth = font.width(unit);
font.draw(ms, unit, x + getLabelWidth(width) - unitWidth - 5, y + height / 2 + 2, Theme.Key.TEXT_DARKER.i());
label.at(x + 10, y + height / 2 - 10, 0).render(ms);
} else {
label.at(x + 10, y + height / 2 - 4, 0).render(ms);
}
if (annotations.containsKey("highlight")) {
highlightAnimation.startWithValue(1).chase(0, 0.1f, LerpedFloat.Chaser.LINEAR);
annotations.remove("highlight");
}
animation = highlightAnimation.getValue(partialTicks);
if (animation > .01f) {
Color highlight = new Color(0xa0_ffffff).scaleAlpha(animation);
UIRenderHelper.streak(ms, 0, x - 10, y + height / 2, height - 6, 5, highlight);
UIRenderHelper.streak(ms, 180, x + width, y + height / 2, height - 6, 5, highlight);
UIRenderHelper.streak(ms, 90, x + width / 2 - 5, y + 3, width + 10, 5, highlight);
UIRenderHelper.streak(ms, -90, x + width / 2 - 5, y + height - 3, width + 10, 5, highlight);
}
if (mouseX > x && mouseX < x + getLabelWidth(width) && mouseY > y + 5 && mouseY < y + height - 5) {
List<Component> tooltip = getLabelTooltip();
if (tooltip.isEmpty())
return;
RenderSystem.disableScissor();
Screen screen = Minecraft.getInstance().screen;
ms.pushPose();
ms.translate(0, 0, 400);
RemovedGuiUtils.drawHoveringText(ms, tooltip, mouseX, mouseY, screen.width, screen.height, 300, font);
ms.popPose();
GlStateManager._enableScissorTest();
}
}
public List<Component> getLabelTooltip() {
return labelTooltip;
}
protected int getLabelWidth(int totalWidth) {
return totalWidth;
}
// TODO 1.17
@Override
public Component getNarration() {
return TextComponent.EMPTY;
}
}
}

View file

@ -1,27 +0,0 @@
package com.simibubi.create.foundation.config.ui;
import net.minecraft.client.gui.Font;
public class ConfigTextField extends HintableTextFieldWidget {
public ConfigTextField(Font font, int x, int y, int width, int height) {
super(font, x, y, width, height);
}
@Override
public void setFocus(boolean focus) {
super.setFocus(focus);
if (!focus) {
if (ConfigScreenList.currentText == this)
ConfigScreenList.currentText = null;
return;
}
if (ConfigScreenList.currentText != null && ConfigScreenList.currentText != this)
ConfigScreenList.currentText.setFocus(false);
ConfigScreenList.currentText = this;
}
}

View file

@ -1,62 +0,0 @@
package com.simibubi.create.foundation.config.ui;
import org.lwjgl.glfw.GLFW;
import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.vertex.PoseStack;
import net.createmod.catnip.utility.theme.Theme;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.network.chat.TextComponent;
public class HintableTextFieldWidget extends EditBox {
protected Font font;
protected String hint;
public HintableTextFieldWidget(Font font, int x, int y, int width, int height) {
super(font, x, y, width, height, TextComponent.EMPTY);
this.font = font;
}
public void setHint(String hint) {
this.hint = hint;
}
@Override
public void renderButton(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
super.renderButton(ms, mouseX, mouseY, partialTicks);
if (hint == null || hint.isEmpty())
return;
if (!getValue().isEmpty())
return;
font.draw(ms, hint, x + 5, this.y + (this.height - 8) / 2, Theme.Key.TEXT.c().scaleAlpha(.75f).getRGB());
}
@Override
public boolean mouseClicked(double x, double y, int button) {
if (!isMouseOver(x, y))
return false;
if (button == GLFW.GLFW_MOUSE_BUTTON_RIGHT) {
setValue("");
return true;
} else
return super.mouseClicked(x, y, button);
}
@Override
public boolean keyPressed(int code, int p_keyPressed_2_, int p_keyPressed_3_) {
InputConstants.Key mouseKey = InputConstants.getKey(code, p_keyPressed_2_);
if (Minecraft.getInstance().options.keyInventory.isActiveAndMatches(mouseKey)) {
return true;
}
return super.keyPressed(code, p_keyPressed_2_, p_keyPressed_3_);
}
}

View file

@ -1,469 +0,0 @@
package com.simibubi.create.foundation.config.ui;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.lwjgl.glfw.GLFW;
import com.electronwill.nightconfig.core.AbstractConfig;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.google.common.collect.Lists;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.foundation.config.ui.ConfigScreenList.LabeledEntry;
import com.simibubi.create.foundation.config.ui.entries.BooleanEntry;
import com.simibubi.create.foundation.config.ui.entries.EnumEntry;
import com.simibubi.create.foundation.config.ui.entries.NumberEntry;
import com.simibubi.create.foundation.config.ui.entries.SubMenuEntry;
import com.simibubi.create.foundation.config.ui.entries.ValueEntry;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.networking.AllPackets;
import net.createmod.catnip.gui.ConfirmationScreen;
import net.createmod.catnip.gui.ConfirmationScreen.Response;
import net.createmod.catnip.gui.ScreenOpener;
import net.createmod.catnip.gui.UIRenderHelper;
import net.createmod.catnip.gui.element.DelegatedStencilElement;
import net.createmod.catnip.gui.widget.BoxWidget;
import net.createmod.catnip.utility.Couple;
import net.createmod.catnip.utility.FontHelper;
import net.createmod.catnip.utility.Pair;
import net.createmod.catnip.utility.theme.Color;
import net.createmod.catnip.utility.theme.Theme;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.FormattedText;
import net.minecraft.network.chat.TextComponent;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.config.ModConfig;
public class SubMenuConfigScreen extends ConfigScreen {
public final ModConfig.Type type;
protected ForgeConfigSpec spec;
protected UnmodifiableConfig configGroup;
protected ConfigScreenList list;
protected BoxWidget resetAll;
protected BoxWidget saveChanges;
protected BoxWidget discardChanges;
protected BoxWidget goBack;
protected BoxWidget serverLocked;
protected HintableTextFieldWidget search;
protected int listWidth;
protected String title;
protected Set<String> highlights = new HashSet<>();
public static SubMenuConfigScreen find(ConfigHelper.ConfigPath path) {
// TODO 1.17: can be null
ForgeConfigSpec spec = ConfigHelper.findForgeConfigSpecFor(path.getType(), path.getModID());
UnmodifiableConfig values = spec.getValues();
BaseConfigScreen base = new BaseConfigScreen(null, path.getModID());
SubMenuConfigScreen screen = new SubMenuConfigScreen(base, "root", path.getType(), spec, values);
List<String> remainingPath = Lists.newArrayList(path.getPath());
path: while (!remainingPath.isEmpty()) {
String next = remainingPath.remove(0);
for (Map.Entry<String, Object> entry : values.valueMap().entrySet()) {
String key = entry.getKey();
Object obj = entry.getValue();
if (!key.equalsIgnoreCase(next))
continue;
if (!(obj instanceof AbstractConfig)) {
//highlight entry
screen.highlights.add(path.getPath()[path.getPath().length - 1]);
continue;
}
values = (UnmodifiableConfig) obj;
screen = new SubMenuConfigScreen(screen, toHumanReadable(key), path.getType(), spec, values);
continue path;
}
break;
}
ConfigScreen.modID = path.getModID();
return screen;
}
public SubMenuConfigScreen(Screen parent, String title, ModConfig.Type type, ForgeConfigSpec configSpec, UnmodifiableConfig configGroup) {
super(parent);
this.type = type;
this.spec = configSpec;
this.title = title;
this.configGroup = configGroup;
}
public SubMenuConfigScreen(Screen parent, ModConfig.Type type, ForgeConfigSpec configSpec) {
super(parent);
this.type = type;
this.spec = configSpec;
this.title = "root";
this.configGroup = configSpec.getValues();
}
protected void clearChanges() {
ConfigHelper.changes.clear();
list.children()
.stream()
.filter(e -> e instanceof ValueEntry)
.forEach(e -> ((ValueEntry<?>) e).onValueChange());
}
protected void saveChanges() {
UnmodifiableConfig values = spec.getValues();
ConfigHelper.changes.forEach((path, change) -> {
ForgeConfigSpec.ConfigValue<Object> configValue = values.get(path);
configValue.set(change.value);
if (type == ModConfig.Type.SERVER) {
AllPackets.channel.sendToServer(new CConfigureConfigPacket<>(ConfigScreen.modID, path, change.value));
}
String command = change.annotations.get("Execute");
if (minecraft.player != null && command != null && command.startsWith("/")) {
minecraft.player.chat(command);
//AllPackets.channel.sendToServer(new CChatMessagePacket(command));
}
});
clearChanges();
}
protected void resetConfig(UnmodifiableConfig values) {
values.valueMap().forEach((key, obj) -> {
if (obj instanceof AbstractConfig) {
resetConfig((UnmodifiableConfig) obj);
} else if (obj instanceof ForgeConfigSpec.ConfigValue) {
ForgeConfigSpec.ConfigValue<Object> configValue = (ForgeConfigSpec.ConfigValue<Object>) obj;
ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw((List<String>) configValue.getPath());
List<String> comments = new ArrayList<>();
if (valueSpec.getComment() != null)
comments.addAll(Arrays.asList(valueSpec.getComment().split("\n")));
Pair<String, Map<String, String>> metadata = ConfigHelper.readMetadataFromComment(comments);
ConfigHelper.setValue(String.join(".", configValue.getPath()), configValue, valueSpec.getDefault(), metadata.getSecond());
}
});
list.children()
.stream()
.filter(e -> e instanceof ValueEntry)
.forEach(e -> ((ValueEntry<?>) e).onValueChange());
}
@Override
protected void init() {
super.init();
listWidth = Math.min(width - 80, 300);
int yCenter = height / 2;
int listL = this.width / 2 - listWidth / 2;
int listR = this.width / 2 + listWidth / 2;
resetAll = new BoxWidget(listR + 10, yCenter - 25, 20, 20)
.withPadding(2, 2)
.withCallback((x, y) ->
new ConfirmationScreen()
.centered()
.withText(FormattedText.of("Resetting all settings of the " + type.toString() + " config. Are you sure?"))
.withAction(success -> {
if (success)
resetConfig(spec.getValues());
})
.open(this)
);
resetAll.showingElement(AllIcons.I_CONFIG_RESET.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(resetAll)));
resetAll.getToolTip().add(new TextComponent("Reset All"));
resetAll.getToolTip().addAll(FontHelper.cutStringTextComponent("Click here to reset all settings to their default value.", ChatFormatting.GRAY, ChatFormatting.GRAY));
saveChanges = new BoxWidget(listL - 30, yCenter - 25, 20, 20)
.withPadding(2, 2)
.withCallback((x, y) -> {
if (ConfigHelper.changes.isEmpty())
return;
ConfirmationScreen confirm = new ConfirmationScreen()
.centered()
.withText(FormattedText.of("Saving " + ConfigHelper.changes.size() + " changed value" + (ConfigHelper.changes.size() != 1 ? "s" : "") + ""))
.withAction(success -> {
if (success)
saveChanges();
});
addAnnotationsToConfirm(confirm).open(this);
});
saveChanges.showingElement(AllIcons.I_CONFIG_SAVE.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(saveChanges)));
saveChanges.getToolTip().add(new TextComponent("Save Changes"));
saveChanges.getToolTip().addAll(FontHelper.cutStringTextComponent("Click here to save your current changes.", ChatFormatting.GRAY, ChatFormatting.GRAY));
discardChanges = new BoxWidget(listL - 30, yCenter + 5, 20, 20)
.withPadding(2, 2)
.withCallback((x, y) -> {
if (ConfigHelper.changes.isEmpty())
return;
new ConfirmationScreen()
.centered()
.withText(FormattedText.of("Discarding " + ConfigHelper.changes.size() + " unsaved change" + (ConfigHelper.changes.size() != 1 ? "s" : "") + ""))
.withAction(success -> {
if (success)
clearChanges();
})
.open(this);
});
discardChanges.showingElement(AllIcons.I_CONFIG_DISCARD.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(discardChanges)));
discardChanges.getToolTip().add(new TextComponent("Discard Changes"));
discardChanges.getToolTip().addAll(FontHelper.cutStringTextComponent("Click here to discard all the changes you made.", ChatFormatting.GRAY, ChatFormatting.GRAY));
goBack = new BoxWidget(listL - 30, yCenter + 65, 20, 20)
.withPadding(2, 2)
.withCallback(this::attemptBackstep);
goBack.showingElement(AllIcons.I_CONFIG_BACK.asStencil().withElementRenderer(BoxWidget.gradientFactory.apply(goBack)));
goBack.getToolTip().add(new TextComponent("Go Back"));
addRenderableWidget(resetAll);
addRenderableWidget(saveChanges);
addRenderableWidget(discardChanges);
addRenderableWidget(goBack);
list = new ConfigScreenList(minecraft, listWidth, height - 80, 35, height - 45, 40);
list.setLeftPos(this.width / 2 - list.getWidth() / 2);
addRenderableWidget(list);
search = new ConfigTextField(font, width / 2 - listWidth / 2, height - 35, listWidth, 20);
search.setResponder(this::updateFilter);
search.setHint("Search...");
search.moveCursorToStart();
addRenderableWidget(search);
configGroup.valueMap().forEach((key, obj) -> {
String humanKey = toHumanReadable(key);
if (obj instanceof AbstractConfig) {
SubMenuEntry entry = new SubMenuEntry(this, humanKey, spec, (UnmodifiableConfig) obj);
entry.path = key;
list.children().add(entry);
if (configGroup.valueMap()
.size() == 1)
ScreenOpener.open(
new SubMenuConfigScreen(parent, humanKey, type, spec, (UnmodifiableConfig) obj));
} else if (obj instanceof ForgeConfigSpec.ConfigValue<?>) {
ForgeConfigSpec.ConfigValue<?> configValue = (ForgeConfigSpec.ConfigValue<?>) obj;
ForgeConfigSpec.ValueSpec valueSpec = spec.getRaw(configValue.getPath());
Object value = configValue.get();
ConfigScreenList.Entry entry = null;
if (value instanceof Boolean) {
entry = new BooleanEntry(humanKey, (ForgeConfigSpec.ConfigValue<Boolean>) configValue, valueSpec);
} else if (value instanceof Enum) {
entry = new EnumEntry(humanKey, (ForgeConfigSpec.ConfigValue<Enum<?>>) configValue, valueSpec);
} else if (value instanceof Number) {
entry = NumberEntry.create(value, humanKey, configValue, valueSpec);
}
if (entry == null)
entry = new LabeledEntry("Impl missing - " + configValue.get().getClass().getSimpleName() + " " + humanKey + " : " + value);
if (highlights.contains(key))
entry.annotations.put("highlight", ":)");
list.children().add(entry);
}
});
Collections.sort(list.children(),
(e, e2) -> {
int group = (e2 instanceof SubMenuEntry ? 1 : 0) - (e instanceof SubMenuEntry ? 1 : 0);
if (group == 0 && e instanceof LabeledEntry && e2 instanceof LabeledEntry) {
LabeledEntry le = (LabeledEntry) e;
LabeledEntry le2 = (LabeledEntry) e2;
return le.label.getComponent()
.getString()
.compareTo(le2.label.getComponent()
.getString());
}
return group;
});
list.search(highlights.stream().findFirst().orElse(""));
//extras for server configs
if (type != ModConfig.Type.SERVER)
return;
if (minecraft.hasSingleplayerServer())
return;
boolean canEdit = minecraft != null && minecraft.player != null && minecraft.player.hasPermissions(2);
Couple<Color> red = Theme.Key.BUTTON_FAIL.p();
Couple<Color> green = Theme.Key.BUTTON_SUCCESS.p();
DelegatedStencilElement stencil = new DelegatedStencilElement();
serverLocked = new BoxWidget(listR + 10, yCenter + 5, 20, 20)
.withPadding(2, 2)
.showingElement(stencil);
if (!canEdit) {
list.children().forEach(e -> e.setEditable(false));
resetAll.active = false;
stencil.withStencilRenderer((ms, w, h, alpha) -> AllIcons.I_CONFIG_LOCKED.render(ms, 0, 0));
stencil.withElementRenderer((ms, w, h, alpha) -> UIRenderHelper.angledGradient(ms, 90, 8, 0, 16, 16, red));
serverLocked.withBorderColors(red);
serverLocked.getToolTip().add(new TextComponent("Locked").withStyle(ChatFormatting.BOLD));
serverLocked.getToolTip().addAll(FontHelper.cutStringTextComponent("You do not have enough permissions to edit the server config. You can still look at the current values here though.", ChatFormatting.GRAY, ChatFormatting.GRAY));
} else {
stencil.withStencilRenderer((ms, w, h, alpha) -> AllIcons.I_CONFIG_UNLOCKED.render(ms, 0, 0));
stencil.withElementRenderer((ms, w, h, alpha) -> UIRenderHelper.angledGradient(ms, 90, 8, 0, 16, 16, green));
serverLocked.withBorderColors(green);
serverLocked.getToolTip().add(new TextComponent("Unlocked").withStyle(ChatFormatting.BOLD));
serverLocked.getToolTip().addAll(FontHelper.cutStringTextComponent("You have enough permissions to edit the server config. Changes you make here will be synced with the server when you save them.", ChatFormatting.GRAY, ChatFormatting.GRAY));
}
addRenderableWidget(serverLocked);
}
@Override
protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
super.renderWindow(ms, mouseX, mouseY, partialTicks);
int x = width / 2;
drawCenteredString(ms, minecraft.font, ConfigScreen.modID + " > " + type.toString().toLowerCase(Locale.ROOT) + " > " + title, x, 15, Theme.Key.TEXT.i());
}
@Override
protected void renderWindowForeground(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
super.renderWindowForeground(ms, mouseX, mouseY, partialTicks);
}
@Override
public void resize(@Nonnull Minecraft client, int width, int height) {
double scroll = list.getScrollAmount();
init(client, width, height);
list.setScrollAmount(scroll);
}
@Nullable
@Override
public GuiEventListener getFocused() {
if (ConfigScreenList.currentText != null)
return ConfigScreenList.currentText;
return super.getFocused();
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (super.keyPressed(keyCode, scanCode, modifiers))
return true;
if (Screen.hasControlDown()) {
if (keyCode == GLFW.GLFW_KEY_F) {
search.setFocus(true);
}
}
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
attemptBackstep();
}
return false;
}
private void updateFilter(String search) {
if (list.search(search)) {
this.search.setTextColor(Theme.Key.TEXT.i());
} else {
this.search.setTextColor(Theme.Key.BUTTON_FAIL.i());
}
}
private void attemptBackstep() {
if (ConfigHelper.changes.isEmpty() || !(parent instanceof BaseConfigScreen)) {
ScreenOpener.open(parent);
return;
}
showLeavingPrompt(success -> {
if (success == Response.Cancel)
return;
if (success == Response.Confirm)
saveChanges();
ConfigHelper.changes.clear();
ScreenOpener.open(parent);
});
}
@Override
public void onClose() {
if (ConfigHelper.changes.isEmpty()) {
super.onClose();
return;
}
showLeavingPrompt(success -> {
if (success == Response.Cancel)
return;
if (success == Response.Confirm)
saveChanges();
ConfigHelper.changes.clear();
super.onClose();
});
}
public void showLeavingPrompt(Consumer<ConfirmationScreen.Response> action) {
ConfirmationScreen screen = new ConfirmationScreen()
.centered()
.withThreeActions(action)
.addText(FormattedText.of("Leaving with " + ConfigHelper.changes.size() + " unsaved change"
+ (ConfigHelper.changes.size() != 1 ? "s" : "") + " for this config"));
addAnnotationsToConfirm(screen).open(this);
}
private ConfirmationScreen addAnnotationsToConfirm(ConfirmationScreen screen) {
AtomicBoolean relog = new AtomicBoolean(false);
AtomicBoolean restart = new AtomicBoolean(false);
ConfigHelper.changes.values().forEach(change -> {
if (change.annotations.containsKey(ConfigAnnotations.RequiresRelog.TRUE.getName()))
relog.set(true);
if (change.annotations.containsKey(ConfigAnnotations.RequiresRestart.CLIENT.getName()))
restart.set(true);
});
if (relog.get()) {
screen.addText(FormattedText.of(" "));
screen.addText(FormattedText.of("At least one changed value will require you to relog to take full effect"));
}
if (restart.get()) {
screen.addText(FormattedText.of(" "));
screen.addText(FormattedText.of("At least one changed value will require you to restart your game to take full effect"));
}
return screen;
}
}

View file

@ -1,66 +0,0 @@
package com.simibubi.create.foundation.config.ui.entries;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.foundation.gui.AllIcons;
import net.createmod.catnip.gui.UIRenderHelper;
import net.createmod.catnip.gui.element.RenderElement;
import net.createmod.catnip.gui.widget.BoxWidget;
import net.createmod.catnip.utility.theme.Theme;
import net.minecraftforge.common.ForgeConfigSpec;
public class BooleanEntry extends ValueEntry<Boolean> {
RenderElement enabled;
RenderElement disabled;
BoxWidget button;
public BooleanEntry(String label, ForgeConfigSpec.ConfigValue<Boolean> value, ForgeConfigSpec.ValueSpec spec) {
super(label, value, spec);
enabled = AllIcons.I_CONFIRM.asStencil()
.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, height, width, Theme.Key.BUTTON_SUCCESS.p()))
.at(10, 0);
disabled = AllIcons.I_DISABLE.asStencil()
.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2, height, width, Theme.Key.BUTTON_FAIL.p()))
.at(10, 0);
button = new BoxWidget().showingElement(enabled)
.withCallback(() -> setValue(!getValue()));
listeners.add(button);
onReset();
}
@Override
protected void setEditable(boolean b) {
super.setEditable(b);
button.active = b;
}
@Override
public void tick() {
super.tick();
button.tick();
}
@Override
public void render(PoseStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY,
boolean p_230432_9_, float partialTicks) {
super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks);
button.x = x + width - 80 - resetWidth;
button.y = y + 10;
button.setWidth(35);
button.setHeight(height - 20);
button.render(ms, mouseX, mouseY, partialTicks);
}
@Override
public void onValueChange(Boolean newValue) {
super.onValueChange(newValue);
button.showingElement(newValue ? enabled : disabled);
bumpCog(newValue ? 15f : -16f);
}
}

View file

@ -1,109 +0,0 @@
package com.simibubi.create.foundation.config.ui.entries;
import java.util.Locale;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.foundation.config.ui.ConfigScreen;
import com.simibubi.create.foundation.gui.AllIcons;
import net.createmod.catnip.gui.UIRenderHelper;
import net.createmod.catnip.gui.element.BoxElement;
import net.createmod.catnip.gui.element.DelegatedStencilElement;
import net.createmod.catnip.gui.element.TextStencilElement;
import net.createmod.catnip.gui.widget.BoxWidget;
import net.createmod.catnip.utility.theme.Theme;
import net.minecraft.client.Minecraft;
import net.minecraftforge.common.ForgeConfigSpec;
public class EnumEntry extends ValueEntry<Enum<?>> {
protected static final int cycleWidth = 34;
protected TextStencilElement valueText;
protected BoxWidget cycleLeft;
protected BoxWidget cycleRight;
public EnumEntry(String label, ForgeConfigSpec.ConfigValue<Enum<?>> value, ForgeConfigSpec.ValueSpec spec) {
super(label, value, spec);
valueText = new TextStencilElement(Minecraft.getInstance().font, "YEP").centered(true, true);
valueText.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0, 0, height / 2,
height, width, Theme.Key.TEXT.p()));
DelegatedStencilElement l = AllIcons.I_CONFIG_PREV.asStencil();
cycleLeft = new BoxWidget(0, 0, cycleWidth + 8, 16)
.withCustomBackground(Theme.Key.PONDER_BACKGROUND_FLAT.c())
.showingElement(l)
.withCallback(() -> cycleValue(-1));
l.withElementRenderer(BoxWidget.gradientFactory.apply(cycleLeft));
DelegatedStencilElement r = AllIcons.I_CONFIG_NEXT.asStencil();
cycleRight = new BoxWidget(0, 0, cycleWidth + 8, 16)
.withCustomBackground(Theme.Key.PONDER_BACKGROUND_FLAT.c())
.showingElement(r)
.withCallback(() -> cycleValue(1));
r.at(cycleWidth - 8, 0);
r.withElementRenderer(BoxWidget.gradientFactory.apply(cycleRight));
listeners.add(cycleLeft);
listeners.add(cycleRight);
onReset();
}
protected void cycleValue(int direction) {
Enum<?> e = getValue();
Enum<?>[] options = e.getDeclaringClass()
.getEnumConstants();
e = options[Math.floorMod(e.ordinal() + direction, options.length)];
setValue(e);
bumpCog(direction * 15f);
}
@Override
protected void setEditable(boolean b) {
super.setEditable(b);
cycleLeft.active = b;
cycleLeft.animateGradientFromState();
cycleRight.active = b;
cycleRight.animateGradientFromState();
}
@Override
public void tick() {
super.tick();
cycleLeft.tick();
cycleRight.tick();
}
@Override
public void render(PoseStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY,
boolean p_230432_9_, float partialTicks) {
super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks);
cycleLeft.x = x + getLabelWidth(width) + 4;
cycleLeft.y = y + 10;
cycleLeft.render(ms, mouseX, mouseY, partialTicks);
valueText.at(cycleLeft.x + cycleWidth - 8, y + 10, 200)
.withBounds(width - getLabelWidth(width) - 2 * cycleWidth - resetWidth - 4, 16)
.render(ms);
cycleRight.x = x + width - cycleWidth * 2 - resetWidth + 10;
cycleRight.y = y + 10;
cycleRight.render(ms, mouseX, mouseY, partialTicks);
new BoxElement()
.withBackground(Theme.Key.PONDER_BACKGROUND_FLAT.c())
.flatBorder(0x01_000000)
.withBounds(48, 6)
.at(cycleLeft.x + 22, cycleLeft.y + 5)
.render(ms);
}
@Override
public void onValueChange(Enum<?> newValue) {
super.onValueChange(newValue);
valueText.withText(ConfigScreen.toHumanReadable(newValue.name().toLowerCase(Locale.ROOT)));
}
}

View file

@ -1,246 +0,0 @@
package com.simibubi.create.foundation.config.ui.entries;
import java.lang.reflect.Field;
import java.util.Locale;
import java.util.function.Function;
import javax.annotation.Nullable;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.foundation.config.ui.ConfigTextField;
import net.createmod.catnip.utility.theme.Theme;
import net.createmod.catnip.gui.UIRenderHelper;
import net.createmod.catnip.gui.element.TextStencilElement;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.network.chat.TextComponent;
import net.minecraftforge.common.ForgeConfigSpec;
public abstract class NumberEntry<T extends Number> extends ValueEntry<T> {
protected int minOffset = 0, maxOffset = 0;
protected TextStencilElement minText = null, maxText = null;
protected EditBox textField;
@Nullable
public static NumberEntry<? extends Number> create(Object type, String label, ForgeConfigSpec.ConfigValue<?> value, ForgeConfigSpec.ValueSpec spec) {
if (type instanceof Integer) {
return new IntegerEntry(label, (ForgeConfigSpec.ConfigValue<Integer>) value, spec);
} else if (type instanceof Float) {
return new FloatEntry(label, (ForgeConfigSpec.ConfigValue<Float>) value, spec);
} else if (type instanceof Double) {
return new DoubleEntry(label, (ForgeConfigSpec.ConfigValue<Double>) value, spec);
}
return null;
}
public NumberEntry(String label, ForgeConfigSpec.ConfigValue<T> value, ForgeConfigSpec.ValueSpec spec) {
super(label, value, spec);
textField = new ConfigTextField(Minecraft.getInstance().font, 0, 0, 200, 20);
if (this instanceof IntegerEntry && annotations.containsKey("IntDisplay")) {
String intDisplay = annotations.get("IntDisplay");
int intValue = (Integer) getValue();
String textValue;
switch (intDisplay) {
case "#":
textValue = "#" + Integer.toHexString(intValue).toUpperCase(Locale.ROOT);
break;
case "0x":
textValue = "0x" + Integer.toHexString(intValue).toUpperCase(Locale.ROOT);
break;
case "0b":
textValue = "0b" + Integer.toBinaryString(intValue);
break;
default:
textValue = String.valueOf(intValue);
}
textField.setValue(textValue);
} else {
textField.setValue(String.valueOf(getValue()));
}
textField.setTextColor(Theme.Key.TEXT.i());
Object range = spec.getRange();
try {
Field minField = range.getClass().getDeclaredField("min");
Field maxField = range.getClass().getDeclaredField("max");
minField.setAccessible(true);
maxField.setAccessible(true);
T min = (T) minField.get(range);
T max = (T) maxField.get(range);
Font font = Minecraft.getInstance().font;
if (min.doubleValue() > getTypeMin().doubleValue()) {
TextComponent t = new TextComponent(formatBound(min) + " < ");
minText = new TextStencilElement(font, t).centered(true, false);
minText.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0 ,0, height/2, height, width, Theme.Key.TEXT_DARKER.p()));
minOffset = font.width(t);
}
if (max.doubleValue() < getTypeMax().doubleValue()) {
TextComponent t = new TextComponent(" < " + formatBound(max));
maxText = new TextStencilElement(font, t).centered(true, false);
maxText.withElementRenderer((ms, width, height, alpha) -> UIRenderHelper.angledGradient(ms, 0 ,0, height/2, height, width, Theme.Key.TEXT_DARKER.p()));
maxOffset = font.width(t);
}
} catch (NoSuchFieldException | IllegalAccessException | ClassCastException | NullPointerException ignored) {
}
textField.setResponder(s -> {
try {
T number = getParser().apply(s);
if (!spec.test(number))
throw new IllegalArgumentException();
textField.setTextColor(Theme.Key.TEXT.i());
setValue(number);
} catch (IllegalArgumentException ignored) {
textField.setTextColor(Theme.Key.BUTTON_FAIL.i());
}
});
textField.moveCursorToStart();
listeners.add(textField);
onReset();
}
protected String formatBound(T bound) {
String sci = String.format("%.2E", bound.doubleValue());
String str = String.valueOf(bound);
return sci.length() < str.length() ? sci : str;
}
protected abstract T getTypeMin();
protected abstract T getTypeMax();
protected abstract Function<String, T> getParser();
@Override
protected void setEditable(boolean b) {
super.setEditable(b);
textField.setEditable(b);
}
@Override
public void onValueChange(T newValue) {
super.onValueChange(newValue);
try {
T current = getParser().apply(textField.getValue());
if (!current.equals(newValue)) {
textField.setValue(String.valueOf(newValue));
}
} catch (IllegalArgumentException ignored) {}
}
@Override
public void tick() {
super.tick();
textField.tick();
}
@Override
public void render(PoseStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) {
super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks);
textField.x = x + width - 82 - resetWidth;
textField.y = y + 8;
textField.setWidth(Math.min(width - getLabelWidth(width) - resetWidth - minOffset - maxOffset, 40));
textField.setHeight(20);
textField.render(ms, mouseX, mouseY, partialTicks);
if (minText != null)
minText
.at(textField.x - minOffset, textField.y, 0)
.withBounds(minOffset, textField.getHeight())
.render(ms);
if (maxText != null)
maxText
.at(textField.x + textField.getWidth(), textField.y, 0)
.withBounds(maxOffset, textField.getHeight())
.render(ms);
}
public static class IntegerEntry extends NumberEntry<Integer> {
public IntegerEntry(String label, ForgeConfigSpec.ConfigValue<Integer> value, ForgeConfigSpec.ValueSpec spec) {
super(label, value, spec);
}
@Override
protected Integer getTypeMin() {
return Integer.MIN_VALUE;
}
@Override
protected Integer getTypeMax() {
return Integer.MAX_VALUE;
}
@Override
protected Function<String, Integer> getParser() {
return (string) -> {
if (string.startsWith("#")) {
return Integer.parseUnsignedInt(string.substring(1), 16);
} else if (string.startsWith("0x")) {
return Integer.parseUnsignedInt(string.substring(2), 16);
} else if (string.startsWith("0b")) {
return Integer.parseUnsignedInt(string.substring(2), 2);
} else {
return Integer.parseInt(string);
}
};
}
}
public static class FloatEntry extends NumberEntry<Float> {
public FloatEntry(String label, ForgeConfigSpec.ConfigValue<Float> value, ForgeConfigSpec.ValueSpec spec) {
super(label, value, spec);
}
@Override
protected Float getTypeMin() {
return -Float.MAX_VALUE;
}
@Override
protected Float getTypeMax() {
return Float.MAX_VALUE;
}
@Override
protected Function<String, Float> getParser() {
return Float::parseFloat;
}
}
public static class DoubleEntry extends NumberEntry<Double> {
public DoubleEntry(String label, ForgeConfigSpec.ConfigValue<Double> value, ForgeConfigSpec.ValueSpec spec) {
super(label, value, spec);
}
@Override
protected Double getTypeMin() {
return (double) -Float.MAX_VALUE;
}
@Override
protected Double getTypeMax() {
return (double) Float.MAX_VALUE;
}
@Override
protected Function<String, Double> getParser() {
return Double::parseDouble;
}
}
}

View file

@ -1,49 +0,0 @@
package com.simibubi.create.foundation.config.ui.entries;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.foundation.config.ui.ConfigScreenList;
import com.simibubi.create.foundation.config.ui.SubMenuConfigScreen;
import com.simibubi.create.foundation.gui.AllIcons;
import net.createmod.catnip.gui.ScreenOpener;
import net.createmod.catnip.gui.element.DelegatedStencilElement;
import net.createmod.catnip.gui.widget.BoxWidget;
import net.minecraftforge.common.ForgeConfigSpec;
public class SubMenuEntry extends ConfigScreenList.LabeledEntry {
protected BoxWidget button;
public SubMenuEntry(SubMenuConfigScreen parent, String label, ForgeConfigSpec spec, UnmodifiableConfig config) {
super(label);
button = new BoxWidget(0, 0, 35, 16)
.showingElement(AllIcons.I_CONFIG_OPEN.asStencil().at(10, 0))
.withCallback(() -> ScreenOpener.open(new SubMenuConfigScreen(parent, label, parent.type, spec, config)));
button.modifyElement(e -> ((DelegatedStencilElement) e).withElementRenderer(BoxWidget.gradientFactory.apply(button)));
listeners.add(button);
}
@Override
public void tick() {
super.tick();
button.tick();
}
@Override
public void render(PoseStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) {
super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks);
button.x = x + width - 108;
button.y = y + 10;
button.setHeight(height - 20);
button.render(ms, mouseX, mouseY, partialTicks);
}
@Override
protected int getLabelWidth(int totalWidth) {
return (int) (totalWidth * labelWidthMult) + 30;
}
}

View file

@ -1,143 +0,0 @@
package com.simibubi.create.foundation.config.ui.entries;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import com.google.common.base.Predicates;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.foundation.config.ui.ConfigAnnotations;
import com.simibubi.create.foundation.config.ui.ConfigHelper;
import com.simibubi.create.foundation.config.ui.ConfigScreen;
import com.simibubi.create.foundation.config.ui.ConfigScreenList;
import com.simibubi.create.foundation.gui.AllIcons;
import net.createmod.catnip.gui.element.DelegatedStencilElement;
import net.createmod.catnip.gui.widget.BoxWidget;
import net.createmod.catnip.utility.FontHelper;
import net.createmod.catnip.utility.Pair;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.TextComponent;
import net.minecraftforge.common.ForgeConfigSpec;
public class ValueEntry<T> extends ConfigScreenList.LabeledEntry {
protected static final int resetWidth = 28;//including 6px offset on either side
protected ForgeConfigSpec.ConfigValue<T> value;
protected ForgeConfigSpec.ValueSpec spec;
protected BoxWidget resetButton;
protected boolean editable = true;
public ValueEntry(String label, ForgeConfigSpec.ConfigValue<T> value, ForgeConfigSpec.ValueSpec spec) {
super(label);
this.value = value;
this.spec = spec;
this.path = String.join(".", value.getPath());
resetButton = new BoxWidget(0, 0, resetWidth - 12, 16)
.showingElement(AllIcons.I_CONFIG_RESET.asStencil())
.withCallback(() -> {
setValue((T) spec.getDefault());
this.onReset();
});
resetButton.modifyElement(e -> ((DelegatedStencilElement) e).withElementRenderer(BoxWidget.gradientFactory.apply(resetButton)));
listeners.add(resetButton);
List<String> path = value.getPath();
labelTooltip.add(new TextComponent(label).withStyle(ChatFormatting.WHITE));
String comment = spec.getComment();
if (comment == null || comment.isEmpty())
return;
List<String> commentLines = new ArrayList<>(Arrays.asList(comment.split("\n")));
Pair<String, Map<String, String>> metadata = ConfigHelper.readMetadataFromComment(commentLines);
if (metadata.getFirst() != null) {
unit = metadata.getFirst();
}
if (metadata.getSecond() != null && !metadata.getSecond().isEmpty()) {
annotations.putAll(metadata.getSecond());
}
// add comment to tooltip
labelTooltip.addAll(commentLines.stream()
.filter(Predicates.not(s -> s.startsWith("Range")))
.map(TextComponent::new)
.flatMap(stc -> FontHelper.cutTextComponent(stc, ChatFormatting.GRAY, ChatFormatting.GRAY)
.stream())
.collect(Collectors.toList()));
if (annotations.containsKey(ConfigAnnotations.RequiresRelog.TRUE.getName()))
labelTooltip.addAll(FontHelper.cutTextComponent(new TextComponent("Changing this value will require a _relog_ to take full effect"), ChatFormatting.GRAY, ChatFormatting.GOLD));
if (annotations.containsKey(ConfigAnnotations.RequiresRestart.CLIENT.getName()))
labelTooltip.addAll(FontHelper.cutTextComponent(new TextComponent("Changing this value will require a _restart_ to take full effect"), ChatFormatting.GRAY, ChatFormatting.RED));
labelTooltip.add(new TextComponent(ConfigScreen.modID + ":" + path.get(path.size() - 1)).withStyle(ChatFormatting.DARK_GRAY));
}
@Override
protected void setEditable(boolean b) {
editable = b;
resetButton.active = editable && !isCurrentValueDefault();
resetButton.animateGradientFromState();
}
@Override
public void tick() {
super.tick();
resetButton.tick();
}
@Override
public void render(PoseStack ms, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean p_230432_9_, float partialTicks) {
super.render(ms, index, y, x, width, height, mouseX, mouseY, p_230432_9_, partialTicks);
resetButton.x = x + width - resetWidth + 6;
resetButton.y = y + 10;
resetButton.render(ms, mouseX, mouseY, partialTicks);
}
@Override
protected int getLabelWidth(int totalWidth) {
return (int) (totalWidth * labelWidthMult) + 30;
}
public void setValue(@Nonnull T value) {
ConfigHelper.setValue(path, this.value, value, annotations);
onValueChange(value);
}
@Nonnull
public T getValue() {
return ConfigHelper.getValue(path, this.value);
}
protected boolean isCurrentValueDefault() {
return spec.getDefault().equals(getValue());
}
public void onReset() {
onValueChange(getValue());
}
public void onValueChange() {
onValueChange(getValue());
}
public void onValueChange(T newValue) {
resetButton.active = editable && !isCurrentValueDefault();
resetButton.animateGradientFromState();
}
protected void bumpCog() {bumpCog(10f);}
protected void bumpCog(float force) {
if (list != null && list instanceof ConfigScreenList)
((ConfigScreenList) list).bumpCog(force);
}
}

View file

@ -6,9 +6,9 @@ import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.config.ui.BaseConfigScreen;
import com.simibubi.create.foundation.utility.CreateLang;
import net.createmod.catnip.config.ui.BaseConfigScreen;
import net.createmod.catnip.gui.AbstractSimiScreen;
import net.createmod.catnip.gui.ScreenOpener;
import net.createmod.catnip.gui.element.BoxElement;
@ -147,7 +147,7 @@ public class CreateMainMenuScreen extends AbstractSimiScreen {
addRenderableWidget(
new Button(center - 100, yStart + 92, bLongWidth, bHeight, CreateLang.translateDirect("menu.return"), $ -> linkTo(parent)));
addRenderableWidget(new Button(center - 100, yStart + 24 + -16, bLongWidth, bHeight, CreateLang.translateDirect("menu.configure"),
$ -> linkTo(BaseConfigScreen.forCreate(this))));
$ -> linkTo(new BaseConfigScreen(this, Create.ID))));
gettingStarted = new Button(center + 2, yStart + 48 + -16, bShortWidth, bHeight,
CreateLang.translateDirect("menu.ponder_index"), $ -> linkTo(new PonderTagIndexScreen()));

View file

@ -1,4 +1,4 @@
package com.simibubi.create.foundation.config.ui;
package com.simibubi.create.foundation.gui.widget;
import java.util.Arrays;
import java.util.List;
@ -10,8 +10,8 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllItems;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.gui.CreateMainMenuScreen;
import net.createmod.catnip.gui.ScreenOpener;
import net.createmod.catnip.gui.ScreenOpener;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;

View file

@ -75,8 +75,7 @@ import com.simibubi.create.content.schematics.packet.SchematicPlacePacket;
import com.simibubi.create.content.schematics.packet.SchematicSyncPacket;
import com.simibubi.create.content.schematics.packet.SchematicUploadPacket;
import com.simibubi.create.foundation.command.HighlightPacket;
import com.simibubi.create.foundation.command.SConfigureConfigPacket;
import com.simibubi.create.foundation.config.ui.CConfigureConfigPacket;
import com.simibubi.create.foundation.command.SimpleCreateActions;
import com.simibubi.create.foundation.gui.container.ClearContainerPacket;
import com.simibubi.create.foundation.gui.container.GhostItemSubmitPacket;
import com.simibubi.create.foundation.tileEntity.RemoveTileEntityPacket;
@ -84,6 +83,7 @@ import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringCo
import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueUpdatePacket;
import com.simibubi.create.foundation.utility.ServerSpeedProvider;
import net.createmod.catnip.net.ClientboundSimpleActionPacket;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
@ -123,7 +123,7 @@ public enum AllPackets {
LINKED_CONTROLLER_BIND(LinkedControllerBindPacket.class, LinkedControllerBindPacket::new, PLAY_TO_SERVER),
LINKED_CONTROLLER_USE_LECTERN(LinkedControllerStopLecternPacket.class, LinkedControllerStopLecternPacket::new,
PLAY_TO_SERVER),
C_CONFIGURE_CONFIG(CConfigureConfigPacket.class, CConfigureConfigPacket::new, PLAY_TO_SERVER),
//C_CONFIGURE_CONFIG(CConfigureConfigPacket.class, CConfigureConfigPacket::new, PLAY_TO_SERVER),
SUBMIT_GHOST_ITEM(GhostItemSubmitPacket.class, GhostItemSubmitPacket::new, PLAY_TO_SERVER),
BLUEPRINT_COMPLETE_RECIPE(BlueprintAssignCompleteRecipePacket.class, BlueprintAssignCompleteRecipePacket::new,
PLAY_TO_SERVER),
@ -153,7 +153,7 @@ public enum AllPackets {
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT),
SERVER_SPEED(ServerSpeedProvider.Packet.class, ServerSpeedProvider.Packet::new, PLAY_TO_CLIENT),
BEAM_EFFECT(ZapperBeamPacket.class, ZapperBeamPacket::new, PLAY_TO_CLIENT),
S_CONFIGURE_CONFIG(SConfigureConfigPacket.class, SConfigureConfigPacket::new, PLAY_TO_CLIENT),
//S_CONFIGURE_CONFIG(SConfigureConfigPacket.class, SConfigureConfigPacket::new, PLAY_TO_CLIENT),
CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new, PLAY_TO_CLIENT),
CONTRAPTION_DISASSEMBLE(ContraptionDisassemblyPacket.class, ContraptionDisassemblyPacket::new, PLAY_TO_CLIENT),
CONTRAPTION_BLOCK_CHANGED(ContraptionBlockChangedPacket.class, ContraptionBlockChangedPacket::new, PLAY_TO_CLIENT),
@ -192,6 +192,18 @@ public enum AllPackets {
public static final String NETWORK_VERSION_STR = String.valueOf(NETWORK_VERSION);
public static SimpleChannel channel;
static {
ClientboundSimpleActionPacket.addAction("rainbowDebug", () -> SimpleCreateActions::rainbowDebug);
ClientboundSimpleActionPacket.addAction("overlayReset", () -> SimpleCreateActions::overlayReset);
ClientboundSimpleActionPacket.addAction("overlayScreen", () -> SimpleCreateActions::overlayScreen);
ClientboundSimpleActionPacket.addAction("experimentalLighting", () -> SimpleCreateActions::experimentalLighting);
ClientboundSimpleActionPacket.addAction("fabulousWarning", () -> SimpleCreateActions::fabulousWarning);
ClientboundSimpleActionPacket.addAction("zoomMultiplier", () -> SimpleCreateActions::zoomMultiplier);
ClientboundSimpleActionPacket.addAction("camAngleYawTarget", () -> value -> SimpleCreateActions.camAngleTarget(value, true));
ClientboundSimpleActionPacket.addAction("camAnglePitchTarget", () -> value -> SimpleCreateActions.camAngleTarget(value, false));
ClientboundSimpleActionPacket.addAction("camAngleFunction", () -> SimpleCreateActions::camAngleFunction);
}
private LoadedPacket<?> packet;
<T extends SimplePacketBase> AllPackets(Class<T> type, Function<FriendlyByteBuf, T> factory,

View file

@ -1,8 +1,12 @@
package com.simibubi.create.foundation.ponder;
import java.util.List;
import java.util.function.Predicate;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.components.crank.ValveHandleBlock;
import com.simibubi.create.foundation.ponder.content.ArmScenes;
import com.simibubi.create.foundation.ponder.content.BearingScenes;
import com.simibubi.create.foundation.ponder.content.BeltScenes;
@ -45,15 +49,28 @@ import com.tterrag.registrate.util.entry.ItemProviderEntry;
import com.tterrag.registrate.util.entry.RegistryEntry;
import net.createmod.ponder.foundation.CustomPonderRegistrationHelper;
import net.createmod.ponder.foundation.content.DebugScenes;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
public class CreatePonderIndex {
private static final CustomPonderRegistrationHelper<ItemProviderEntry<?>> HELPER = new CustomPonderRegistrationHelper<>(Create.ID, RegistryEntry::getId);
public static final boolean REGISTER_DEBUG_SCENES = false;
public static final List<Predicate<ItemLike>> INDEX_SCREEN_EXCLUSIONS = List.of(
itemLike -> {
if (!(itemLike instanceof BlockItem blockItem))
return false;
Block block = blockItem.getBlock();
if (!(block instanceof ValveHandleBlock))
return false;
return !AllBlocks.COPPER_VALVE_HANDLE.is(block);
}
);
public static void register() {
// Register storyboards here
@ -364,10 +381,6 @@ public class CreatePonderIndex {
.addStoryBoard("steam_whistle", SteamScenes::whistle);
HELPER.forComponents(AllBlocks.STEAM_ENGINE)
.addStoryBoard("steam_engine", SteamScenes::engine);
// Debug scenes, can be found in game via the Brass Hand
if (REGISTER_DEBUG_SCENES)
DebugScenes.registerAll();
}
public static void registerTags() {
// Add items to tags here

View file

@ -0,0 +1,31 @@
package com.simibubi.create.foundation.ponder;
import java.util.function.Predicate;
import java.util.stream.Stream;
import net.createmod.ponder.foundation.PonderPlugin;
import net.createmod.ponder.foundation.PonderWorld;
import net.minecraft.world.level.ItemLike;
public class CreatePonderPlugin implements PonderPlugin {
@Override
public void registerScenes() {
CreatePonderIndex.register();
}
@Override
public void registerTags() {
CreatePonderIndex.registerTags();
}
@Override
public void onPonderWorldRestore(PonderWorld world) {
PonderWorldTileFix.fixControllerTiles(world);
}
@Override
public Stream<Predicate<ItemLike>> indexExclusions() {
return CreatePonderIndex.INDEX_SCREEN_EXCLUSIONS.stream();
}
}

View file

@ -1,10 +1,10 @@
package com.simibubi.create.foundation.ponder.content;
import com.simibubi.create.AllItems;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.ponder.CreateSceneBuilder;
import net.createmod.catnip.utility.Pointing;
import net.createmod.ponder.enums.PonderGuiTextures;
import net.createmod.ponder.foundation.ElementLink;
import net.createmod.ponder.foundation.PonderPalette;
import net.createmod.ponder.foundation.SceneBuilder;
@ -62,7 +62,7 @@ public class ItemVaultScenes {
ItemStack hand = AllItems.BRASS_HAND.asStack();
scene.overlay
.showControls(new InputWindowElement(util.vector.blockSurface(frontVault, Direction.NORTH), Pointing.RIGHT)
.showing(AllIcons.I_MTD_CLOSE)
.showing(PonderGuiTextures.ICON_PONDER_CLOSE)
.withItem(hand), 40);
scene.idle(7);

View file

@ -12,11 +12,11 @@ import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity;
import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity;
import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.ponder.CreateSceneBuilder;
import net.createmod.catnip.utility.Pointing;
import net.createmod.catnip.utility.VecHelper;
import net.createmod.ponder.enums.PonderGuiTextures;
import net.createmod.ponder.foundation.ElementLink;
import net.createmod.ponder.foundation.PonderPalette;
import net.createmod.ponder.foundation.SceneBuilder;
@ -162,7 +162,7 @@ public class FluidTankScenes {
ItemStack bucket = new ItemStack(Items.BUCKET, 1);
scene.overlay.showControls(
new InputWindowElement(util.vector.blockSurface(util.grid.at(2, 2, 2), Direction.NORTH), Pointing.RIGHT)
.showing(AllIcons.I_MTD_CLOSE)
.showing(PonderGuiTextures.ICON_PONDER_CLOSE)
.withItem(bucket),
40);
scene.idle(7);

View file

@ -5,12 +5,12 @@ import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.fluids.FluidFX;
import com.simibubi.create.content.contraptions.fluids.actors.SpoutTileEntity;
import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.ponder.CreateSceneBuilder;
import com.simibubi.create.foundation.ponder.element.BeltItemElement;
import net.createmod.catnip.utility.Pointing;
import net.createmod.catnip.utility.VecHelper;
import net.createmod.ponder.enums.PonderGuiTextures;
import net.createmod.ponder.foundation.ElementLink;
import net.createmod.ponder.foundation.PonderPalette;
import net.createmod.ponder.foundation.SceneBuilder;
@ -74,7 +74,7 @@ public class SpoutScenes {
.getBucket(honey);
scene.overlay.showControls(
new InputWindowElement(util.vector.blockSurface(util.grid.at(2, 3, 2), Direction.NORTH), Pointing.RIGHT)
.showing(AllIcons.I_MTD_CLOSE)
.showing(PonderGuiTextures.ICON_PONDER_CLOSE)
.withItem(bucket),
40);
scene.idle(7);

View file

@ -1,4 +1,3 @@
public net.minecraft.client.Minecraft f_91013_ # pausePartialTick
public net.minecraft.client.gui.Font m_92863_(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/gui/font/FontSet; # getFontSet
public net.minecraft.client.gui.screens.TitleScreen f_96729_ # panorama
public net.minecraft.client.multiplayer.ClientPacketListener f_104897_ # serverChunkRadius
@ -7,8 +6,6 @@ public net.minecraft.client.renderer.ItemInHandRenderer f_109300_ # mainHandItem
public net.minecraft.client.renderer.ItemInHandRenderer f_109301_ # offHandItem
public net.minecraft.client.renderer.entity.ItemRenderer f_115096_ # textureManager
public-f net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket f_132663_ # flyingSpeed
public net.minecraft.server.MinecraftServer f_129744_ # storageSource
public net.minecraft.server.network.ServerGamePacketListenerImpl f_9737_ # aboveGroundTickCount
@ -40,4 +37,4 @@ public net.minecraft.client.model.AgeableListModel f_102011_ # babyBodyScale
public net.minecraft.client.model.AgeableListModel f_102012_ # bodyYOffset
public net.minecraft.client.gui.components.CommandSuggestions f_93866_ # suggestions
public net.minecraft.client.gui.components.CommandSuggestions$SuggestionsList <init>(Lnet/minecraft/client/gui/components/CommandSuggestions;IIILjava/util/List;Z)V # <init>
public net.minecraft.client.gui.components.CommandSuggestions$SuggestionsList <init>(Lnet/minecraft/client/gui/components/CommandSuggestions;IIILjava/util/List;Z)V # <init>