Skip to content

Commit

Permalink
introduced the TranslationResolver; added tests; added support for Ec…
Browse files Browse the repository at this point in the history
…oEnchants
  • Loading branch information
BlvckBytes committed Oct 2, 2024
1 parent 8e64054 commit c6f9132
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 14 deletions.
22 changes: 22 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>auxilor</id>
<url>https://repo.auxilor.io/repository/maven-public/</url>
</repository>
</repositories>

<dependencies>
Expand Down Expand Up @@ -58,6 +62,24 @@
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.willfp</groupId>
<artifactId>EcoEnchants</artifactId>
<version>12.18.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.willfp</groupId>
<artifactId>eco</artifactId>
<version>6.71.6</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import me.blvckbytes.bukkitevaluable.ConfigManager;
import me.blvckbytes.item_predicate_parser.config.MainSection;
import me.blvckbytes.item_predicate_parser.translation.LanguageRegistry;
import me.blvckbytes.item_predicate_parser.translation.resolver.TranslationResolver;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.Nullable;
Expand All @@ -11,17 +12,28 @@

public class ItemPredicateParserPlugin extends JavaPlugin {

private static final String ECO_ENCHANTS_RESOLVER_PATH = "me/blvckbytes/item_predicate_parser/translation/resolver/EcoEnchantsResolver";

private static ItemPredicateParserPlugin instance;
private PredicateHelper predicateHelper;

@Override
public void onEnable() {
try {
TranslationResolver translationResolver = null;

if (Bukkit.getPluginManager().isPluginEnabled("EcoEnchants")) {
translationResolver = (TranslationResolver) Class
.forName(ECO_ENCHANTS_RESOLVER_PATH.replace('/', '.'))
.getConstructor()
.newInstance();
}

var configManager = new ConfigManager(this);
var configMapper = configManager.loadConfig("config.yml");
var mainSection = configMapper.mapSection(null, MainSection.class);

var languageRegistry = new LanguageRegistry(this);
var languageRegistry = new LanguageRegistry(this, translationResolver);
this.predicateHelper = new PredicateHelper(languageRegistry, mainSection);

instance = this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import me.blvckbytes.item_predicate_parser.translation.keyed.*;
import me.blvckbytes.item_predicate_parser.translation.resolver.TranslationResolver;
import me.blvckbytes.item_predicate_parser.translation.version.IVersionDependentCode;
import org.apache.commons.io.FileUtils;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.nio.charset.StandardCharsets;
Expand All @@ -20,14 +22,16 @@ public class LanguageRegistry {

private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();

private final @Nullable TranslationResolver translationResolver;
private final AssetIndex assetIndex;
private final File languagesFolder;
private final Logger logger;
private final IVersionDependentCode versionDependentCode;

private final Map<TranslationLanguage, TranslationRegistry> translationRegistryByLanguage;

public LanguageRegistry(Plugin plugin) throws Throwable {
public LanguageRegistry(Plugin plugin, @Nullable TranslationResolver translationResolver) throws Throwable {
this.translationResolver = translationResolver;
this.translationRegistryByLanguage = new HashMap<>();
this.logger = plugin.getLogger();
this.assetIndex = new AssetIndex(null);
Expand Down Expand Up @@ -83,7 +87,7 @@ private void initializeTranslationRegistry(TranslationLanguage language) throws

language.customTranslations.apply(languageFile);

TranslationRegistry registry = new TranslationRegistry(languageFile, versionDependentCode, logger);
TranslationRegistry registry = new TranslationRegistry(languageFile, versionDependentCode, translationResolver, logger);
registry.initialize(makeSources(language.collisionPrefixes, languageFile));
translationRegistryByLanguage.put(language, registry);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import me.blvckbytes.item_predicate_parser.parse.SubstringIndices;
import me.blvckbytes.item_predicate_parser.token.UnquotedStringToken;
import me.blvckbytes.item_predicate_parser.translation.keyed.LangKeyed;
import me.blvckbytes.item_predicate_parser.translation.resolver.TranslationResolver;
import me.blvckbytes.item_predicate_parser.translation.version.IVersionDependentCode;
import org.bukkit.Material;
import org.jetbrains.annotations.Nullable;
Expand All @@ -16,12 +17,19 @@ public class TranslationRegistry {

private final JsonObject languageFile;
private final IVersionDependentCode versionDependentCode;
private final @Nullable TranslationResolver translationResolver;
private final Logger logger;
private TranslatedLangKeyed<?>[] entries;

public TranslationRegistry(JsonObject languageFile, IVersionDependentCode versionDependentCode, Logger logger) {
public TranslationRegistry(
JsonObject languageFile,
IVersionDependentCode versionDependentCode,
@Nullable TranslationResolver translationResolver,
Logger logger
) {
this.languageFile = languageFile;
this.versionDependentCode = versionDependentCode;
this.translationResolver = translationResolver;
this.logger = logger;
}

Expand Down Expand Up @@ -147,11 +155,14 @@ private void createEntries(LangKeyedSource source, ArrayList<TranslatedLangKeyed
}
}

private @Nullable String accessLanguageKey(String key) {
private @Nullable String accessLanguageKey(String key, LangKeyed<?> langKeyed) {
var translationValue = languageFile.get(key);

if (translationValue == null)
if (translationValue == null) {
if (langKeyed != null && translationResolver != null)
return translationResolver.resolve(langKeyed);
return null;
}

if (!(translationValue instanceof JsonPrimitive))
return null;
Expand Down Expand Up @@ -198,12 +209,12 @@ private String normalizeDescriptionTranslation(String descriptionTranslation) {
if (descriptionTranslationKey == null)
descriptionTranslationKey = fileKey + ".desc";

var descriptionTranslation = accessLanguageKey(descriptionTranslationKey);
var descriptionTranslation = accessLanguageKey(descriptionTranslationKey, null);

if (descriptionTranslation != null)
return accessLanguageKey(fileKey) + " " + normalizeDescriptionTranslation(descriptionTranslation);
return accessLanguageKey(fileKey, langKeyed) + " " + normalizeDescriptionTranslation(descriptionTranslation);
}

return accessLanguageKey(fileKey);
return accessLanguageKey(fileKey, langKeyed);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package me.blvckbytes.item_predicate_parser.translation.resolver;

import com.willfp.ecoenchants.enchant.EcoEnchants;
import me.blvckbytes.item_predicate_parser.translation.keyed.LangKeyed;
import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.Nullable;

public class EcoEnchantsResolver extends TranslationResolver {

@Override
public @Nullable String resolve(LangKeyed<?> langKeyed) {

if (langKeyed.getWrapped() instanceof Enchantment enchantment) {
var id = enchantment.getKey().getKey();
var ecoEnchant = EcoEnchants.INSTANCE.get(id);

if (ecoEnchant == null)
return null;

return sanitize(ecoEnchant.getRawDisplayName());
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package me.blvckbytes.item_predicate_parser.translation.resolver;

import me.blvckbytes.item_predicate_parser.translation.keyed.LangKeyed;
import org.jetbrains.annotations.Nullable;

import java.util.Stack;

public abstract class TranslationResolver {

public abstract @Nullable String resolve(LangKeyed<?> langKeyed);

public static String sanitize(String input) {
var inputLength = input.length();
var result = new StringBuilder(inputLength);

/*
- Simple Colors: (§|&)[0-9a-fklmnor]
- Hex Colors: (§|&)#([0-9a-fA-F]{3} | [0-9a-fA-F]{6})
- XML-Tags (Mini-Message)
- May contain other tags in string-parameters, marked by " or '
- Example: <hover:show_text:"<red>test:TEST">
*/

int possibleTagBeginning = -1;
var quoteStack = new Stack<Character>();

for (var i = 0; i < inputLength; ++i) {
var currentChar = input.charAt(i);

if (possibleTagBeginning >= 0) {
if (currentChar == '"' || currentChar == '\'') {
if (!quoteStack.empty() && quoteStack.peek() == currentChar)
quoteStack.pop();
else
quoteStack.push(currentChar);
}

// No need to step through tags in strings; just anticipate non-stringed close char
if (!quoteStack.empty())
continue;

if (currentChar == '>') {
possibleTagBeginning = -1;
continue;
}

continue;
}

var isLastChar = i == inputLength - 1;

if (!isLastChar && (currentChar == '§' || currentChar == '&')) {
var nextChar = input.charAt(i + 1);

if (
isAlphaNumeric(nextChar) ||
(nextChar >= 'k' && nextChar <= 'o') ||
nextChar == 'r'
) {
++i;
continue;
}

if (nextChar == '#') {
var remainingChars = inputLength - 1 - i;
var maxMatchingChars = Math.min(6, remainingChars);

var matchedChars = 0;

for (; matchedChars < maxMatchingChars; ++matchedChars) {
if (!isAlphaNumeric(input.charAt(1 + (matchedChars + 1))))
break;
}

// Skips & (current), # (next; +1) and the number of matched alphanumerics, up to 6
// I think I've seen shorthands - so that's why 3 or 6; leave &# or malformed as is
if (matchedChars == 3 || matchedChars == 6) {
i += matchedChars + 1;
continue;
}
}
}

if (currentChar == '<') {
possibleTagBeginning = i;
continue;
}

result.append(currentChar);
}

// Tag was never closed, so let's leave it in
if (possibleTagBeginning >= 0)
result.append(input.substring(possibleTagBeginning));

return result.toString().trim();
}

private static boolean isAlphaNumeric(char c) {
return (
(c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F')
);
}
}
3 changes: 2 additions & 1 deletion src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ name: ItemPredicateParser
main: me.blvckbytes.item_predicate_parser.ItemPredicateParserPlugin
version: 0.1
author: BlvckBytes
api-version: 1.13
api-version: 1.13
softdepend: [EcoEnchants]
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public abstract class ParseTestBase {
.interceptAndUseAssertEquals(PotionEffectType.class)
.interceptAndUseAssertEquals(LangKeyed.class)
.intercept(List.class, (rootActualType, pathParts, expected, actual) -> {
var lastPathPart = pathParts.getLast();
var lastPathPart = pathParts.get(pathParts.size() - 1);

// Manual list content comparison
if (MaterialPredicate.class == lastPathPart.getDeclaringClass()) {
Expand All @@ -54,7 +54,7 @@ public abstract class ParseTestBase {
);
})
.intercept(Iterable.class, (rootActualType, pathParts, expected, actual) -> {
var lastPathPart = pathParts.getLast();
var lastPathPart = pathParts.get(pathParts.size() - 1);

// There's no need to compare the items of a source, as the collision-prefix will always be unique
return (
Expand Down Expand Up @@ -84,7 +84,7 @@ public static void setup() throws Throwable {

var versionDependentCode = new VersionDependentCodeFactory(serverVersion, logger).get();

translationRegistry = new TranslationRegistry(languageJson, versionDependentCode, logger);
translationRegistry = new TranslationRegistry(languageJson, versionDependentCode, null, logger);
translationRegistry.initialize(makeSources());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ private void compareRecursively(@Nullable Class<?> rootActualType, @Nullable Fie
pathParts.add(field);
compareRecursively(rootActualType, field, expectedValue, actualValue, pathParts);

if (!field.equals(pathParts.removeLast()))
if (!field.equals(pathParts.remove(pathParts.size() - 1)))
throw new IllegalStateException("Expected " + field.getName() + " to be at the end of the path-part list");
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(
Expand Down
Loading

0 comments on commit c6f9132

Please sign in to comment.