mirror of
https://github.com/ashhhleyyy/player-pronouns.git
synced 2024-11-23 17:48:09 +00:00
Support custom formatting for pronouns, along with a new database format using a palette
This commit is contained in:
parent
9f9977a3da
commit
915fd82f15
12 changed files with 416 additions and 39 deletions
|
@ -4,7 +4,7 @@ plugins {
|
|||
`maven-publish`
|
||||
}
|
||||
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
group = "io.github.ashisbored"
|
||||
|
||||
repositories {
|
||||
|
@ -27,6 +27,10 @@ dependencies {
|
|||
// placeholder-api
|
||||
modImplementation(libs.placeholder.api)
|
||||
include(libs.placeholder.api)
|
||||
|
||||
// more-codecs
|
||||
modImplementation(libs.more.codecs)
|
||||
include(libs.more.codecs)
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
|
|
|
@ -6,6 +6,7 @@ fabric-loader = "0.11.6"
|
|||
fabric-api = "0.37.1+1.17"
|
||||
|
||||
placeholder-api = "1.0.1+1.17"
|
||||
more-codecs = "0.2.0"
|
||||
|
||||
[libraries]
|
||||
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
|
||||
|
@ -15,3 +16,4 @@ fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-l
|
|||
fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" }
|
||||
|
||||
placeholder-api = { module = "eu.pb4:placeholder-api", version.ref = "placeholder-api" }
|
||||
more-codecs = { module = "xyz.nucleoid:more-codecs", version.ref = "more-codecs" }
|
||||
|
|
|
@ -5,8 +5,10 @@ import com.google.gson.JsonElement;
|
|||
import com.google.gson.JsonParser;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import io.github.ashisbored.playerpronouns.data.Pronoun;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -19,15 +21,15 @@ import java.util.Optional;
|
|||
public class Config {
|
||||
private static final Codec<Config> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Codec.BOOL.fieldOf("allow_custom").forGetter(config -> config.allowCustom),
|
||||
Codec.STRING.listOf().fieldOf("single").forGetter(config -> config.single),
|
||||
Codec.STRING.listOf().fieldOf("pairs").forGetter(config -> config.pairs)
|
||||
Pronoun.CODEC.listOf().fieldOf("single").forGetter(config -> config.single),
|
||||
Pronoun.CODEC.listOf().fieldOf("pairs").forGetter(config -> config.pairs)
|
||||
).apply(instance, Config::new));
|
||||
|
||||
private final boolean allowCustom;
|
||||
private final List<String> single;
|
||||
private final List<String> pairs;
|
||||
private final List<Pronoun> single;
|
||||
private final List<Pronoun> pairs;
|
||||
|
||||
private Config(boolean allowCustom, List<String> single, List<String> pairs) {
|
||||
private Config(boolean allowCustom, List<Pronoun> single, List<Pronoun> pairs) {
|
||||
this.allowCustom = allowCustom;
|
||||
this.single = single;
|
||||
this.pairs = pairs;
|
||||
|
@ -41,11 +43,11 @@ public class Config {
|
|||
return allowCustom;
|
||||
}
|
||||
|
||||
public List<String> getSingle() {
|
||||
public List<Pronoun> getSingle() {
|
||||
return single;
|
||||
}
|
||||
|
||||
public List<String> getPairs() {
|
||||
public List<Pronoun> getPairs() {
|
||||
return pairs;
|
||||
}
|
||||
|
||||
|
@ -69,7 +71,10 @@ public class Config {
|
|||
String s = Files.readString(path);
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonElement ele = parser.parse(s);
|
||||
return CODEC.decode(JsonOps.INSTANCE, ele).map(Pair::getFirst).result().orElseGet(Config::new);
|
||||
DataResult<Config> result = CODEC.decode(JsonOps.INSTANCE, ele).map(Pair::getFirst);
|
||||
Optional<DataResult.PartialResult<Config>> err = result.error();
|
||||
err.ifPresent(e -> PlayerPronouns.LOGGER.warn("Failed to load config: {}", e.message()));
|
||||
return result.result().orElseGet(Config::new);
|
||||
} catch (IOException e) {
|
||||
PlayerPronouns.LOGGER.warn("Failed to load config!", e);
|
||||
return new Config();
|
||||
|
|
|
@ -3,8 +3,9 @@ package io.github.ashisbored.playerpronouns;
|
|||
import eu.pb4.placeholders.PlaceholderAPI;
|
||||
import eu.pb4.placeholders.PlaceholderResult;
|
||||
import io.github.ashisbored.playerpronouns.command.PronounsCommand;
|
||||
import io.github.ashisbored.playerpronouns.data.BinaryPronounDatabase;
|
||||
import io.github.ashisbored.playerpronouns.data.PronounDatabase;
|
||||
import io.github.ashisbored.playerpronouns.data.PronounList;
|
||||
import io.github.ashisbored.playerpronouns.data.Pronouns;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
|
@ -24,7 +25,7 @@ public class PlayerPronouns implements ModInitializer {
|
|||
public static final Logger LOGGER = LogManager.getLogger();
|
||||
public static final String MOD_ID = "playerpronouns";
|
||||
|
||||
private static BinaryPronounDatabase pronounDatabase;
|
||||
private static PronounDatabase pronounDatabase;
|
||||
public static Config config;
|
||||
|
||||
@Override
|
||||
|
@ -40,7 +41,7 @@ public class PlayerPronouns implements ModInitializer {
|
|||
if (!Files.exists(playerData)) {
|
||||
Files.createDirectories(playerData);
|
||||
}
|
||||
pronounDatabase = BinaryPronounDatabase.load(playerData.resolve("pronouns.dat"));
|
||||
pronounDatabase = PronounDatabase.load(playerData.resolve("pronouns.dat"));
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Failed to create/load pronoun database!", e);
|
||||
}
|
||||
|
@ -69,8 +70,26 @@ public class PlayerPronouns implements ModInitializer {
|
|||
if (pronounDatabase == null) {
|
||||
return PlaceholderResult.value("Unknown");
|
||||
}
|
||||
String pronouns = pronounDatabase.get(player.getUuid());
|
||||
return PlaceholderResult.value(Objects.requireNonNullElse(pronouns, "Unknown"));
|
||||
Pronouns pronouns = pronounDatabase.get(player.getUuid());
|
||||
if (pronouns == null) {
|
||||
return PlaceholderResult.value("Unknown");
|
||||
}
|
||||
return PlaceholderResult.value(pronouns.formatted());
|
||||
});
|
||||
|
||||
PlaceholderAPI.register(new Identifier(MOD_ID, "raw_pronouns"), ctx -> {
|
||||
if (!ctx.hasPlayer()) {
|
||||
return PlaceholderResult.invalid("missing player");
|
||||
}
|
||||
ServerPlayerEntity player = ctx.getPlayer();
|
||||
if (pronounDatabase == null) {
|
||||
return PlaceholderResult.value("Unknown");
|
||||
}
|
||||
Pronouns pronouns = pronounDatabase.get(player.getUuid());
|
||||
if (pronouns == null) {
|
||||
return PlaceholderResult.value("Unknown");
|
||||
}
|
||||
return PlaceholderResult.value(pronouns.raw());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -82,7 +101,7 @@ public class PlayerPronouns implements ModInitializer {
|
|||
pronounDatabase.save(playerData.resolve("pronouns.dat"));
|
||||
}
|
||||
|
||||
public static boolean setPronouns(ServerPlayerEntity player, String pronouns) {
|
||||
public static boolean setPronouns(ServerPlayerEntity player, Pronouns pronouns) {
|
||||
if (pronounDatabase == null) return false;
|
||||
|
||||
pronounDatabase.put(player.getUuid(), pronouns);
|
||||
|
|
|
@ -15,7 +15,7 @@ public class PronounsArgument {
|
|||
.suggests((ctx, builder) -> {
|
||||
String remaining = builder.getRemainingLowerCase();
|
||||
|
||||
for (String pronouns : PronounList.get().getCalculatedPronounStrings()) {
|
||||
for (String pronouns : PronounList.get().getCalculatedPronounStrings().keySet()) {
|
||||
if (pronouns.toLowerCase(Locale.ROOT).startsWith(remaining)) {
|
||||
builder.suggest(pronouns);
|
||||
}
|
||||
|
|
|
@ -4,11 +4,15 @@ import com.mojang.brigadier.Command;
|
|||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import io.github.ashisbored.playerpronouns.PlayerPronouns;
|
||||
import io.github.ashisbored.playerpronouns.data.PronounList;
|
||||
import io.github.ashisbored.playerpronouns.data.Pronouns;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
import static io.github.ashisbored.playerpronouns.command.PronounsArgument.pronouns;
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
|
@ -19,17 +23,26 @@ public class PronounsCommand {
|
|||
.then(pronouns("pronouns")
|
||||
.executes(ctx -> {
|
||||
ServerPlayerEntity player = ctx.getSource().getPlayer();
|
||||
String pronouns = getString(ctx, "pronouns");
|
||||
String pronounsString = getString(ctx, "pronouns");
|
||||
|
||||
if (!PlayerPronouns.config.allowCustom() && !PronounList.get().getCalculatedPronounStrings().contains(pronouns)) {
|
||||
Map<String, Text> pronounTexts = PronounList.get().getCalculatedPronounStrings();
|
||||
if (!PlayerPronouns.config.allowCustom() && !pronounTexts.containsKey(pronounsString)) {
|
||||
ctx.getSource().sendError(new LiteralText("Custom pronouns have been disabled by the server administrator."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
Pronouns pronouns;
|
||||
if (pronounTexts.containsKey(pronounsString)) {
|
||||
pronouns = new Pronouns(pronounsString, pronounTexts.get(pronounsString));
|
||||
} else {
|
||||
pronouns = new Pronouns(pronounsString, new LiteralText(pronounsString));
|
||||
}
|
||||
|
||||
if (!PlayerPronouns.setPronouns(player, pronouns)) {
|
||||
ctx.getSource().sendError(new LiteralText("Failed to update pronouns, sorry"));
|
||||
} else {
|
||||
ctx.getSource().sendFeedback(new LiteralText("Updated your pronouns to " + pronouns + "!")
|
||||
ctx.getSource().sendFeedback(new LiteralText("Updated your pronouns to ")
|
||||
.append(pronouns.formatted())
|
||||
.formatted(Formatting.GREEN), false);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,14 @@ package io.github.ashisbored.playerpronouns.data;
|
|||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BinaryPronounDatabase {
|
||||
|
@ -48,6 +51,19 @@ public class BinaryPronounDatabase {
|
|||
}
|
||||
}
|
||||
|
||||
public static PalettePronounDatabase convert(Path path) throws IOException {
|
||||
Object2ObjectMap<UUID, Pronouns> pronouns = new Object2ObjectOpenHashMap<>();
|
||||
Map<String, Text> pronounStrings = PronounList.get().getCalculatedPronounStrings();
|
||||
for (var entry : BinaryPronounDatabase.load(path).data.entrySet()) {
|
||||
Text formatted = new LiteralText(entry.getValue());
|
||||
if (pronounStrings.containsKey(entry.getValue())) {
|
||||
formatted = pronounStrings.get(entry.getValue());
|
||||
}
|
||||
pronouns.put(entry.getKey(), new Pronouns(entry.getValue(), formatted));
|
||||
}
|
||||
return new PalettePronounDatabase(pronouns);
|
||||
}
|
||||
|
||||
public static BinaryPronounDatabase load(Path path) throws IOException {
|
||||
if (!Files.exists(path)) {
|
||||
return new BinaryPronounDatabase();
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
package io.github.ashisbored.playerpronouns.data;
|
||||
|
||||
import com.google.gson.JsonParser;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import io.github.ashisbored.playerpronouns.PlayerPronouns;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.minecraft.util.Pair;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* An improved version of {@link io.github.ashisbored.playerpronouns.data.BinaryPronounDatabase} that uses a palette
|
||||
* for efficiency when storing lots of players. It also supports versioning of the file to allow for changes to be
|
||||
* made to the format in the future.
|
||||
*/
|
||||
public class PalettePronounDatabase implements PronounDatabase {
|
||||
public static final int VERSION_NUMBER = 1;
|
||||
private static final JsonParser JSON_PARSER = new JsonParser();
|
||||
private final Object2ObjectMap<UUID, Pronouns> data;
|
||||
|
||||
protected PalettePronounDatabase(Object2ObjectMap<UUID, Pronouns> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
private PalettePronounDatabase() {
|
||||
this(new Object2ObjectOpenHashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(UUID player, Pronouns pronouns) {
|
||||
this.data.put(player, pronouns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Pronouns get(UUID player) {
|
||||
return this.data.get(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void save(Path path) throws IOException {
|
||||
try (OutputStream os = Files.newOutputStream(path);
|
||||
DataOutputStream out = new DataOutputStream(os)) {
|
||||
|
||||
out.writeShort(0x4568);
|
||||
out.writeInt(VERSION_NUMBER);
|
||||
|
||||
Pair<List<Pronouns>, Object2IntMap<UUID>> pair = this.convertToPalette();
|
||||
List<Pronouns> palette = pair.getLeft();
|
||||
Object2IntMap<UUID> values = pair.getRight();
|
||||
|
||||
out.writeInt(palette.size());
|
||||
for (Pronouns pronouns : palette) {
|
||||
String p = Pronouns.CODEC.encodeStart(JsonOps.INSTANCE, pronouns).result().orElseThrow().toString();
|
||||
out.writeUTF(p);
|
||||
}
|
||||
|
||||
out.writeInt(values.size());
|
||||
for (var entry : values.object2IntEntrySet()) {
|
||||
out.writeLong(entry.getKey().getMostSignificantBits());
|
||||
out.writeLong(entry.getKey().getLeastSignificantBits());
|
||||
out.writeInt(entry.getIntValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<List<Pronouns>, Object2IntMap<UUID>> convertToPalette() {
|
||||
List<Pronouns> palette = new ArrayList<>();
|
||||
Object2IntMap<UUID> values = new Object2IntOpenHashMap<>();
|
||||
for (var entry : this.data.entrySet()) {
|
||||
if (!palette.contains(entry.getValue())) {
|
||||
palette.add(entry.getValue());
|
||||
}
|
||||
values.put(entry.getKey(), palette.indexOf(entry.getValue()));
|
||||
}
|
||||
return new Pair<>(palette, values);
|
||||
}
|
||||
|
||||
public static PalettePronounDatabase load(Path path) throws IOException {
|
||||
if (!Files.exists(path)) {
|
||||
return new PalettePronounDatabase();
|
||||
}
|
||||
|
||||
try (InputStream is = Files.newInputStream(path);
|
||||
DataInputStream in = new DataInputStream(is)) {
|
||||
|
||||
short magic = in.readShort();
|
||||
if (magic != 0x4568) {
|
||||
throw new IOException("Invalid DB magic: " + magic);
|
||||
}
|
||||
|
||||
int version = in.readInt();
|
||||
if (version > VERSION_NUMBER) {
|
||||
throw new IOException("DB version " + version + " is greater than the latest supported: " + version);
|
||||
}
|
||||
|
||||
List<Pronouns> palette = new ArrayList<>();
|
||||
int paletteSize = in.readInt();
|
||||
for (int i = 0; i < paletteSize; i++) {
|
||||
String s = in.readUTF();
|
||||
Optional<Pronouns> optionalPronouns = Pronouns.CODEC.decode(JsonOps.INSTANCE, JSON_PARSER.parse(s)).resultOrPartial(e -> {
|
||||
throw new RuntimeException(new IOException("Invalid pronouns in database: " + s));
|
||||
}).map(com.mojang.datafixers.util.Pair::getFirst);
|
||||
if (optionalPronouns.isEmpty()) {
|
||||
throw new IOException("Invalid pronouns in database: " + s);
|
||||
}
|
||||
palette.add(optionalPronouns.get());
|
||||
}
|
||||
|
||||
Object2ObjectMap<UUID, Pronouns> data = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
// V1 Parsing
|
||||
if (version == 1) {
|
||||
int playerCount = in.readInt();
|
||||
for (int i = 0; i < playerCount; i++) {
|
||||
long mostSigBits = in.readLong();
|
||||
long leastSigBits = in.readLong();
|
||||
UUID uuid = new UUID(mostSigBits, leastSigBits);
|
||||
int pronounIndex = in.readInt();
|
||||
Pronouns old = data.put(uuid, palette.get(pronounIndex));
|
||||
if (old != null) {
|
||||
PlayerPronouns.LOGGER.warn("Duplicate UUID in database: " + uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new PalettePronounDatabase(data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package io.github.ashisbored.playerpronouns.data;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import io.github.ashisbored.playerpronouns.PlayerPronouns;
|
||||
import net.minecraft.text.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public record Pronoun(
|
||||
String pronoun,
|
||||
Style style
|
||||
) {
|
||||
public static final Codec<Pronoun> CODEC = new PronounCodec();
|
||||
|
||||
private static class PronounCodec implements Codec<Pronoun> {
|
||||
private static final Codec<Pronoun> OBJECT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Codec.STRING.fieldOf("pronoun").forGetter(Pronoun::pronoun),
|
||||
Codec.STRING.listOf().xmap(Pronoun::styleFrom, Pronoun::fromStyle).fieldOf("style").forGetter(Pronoun::style)
|
||||
).apply(instance, Pronoun::new));
|
||||
|
||||
private PronounCodec() { }
|
||||
|
||||
@Override
|
||||
public <T> DataResult<Pair<Pronoun, T>> decode(DynamicOps<T> ops, T input) {
|
||||
Optional<String> asString = ops.getStringValue(input).result();
|
||||
return asString.map(s -> DataResult.success(new Pair<>(new Pronoun(s, Style.EMPTY), ops.empty())))
|
||||
.orElseGet(() -> OBJECT_CODEC.decode(ops, input));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> DataResult<T> encode(Pronoun input, DynamicOps<T> ops, T prefix) {
|
||||
if (input.style.isEmpty()) {
|
||||
return ops.mergeToPrimitive(prefix, ops.createString(input.pronoun));
|
||||
} else {
|
||||
return OBJECT_CODEC.encode(input, ops, prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Style styleFrom(List<String> formatting) {
|
||||
Style style = Style.EMPTY;
|
||||
|
||||
for (String format : formatting) {
|
||||
switch (format) {
|
||||
case "bold" -> style = style.withBold(true);
|
||||
case "italic" -> style = style.withItalic(true);
|
||||
case "strikethrough" -> style = style.withStrikethrough(true);
|
||||
case "underline" -> style = style.withUnderline(true);
|
||||
case "obfuscated" -> style = style.obfuscated(true);
|
||||
default -> {
|
||||
TextColor col = TextColor.parse(format);
|
||||
if (col != null) {
|
||||
style = style.withColor(col);
|
||||
} else {
|
||||
PlayerPronouns.LOGGER.warn("Invalid formatting: {}", format);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
private static List<String> fromStyle(Style style) {
|
||||
List<String> ret = new ArrayList<>();
|
||||
TextColor colour = style.getColor();
|
||||
if (colour != null) {
|
||||
ret.add(colour.toString());
|
||||
}
|
||||
if (style.isBold()) {
|
||||
ret.add("bold");
|
||||
}
|
||||
if (style.isItalic()) {
|
||||
ret.add("italic");
|
||||
}
|
||||
if (style.isStrikethrough()) {
|
||||
ret.add("strikethrough");
|
||||
}
|
||||
if (style.isUnderlined()) {
|
||||
ret.add("underline");
|
||||
}
|
||||
if (style.isObfuscated()) {
|
||||
ret.add("obfuscated");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public MutableText toText() {
|
||||
return new LiteralText(this.pronoun).setStyle(this.style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.pronoun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.pronoun.hashCode();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package io.github.ashisbored.playerpronouns.data;
|
||||
|
||||
import io.github.ashisbored.playerpronouns.PlayerPronouns;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface PronounDatabase {
|
||||
void put(UUID player, Pronouns pronouns);
|
||||
@Nullable Pronouns get(UUID player);
|
||||
void save(Path path) throws IOException;
|
||||
|
||||
static PronounDatabase load(Path path) throws IOException {
|
||||
if (!Files.exists(path)) {
|
||||
// Will create a new empty database.
|
||||
return PalettePronounDatabase.load(path);
|
||||
}
|
||||
|
||||
boolean legacy = false;
|
||||
try (InputStream is = Files.newInputStream(path);
|
||||
DataInputStream in = new DataInputStream(is)) {
|
||||
short magic = in.readShort();
|
||||
if (magic == 0x4567) {
|
||||
legacy = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (legacy) {
|
||||
PlayerPronouns.LOGGER.info("Old (1.0.0) format pronoun database found, converting...");
|
||||
Path backupPath = path.getParent().resolve(path.getFileName().toString() + ".bak");
|
||||
Files.copy(path, backupPath);
|
||||
PlayerPronouns.LOGGER.info("Old database backed up to {}", backupPath);
|
||||
return BinaryPronounDatabase.convert(path);
|
||||
}
|
||||
|
||||
return PalettePronounDatabase.load(path);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,10 @@ import com.google.gson.JsonObject;
|
|||
import com.google.gson.JsonParser;
|
||||
import io.github.ashisbored.playerpronouns.Config;
|
||||
import io.github.ashisbored.playerpronouns.PlayerPronouns;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Style;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Pair;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -15,13 +19,13 @@ import java.util.*;
|
|||
public class PronounList {
|
||||
private static PronounList INSTANCE;
|
||||
|
||||
private final List<String> defaultSingle;
|
||||
private final List<String> defaultPairs;
|
||||
private final List<String> customSingle;
|
||||
private final List<String> customPairs;
|
||||
private final List<String> calculatedPronounStrings;
|
||||
private final List<Pronoun> defaultSingle;
|
||||
private final List<Pronoun> defaultPairs;
|
||||
private final List<Pronoun> customSingle;
|
||||
private final List<Pronoun> customPairs;
|
||||
private final Map<String, Text> calculatedPronounStrings;
|
||||
|
||||
public PronounList(List<String> defaultSingle, List<String> defaultPairs, List<String> customSingle, List<String> customPairs) {
|
||||
public PronounList(List<Pronoun> defaultSingle, List<Pronoun> defaultPairs, List<Pronoun> customSingle, List<Pronoun> customPairs) {
|
||||
this.defaultSingle = defaultSingle;
|
||||
this.defaultPairs = defaultPairs;
|
||||
this.customSingle = customSingle;
|
||||
|
@ -29,24 +33,33 @@ public class PronounList {
|
|||
this.calculatedPronounStrings = this.computePossibleCombinations();
|
||||
}
|
||||
|
||||
public List<String> getCalculatedPronounStrings() {
|
||||
public Map<String, Text> getCalculatedPronounStrings() {
|
||||
return this.calculatedPronounStrings;
|
||||
}
|
||||
|
||||
private List<String> computePossibleCombinations() {
|
||||
List<String> ret = new ArrayList<>();
|
||||
ret.addAll(this.defaultSingle);
|
||||
ret.addAll(this.customSingle);
|
||||
List<String> combinedPairs = new ArrayList<>();
|
||||
private Map<String, Text> computePossibleCombinations() {
|
||||
Map<String, Text> ret = new HashMap<>();
|
||||
for (Pronoun pronoun : this.defaultSingle) {
|
||||
ret.put(pronoun.pronoun(), pronoun.toText());
|
||||
}
|
||||
for (Pronoun pronoun : this.customSingle) {
|
||||
ret.put(pronoun.pronoun(), pronoun.toText());
|
||||
}
|
||||
List<Pronoun> combinedPairs = new ArrayList<>();
|
||||
combinedPairs.addAll(this.defaultPairs);
|
||||
combinedPairs.addAll(this.customPairs);
|
||||
for (int i = 0; i < combinedPairs.size(); i++) {
|
||||
for (int j = 0; j < combinedPairs.size(); j++) {
|
||||
if (i == j) continue;
|
||||
ret.add(combinedPairs.get(i) + "/" + combinedPairs.get(j));
|
||||
Pronoun a = combinedPairs.get(i);
|
||||
Pronoun b = combinedPairs.get(j);
|
||||
MutableText combined = new LiteralText("");
|
||||
combined.append(a.toText());
|
||||
combined.append(new LiteralText("/"));
|
||||
combined.append(b.toText());
|
||||
ret.put(a.pronoun() + "/" + b.pronoun(), combined);
|
||||
}
|
||||
}
|
||||
ret.sort(Comparator.naturalOrder());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -55,7 +68,7 @@ public class PronounList {
|
|||
throw new IllegalStateException("PronounList has already been loaded!");
|
||||
}
|
||||
|
||||
Pair<List<String>, List<String>> defaults = loadDefaults();
|
||||
Pair<List<Pronoun>, List<Pronoun>> defaults = loadDefaults();
|
||||
INSTANCE = new PronounList(
|
||||
defaults.getLeft(),
|
||||
defaults.getRight(),
|
||||
|
@ -71,16 +84,16 @@ public class PronounList {
|
|||
return INSTANCE;
|
||||
}
|
||||
|
||||
private static Pair<List<String>, List<String>> loadDefaults() {
|
||||
private static Pair<List<Pronoun>, List<Pronoun>> loadDefaults() {
|
||||
try (InputStream is = Objects.requireNonNull(PronounList.class.getResourceAsStream("/default_pronouns.json"));
|
||||
InputStreamReader reader = new InputStreamReader(is)) {
|
||||
JsonObject ele = new JsonParser().parse(reader).getAsJsonObject();
|
||||
JsonArray jsonSingle = ele.getAsJsonArray("single");
|
||||
JsonArray jsonPairs = ele.getAsJsonArray("pairs");
|
||||
List<String> single = new ArrayList<>();
|
||||
List<String> pairs = new ArrayList<>();
|
||||
jsonSingle.forEach(e -> single.add(e.getAsString()));
|
||||
jsonPairs.forEach(e -> pairs.add(e.getAsString()));
|
||||
List<Pronoun> single = new ArrayList<>();
|
||||
List<Pronoun> pairs = new ArrayList<>();
|
||||
jsonSingle.forEach(e -> single.add(new Pronoun(e.getAsString(), Style.EMPTY)));
|
||||
jsonPairs.forEach(e -> pairs.add(new Pronoun(e.getAsString(), Style.EMPTY)));
|
||||
return new Pair<>(single, pairs);
|
||||
} catch (IOException e) {
|
||||
PlayerPronouns.LOGGER.error("Failed to load default pronouns!", e);
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package io.github.ashisbored.playerpronouns.data;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import net.minecraft.text.Text;
|
||||
import xyz.nucleoid.codecs.MoreCodecs;
|
||||
|
||||
public record Pronouns(
|
||||
String raw,
|
||||
Text formatted
|
||||
) {
|
||||
public static final Codec<Pronouns> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Codec.STRING.fieldOf("raw").forGetter(Pronouns::raw),
|
||||
MoreCodecs.TEXT.fieldOf("formatted").forGetter(Pronouns::formatted)
|
||||
).apply(instance, Pronouns::new));
|
||||
}
|
Loading…
Reference in a new issue