diff --git a/src/main/java/net/TheElm/project/commands/ArgumentTypes/EnumArgumentType.java b/src/main/java/net/TheElm/project/commands/ArgumentTypes/EnumArgumentType.java index e6850b6..26af16b 100644 --- a/src/main/java/net/TheElm/project/commands/ArgumentTypes/EnumArgumentType.java +++ b/src/main/java/net/TheElm/project/commands/ArgumentTypes/EnumArgumentType.java @@ -34,34 +34,59 @@ import net.TheElm.project.interfaces.BoolEnums; import net.minecraft.command.CommandSource; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; import net.minecraft.text.TranslatableText; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.EnumSet; +import java.util.Locale; import java.util.concurrent.CompletableFuture; +import java.util.function.Function; public class EnumArgumentType> { public static final DynamicCommandExceptionType INVALID_COMPONENT_EXCEPTION = new DynamicCommandExceptionType((object_1) -> new TranslatableText("argument.component.invalid", object_1)); + private final EnumSet enumValues; + private final Function nameFormatter; + private final Function tooltipFormatter; - private EnumArgumentType( final Class enumClass ) { - this.enumValues = EnumSet.allOf( enumClass ); + private EnumArgumentType(@NotNull final Class enumClass) { + this(enumClass, null); + } + private EnumArgumentType(@NotNull final Class enumClass, @Nullable Function tooltips) { + this(enumClass, tooltips, (enumValue) -> enumValue.name().toLowerCase()); + } + private EnumArgumentType(@NotNull final Class enumClass, @Nullable Function tooltips, @NotNull Function names) { + this.enumValues = EnumSet.allOf(enumClass); + this.nameFormatter = names; + this.tooltipFormatter = tooltips; } public static > T getEnum(Class tClass, String search) throws CommandSyntaxException { - return EnumSet.allOf( tClass ).stream().filter((enumValue) -> { - return enumValue.name().equalsIgnoreCase( search ); + return EnumSet.allOf(tClass).stream().filter((enumValue) -> { + return enumValue.name().equalsIgnoreCase(search); }).findFirst().orElseThrow(() -> INVALID_COMPONENT_EXCEPTION.create(search)); } - public CompletableFuture suggests(CommandContext context, SuggestionsBuilder builder) { - return CommandSource.suggestMatching( - this.enumValues.stream() - .filter((val) -> ((!(val instanceof BoolEnums)) || ((BoolEnums)val).isEnabled())) - .map((enumValue) -> enumValue.name().toLowerCase()), - builder - ); + public @NotNull CompletableFuture suggests(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) { + final String remaining = builder.getRemaining().toLowerCase(Locale.ROOT); + this.enumValues.stream() + .filter((eVal) -> ((!(eVal instanceof BoolEnums)) || ((BoolEnums)eVal).isEnabled())) + .filter((eName) -> CommandSource.method_27136(remaining, eName.name().toLowerCase(Locale.ROOT))) + .forEach((eVal) -> { + Text text = this.tooltipFormatter != null ? this.tooltipFormatter.apply(eVal) : null; + builder.suggest(this.nameFormatter.apply(eVal), text); + }); + return builder.buildFuture(); + } + public static @NotNull > SuggestionProvider enumerate(@NotNull Class claimRanksClass) { + return new EnumArgumentType<>(claimRanksClass)::suggests; + } + public static @NotNull > SuggestionProvider enumerate(@NotNull Class claimRanksClass, @NotNull Function tooltips) { + return new EnumArgumentType<>(claimRanksClass, tooltips)::suggests; } - public static > SuggestionProvider enumerate(Class claimRanksClass) { - return new EnumArgumentType<>( claimRanksClass )::suggests; + public static @NotNull > SuggestionProvider enumerate(@NotNull Class claimRanksClass, @NotNull Function tooltips, @NotNull Function names) { + return new EnumArgumentType<>(claimRanksClass, tooltips, names)::suggests; } } diff --git a/src/main/java/net/TheElm/project/commands/ClaimCommand.java b/src/main/java/net/TheElm/project/commands/ClaimCommand.java index 1d76d3f..7711927 100644 --- a/src/main/java/net/TheElm/project/commands/ClaimCommand.java +++ b/src/main/java/net/TheElm/project/commands/ClaimCommand.java @@ -248,7 +248,7 @@ public static void register(CommandDispatcher dispatcher) { // Set a friends rank .then(CommandManager.literal("set") .then(CommandManager.argument("rank", StringArgumentType.word()) - .suggests(EnumArgumentType.enumerate(ClaimRanks.class)) + .suggests(EnumArgumentType.enumerate(ClaimRanks.class, ClaimRanks::rankSetterDescription)) .then(CommandManager.argument("friend", GameProfileArgumentType.gameProfile()) .suggests(CommandUtils::getAllPlayerNames) .executes(ClaimCommand::addRank) @@ -306,7 +306,7 @@ public static void register(CommandDispatcher dispatcher) { ) ) .then(CommandManager.literal("leave") - .requires((source) -> ClaimCommand.sourceInTown( source ) && ClaimCommand.sourceNotMayor( source )) + .requires((source) -> ClaimCommand.sourceInTown(source) && ClaimCommand.sourceNotMayor(source)) .executes(ClaimCommand::playerPartsTown) ) .then(CommandManager.literal("set") @@ -348,15 +348,15 @@ public static void register(CommandDispatcher dispatcher) { // Update claim permissions .then(CommandManager.literal("permissions") .then(CommandManager.argument("permission", StringArgumentType.word()) - .suggests(EnumArgumentType.enumerate(ClaimPermissions.class)) + .suggests(EnumArgumentType.enumerate(ClaimPermissions.class, ClaimPermissions::getDescription)) .then(CommandManager.argument("rank", StringArgumentType.word()) - .suggests(EnumArgumentType.enumerate(ClaimRanks.class)) + .suggests(EnumArgumentType.enumerate(ClaimRanks.class, ClaimRanks::rankNormalDescription)) .executes(ClaimCommand::updateSetting) ) ) .then(CommandManager.literal("*") .then(CommandManager.argument( "rank", StringArgumentType.word()) - .suggests(EnumArgumentType.enumerate(ClaimRanks.class)) + .suggests(EnumArgumentType.enumerate(ClaimRanks.class, ClaimRanks::rankNormalDescription)) .executes(ClaimCommand::updateSettings) ) ) @@ -368,7 +368,7 @@ public static void register(CommandDispatcher dispatcher) { // Chunk settings .then(CommandManager.literal("settings") .then(CommandManager.argument("setting", StringArgumentType.word()) - .suggests(EnumArgumentType.enumerate(ClaimSettings.class)) + .suggests(EnumArgumentType.enumerate(ClaimSettings.class, ClaimSettings::getDescription)) .then(CommandManager.argument("bool", BoolArgumentType.bool()) .executes(ClaimCommand::updateBoolean) ) @@ -1040,8 +1040,8 @@ private static CompletableFuture listTownInvites(@NotNull CommandCo private static int updateSetting(@NotNull CommandContext context) throws CommandSyntaxException { // Get enums - ClaimPermissions permissions = EnumArgumentType.getEnum( ClaimPermissions.class, StringArgumentType.getString( context, "permission" ) ); - ClaimRanks rank = EnumArgumentType.getEnum( ClaimRanks.class, StringArgumentType.getString( context, "rank" ) ); + ClaimPermissions permissions = EnumArgumentType.getEnum(ClaimPermissions.class, StringArgumentType.getString(context, "permission")); + ClaimRanks rank = EnumArgumentType.getEnum(ClaimRanks.class, StringArgumentType.getString(context, "rank")); // Get the player ServerPlayerEntity player = context.getSource().getPlayer(); diff --git a/src/main/java/net/TheElm/project/commands/MiscCommands.java b/src/main/java/net/TheElm/project/commands/MiscCommands.java index bdd8244..21ffa97 100644 --- a/src/main/java/net/TheElm/project/commands/MiscCommands.java +++ b/src/main/java/net/TheElm/project/commands/MiscCommands.java @@ -41,6 +41,7 @@ import net.minecraft.text.LiteralText; import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; import net.minecraft.util.Formatting; import org.jetbrains.annotations.NotNull; @@ -92,23 +93,28 @@ public static int playerSendsMessageAndData(@NotNull ServerPlayerEntity player, return MiscCommands.playerSendsMessageAndData(player, message, new LiteralText( main )); } public static int playerSendsMessageAndData(@NotNull ServerPlayerEntity player, @NotNull String message, @NotNull Text main) { - // Create the player display for chat - MutableText text = PlayerNameUtils.getPlayerChatDisplay( player, ((PlayerChat) player).getChatRoom() ) - .append(new LiteralText( ": " ).formatted(Formatting.GRAY)); - - // Append the users message - if ( !"".equals( message ) ) - text.append( message ) - .append( " " ); - - // Append the main information - text.append( main ); + MutableText text; + if (SewConfig.get(SewConfig.CHAT_MODIFY)) { + // Create the player display for chat + text = PlayerNameUtils.getPlayerChatDisplay(player, ((PlayerChat) player).getChatRoom()) + .append(new LiteralText(": ").formatted(Formatting.GRAY)); + + // Append the users message + if (!"".equals(message)) + text.append(message) + .append(" "); + + // Append the main information + text.append(main); + } else { + text = new TranslatableText("chat.type.text", player.getDisplayName(), main); + } // Send to all players MessageUtils.sendTo( - ((PlayerChat) player).getChatRoom(), - player, - text + ((PlayerChat) player).getChatRoom(), + player, + text ); return Command.SINGLE_SUCCESS; diff --git a/src/main/java/net/TheElm/project/commands/PermissionCommand.java b/src/main/java/net/TheElm/project/commands/PermissionCommand.java index 62aa244..ff1054e 100644 --- a/src/main/java/net/TheElm/project/commands/PermissionCommand.java +++ b/src/main/java/net/TheElm/project/commands/PermissionCommand.java @@ -46,28 +46,28 @@ public static void register(@NotNull CommandDispatcher disp .requires(CommandUtils.isEnabledAnd(SewConfig.HANDLE_PERMISSIONS, OpLevels.CHEATING)) .then(CommandManager.literal("help") .then(CommandManager.argument("permission", StringArgumentType.word()) - .suggests( ArgumentSuggestions::suggestNodes) - .executes( PermissionCommand::nodeInfo ) + .suggests(ArgumentSuggestions::suggestNodes) + .executes(PermissionCommand::nodeInfo ) ) ) .then(CommandManager.literal("add") .then(CommandManager.argument("rank", StringArgumentType.word()) - .suggests( ArgumentSuggestions::suggestRanks) + .suggests(ArgumentSuggestions::suggestRanks) .then(CommandManager.argument("permission", StringArgumentType.word()) - .suggests( ArgumentSuggestions::suggestNodes) - .executes( PermissionCommand::addNodeToRank ) + .suggests(ArgumentSuggestions::suggestNodes) + .executes(PermissionCommand::addNodeToRank ) ) - .executes( PermissionCommand::addRank ) + .executes(PermissionCommand::addRank) ) ) .then(CommandManager.literal("remove") .then(CommandManager.argument("rank", StringArgumentType.word()) - .suggests( ArgumentSuggestions::suggestRanks) + .suggests(ArgumentSuggestions::suggestRanks) .then(CommandManager.argument("permission", StringArgumentType.word()) - .suggests( ArgumentSuggestions::suggestNodes) - .executes( PermissionCommand::delNodeFromRank ) + .suggests(ArgumentSuggestions::suggestNodes) + .executes(PermissionCommand::delNodeFromRank ) ) - .executes( PermissionCommand::delRank ) + .executes(PermissionCommand::delRank) ) ) ); diff --git a/src/main/java/net/TheElm/project/commands/TeleportsCommand.java b/src/main/java/net/TheElm/project/commands/TeleportsCommand.java index 84aa393..b1421d6 100644 --- a/src/main/java/net/TheElm/project/commands/TeleportsCommand.java +++ b/src/main/java/net/TheElm/project/commands/TeleportsCommand.java @@ -42,7 +42,6 @@ import net.TheElm.project.utilities.*; import net.TheElm.project.utilities.WarpUtils.Warp; import net.TheElm.project.utilities.text.MessageUtils; -import net.minecraft.command.CommandSource; import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.command.argument.GameProfileArgumentType; import net.minecraft.entity.Entity; @@ -273,13 +272,13 @@ private static int setHomePrimaryCommand(@NotNull CommandContext playerHomeNames(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) throws CommandSyntaxException { ServerCommandSource source = context.getSource(); - return CommandSource.suggestMatching(WarpUtils.getWarpNames(source.getPlayer()), builder); + return WarpUtils.buildSuggestions(source.getPlayer(), builder); } private static @NotNull CompletableFuture playerHomeNamesOfPlayer(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) throws CommandSyntaxException { Collection profiles = GameProfileArgumentType.getProfileArgument(context, "player"); GameProfile target = profiles.stream().findAny() .orElseThrow(GameProfileArgumentType.UNKNOWN_PLAYER_EXCEPTION::create); - return CommandSource.suggestMatching(WarpUtils.getWarpNames(target.getId()), builder); + return WarpUtils.buildSuggestions(target.getId(), builder); } private static int tpaCommand(@NotNull CommandContext context) throws CommandSyntaxException { @@ -418,7 +417,7 @@ private static int sendEntitiesToEnd(@NotNull Collection entit return Command.SINGLE_SUCCESS; } - private static void feedback(@NotNull PlayerEntity porter, @NotNull PlayerEntity target, @Nullable String location) { + public static void feedback(@NotNull PlayerEntity porter, @NotNull PlayerEntity target, @Nullable String location) { TeleportsCommand.feedback(porter, target.getGameProfile(), location); } public static void feedback(@NotNull PlayerEntity porter, @NotNull GameProfile target, @Nullable String location) { diff --git a/src/main/java/net/TheElm/project/commands/WaystoneCommand.java b/src/main/java/net/TheElm/project/commands/WaystoneCommand.java index 76083b9..d2be167 100644 --- a/src/main/java/net/TheElm/project/commands/WaystoneCommand.java +++ b/src/main/java/net/TheElm/project/commands/WaystoneCommand.java @@ -41,7 +41,6 @@ import net.TheElm.project.utilities.TranslatableServerSide; import net.TheElm.project.utilities.WarpUtils; import net.TheElm.project.utilities.text.MessageUtils; -import net.minecraft.command.CommandSource; import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.command.argument.GameProfileArgumentType; import net.minecraft.entity.Entity; @@ -225,12 +224,12 @@ private static int sendPlayersToLocation(@NotNull CommandContext getPlayerEntityLocations(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) throws CommandSyntaxException { ServerPlayerEntity player = EntityArgumentType.getPlayer(context, "player"); - return CommandSource.suggestMatching(WarpUtils.getWarpNames(player), builder); + return WarpUtils.buildSuggestions(player, builder); } private static @NotNull CompletableFuture getPlayersToLocations(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) throws CommandSyntaxException { Collection profiles = GameProfileArgumentType.getProfileArgument(context, "to"); GameProfile target = profiles.stream().findAny() .orElseThrow(GameProfileArgumentType.UNKNOWN_PLAYER_EXCEPTION::create); - return CommandSource.suggestMatching(WarpUtils.getWarpNames(target.getId()), builder); + return WarpUtils.buildSuggestions(target.getId(), builder); } } diff --git a/src/main/java/net/TheElm/project/enums/ClaimPermissions.java b/src/main/java/net/TheElm/project/enums/ClaimPermissions.java index 180cbb9..e1f3e76 100644 --- a/src/main/java/net/TheElm/project/enums/ClaimPermissions.java +++ b/src/main/java/net/TheElm/project/enums/ClaimPermissions.java @@ -25,27 +25,41 @@ package net.TheElm.project.enums; +import net.TheElm.project.utilities.CasingUtils; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; + public enum ClaimPermissions { - CREATURES( ClaimRanks.PASSIVE ), // Harm passive mods - HARVEST( ClaimRanks.ALLY ), // Harvest plants - BLOCKS( ClaimRanks.ALLY ), // Break or Place blocks - STORAGE( ClaimRanks.ALLY ), // Access storage containers - DOORS( ClaimRanks.PASSIVE ), // Open doors and gates - PICKUP( ClaimRanks.ALLY ), // Pickup entities - RIDING( ClaimRanks.ALLY ), // Ride carts and animals - WARP( ClaimRanks.OWNER ), // Warp to the players warp location - TRADING( ClaimRanks.PASSIVE ), // Trade with villagers - CRAFTING( ClaimRanks.PASSIVE ) // Open crafting benches + CREATURES(ClaimRanks.PASSIVE, "Harm or kill passive mobs"), // Harm passive mods + HARVEST(ClaimRanks.ALLY, "Harvest crops that are fully grown"), // Harvest plants + BLOCKS(ClaimRanks.ALLY, "Place or break any block"), // Break or Place blocks + STORAGE(ClaimRanks.ALLY, "Access shared inventories: chests, hoppers, furnaces, etc"), // Access storage containers + DOORS(ClaimRanks.PASSIVE, "Open or close doors"), // Open doors and gates + PICKUP(ClaimRanks.ALLY, "Pickup dropped items"), // Pickup entities + RIDING(ClaimRanks.ALLY, "Ride on horses and llamas"), // Ride carts and animals + WARP(ClaimRanks.OWNER, "Teleport to waystones"), // Warp to the players warp location + TRADING(ClaimRanks.PASSIVE, "Make trades with villagers"), // Trade with villagers + CRAFTING(ClaimRanks.PASSIVE, "Access non-shared inventories: crafting tables, looms, etc") // Open crafting benches ; - private final ClaimRanks defaultRank; + private final @NotNull ClaimRanks defaultRank; + private final @NotNull Text description; - ClaimPermissions(ClaimRanks defaultRank) { + ClaimPermissions(@NotNull ClaimRanks defaultRank, @NotNull String description) { this.defaultRank = defaultRank; + this.description = new LiteralText(description) + .append(" (Default: ") + .append(new LiteralText(CasingUtils.Sentence(this.defaultRank.name())) + .formatted(this.defaultRank.getColor())) + .append(")"); } - public ClaimRanks getDefault() { + public @NotNull Text getDescription() { + return this.description; + } + public @NotNull ClaimRanks getDefault() { return this.defaultRank; } } diff --git a/src/main/java/net/TheElm/project/enums/ClaimRanks.java b/src/main/java/net/TheElm/project/enums/ClaimRanks.java index 88bd728..0e0168b 100644 --- a/src/main/java/net/TheElm/project/enums/ClaimRanks.java +++ b/src/main/java/net/TheElm/project/enums/ClaimRanks.java @@ -25,21 +25,36 @@ package net.TheElm.project.enums; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; import net.minecraft.util.Formatting; import org.jetbrains.annotations.NotNull; public enum ClaimRanks { - OWNER( 2, Formatting.DARK_GREEN ), - ALLY( 1, Formatting.DARK_GREEN ), - PASSIVE( 0, Formatting.YELLOW ), - ENEMY( -1, Formatting.DARK_RED ); + OWNER(2, "Restrict to Owners only", "Let this player do everything", Formatting.DARK_GREEN), + ALLY(1, "Restrict to Allies and Owners", "Make this player your Ally", Formatting.DARK_GREEN), + PASSIVE(0, "Restrict to anyone but Enemies", "This player is Nothing to you", Formatting.YELLOW), + ENEMY(-1, "Anyone can do this", "Make this player your Enemy", Formatting.DARK_RED); private final Formatting[] color; public final int power; - ClaimRanks( int power, Formatting... formatting ) { + private final String baseDescription; + private final String setterDescription; + + ClaimRanks(int power, String desc, String setter, Formatting... formatting ) { this.power = power; this.color = formatting; + + this.baseDescription = desc; + this.setterDescription = setter; + } + + public @NotNull Text rankNormalDescription() { + return new LiteralText(this.baseDescription); + } + public @NotNull Text rankSetterDescription() { + return new LiteralText(this.setterDescription); } public boolean canPerform( @NotNull ClaimRanks userRank ) { diff --git a/src/main/java/net/TheElm/project/enums/ClaimSettings.java b/src/main/java/net/TheElm/project/enums/ClaimSettings.java index b61746e..571edc3 100644 --- a/src/main/java/net/TheElm/project/enums/ClaimSettings.java +++ b/src/main/java/net/TheElm/project/enums/ClaimSettings.java @@ -28,38 +28,41 @@ import net.TheElm.project.CoreMod; import net.TheElm.project.config.SewConfig; import net.TheElm.project.interfaces.BoolEnums; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.UUID; public enum ClaimSettings implements BoolEnums { // "False positives" - ENDERMAN_GRIEFING( false, true, false ) { + ENDERMAN_GRIEFING("Allow Endermen to pickup blocks", false, true, false) { @Override public boolean isEnabled() { return SewConfig.get(SewConfig.CLAIM_ALLOW_GRIEFING_ENDERMAN); } }, - CREEPER_GRIEFING( false, true, false ) { + CREEPER_GRIEFING("Allow Creepers to destroy blocks", false, true, false) { @Override public boolean isEnabled() { return SewConfig.get(SewConfig.CLAIM_ALLOW_GRIEFING_CREEPER); } }, - GHAST_GRIEFING( false, true, false ) { + GHAST_GRIEFING("Allow Ghasts to destroy blocks", false, true, false) { @Override public boolean isEnabled() { return SewConfig.get(SewConfig.CLAIM_ALLOW_GRIEFING_GHAST); } }, - PLAYER_COMBAT( false, true, false ) { + PLAYER_COMBAT("Allow Player vs Player", false, true, false) { @Override public boolean isEnabled() { return SewConfig.get(SewConfig.CLAIM_ALLOW_PLAYER_COMBAT); } }, - HURT_TAMED( false, false, false ) { + HURT_TAMED("Allow Players to harm Wolves, Cats and other tamed pets", false, false, false) { @Override public boolean isEnabled() { return true; @@ -67,33 +70,39 @@ public boolean isEnabled() { }, // "True positives" - CROP_AUTOREPLANT( true, false, true ) { + CROP_AUTOREPLANT("Automatically replant harvested crops", true, false, true) { @Override public boolean isEnabled() { return SewConfig.get(SewConfig.CLAIM_ALLOW_CROP_AUTOREPLANT); } }, - TREE_CAPACITATE(true, false, false ) { + TREE_CAPACITATE("Automatically knock down entire trees", true, false, false) { @Override public boolean isEnabled() { return SewConfig.get(SewConfig.CLAIM_ALLOW_TREE_CAPACITATOR); } }, - VEIN_MINER( true, false, false ) { + VEIN_MINER("Automatically mine entire ore veins", true, false, false) { @Override public boolean isEnabled() { return SewConfig.get(SewConfig.CLAIM_ALLOW_VEIN_MINER); } }; + private final @NotNull Text description; private final boolean valueShouldBe; private final boolean playrDef; private final boolean spawnDef; - ClaimSettings( boolean valueShouldBe, boolean playerDefault, boolean spawnDefault ) { + ClaimSettings(@NotNull String description, boolean valueShouldBe, boolean playerDefault, boolean spawnDefault) { this.valueShouldBe = valueShouldBe; this.playrDef = playerDefault; this.spawnDef = spawnDefault; + this.description = new LiteralText(description) + .append(" (Default: ") + .append(new LiteralText(Boolean.toString(this.playrDef)) + .formatted(this.getAttributeColor(this.playrDef))) + .append(")"); } public boolean isTruePositive() { @@ -119,5 +128,7 @@ public boolean getDefault(@Nullable UUID owner) { return this.getSpawnDefault(); return this.getPlayerDefault(); } - + public @NotNull Text getDescription() { + return this.description; + } } diff --git a/src/main/java/net/TheElm/project/enums/ShopSigns.java b/src/main/java/net/TheElm/project/enums/ShopSigns.java index d0331eb..c44d474 100644 --- a/src/main/java/net/TheElm/project/enums/ShopSigns.java +++ b/src/main/java/net/TheElm/project/enums/ShopSigns.java @@ -596,11 +596,8 @@ public boolean formatSign(@NotNull final ShopSignBuilder signBuilder, @NotNull f @Override public Either onInteract(@NotNull final ServerPlayerEntity player, @NotNull final BlockPos signPos, final ShopSignBlockEntity sign) { try { - if (!MoneyUtils.takePlayerMoney(player, SewConfig.get(SewConfig.WARP_WAYSTONE_COST))) - return Either.left(TranslatableServerSide.text(player, "shop.error.money_player")); - ServerWorld world = player.getServerWorld(); - if (DimensionUtils.isOutOfBuildLimitVertically(world, signPos) || !ChunkUtils.canPlayerBreakInChunk(player, signPos)) + if (DimensionUtils.isOutOfBuildLimitVertically(world, signPos) || DimensionUtils.isWithinProtectedZone(world, signPos) || !ChunkUtils.canPlayerBreakInChunk(player, signPos)) return Either.left(new LiteralText("Can't build that here")); final String warpName = sign.getSignLine(1) @@ -609,6 +606,9 @@ public Either onInteract(@NotNull final ServerPlayerEntity player if (WarpUtils.getWarps(player).size() >= 3 && (WarpUtils.getWarp(player, warpName) == null)) return Either.left(new LiteralText("Too many waystones. Can't build any more.")); + if (!MoneyUtils.takePlayerMoney(player, SewConfig.get(SewConfig.WARP_WAYSTONE_COST))) + return Either.left(TranslatableServerSide.text(player, "shop.error.money_player")); + (new Thread(() -> { WarpUtils warp = new WarpUtils(warpName, player, signPos.down()); if (!warp.build(player, player.getServerWorld())) { diff --git a/src/main/java/net/TheElm/project/objects/ChatFormat.java b/src/main/java/net/TheElm/project/objects/ChatFormat.java index 7157b28..1142094 100644 --- a/src/main/java/net/TheElm/project/objects/ChatFormat.java +++ b/src/main/java/net/TheElm/project/objects/ChatFormat.java @@ -29,12 +29,11 @@ import com.google.gson.JsonSerializationContext; import net.TheElm.project.CoreMod; import net.TheElm.project.enums.ChatRooms; +import net.TheElm.project.utilities.DimensionUtils; import net.TheElm.project.utilities.text.MessageUtils; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; import net.minecraft.text.MutableText; import net.minecraft.text.Text; -import net.minecraft.text.TranslatableText; import net.minecraft.util.Formatting; import net.minecraft.util.registry.RegistryKey; import net.minecraft.world.World; @@ -51,7 +50,7 @@ private ChatFormat( String raw ) { this.raw = raw; // Debug - CoreMod.logDebug( raw ); + CoreMod.logDebug(raw); } @Nullable @@ -60,39 +59,16 @@ public Text format(ChatRooms room, ServerPlayerEntity player) { } private Text worldText(@NotNull RegistryKey dimension, boolean showAsLong) { - String longKey = null, shortKey = null; - - // Set keys based on the world - if (World.OVERWORLD.equals(dimension)) { - longKey = "generator.minecraft.surface"; - shortKey = "S"; - } else if (World.NETHER.equals(dimension)) { - longKey = "biome.minecraft.nether"; - shortKey = "N"; - } else if (World.END.equals(dimension)) { - longKey = "biome.minecraft.the_end"; - shortKey = "E"; - } - // Create the text - MutableText longer = ( longKey == null ? new LiteralText("Server") : new TranslatableText( longKey )); - MutableText shorter = new LiteralText( shortKey == null ? "~" : shortKey ); + MutableText longer = DimensionUtils.longDimensionName(dimension); + MutableText shorter = DimensionUtils.shortDimensionName(dimension); // Create the hover event - Formatting formatting = this.worldColor(dimension); + Formatting formatting = DimensionUtils.dimensionColor(dimension); return ( showAsLong ? longer : shorter ) .formatted(formatting) - .styled(MessageUtils.simpleHoverText(longer.formatted( formatting ))); - } - private Formatting worldColor(@NotNull RegistryKey world) { - if (World.OVERWORLD.equals(world)) - return Formatting.GREEN; - if (World.NETHER.equals(world)) - return Formatting.RED; - if (World.END.equals(world)) - return Formatting.DARK_GRAY; - return Formatting.WHITE; + .styled(MessageUtils.simpleHoverText(longer.formatted(formatting))); } @Override diff --git a/src/main/java/net/TheElm/project/utilities/ColorUtils.java b/src/main/java/net/TheElm/project/utilities/ColorUtils.java index 3db11bf..e73cd69 100644 --- a/src/main/java/net/TheElm/project/utilities/ColorUtils.java +++ b/src/main/java/net/TheElm/project/utilities/ColorUtils.java @@ -200,13 +200,13 @@ private ColorUtils() {} COLORS = colors; } - public static MutableText format(Text text, Formatting... formatting) { + public static @NotNull MutableText format(@NotNull Text text, @NotNull Formatting... formatting) { if (text instanceof MutableText) return ((MutableText)text).formatted(formatting); return ColorUtils.format(new LiteralText("") .append(text), formatting); } - public static MutableText format(Text text, TextColor color) { + public static @NotNull MutableText format(@NotNull Text text, @NotNull TextColor color) { if (text instanceof MutableText) return ((MutableText)text).styled((style) -> style.withColor(color)); return ColorUtils.format(new LiteralText("") diff --git a/src/main/java/net/TheElm/project/utilities/DimensionUtils.java b/src/main/java/net/TheElm/project/utilities/DimensionUtils.java index ed2bcc5..489a9ff 100644 --- a/src/main/java/net/TheElm/project/utilities/DimensionUtils.java +++ b/src/main/java/net/TheElm/project/utilities/DimensionUtils.java @@ -29,6 +29,9 @@ import net.minecraft.network.packet.s2c.play.WorldBorderS2CPacket; import net.minecraft.network.packet.s2c.play.WorldBorderS2CPacket.Type; import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.LiteralText; +import net.minecraft.text.MutableText; +import net.minecraft.util.Formatting; import net.minecraft.util.math.BlockPos; import net.minecraft.util.registry.RegistryKey; import net.minecraft.world.World; @@ -36,6 +39,7 @@ import net.minecraft.world.border.WorldBorderListener; import net.minecraft.world.dimension.DimensionType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public final class DimensionUtils { @@ -60,6 +64,46 @@ public static boolean isOutOfBuildLimitVertically(@NotNull DimensionType dimensi return y < 0 || y >= dimension.getLogicalHeight(); } + public static boolean isWithinProtectedZone(@NotNull World world, BlockPos pos) { + return DimensionUtils.isWithinProtectedZone(world.getRegistryKey(), pos); + } + public static boolean isWithinProtectedZone(@NotNull RegistryKey world, BlockPos pos) { + if (world.equals(World.END)) { + int x = Math.abs(pos.getX()); + int z = Math.abs(pos.getZ()); + return x <= 200 & z <= 200; + } + return false; + } + + public static @NotNull MutableText longDimensionName(@Nullable RegistryKey world) { + if (World.OVERWORLD.equals(world)) + return new LiteralText("Surface"); + if (World.NETHER.equals(world)) + return new LiteralText("Nether"); + if (World.END.equals(world)) + return new LiteralText("The End"); + return new LiteralText("Server"); + } + public static @NotNull MutableText shortDimensionName(@Nullable RegistryKey world) { + if (World.OVERWORLD.equals(world)) + return new LiteralText("S"); + if (World.NETHER.equals(world)) + return new LiteralText("N"); + if (World.END.equals(world)) + return new LiteralText("E"); + return new LiteralText("~"); + } + public static @NotNull Formatting dimensionColor(@Nullable RegistryKey world) { + if (World.OVERWORLD.equals(world)) + return Formatting.GREEN; + if (World.NETHER.equals(world)) + return Formatting.RED; + if (World.END.equals(world)) + return Formatting.DARK_GRAY; + return Formatting.WHITE; + } + private static final class IndividualWorldListener implements WorldBorderListener { private final ServerWorld world; diff --git a/src/main/java/net/TheElm/project/utilities/PlayerNameUtils.java b/src/main/java/net/TheElm/project/utilities/PlayerNameUtils.java index 0cf27de..3fb7625 100644 --- a/src/main/java/net/TheElm/project/utilities/PlayerNameUtils.java +++ b/src/main/java/net/TheElm/project/utilities/PlayerNameUtils.java @@ -39,6 +39,7 @@ import net.TheElm.project.protections.claiming.ClaimantPlayer; import net.TheElm.project.protections.claiming.ClaimantTown; import net.TheElm.project.utilities.nbt.NbtUtils; +import net.TheElm.project.utilities.text.MessageUtils; import net.fabricmc.fabric.api.util.NbtType; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.MinecraftServer; @@ -130,43 +131,18 @@ private PlayerNameUtils() {} * Message Components */ public static @NotNull MutableText formattedWorld(@Nullable World world) { - return PlayerNameUtils.formattedWorld(world == null ? null : world.getRegistryKey()); + return PlayerNameUtils.formattedWorld(world == null ? null : world.getRegistryKey(), false); } - public static @NotNull MutableText formattedWorld(@Nullable RegistryKey world) { - String name = null; - String ico = null; - - Formatting color = Formatting.OBFUSCATED; - if (world == null) { - name = "Server"; - color = Formatting.WHITE; - ico = "-"; - } else if (world == World.OVERWORLD) { - name = "Surface"; - color = Formatting.GREEN; - } else if (world == World.END) { - name = "End"; - color = Formatting.DARK_GRAY; - } else if (world == World.NETHER) { - name = "Nether"; - color = Formatting.RED; - } - - if (ico == null) - ico = name == null ? "~" : name.substring( 0, 1 ); - + public static @NotNull MutableText formattedWorld(@Nullable RegistryKey world, boolean showAsLong) { // Create the text - MutableText text = new LiteralText(ico) - .formatted(color); + MutableText longer = DimensionUtils.longDimensionName(world); - // Set the hover event - if ( name != null ) { - // Create the hover event - final HoverEvent hover = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new LiteralText(name).formatted(color)); - - text.styled((style) -> style.withHoverEvent( hover )); - } - return text; + // Create the hover event + Formatting formatting = DimensionUtils.dimensionColor(world); + + return (showAsLong ? longer : DimensionUtils.shortDimensionName(world)) + .formatted(formatting) + .styled(MessageUtils.simpleHoverText(longer.formatted(formatting))); } public static @NotNull MutableText formattedChat(ChatRooms chatRoom) { String name = CasingUtils.Sentence( chatRoom.name() ); diff --git a/src/main/java/net/TheElm/project/utilities/RegistryUtils.java b/src/main/java/net/TheElm/project/utilities/RegistryUtils.java new file mode 100644 index 0000000..9d87216 --- /dev/null +++ b/src/main/java/net/TheElm/project/utilities/RegistryUtils.java @@ -0,0 +1,51 @@ +/* + * This software is licensed under the MIT License + * https://github.com/GStefanowich/MC-Server-Protection + * + * Copyright (c) 2019 Gregory Stefanowich + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.TheElm.project.utilities; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryKey; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +/** + * Created on Jun 15 2021 at 5:48 PM. + * By greg in SewingMachineMod + */ +public class RegistryUtils { + private RegistryUtils() {} + + public static RegistryKey getFromRegistry(@NotNull MinecraftServer server, RegistryKey> registry, T type) { + return server.getRegistryManager().get(registry) + .getEntries() + .stream() + .filter(registryKeyBiomeEntry -> registryKeyBiomeEntry.getValue().equals(type)) + .map(Map.Entry::getKey) + .findFirst() + .orElse(null); + } +} diff --git a/src/main/java/net/TheElm/project/utilities/SleepUtils.java b/src/main/java/net/TheElm/project/utilities/SleepUtils.java index 465c1c5..0843e85 100644 --- a/src/main/java/net/TheElm/project/utilities/SleepUtils.java +++ b/src/main/java/net/TheElm/project/utilities/SleepUtils.java @@ -38,13 +38,13 @@ public final class SleepUtils { - public static void entityBedToggle(final LivingEntity entity, final boolean isInBed, final boolean isSleeping) { + public static void entityBedToggle(@NotNull final LivingEntity entity, final boolean isInBed, final boolean isSleeping) { if (!( entity instanceof ServerPlayerEntity)) return; - SleepUtils.playerBedToggle( (ServerPlayerEntity)entity, isInBed, isSleeping ); + SleepUtils.playerBedToggle((ServerPlayerEntity)entity, isInBed, isSleeping ); } - public static void playerBedToggle(final PlayerEntity player, final boolean isInBed, final boolean isSleeping) { + public static void playerBedToggle(@NotNull final PlayerEntity player, final boolean isInBed, final boolean isSleeping) { // Get the server object MinecraftServer server = player.getServer(); if ( server != null ) { @@ -57,7 +57,7 @@ public static void playerBedToggle(final PlayerEntity player, final boolean isIn if ( world.getPlayers().size() > 1 ) { TitleUtils.showPlayerAlert((ServerWorld) player.world, - ColorUtils.format(player.getDisplayName(), Formatting.AQUA), + new LiteralText(player.getDisplayName().asString()).formatted(Formatting.AQUA), new LiteralText(isSleeping ? " is now sleeping (" + percentage + "%)." : " is now in bed") ); } @@ -100,7 +100,7 @@ public static int getSleepingPercentage(@NotNull final World world) { return percentage; } - public static String timeFromMillis(long millis) { + public static @NotNull String timeFromMillis(long millis) { if (millis >= 23000) return "sunrise"; if (millis >= 18000) diff --git a/src/main/java/net/TheElm/project/utilities/StructureBuilderUtils.java b/src/main/java/net/TheElm/project/utilities/StructureBuilderUtils.java index ea2af9f..1749a03 100644 --- a/src/main/java/net/TheElm/project/utilities/StructureBuilderUtils.java +++ b/src/main/java/net/TheElm/project/utilities/StructureBuilderUtils.java @@ -26,15 +26,23 @@ package net.TheElm.project.utilities; import net.TheElm.project.CoreMod; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.PressurePlateBlock; import net.minecraft.block.entity.BlockEntity; import net.minecraft.particle.ParticleEffect; import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvents; +import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.RegistryKey; import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.LinkedHashMap; @@ -42,6 +50,11 @@ import java.util.function.Supplier; public final class StructureBuilderUtils { + public static final StructureBuilderMaterial DEFAULT_OVERWORLD = new StructureBuilderMaterial(Blocks.CHISELED_STONE_BRICKS, Blocks.SMOOTH_STONE, Blocks.REDSTONE_LAMP, Blocks.POLISHED_BLACKSTONE_PRESSURE_PLATE); + public static final StructureBuilderMaterial DEFAULT_NETHER = new StructureBuilderMaterial(Blocks.CHISELED_POLISHED_BLACKSTONE, Blocks.POLISHED_BLACKSTONE, Blocks.SHROOMLIGHT); + public static final StructureBuilderMaterial DESERT = new StructureBuilderMaterial(Blocks.SMOOTH_SANDSTONE, Blocks.RED_SANDSTONE, Blocks.REDSTONE_LAMP, Blocks.POLISHED_BLACKSTONE_PRESSURE_PLATE); + public static final StructureBuilderMaterial BEACH = new StructureBuilderMaterial(Blocks.DARK_PRISMARINE, Blocks.PRISMARINE_BRICKS, Blocks.SEA_LANTERN, Blocks.POLISHED_BLACKSTONE_PRESSURE_PLATE); + public static final StructureBuilderMaterial END = new StructureBuilderMaterial(Blocks.PURPUR_BLOCK, Blocks.END_STONE_BRICKS, Blocks.PURPUR_PILLAR, Blocks.STONE_PRESSURE_PLATE, Blocks.END_ROD); private final String name; private final World world; @@ -50,27 +63,27 @@ public final class StructureBuilderUtils { private HashMap structureBlocks = new LinkedHashMap<>(); private HashMap> structureEntity = new LinkedHashMap<>(); - public StructureBuilderUtils(World world, String structureName) { + public StructureBuilderUtils(@NotNull World world, @NotNull String structureName) { this.world = world; this.name = structureName; - CoreMod.logInfo( "Building new " + structureName ); + CoreMod.logInfo("Building new " + structureName); } public String getName() { return this.name; } - public void addBlock(BlockPos blockPos, BlockState blockState) { - this.structureBlocks.put( blockPos, blockState ); + public void addBlock(@NotNull BlockPos blockPos, @NotNull BlockState blockState) { + this.structureBlocks.put(blockPos, blockState); } - public void addEntity(BlockPos blockPos, Supplier blockEntity) { + public void addEntity(@NotNull BlockPos blockPos, @NotNull Supplier blockEntity) { this.structureEntity.put( blockPos, blockEntity ); } public void destroy(boolean dropBlocks) throws InterruptedException { for (BlockPos blockPos : this.structureBlocks.keySet()) { this.world.breakBlock(blockPos, dropBlocks); - Thread.sleep( this.delay ); + Thread.sleep(this.delay); } } public void build() throws InterruptedException { @@ -98,7 +111,7 @@ public void build() throws InterruptedException { .setBlockEntity( blockPos, entity ); } } - public void particlesSounds(T particle, SoundEvent sound, double deltaX, double deltaY, double deltaZ, double speed, int count, BlockPos... blockPositions) throws InterruptedException { + public void particlesSounds(T particle, SoundEvent sound, double deltaX, double deltaY, double deltaZ, double speed, int count, @NotNull BlockPos... blockPositions) throws InterruptedException { for (BlockPos blockPos : blockPositions) { // Spawn the particles ((ServerWorld) this.world).spawnParticles( @@ -114,11 +127,92 @@ public void particlesSounds(T particle, SoundEvent so ); // Play the sound effect - world.playSound( null, blockPos, sound, SoundCategory.MASTER, 1.0f, 1.0f ); + world.playSound(null, blockPos, sound, SoundCategory.MASTER, 1.0f, 1.0f); // Sleep Thread.sleep(this.delay * 10); } } + public @NotNull StructureBuilderMaterial forBiome(@NotNull RegistryKey dimension, @NotNull RegistryKey biome) { + Identifier identifier = biome.getValue(); + String path = identifier.getPath(); + + if (dimension.equals(World.OVERWORLD)) { + if (path.contains("desert")) + return DESERT; + /*if (path.contains("snow")) + return COLD;*/ + if (path.contains("ocean") || path.contains("beach")) + return BEACH; + } + else if (dimension.equals(World.NETHER)) { + + return DEFAULT_NETHER; + } + else if (dimension.equals(World.END)) { + return END; + } + return DEFAULT_OVERWORLD; + } + + public static class StructureBuilderMaterial { + private final @NotNull Block mainBlock; + private final @NotNull Block decoratingBlock; + private final @NotNull Block pressurePlateBlock; + + private final @NotNull Block lightingBlock; + private final @Nullable Block coveringBlock; + private final @Nullable Block supportBlock; + + private final @NotNull Block structureBlock; + + private StructureBuilderMaterial(@NotNull Block main, @NotNull Block decorating, @NotNull Block lightSource) { + this(main, decorating, lightSource, null); + } + private StructureBuilderMaterial(@NotNull Block main, @NotNull Block decorating, @NotNull Block lightSource, @Nullable Block plate) { + this(main, decorating, lightSource, plate, null); + } + private StructureBuilderMaterial(@NotNull Block main, @NotNull Block decorating, @NotNull Block lightSource, @Nullable Block plate, @Nullable Block coveringBlock) { + this(main, decorating, lightSource, plate, coveringBlock, lightSource.equals(Blocks.REDSTONE_LAMP) ? Blocks.REDSTONE_BLOCK : null); + } + private StructureBuilderMaterial(@NotNull Block main, @NotNull Block decorating, @NotNull Block lightSource, @Nullable Block plate, @Nullable Block coveringBlock, @Nullable Block supportingBlock) { + this.mainBlock = main; + this.decoratingBlock = decorating; + this.lightingBlock = lightSource; + this.pressurePlateBlock = (plate instanceof PressurePlateBlock ? plate : Blocks.STONE_PRESSURE_PLATE); + this.coveringBlock = coveringBlock; + this.supportBlock = supportingBlock; + this.structureBlock = Blocks.BEDROCK; + } + + public @NotNull BlockState getMainBlock() { + return this.mainBlock.getDefaultState(); + } + public @NotNull BlockState getDecoratingBlock() { + return this.decoratingBlock.getDefaultState(); + } + public @NotNull BlockState getPressurePlateBlock() { + return this.pressurePlateBlock.getDefaultState(); + } + public @NotNull BlockState getLightSourceBlock() { + return this.lightingBlock.getDefaultState(); + } + public @Nullable BlockState getCoveringBlock() { + return this.coveringBlock == null ? null : this.coveringBlock.getDefaultState(); + } + public @Nullable BlockState getSupportingBlock() { + return this.supportBlock == null ? null : this.supportBlock.getDefaultState(); + } + public @NotNull BlockState getStructureBlock() { + return this.structureBlock.getDefaultState(); + } + public @NotNull BlockState getAirBlock(@NotNull RegistryKey world) { + if (world.equals(World.END)) + return Blocks.VOID_AIR.getDefaultState(); + if (world.equals(World.NETHER)) + return Blocks.CAVE_AIR.getDefaultState(); + return Blocks.AIR.getDefaultState(); + } + } } diff --git a/src/main/java/net/TheElm/project/utilities/WarpUtils.java b/src/main/java/net/TheElm/project/utilities/WarpUtils.java index 8d6f6fd..0fc1fde 100644 --- a/src/main/java/net/TheElm/project/utilities/WarpUtils.java +++ b/src/main/java/net/TheElm/project/utilities/WarpUtils.java @@ -25,6 +25,8 @@ package net.TheElm.project.utilities; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.TheElm.project.CoreMod; import net.TheElm.project.ServerCore; import net.TheElm.project.config.SewConfig; @@ -34,6 +36,7 @@ import net.TheElm.project.objects.MaskSet; import net.TheElm.project.protections.BlockRange; import net.TheElm.project.utilities.nbt.NbtUtils; +import net.TheElm.project.utilities.text.MessageUtils; import net.fabricmc.fabric.api.util.NbtType; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -41,6 +44,7 @@ import net.minecraft.block.MushroomBlock; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.entity.CommandBlockBlockEntity; +import net.minecraft.command.CommandSource; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.mob.MobEntity; @@ -54,14 +58,20 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; import net.minecraft.util.math.*; +import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryKey; import net.minecraft.world.World; import net.minecraft.world.WorldProperties; +import net.minecraft.world.biome.Biome; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import java.util.regex.Pattern; @@ -180,14 +190,20 @@ public boolean build(final ServerPlayerEntity player, final ServerWorld world, f // Claim the defined slices in the name of Spawn ChunkUtils.claimSlices(world, CoreMod.SPAWN_ID, this.region); + + Biome biome = world.getBiome(this.createWarpAt); + RegistryKey biomeKey = RegistryUtils.getFromRegistry(world.getServer(), Registry.BIOME_KEY, biome); // Create the structure - StructureBuilderUtils structure = new StructureBuilderUtils( world, "waystone" ); + StructureBuilderUtils structure = new StructureBuilderUtils(world, "waystone"); + StructureBuilderUtils.StructureBuilderMaterial material = structure.forBiome(world.getRegistryKey(), biomeKey); - final BlockState air = Blocks.AIR.getDefaultState(); + final BlockState air = material.getAirBlock(world.getRegistryKey()); // Light-source blocks - final BlockState decLight = Blocks.SHROOMLIGHT.getDefaultState(); + final BlockState decLight = material.getLightSourceBlock(); + final BlockState ovrLight = material.getCoveringBlock(); + final BlockState undLight = material.getSupportingBlock(); BlockPos[] decLightBlocks = new BlockPos[]{ new BlockPos(this.createWarpAt.getX() + 1, this.createWarpAt.getY(), this.createWarpAt.getZ() + 1), new BlockPos(this.createWarpAt.getX() + 1, this.createWarpAt.getY(), this.createWarpAt.getZ() - 1), @@ -195,13 +211,15 @@ public boolean build(final ServerPlayerEntity player, final ServerWorld world, f new BlockPos(this.createWarpAt.getX() - 1, this.createWarpAt.getY(), this.createWarpAt.getZ() - 1) }; for ( BlockPos blockPos : decLightBlocks ) { - structure.addBlock(blockPos.up( 1 ), air); - structure.addBlock(blockPos.up( 2 ), air); + structure.addBlock(blockPos.up(1), ovrLight == null ? air : ovrLight); + structure.addBlock(blockPos.up(2), air); structure.addBlock(blockPos, decLight); + if (undLight != null) + structure.addBlock(blockPos.down(), undLight); } // Andesite blocks - final BlockState decJewel = Blocks.POLISHED_BLACKSTONE.getDefaultState(); + final BlockState decJewel = material.getDecoratingBlock(); BlockPos[] decJewelBlocks = new BlockPos[]{ this.createWarpAt.offset(Direction.NORTH), this.createWarpAt.offset(Direction.SOUTH), @@ -215,7 +233,7 @@ public boolean build(final ServerPlayerEntity player, final ServerWorld world, f } // Diorite blocks - final BlockState decBelowPlate = Blocks.CHISELED_POLISHED_BLACKSTONE.getDefaultState(); + final BlockState decBelowPlate = material.getMainBlock(); BlockPos[] decBelowPlateBlocks = new BlockPos[]{ this.createWarpAt }; @@ -226,7 +244,7 @@ public boolean build(final ServerPlayerEntity player, final ServerWorld world, f } // Bedrock blocks - final BlockState decSupport = Blocks.BEDROCK.getDefaultState(); + final BlockState decSupport = material.getStructureBlock(); BlockPos[] bedrockBlocks = new BlockPos[]{ this.createWarpAt.down(2), new BlockPos(this.createWarpAt.getX() + 1, this.createWarpAt.getY() - 1, this.createWarpAt.getZ()), @@ -260,12 +278,12 @@ public boolean build(final ServerPlayerEntity player, final ServerWorld world, f } // Pressure plate - final BlockState plate = Blocks.STONE_PRESSURE_PLATE.getDefaultState(); + final BlockState plate = material.getPressurePlateBlock(); BlockPos[] pressurePlates = new BlockPos[]{ this.createWarpAt.up() }; for ( BlockPos blockPos : pressurePlates ) { - structure.addBlock( blockPos, plate ); + structure.addBlock(blockPos, plate); } try { @@ -588,6 +606,36 @@ private static void teleportPoof(@NotNull final Entity entity) { return new BlockPos(properties.getSpawnX(), properties.getSpawnY(), properties.getSpawnZ()); } + public static CompletableFuture buildSuggestions(@NotNull ServerPlayerEntity player, @NotNull SuggestionsBuilder builder) { + return WarpUtils.buildSuggestions(WarpUtils.getWarps(player), builder); + } + public static CompletableFuture buildSuggestions(@NotNull UUID uuid, @NotNull SuggestionsBuilder builder) { + return WarpUtils.buildSuggestions(WarpUtils.getWarps(uuid), builder); + } + private static CompletableFuture buildSuggestions(@NotNull Map warps, @NotNull SuggestionsBuilder builder) { + String remainder = builder.getRemaining().toLowerCase(Locale.ROOT); + + for (Map.Entry iterator : warps.entrySet()) { + String name = iterator.getKey(); + if (name.contains(" ")) + name = "\"" + name + "\""; + + if (CommandSource.method_27136(remainder, name.toLowerCase(Locale.ROOT))) { + Warp warp = iterator.getValue(); + Text position = new LiteralText(" [").formatted(Formatting.WHITE) + .append(MessageUtils.xyzToText(warp.warpPos)) + .append("]"); + + // Add the suggestion to the builder + builder.suggest(name, DimensionUtils.longDimensionName(warp.world) + .formatted(DimensionUtils.dimensionColor(warp.world)) + .append(position)); + } + } + + return builder.buildFuture(); + } + public static class Warp { public final @NotNull String name; public final @NotNull BlockPos warpPos;