Gametext loading in hjson cards, tweaks to card loading
- Added game text, lore, and promo text processors for hjson card loading - Tweaked title hjson field loading to deprecate the * in titles for uniqueness - Added an ID field to the base blueprint so that blueprint references are aware of what their own ID is - Added population of the blueprint ID on creation for both hjson and java cards - Fixed bad version of a dependency (was using a RC)
This commit is contained in:
@@ -12,8 +12,8 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-collections</artifactId>
|
||||
<version>r03</version>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>33.1.0-jre</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.gempukku.lotro.common;
|
||||
|
||||
import java.text.Normalizer;
|
||||
|
||||
public class GameText {
|
||||
|
||||
public static String ConvertTextToHTML(String text) {
|
||||
String html = GameText.ConvertNanDeckNotation(text);
|
||||
html = GameText.ConvertAnnotatedHTMLToFormattedHTML(html);
|
||||
html = GameText.ConvertPlainQuotesToSmartQuotes(html);
|
||||
html = Names.AddAccentsToPlainText(html);
|
||||
|
||||
return html;
|
||||
}
|
||||
public static String ConvertNanDeckNotation(String text) {
|
||||
return text
|
||||
//Replacing a single backslash and other line breaks
|
||||
.replaceAll("\\\\", "<br>")
|
||||
.replaceAll("\n", "<br>")
|
||||
.replaceAll("\\n", "<br>")
|
||||
//non-breaking space
|
||||
.replaceAll("_", " ")
|
||||
//em dash helper
|
||||
.replaceAll("---", "—")
|
||||
//en dash helper
|
||||
.replaceAll("--", "–")
|
||||
//en dash instead of hyphen in front of negative numbers
|
||||
.replaceAll("-(\\d)", "–$1");
|
||||
}
|
||||
|
||||
public static String ConvertAnnotatedHTMLToFormattedHTML(String text) {
|
||||
return text
|
||||
.replaceAll("<helper>", "<i>")
|
||||
.replaceAll("</helper>", "</i>")
|
||||
.replaceAll("<keyword>", "<b>")
|
||||
.replaceAll("</keyword>", "</b>")
|
||||
.replaceAll("<phase>", "<b>")
|
||||
.replaceAll("</phase>", "</b>")
|
||||
.replaceAll("<br/>", "<br>");
|
||||
//TODO: symbol replacement
|
||||
}
|
||||
|
||||
public static String ConvertPlainQuotesToSmartQuotes(String text) {
|
||||
|
||||
return text
|
||||
//Quote characters at the beginning and end of the string are unambiguous
|
||||
.replaceAll("^'", "‘")
|
||||
.replaceAll("'$", "’")
|
||||
.replaceAll("^\"", "“")
|
||||
.replaceAll("\"$", "”")
|
||||
//If a space is on one side, also unambiguous
|
||||
.replaceAll(" '", " ‘")
|
||||
.replaceAll("' ", "’ ")
|
||||
.replaceAll(" \"", " “")
|
||||
.replaceAll("\" ", "” ")
|
||||
//When next to punctuation, it must be an end quote
|
||||
.replaceAll("([.,?!/])'", "$1’")
|
||||
.replaceAll("([.,?!/])\"", "$1”")
|
||||
//If we've figured out one of the smart quotes and it's right next
|
||||
// to a dumb quote, we can use that to figure out the other
|
||||
.replaceAll("\"‘", "“‘")
|
||||
.replaceAll("\"’", "”’")
|
||||
.replaceAll("‘\"", "‘“")
|
||||
.replaceAll("’\"", "’”")
|
||||
.replaceAll("'“", "‘“")
|
||||
.replaceAll("'”", "’”")
|
||||
.replaceAll("“'", "“‘")
|
||||
.replaceAll("”'", "”’")
|
||||
//Possessives (the s' case is already handled above)
|
||||
.replaceAll("'s", "’s")
|
||||
//If any pair of dumb quotes has evaded the above, we will assume they
|
||||
// are open or closed depending on order
|
||||
.replaceAll("\"'", "“‘")
|
||||
.replaceAll("'\"", "’”")
|
||||
//Any remaining single quotes must be in a contraction like I'm
|
||||
.replaceAll("'", "’")
|
||||
//Any remaining double quotes are just asking for it
|
||||
.replaceAll("\"", "“");
|
||||
}
|
||||
|
||||
public static String ConvertSmartQuotesToPlainQuotes(String text) {
|
||||
return text
|
||||
.replaceAll("’", "'")
|
||||
.replaceAll("‘", "'")
|
||||
.replaceAll("”", "\"")
|
||||
.replaceAll("“", "\"");
|
||||
}
|
||||
|
||||
public static String SanitizeHTMLToSearchText(String text) {
|
||||
String output = Normalizer.normalize(text, Normalizer.Form.NFD)
|
||||
//Removes any unicode "combining mark", aka diacritics
|
||||
.replaceAll("\\p{M}", "");
|
||||
output = ConvertSmartQuotesToPlainQuotes(output);
|
||||
|
||||
return output
|
||||
.replaceAll("</?b>", "")
|
||||
.replaceAll("</?i>", "")
|
||||
.replaceAll("\\s*<br/?>\\s*", " ");
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ public class Names {
|
||||
.replaceAll("‘", "'")
|
||||
.replaceAll("”", "\"")
|
||||
.replaceAll("“", "\"")
|
||||
//Removes any unicode "combining mark", aka diacritics
|
||||
.replaceAll("\\p{M}", "")
|
||||
.replaceAll(" ", "")
|
||||
.replaceAll("_", "")
|
||||
@@ -37,6 +38,73 @@ public class Names {
|
||||
.replaceAll("‘", "'")
|
||||
.replaceAll("”", "\"")
|
||||
.replaceAll("“", "\"")
|
||||
//Removes any unicode "combining mark", aka diacritics
|
||||
.replaceAll("\\p{M}", "");
|
||||
}
|
||||
|
||||
public static String AddAccentsToPlainText(String text) {
|
||||
return text
|
||||
.replaceAll("Anarion", "Anárion")
|
||||
.replaceAll("Anduril", "Andúril")
|
||||
.replaceAll("Annun", "Annûn")
|
||||
.replaceAll("Attea", "Attëa")
|
||||
.replaceAll("Barad-dur", "Barad-dûr")
|
||||
.replaceAll("Baruk khazad", "Baruk Khazâd")
|
||||
.replaceAll("Cantea", "Cantëa")
|
||||
.replaceAll("Cirdan", "Círdan")
|
||||
.replaceAll("Curunir", "Curunír")
|
||||
.replaceAll("Deagol", "Déagol")
|
||||
.replaceAll("Deor", "Déor")
|
||||
.replaceAll("Dinendal", "Dínendal")
|
||||
.replaceAll("Dunadan", "Dúnadan")
|
||||
.replaceAll("Dunedain", "Dúnedain")
|
||||
.replaceAll("Enquea", "Enquëa")
|
||||
.replaceAll("Eomer", "Éomer")
|
||||
.replaceAll("Eomund", "Éomund")
|
||||
.replaceAll("Eored", "Éored")
|
||||
.replaceAll("Eothain", "Éothain")
|
||||
.replaceAll("Eowyn", "Éowyn")
|
||||
.replaceAll("Erethon", "Erethón")
|
||||
.replaceAll("Fror", "Frór")
|
||||
.replaceAll("Ghan-buri-ghan", "Ghan-bûri-ghan")
|
||||
.replaceAll("Gloin", "Glóin")
|
||||
.replaceAll("Grima", "Gríma")
|
||||
.replaceAll("Grishnakh", "Grishnákh")
|
||||
.replaceAll("Guthlaf", "Guthláf")
|
||||
.replaceAll("Guthwine", "Gúthwinë")
|
||||
.replaceAll("Hama", "Háma")
|
||||
.replaceAll("Jarnsmid", "Járnsmid")
|
||||
.replaceAll("Khazad ai-menu", "Khazâd ai-mênu")
|
||||
.replaceAll("Khazad-dum", "Khazad-dûm")
|
||||
.replaceAll("Lathspell", "Láthspell")
|
||||
.replaceAll("Leod", "Léod")
|
||||
.replaceAll("Leofric", "Léofric")
|
||||
.replaceAll("Leowyn", "Léowyn")
|
||||
.replaceAll("Lorien", "Lórien")
|
||||
.replaceAll("Lothlorien", "Lothlórien")
|
||||
.replaceAll("Luthien", "Lúthien")
|
||||
.replaceAll("Mauhur", "Mauhúr")
|
||||
.replaceAll("Miruvore", "Miruvóre")
|
||||
.replaceAll("Mumak", "Mûmak")
|
||||
.replaceAll("Mumakil", "Mûmakil")
|
||||
.replaceAll("Namarie", "Namárië")
|
||||
.replaceAll("Nazgul", "Nazgûl")
|
||||
.replaceAll("Nertea", "Nertëa")
|
||||
.replaceAll("Numenor", "Númenor")
|
||||
.replaceAll("Numenorean", "Númenorean")
|
||||
.replaceAll("Otsea", "Otsëa")
|
||||
.replaceAll("Palantir", "Palantír")
|
||||
.replaceAll("Rhun", "Rhûn")
|
||||
.replaceAll("Rumil", "Rúmil")
|
||||
.replaceAll("Simbelmyne", "Simbelmynë")
|
||||
.replaceAll("Smeagol", "Sméagol")
|
||||
.replaceAll("Theoden", "Théoden")
|
||||
.replaceAll("Theodred", "Théodred")
|
||||
.replaceAll("Thonnas", "Thónnas")
|
||||
.replaceAll("Thror", "Thrór")
|
||||
.replaceAll("Toldea", "Toldëa")
|
||||
.replaceAll("Udun", "Udûn")
|
||||
.replaceAll("Ugluk", "Uglúk")
|
||||
.replaceAll("Ulaire", "Úlairë");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.gempukku.lotro.logic.timing.EffectResult;
|
||||
import java.util.*;
|
||||
|
||||
public class BuiltLotroCardBlueprint implements LotroCardBlueprint {
|
||||
private String id;
|
||||
private String title;
|
||||
private String sanitizedTitle;
|
||||
private String subtitle;
|
||||
@@ -38,6 +39,12 @@ public class BuiltLotroCardBlueprint implements LotroCardBlueprint {
|
||||
private SitesBlock allyHomeBlock;
|
||||
private int[] allyHomeSites = new int[0];
|
||||
|
||||
private String gameText;
|
||||
private String formattedGameText;
|
||||
private String loreText;
|
||||
private String promoText;
|
||||
|
||||
|
||||
private List<Requirement> requirements;
|
||||
private List<FilterableSource> targetFilters;
|
||||
|
||||
@@ -84,6 +91,10 @@ public class BuiltLotroCardBlueprint implements LotroCardBlueprint {
|
||||
|
||||
// Building methods
|
||||
|
||||
public void setBlueprintId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setAllyHomeSites(SitesBlock block, int[] numbers) {
|
||||
this.allyHomeBlock = block;
|
||||
this.allyHomeSites = numbers;
|
||||
@@ -270,6 +281,19 @@ public class BuiltLotroCardBlueprint implements LotroCardBlueprint {
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
public void setGameText(String text) {
|
||||
this.formattedGameText = GameText.ConvertTextToHTML(text.trim());
|
||||
this.gameText = GameText.SanitizeHTMLToSearchText(formattedGameText);
|
||||
}
|
||||
|
||||
public void setLore(String text) {
|
||||
this.loreText = GameText.ConvertTextToHTML(text.trim());
|
||||
}
|
||||
|
||||
public void setPromoText(String text) {
|
||||
this.promoText = GameText.ConvertTextToHTML(text.trim());
|
||||
}
|
||||
|
||||
public void setUnique(boolean unique) {
|
||||
this.unique = unique;
|
||||
}
|
||||
@@ -332,6 +356,19 @@ public class BuiltLotroCardBlueprint implements LotroCardBlueprint {
|
||||
|
||||
// Implemented methods
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(String id) {
|
||||
if(this.id != null)
|
||||
throw new UnsupportedOperationException("Id for this blueprint has already been set");
|
||||
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Side getSide() {
|
||||
return side;
|
||||
|
||||
@@ -45,9 +45,9 @@ public class LotroCardBlueprintBuilder implements CardGenerationEnvironment {
|
||||
fieldProcessors.put("target", new TargetFieldProcessor());
|
||||
fieldProcessors.put("effects", new EffectFieldProcessor());
|
||||
|
||||
fieldProcessors.put("gametext", new NullProcessor());
|
||||
fieldProcessors.put("lore", new NullProcessor());
|
||||
fieldProcessors.put("promotext", new NullProcessor());
|
||||
fieldProcessors.put("gametext", new GameTextFieldProcessor());
|
||||
fieldProcessors.put("lore", new LoreFieldProcessor());
|
||||
fieldProcessors.put("promotext", new PromoTextFieldProcessor());
|
||||
|
||||
//Soon! But not yet
|
||||
fieldProcessors.put("cardinfo", new NullProcessor());
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.gempukku.lotro.cards.build.field;
|
||||
|
||||
import com.gempukku.lotro.cards.build.BuiltLotroCardBlueprint;
|
||||
import com.gempukku.lotro.cards.build.CardGenerationEnvironment;
|
||||
import com.gempukku.lotro.cards.build.FieldProcessor;
|
||||
import com.gempukku.lotro.cards.build.InvalidCardDefinitionException;
|
||||
|
||||
public class GameTextFieldProcessor implements FieldProcessor {
|
||||
@Override
|
||||
public void processField(String key, Object value, BuiltLotroCardBlueprint blueprint, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
|
||||
final String[] textLines = FieldUtils.getStringArray(value, key);
|
||||
String gametext = String.join("<br>", textLines);
|
||||
blueprint.setGameText(gametext);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.gempukku.lotro.cards.build.field;
|
||||
|
||||
import com.gempukku.lotro.cards.build.BuiltLotroCardBlueprint;
|
||||
import com.gempukku.lotro.cards.build.CardGenerationEnvironment;
|
||||
import com.gempukku.lotro.cards.build.FieldProcessor;
|
||||
import com.gempukku.lotro.cards.build.InvalidCardDefinitionException;
|
||||
|
||||
public class LoreFieldProcessor implements FieldProcessor {
|
||||
@Override
|
||||
public void processField(String key, Object value, BuiltLotroCardBlueprint blueprint, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
|
||||
final String[] textLines = FieldUtils.getStringArray(value, key);
|
||||
String lore = String.join("<br>", textLines);
|
||||
blueprint.setLore(lore);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.gempukku.lotro.cards.build.field;
|
||||
|
||||
import com.gempukku.lotro.cards.build.BuiltLotroCardBlueprint;
|
||||
import com.gempukku.lotro.cards.build.CardGenerationEnvironment;
|
||||
import com.gempukku.lotro.cards.build.FieldProcessor;
|
||||
import com.gempukku.lotro.cards.build.InvalidCardDefinitionException;
|
||||
|
||||
public class PromoTextFieldProcessor implements FieldProcessor {
|
||||
@Override
|
||||
public void processField(String key, Object value, BuiltLotroCardBlueprint blueprint, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
|
||||
final String[] textLines = FieldUtils.getStringArray(value, key);
|
||||
String promoText = String.join("<br>", textLines);
|
||||
blueprint.setPromoText(promoText);
|
||||
}
|
||||
}
|
||||
@@ -8,15 +8,10 @@ import com.gempukku.lotro.cards.build.InvalidCardDefinitionException;
|
||||
public class TitleFieldProcessor implements FieldProcessor {
|
||||
@Override
|
||||
public void processField(String key, Object value, BuiltLotroCardBlueprint blueprint, CardGenerationEnvironment environment) throws InvalidCardDefinitionException {
|
||||
boolean unique = false;
|
||||
String title = FieldUtils.getString(value, key);
|
||||
//Deprecated, don't do this. Use the "unique" field instead.
|
||||
if (title.startsWith("*")) {
|
||||
unique = true;
|
||||
title = title.substring(1);
|
||||
}
|
||||
if (unique)
|
||||
blueprint.setUnique(true);
|
||||
if (title.startsWith("*"))
|
||||
throw new InvalidCardDefinitionException("Do not use '*' to indicate uniqueness. Use the 'unique' boolean field instead.");
|
||||
|
||||
blueprint.setTitle(title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,15 @@ public interface LotroCardBlueprint {
|
||||
LEFT, RIGHT
|
||||
}
|
||||
|
||||
default LotroCardBlueprint getParent() {
|
||||
return this;
|
||||
}
|
||||
|
||||
String getId();
|
||||
|
||||
//This isn't ideal, but there's 2,000 java cards that already exist.
|
||||
// Adding the argument to their constructors would be a chore.
|
||||
void setId(String id);
|
||||
Side getSide();
|
||||
|
||||
CardType getCardType();
|
||||
|
||||
@@ -200,16 +200,19 @@ public class LotroCardBlueprintLibrary {
|
||||
final JSONObject cardsFile = (JSONObject) parser.parse(json);
|
||||
final Set<Map.Entry<String, JSONObject>> cardsInFile = cardsFile.entrySet();
|
||||
for (Map.Entry<String, JSONObject> cardEntry : cardsInFile) {
|
||||
String blueprint = cardEntry.getKey();
|
||||
if (validateNew)
|
||||
if (_blueprints.containsKey(blueprint))
|
||||
logger.error(blueprint + " - Replacing existing card definition!");
|
||||
String blueprintId = cardEntry.getKey();
|
||||
if (validateNew && _blueprints.containsKey(blueprintId)) {
|
||||
logger.error(blueprintId + " from " +
|
||||
file.getAbsolutePath() + " - Replacing existing card definition!");
|
||||
}
|
||||
final JSONObject cardDefinition = cardEntry.getValue();
|
||||
try {
|
||||
final LotroCardBlueprint lotroCardBlueprint = cardBlueprintBuilder.buildFromJson(cardDefinition);
|
||||
_blueprints.put(blueprint, lotroCardBlueprint);
|
||||
final var lotroCardBlueprint = cardBlueprintBuilder.buildFromJson(cardDefinition);
|
||||
lotroCardBlueprint.setId(blueprintId);
|
||||
_blueprints.put(blueprintId, lotroCardBlueprint);
|
||||
} catch (InvalidCardDefinitionException exp) {
|
||||
logger.error("Unable to load card " + blueprint, exp);
|
||||
logger.error("Unable to load card " + blueprintId +
|
||||
" from " + file.getAbsolutePath(), exp);
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException exp) {
|
||||
@@ -238,6 +241,7 @@ public class LotroCardBlueprintLibrary {
|
||||
try {
|
||||
// Ensure it's loaded
|
||||
LotroCardBlueprint blueprint = findJavaBlueprint(blueprintId);
|
||||
blueprint.setId(blueprintId);
|
||||
_blueprints.put(blueprintId, blueprint);
|
||||
} catch (CardNotFoundException exp) {
|
||||
throw new RuntimeException("Unable to start the server, due to invalid (missing) card definition - " + blueprintId);
|
||||
@@ -442,30 +446,6 @@ public class LotroCardBlueprintLibrary {
|
||||
return String.valueOf(id);
|
||||
}
|
||||
|
||||
private void determineNeedsLoadingFlag(JSONObject setDefinition, Set<String> flags) {
|
||||
Boolean needsLoading = (Boolean) setDefinition.get("needsLoading");
|
||||
if (needsLoading == null)
|
||||
needsLoading = true;
|
||||
if (needsLoading)
|
||||
flags.add("needsLoading");
|
||||
}
|
||||
|
||||
private void determineMerchantableFlag(JSONObject setDefinition, Set<String> flags) {
|
||||
Boolean merchantable = (Boolean) setDefinition.get("merchantable");
|
||||
if (merchantable == null)
|
||||
merchantable = true;
|
||||
if (merchantable)
|
||||
flags.add("merchantable");
|
||||
}
|
||||
|
||||
private void determineOriginalSetFlag(JSONObject setDefinition, Set<String> flags) {
|
||||
Boolean originalSet = (Boolean) setDefinition.get("originalSet");
|
||||
if (originalSet == null)
|
||||
originalSet = true;
|
||||
if (originalSet)
|
||||
flags.add("originalSet");
|
||||
}
|
||||
|
||||
private void readSetRarityFile(DefaultSetDefinition rarity, String setNo, String rarityFile) throws IOException {
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(_raritiesFolder, rarityFile)), StandardCharsets.UTF_8));
|
||||
try {
|
||||
|
||||
@@ -18,6 +18,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class AbstractLotroCardBlueprint implements LotroCardBlueprint {
|
||||
|
||||
private String _id;
|
||||
private final int _twilightCost;
|
||||
private final String _name;
|
||||
private final String _sanitizedName;
|
||||
@@ -89,6 +91,19 @@ public abstract class AbstractLotroCardBlueprint implements LotroCardBlueprint {
|
||||
return _cardType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getId() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(String id) {
|
||||
if(_id != null)
|
||||
throw new UnsupportedOperationException("Id for this blueprint has already been set");
|
||||
|
||||
_id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Side getSide() {
|
||||
return _side;
|
||||
|
||||
Reference in New Issue
Block a user