diff --git a/src/main/java/xyz/nucleoid/extras/NucleoidExtrasConfig.java b/src/main/java/xyz/nucleoid/extras/NucleoidExtrasConfig.java index 87d8ab5..3c3dff1 100644 --- a/src/main/java/xyz/nucleoid/extras/NucleoidExtrasConfig.java +++ b/src/main/java/xyz/nucleoid/extras/NucleoidExtrasConfig.java @@ -36,6 +36,7 @@ public record NucleoidExtrasConfig( @Nullable IntegrationsConfig integrations, @Nullable CommandAliasConfig aliases, @Nullable ChatFilterConfig chatFilter, + @Nullable RulesConfig rules, @Nullable URL contributorDataUrl, ErrorReportingConfig errorReporting, boolean devServer, @@ -53,19 +54,20 @@ public record NucleoidExtrasConfig( IntegrationsConfig.CODEC.optionalFieldOf("integrations").forGetter(config -> Optional.ofNullable(config.integrations())), CommandAliasConfig.CODEC.optionalFieldOf("aliases").forGetter(config -> Optional.ofNullable(config.aliases())), ChatFilterConfig.CODEC.optionalFieldOf("chat_filter").forGetter(config -> Optional.ofNullable(config.chatFilter())), + RulesConfig.CODEC.optionalFieldOf("rules").forGetter(config -> Optional.ofNullable(config.rules())), MoreCodecs.url("https").optionalFieldOf("contributor_data_url").forGetter(config -> Optional.ofNullable(config.contributorDataUrl())), ErrorReportingConfig.CODEC.optionalFieldOf("error_reporting", ErrorReportingConfig.NONE).forGetter(NucleoidExtrasConfig::errorReporting), Codec.BOOL.optionalFieldOf("dev_server", false).forGetter(NucleoidExtrasConfig::devServer), ExtraCodecs.URI.optionalFieldOf("http_api").forGetter(config -> Optional.ofNullable(config.httpApi())) - ).apply(instance, (sidebar, gamePortalOpener, lobbySpawn, integrations, aliases, filter, contributorDataUrl, errorReporting, devServer, httpApiUrl) -> - new NucleoidExtrasConfig(sidebar, gamePortalOpener, lobbySpawn.orElse(null), integrations.orElse(null), aliases.orElse(null), filter.orElse(null), contributorDataUrl.orElse(null), errorReporting, devServer, httpApiUrl.orElse(null)) + ).apply(instance, (sidebar, gamePortalOpener, lobbySpawn, integrations, aliases, filter, rules, contributorDataUrl, errorReporting, devServer, httpApiUrl) -> + new NucleoidExtrasConfig(sidebar, gamePortalOpener, lobbySpawn.orElse(null), integrations.orElse(null), aliases.orElse(null), filter.orElse(null), rules.orElse(null), contributorDataUrl.orElse(null), errorReporting, devServer, httpApiUrl.orElse(null)) ) ); private static NucleoidExtrasConfig instance; private NucleoidExtrasConfig() { - this(false, Optional.empty(), null, null, null, null, null, ErrorReportingConfig.NONE, false, null); + this(false, Optional.empty(), null, null, null, null, null, null, ErrorReportingConfig.NONE, false, null); } @NotNull diff --git a/src/main/java/xyz/nucleoid/extras/RulesConfig.java b/src/main/java/xyz/nucleoid/extras/RulesConfig.java new file mode 100644 index 0000000..9fe7290 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/RulesConfig.java @@ -0,0 +1,18 @@ +package xyz.nucleoid.extras; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.text.Text; +import xyz.nucleoid.codecs.MoreCodecs; +import xyz.nucleoid.plasmid.util.PlasmidCodecs; + +import java.util.List; + +public record RulesConfig( + List> pages +) { + private static final Codec> PAGE_CODEC = MoreCodecs.listOrUnit(PlasmidCodecs.TEXT); + public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group( + PAGE_CODEC.listOf().fieldOf("pages").forGetter(RulesConfig::pages) + ).apply(i, RulesConfig::new)); +} diff --git a/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java b/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java index 7b54680..cdd95b5 100644 --- a/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java +++ b/src/main/java/xyz/nucleoid/extras/lobby/NEItems.java @@ -22,6 +22,7 @@ import net.minecraft.text.Text; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; +import net.minecraft.util.Rarity; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.math.BlockPos; @@ -30,7 +31,13 @@ import xyz.nucleoid.extras.NucleoidExtras; import xyz.nucleoid.extras.NucleoidExtrasConfig; import xyz.nucleoid.extras.lobby.block.tater.TinyPotatoBlock; -import xyz.nucleoid.extras.lobby.item.*; +import xyz.nucleoid.extras.lobby.item.GamePortalOpenerItem; +import xyz.nucleoid.extras.lobby.item.LaunchFeatherItem; +import xyz.nucleoid.extras.lobby.item.LobbyBlockItem; +import xyz.nucleoid.extras.lobby.item.LobbyHeadItem; +import xyz.nucleoid.extras.lobby.item.LobbyTallBlockItem; +import xyz.nucleoid.extras.lobby.item.QuickArmorStandItem; +import xyz.nucleoid.extras.lobby.item.RuleBookItem; import xyz.nucleoid.extras.lobby.item.tater.CreativeTaterBoxItem; import xyz.nucleoid.extras.lobby.item.tater.TaterBoxItem; @@ -443,6 +450,8 @@ public class NEItems { public static final Item GAME_PORTAL_OPENER = new GamePortalOpenerItem(new Item.Settings().maxCount(1)); public static final Item LAUNCH_FEATHER = new LaunchFeatherItem(new Item.Settings().maxCount(1)); + public static final Item RULE_BOOK = new RuleBookItem(new Item.Settings().rarity(Rarity.EPIC)); + private static Item createHead(Block head) { if (head instanceof TinyPotatoBlock tinyPotatoBlock) { return new LobbyHeadItem(head, new Item.Settings(), tinyPotatoBlock.getItemTexture()); @@ -805,6 +814,7 @@ public static void register() { register("quick_armor_stand", QUICK_ARMOR_STAND); register("game_portal_opener", GAME_PORTAL_OPENER); register("launch_feather", LAUNCH_FEATHER); + register("rule_book", RULE_BOOK); PolymerItemGroupUtils.registerPolymerItemGroup(NucleoidExtras.identifier("general"), ITEM_GROUP); @@ -841,6 +851,10 @@ public static void giveLobbyItems(ServerPlayerEntity player) { tryOfferStack(player, TATER_BOX); + if (config.rules() != null) { + tryOfferStack(player, RULE_BOOK); + } + config.gamePortalOpener().ifPresent(gamePortal -> { tryOfferStack(player, GAME_PORTAL_OPENER, stack -> { GamePortalOpenerItem.setGamePortalId(stack, gamePortal); diff --git a/src/main/java/xyz/nucleoid/extras/lobby/item/RuleBookItem.java b/src/main/java/xyz/nucleoid/extras/lobby/item/RuleBookItem.java new file mode 100644 index 0000000..c864f87 --- /dev/null +++ b/src/main/java/xyz/nucleoid/extras/lobby/item/RuleBookItem.java @@ -0,0 +1,79 @@ +package xyz.nucleoid.extras.lobby.item; + +import eu.pb4.polymer.core.api.item.PolymerItem; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtList; +import net.minecraft.nbt.NbtString; +import net.minecraft.network.packet.s2c.play.OpenWrittenBookS2CPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.stat.Stats; +import net.minecraft.text.Text; +import net.minecraft.text.Texts; +import net.minecraft.util.CachedMapper; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.Util; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; +import xyz.nucleoid.extras.NucleoidExtrasConfig; +import xyz.nucleoid.extras.RulesConfig; +import xyz.nucleoid.server.translations.api.LocalizationTarget; +import xyz.nucleoid.server.translations.api.language.ServerLanguage; +import xyz.nucleoid.server.translations.impl.ServerTranslations; + +import java.util.List; + +public class RuleBookItem extends Item implements PolymerItem { + private static final CachedMapper ENCODED_PAGES = Util.cachedMapper(rules -> { + NbtList pages = new NbtList(); + for (List page : rules.pages()) { + Text combinedPage = Texts.join(page, Text.literal("\n")); + pages.add(NbtString.of(Text.Serialization.toJsonString(combinedPage))); + } + return pages; + }); + + public RuleBookItem(Settings settings) { + super(settings); + } + + @Override + public TypedActionResult use(World world, PlayerEntity user, Hand hand) { + ItemStack itemStack = user.getStackInHand(hand); + if (user instanceof ServerPlayerEntity serverPlayer) { + serverPlayer.networkHandler.sendPacket(new OpenWrittenBookS2CPacket(hand)); + } + user.incrementStat(Stats.USED.getOrCreateStat(this)); + return TypedActionResult.success(itemStack, world.isClient()); + } + + @Override + public Item getPolymerItem(ItemStack itemStack, @Nullable ServerPlayerEntity player) { + return Items.WRITTEN_BOOK; + } + + @Override + public ItemStack getPolymerItemStack(ItemStack itemStack, TooltipContext context, @Nullable ServerPlayerEntity player) { + LocalizationTarget localizationTarget = player != null ? LocalizationTarget.of(player) : LocalizationTarget.ofSystem(); + ServerLanguage targetLanguage = ServerTranslations.INSTANCE.getLanguage(localizationTarget); + + String translationKey = getTranslationKey(); + ItemStack book = PolymerItem.super.getPolymerItemStack(itemStack, context, player); + NbtCompound nbt = book.getOrCreateNbt(); + nbt.putInt("HideFlags", nbt.getInt("HideFlags") & ~ItemStack.TooltipSection.ADDITIONAL.getFlag()); + nbt.putString("title", targetLanguage.serverTranslations().get(translationKey)); + nbt.putString("author", targetLanguage.serverTranslations().get(translationKey + ".author")); + + RulesConfig rules = NucleoidExtrasConfig.get().rules(); + if (rules != null) { + nbt.put("pages", ENCODED_PAGES.map(rules)); + } + + return book; + } +} diff --git a/src/main/resources/data/nucleoid_extras/lang/en_us.json b/src/main/resources/data/nucleoid_extras/lang/en_us.json index b6d8d2c..ad7723c 100644 --- a/src/main/resources/data/nucleoid_extras/lang/en_us.json +++ b/src/main/resources/data/nucleoid_extras/lang/en_us.json @@ -361,6 +361,8 @@ "item.nucleoid_extras.tater_box": "Tater Box", "item.nucleoid_extras.creative_tater_box": "Creative Tater Box", "item.nucleoid_extras.quick_armor_stand": "Quick Armor Stand (Lobby only!)", + "item.nucleoid_extras.rule_book": "Rule Book", + "item.nucleoid_extras.rule_book.author": "Server admins", "entity.nucleoid_extras.quick_armor_stand": "Quick Armor Stand", @@ -395,6 +397,25 @@ "text.nucleoid_extras.wrapped.join": "Nucleoid Wrapped 2023 is here! Check out yours at https://stats.nucleoid.xyz/players/%s/wrapped", + "text.nucleoid_extras.rules.continued_title": "%s (cont.)", + "text.nucleoid_extras.rules.welcome": "Welcome to %s!\n\nWe're building open-source minigames.", + "text.nucleoid_extras.rules.links": "You can find us at %s, or join our Discord at %s.", + "text.nucleoid_extras.rules.guidelines": "We have a couple of guidelines to to keep in mind while playing on the following pages.", + "text.nucleoid_extras.rules.friendly_environment.title": "1. A friendly environment", + "text.nucleoid_extras.rules.friendly_environment.1": "We're all here to have fun! Let's create an inclusive environment where we all feel comfortable to play and share the joy of creating together.", + "text.nucleoid_extras.rules.friendly_environment.2": "Treat all players, regardless of their background, with respect and kindness. Any kind of discrimination or harassment is prohibited.", + "text.nucleoid_extras.rules.suitable_content.title": "2. Suitable content", + "text.nucleoid_extras.rules.suitable_content.1": "We want our community to be friendly to everyone. Not-safe-for-work content is prohibited, and please avoid excessive use of inappropriate language.", + "text.nucleoid_extras.rules.suitable_content.2": "The server makes use of a basic profanity filter to let you know when your messages are not appropriate: do not try to work around it.", + "text.nucleoid_extras.rules.keeping_it_fair.title": "3. Keeping it fair", + "text.nucleoid_extras.rules.keeping_it_fair.1": "Cheats ruin the fun! Use of cheats or hacked clients on the server is not allowed. If you suspect another player to be making use of hacks, please report it to us by messaging @NucleMail on Discord with any evidence you can collect.", + "text.nucleoid_extras.rules.breaking_things.title": "4. Breaking things", + "text.nucleoid_extras.rules.breaking_things.1": "Do not intentionally try to lag or break the server. If you do however find an issue or exploit, please report it so that we can address the issue.", + "text.nucleoid_extras.rules.keeping_it_fun.title": "5. Keeping it fun", + "text.nucleoid_extras.rules.keeping_it_fun.1": "We're a small server, so we're happy for you to play games as you want. If you want to make teams in a game where there wouldn't normally be, please do so! However, make sure that everyone in the game is on board with that before you do.", + "text.nucleoid_extras.rules.keep_in_mind.title": "6. Keep in mind...", + "text.nucleoid_extras.rules.keep_in_mind.1": "If you're working on a cool project, we'd love to see it - especially if it's related to the Nucleoid project! However, this server is not a place for unsolicited spam or advertisement. If you're not sure, ask a moderator!", + "advancements.nucleoid_extras.root.title": "Nucleoid", "advancements.nucleoid_extras.root.description": "Advancements for Nucleoid", "advancements.nucleoid_extras.first_tater.title": "My First Tater",