Sentry upgrade

This commit is contained in:
Hans Mackowiak
2022-03-21 05:11:36 +00:00
parent 678d0a0f85
commit c8e5a02487
30 changed files with 372 additions and 206 deletions

View File

@@ -16,7 +16,6 @@ import forge.util.FileUtil;
import forge.util.OperatingSystem; import forge.util.OperatingSystem;
import forge.util.RestartUtil; import forge.util.RestartUtil;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.SentryClient;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.*; import java.awt.*;
@@ -35,11 +34,12 @@ public class Main {
public static void main(String[] args) { public static void main(String[] args) {
Sentry.init(); Sentry.init(options -> {
SentryClient sentryClient = Sentry.getStoredClient(); options.setEnableExternalConfiguration(true);
sentryClient.setRelease(BuildInfo.getVersionString()); options.setRelease(BuildInfo.getVersionString());
sentryClient.setEnvironment(System.getProperty("os.name")); options.setEnvironment(System.getProperty("os.name"));
sentryClient.addTag("Java Version", System.getProperty("java.version")); options.setTag("Java Version", System.getProperty("java.version"));
}, true);
// HACK - temporary solution to "Comparison method violates it's general contract!" crash // HACK - temporary solution to "Comparison method violates it's general contract!" crash
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

View File

@@ -64,8 +64,8 @@ import forge.util.ComparatorUtil;
import forge.util.Expressions; import forge.util.Expressions;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
import java.util.*; import java.util.*;
@@ -625,7 +625,7 @@ public class AiController {
catch (IllegalArgumentException ex) { catch (IllegalArgumentException ex) {
System.err.println(ex.getMessage()); System.err.println(ex.getMessage());
String assertex = ComparatorUtil.verifyTransitivity(saComparator, all); String assertex = ComparatorUtil.verifyTransitivity(saComparator, all);
Sentry.capture(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex); Sentry.captureMessage(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex);
} }
for (final SpellAbility sa : ComputerUtilAbility.getOriginalAndAltCostAbilities(all, player)) { for (final SpellAbility sa : ComputerUtilAbility.getOriginalAndAltCostAbilities(all, player)) {
@@ -836,21 +836,21 @@ public class AiController {
if (sa.getApi() != null) { if (sa.getApi() != null) {
String msg = "AiController:canPlaySa: AI checks for if can PlaySa"; String msg = "AiController:canPlaySa: AI checks for if can PlaySa";
Sentry.getContext().recordBreadcrumb( Breadcrumb bread = new Breadcrumb(msg);
new BreadcrumbBuilder().setMessage(msg) bread.setData("Api", sa.getApi().toString());
.withData("Api", sa.getApi().toString()) bread.setData("Card", card.getName());
.withData("Card", card.getName()).withData("SA", sa.toString()).build() bread.setData("SA", sa.toString());
); Sentry.addBreadcrumb(bread);
// add Extra for debugging // add Extra for debugging
Sentry.getContext().addExtra("Card", card); Sentry.setExtra("Card", card.getName());
Sentry.getContext().addExtra("SA", sa.toString()); Sentry.setExtra("SA", sa.toString());
boolean canPlay = SpellApiToAi.Converter.get(sa.getApi()).canPlayAIWithSubs(player, sa); boolean canPlay = SpellApiToAi.Converter.get(sa.getApi()).canPlayAIWithSubs(player, sa);
// remove added extra // remove added extra
Sentry.getContext().removeExtra("Card"); Sentry.removeExtra("Card");
Sentry.getContext().removeExtra("SA"); Sentry.removeExtra("SA");
if (!canPlay) { if (!canPlay) {
return AiPlayDecision.CantPlayAi; return AiPlayDecision.CantPlayAi;
@@ -1696,7 +1696,7 @@ public class AiController {
catch (IllegalArgumentException ex) { catch (IllegalArgumentException ex) {
System.err.println(ex.getMessage()); System.err.println(ex.getMessage());
String assertex = ComparatorUtil.verifyTransitivity(saComparator, all); String assertex = ComparatorUtil.verifyTransitivity(saComparator, all);
Sentry.capture(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex); Sentry.captureMessage(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex);
} }
for (final SpellAbility sa : ComputerUtilAbility.getOriginalAndAltCostAbilities(all, player)) { for (final SpellAbility sa : ComputerUtilAbility.getOriginalAndAltCostAbilities(all, player)) {

View File

@@ -16,12 +16,12 @@
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
<version>31.0.1-android</version> <version>31.1-android</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.8.1</version> <version>3.12.0</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -26,51 +26,4 @@ import forge.util.IHasName;
public interface InventoryItem extends IHasName { public interface InventoryItem extends IHasName {
String getItemType(); String getItemType();
String getImageKey(boolean altState); String getImageKey(boolean altState);
/**
* Converts a card name to a sortable name.
* Trim leading quotes, then move article last, then replace characters.
* Because An-Havva Constable.
* Capitals and lowercase sorted as one: "my deck" before "Myr Retribution"
* Apostrophes matter, though: "D'Avenant" before "Danitha"
* TO DO: Commas before apostrophes: "Rakdos, Lord of Riots" before "Rakdos's Return"
*
* @param printedName The name of the card.
* @return A sortable name.
*/
public static String toSortableName(String printedName) {
if (printedName.startsWith("\"")) printedName = printedName.substring(1);
return moveArticleToEnd(printedName).toLowerCase().replaceAll("[^\\s'0-9a-z]", "");
}
/**
* Article words. These words get kicked to the end of a sortable name.
* For localization, simply overwrite this array with appropriate words.
* Words in this list are used by the method String moveArticleToEnd(String), useful
* for alphabetizing phrases, in particular card or other inventory object names.
*/
public static final String[] ARTICLE_WORDS = {
"A",
"An",
"The"
};
/**
* Detects whether a string begins with an article word
*
* @param str The name of the card.
* @return The sort-friendly name of the card. Example: "The Hive" becomes "Hive The".
*/
public static String moveArticleToEnd(String str) {
String articleWord;
for (int i = 0; i < ARTICLE_WORDS.length; i++) {
articleWord = ARTICLE_WORDS[i];
if (str.startsWith(articleWord + " ")) {
str = str.substring(articleWord.length() + 1) + " " + articleWord;
return str;
}
}
return str;
}
} }

View File

@@ -190,7 +190,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
collectorNumber = (collectorNumber0 != null) && (collectorNumber0.length() > 0) ? collectorNumber0 : IPaperCard.NO_COLLECTOR_NUMBER; collectorNumber = (collectorNumber0 != null) && (collectorNumber0.length() > 0) ? collectorNumber0 : IPaperCard.NO_COLLECTOR_NUMBER;
// If the user changes the language this will make cards sort by the old language until they restart the game. // If the user changes the language this will make cards sort by the old language until they restart the game.
// This is a good tradeoff // This is a good tradeoff
sortableName = InventoryItem.toSortableName(CardTranslation.getTranslatedName(rules0.getName())); sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(rules0.getName()));
} }
// Want this class to be a key for HashTable // Want this class to be a key for HashTable

View File

@@ -313,4 +313,51 @@ public class TextUtil {
return "mana";//fix manamorphose stack description and probably others.. return "mana";//fix manamorphose stack description and probably others..
return "{"+TextUtil.fastReplace(ManaProduced," ","}{")+"}"; return "{"+TextUtil.fastReplace(ManaProduced," ","}{")+"}";
} }
/**
* Converts a card name to a sortable name.
* Trim leading quotes, then move article last, then replace characters.
* Because An-Havva Constable.
* Capitals and lowercase sorted as one: "my deck" before "Myr Retribution"
* Apostrophes matter, though: "D'Avenant" before "Danitha"
* TO DO: Commas before apostrophes: "Rakdos, Lord of Riots" before "Rakdos's Return"
*
* @param printedName The name of the card.
* @return A sortable name.
*/
public static String toSortableName(String printedName) {
if (printedName.startsWith("\"")) printedName = printedName.substring(1);
return moveArticleToEnd(printedName).toLowerCase().replaceAll("[^\\s'0-9a-z]", "");
}
/**
* Article words. These words get kicked to the end of a sortable name.
* For localization, simply overwrite this array with appropriate words.
* Words in this list are used by the method String moveArticleToEnd(String), useful
* for alphabetizing phrases, in particular card or other inventory object names.
*/
public static final String[] ARTICLE_WORDS = {
"A",
"An",
"The"
};
/**
* Detects whether a string begins with an article word
*
* @param str The name of the card.
* @return The sort-friendly name of the card. Example: "The Hive" becomes "Hive The".
*/
public static String moveArticleToEnd(String str) {
String articleWord;
for (int i = 0; i < ARTICLE_WORDS.length; i++) {
articleWord = ARTICLE_WORDS[i];
if (str.startsWith(articleWord + " ")) {
str = str.substring(articleWord.length() + 1) + " " + articleWord;
return str;
}
}
return str;
}
} }

View File

@@ -26,14 +26,14 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.10</version> <version>4.13.2</version>
<scope>test</scope> <scope>test</scope>
<type>jar</type> <type>jar</type>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.sentry</groupId> <groupId>io.sentry</groupId>
<artifactId>sentry-logback</artifactId> <artifactId>sentry-logback</artifactId>
<version>1.7.30</version> <version>5.7.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -35,8 +35,8 @@ import forge.game.cost.Cost;
import forge.game.spellability.*; import forge.game.spellability.*;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.FileSection; import forge.util.FileSection;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
/** /**
* <p> * <p>
@@ -145,10 +145,12 @@ public final class AbilityFactory {
return getAbility(mapParams, type, state, sVarHolder); return getAbility(mapParams, type, state, sVarHolder);
} catch (Error | Exception ex) { } catch (Error | Exception ex) {
String msg = "AbilityFactory:getAbility: crash when trying to create ability "; String msg = "AbilityFactory:getAbility: crash when trying to create ability ";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", state.getName()).withData("Ability", abString).build() bread.setData("Card", state.getName());
); bread.setData("Ability", abString);
Sentry.addBreadcrumb(bread);
throw new RuntimeException(msg + " of card: " + state.getName(), ex); throw new RuntimeException(msg + " of card: " + state.getName(), ex);
} }
} }

View File

@@ -73,8 +73,8 @@ import forge.util.MyRandom;
import forge.util.TextUtil; import forge.util.TextUtil;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
public class AbilityUtils { public class AbilityUtils {
@@ -1428,11 +1428,11 @@ public class AbilityUtils {
final Card card = sa.getHostCard(); final Card card = sa.getHostCard();
String msg = "AbilityUtils:resolveApiAbility: try to resolve API ability"; String msg = "AbilityUtils:resolveApiAbility: try to resolve API ability";
Sentry.getContext().recordBreadcrumb( Breadcrumb bread = new Breadcrumb(msg);
new BreadcrumbBuilder().setMessage(msg) bread.setData("Api", sa.getApi().toString());
.withData("Api", sa.getApi().toString()) bread.setData("Card", card.getName());
.withData("Card", card.getName()).withData("SA", sa.toString()).build() bread.setData("SA", sa.toString());
); Sentry.addBreadcrumb(bread);
// check conditions // check conditions
if (sa.metConditions()) { if (sa.metConditions()) {

View File

@@ -23,8 +23,8 @@ import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Localizer; import forge.util.Localizer;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
public class ManaEffect extends SpellAbilityEffect { public class ManaEffect extends SpellAbilityEffect {
@@ -231,10 +231,12 @@ public class ManaEffect extends SpellAbilityEffect {
// this can happen when mana is based on criteria that didn't match // this can happen when mana is based on criteria that didn't match
if (mana.isEmpty()) { if (mana.isEmpty()) {
String msg = "AbilityFactoryMana::manaResolve() - special mana effect is empty for"; String msg = "AbilityFactoryMana::manaResolve() - special mana effect is empty for";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", card.getName()).withData("SA", sa.toString()).build() bread.setData("Card", card.getName());
); bread.setData("SA", sa.toString());
Sentry.addBreadcrumb(bread, sa);
continue; continue;
} }

View File

@@ -70,8 +70,8 @@ import forge.trackable.Tracker;
import forge.util.*; import forge.util.*;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.mutable.MutableBoolean; import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@@ -2183,10 +2183,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
} catch (Exception e) { } catch (Exception e) {
String msg = "Card:keywordToText: crash in Keyword parsing"; String msg = "Card:keywordToText: crash in Keyword parsing";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", this.getName()).withData("Keyword", keyword).build() bread.setData("Card", this.getName());
); bread.setData("Keyword", keyword);
Sentry.addBreadcrumb(bread, this);
throw new RuntimeException("Error in Card " + this.getName() + " with Keyword " + keyword, e); throw new RuntimeException("Error in Card " + this.getName() + " with Keyword " + keyword, e);
} }
@@ -2672,10 +2673,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
} catch (Exception e) { } catch (Exception e) {
String msg = "Card:abilityTextInstantSorcery: crash in Keyword parsing"; String msg = "Card:abilityTextInstantSorcery: crash in Keyword parsing";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", this.getName()).withData("Keyword", keyword).build() bread.setData("Card", this.getName());
); bread.setData("Keyword", keyword);
Sentry.addBreadcrumb(bread, this);
throw new RuntimeException("Error in Card " + this.getName() + " with Keyword " + keyword, e); throw new RuntimeException("Error in Card " + this.getName() + " with Keyword " + keyword, e);
} }

View File

@@ -74,8 +74,8 @@ import forge.game.trigger.TriggerHandler;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Lang; import forge.util.Lang;
import forge.util.TextUtil; import forge.util.TextUtil;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
/** /**
* <p> * <p>
@@ -599,10 +599,11 @@ public class CardFactoryUtil {
intrinsicAbility.setCardState(card.getCurrentState()); intrinsicAbility.setCardState(card.getCurrentState());
} catch (Exception e) { } catch (Exception e) {
String msg = "CardFactoryUtil:addAbilityFactoryAbilities: crash in raw Ability"; String msg = "CardFactoryUtil:addAbilityFactoryAbilities: crash in raw Ability";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", card.getName()).withData("Ability", rawAbility).build() bread.setData("Card", card.getName());
); bread.setData("Ability", rawAbility);
Sentry.addBreadcrumb(bread, card);
// rethrow the exception with card Name for the user // rethrow the exception with card Name for the user
throw new RuntimeException("crash in raw Ability, check card script of " + card.getName(), e); throw new RuntimeException("crash in raw Ability, check card script of " + card.getName(), e);

View File

@@ -50,8 +50,8 @@ import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
public class CardState extends GameObject implements IHasSVars { public class CardState extends GameObject implements IHasSVars {
private String name = ""; private String name = "";
@@ -270,10 +270,11 @@ public class CardState extends GameObject implements IHasSVars {
inst = intrinsicKeywords.add(s); inst = intrinsicKeywords.add(s);
} catch (Exception e) { } catch (Exception e) {
String msg = "CardState:addIntrinsicKeyword: failed to parse Keyword"; String msg = "CardState:addIntrinsicKeyword: failed to parse Keyword";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", card.getName()).withData("Keyword", s).build() bread.setData("Card", card.getName());
); bread.setData("Keyword", s);
Sentry.addBreadcrumb(bread, this);
//rethrow //rethrow
throw new RuntimeException("Error in Keyword " + s + " for card " + card.getName(), e); throw new RuntimeException("Error in Keyword " + s + " for card " + card.getName(), e);

View File

@@ -46,8 +46,8 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.TextUtil; import forge.util.TextUtil;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
public final class CardUtil { public final class CardUtil {
// disable instantiation // disable instantiation
@@ -190,13 +190,12 @@ public final class CardUtil {
return cachedCard; return cachedCard;
} }
String msg = "CardUtil:getLKICopy copy object"; String msg = "CardUtil:getLKICopy copy object";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", in.getName()) bread.setData("Card", in.getName());
.withData("CardState", in.getCurrentStateName().toString()) bread.setData("CardState", in.getCurrentStateName().toString());
.withData("Player", in.getController().getName()) bread.setData("Player", in.getController().getName());
.build() Sentry.addBreadcrumb(bread, in);
);
final Card newCopy = new Card(in.getId(), in.getPaperCard(), in.getGame(), null); final Card newCopy = new Card(in.getId(), in.getPaperCard(), in.getGame(), null);
cachedMap.put(in.getId(), newCopy); cachedMap.put(in.getId(), newCopy);

View File

@@ -16,8 +16,8 @@ import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.util.Lang; import forge.util.Lang;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
public abstract class KeywordInstance<T extends KeywordInstance<?>> implements KeywordInterface { public abstract class KeywordInstance<T extends KeywordInstance<?>> implements KeywordInterface {
private Keyword keyword; private Keyword keyword;
@@ -95,14 +95,15 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
try { try {
String msg = "KeywordInstance:createTraits: make Traits for Keyword"; String msg = "KeywordInstance:createTraits: make Traits for Keyword";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", host.getName()).withData("Keyword", this.original).build() bread.setData("Card", host.getName());
); bread.setData("Keyword", this.original);
Sentry.addBreadcrumb(bread, this);
// add Extra for debugging // add Extra for debugging
Sentry.getContext().addExtra("Card", host); Sentry.setExtra("Card", host.getName());
Sentry.getContext().addExtra("Keyword", this.original); Sentry.setExtra("Keyword", this.original);
CardFactoryUtil.addTriggerAbility(this, host, intrinsic); CardFactoryUtil.addTriggerAbility(this, host, intrinsic);
CardFactoryUtil.addReplacementEffect(this, host.getCurrentState(), intrinsic); CardFactoryUtil.addReplacementEffect(this, host.getCurrentState(), intrinsic);
@@ -110,16 +111,18 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
CardFactoryUtil.addStaticAbility(this, host.getCurrentState(), intrinsic); CardFactoryUtil.addStaticAbility(this, host.getCurrentState(), intrinsic);
} catch (Exception e) { } catch (Exception e) {
String msg = "KeywordInstance:createTraits: failed Traits for Keyword"; String msg = "KeywordInstance:createTraits: failed Traits for Keyword";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", host.getName()).withData("Keyword", this.original).build() bread.setData("Card", host.getName());
); bread.setData("Keyword", this.original);
Sentry.addBreadcrumb(bread, this);
//rethrow //rethrow
throw new RuntimeException("Error in Keyword " + this.original + " for card " + host.getName(), e); throw new RuntimeException("Error in Keyword " + this.original + " for card " + host.getName(), e);
} finally { } finally {
// remove added extra // remove added extra
Sentry.getContext().removeExtra("Card"); Sentry.removeExtra("Card");
Sentry.getContext().removeExtra("Keyword"); Sentry.removeExtra("Keyword");
} }
} }
@@ -143,14 +146,15 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
} }
try { try {
String msg = "KeywordInstance:createTraits: make Traits for Keyword"; String msg = "KeywordInstance:createTraits: make Traits for Keyword";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Player", player.getName()).withData("Keyword", this.original).build() bread.setData("Player", player.getName());
); bread.setData("Keyword", this.original);
Sentry.addBreadcrumb(bread, this);
// add Extra for debugging // add Extra for debugging
Sentry.getContext().addExtra("Player", player); Sentry.setExtra("Player", player.getName());
Sentry.getContext().addExtra("Keyword", this.original); Sentry.setExtra("Keyword", this.original);
PlayerFactoryUtil.addTriggerAbility(this, player); PlayerFactoryUtil.addTriggerAbility(this, player);
PlayerFactoryUtil.addReplacementEffect(this, player); PlayerFactoryUtil.addReplacementEffect(this, player);
@@ -158,16 +162,18 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
PlayerFactoryUtil.addStaticAbility(this, player); PlayerFactoryUtil.addStaticAbility(this, player);
} catch (Exception e) { } catch (Exception e) {
String msg = "KeywordInstance:createTraits: failed Traits for Keyword"; String msg = "KeywordInstance:createTraits: failed Traits for Keyword";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Player", player.getName()).withData("Keyword", this.original).build() bread.setData("Player", player.getName());
); bread.setData("Keyword", this.original);
Sentry.addBreadcrumb(bread, this);
//rethrow //rethrow
throw new RuntimeException("Error in Keyword " + this.original + " for player " + player.getName(), e); throw new RuntimeException("Error in Keyword " + this.original + " for player " + player.getName(), e);
} finally { } finally {
// remove added extra // remove added extra
Sentry.getContext().removeExtra("Player"); Sentry.removeExtra("Player");
Sentry.getContext().removeExtra("Keyword"); Sentry.removeExtra("Keyword");
} }
} }
/* /*

View File

@@ -40,8 +40,8 @@ import forge.game.zone.Zone;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.FileSection; import forge.util.FileSection;
import forge.util.Visitor; import forge.util.Visitor;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
public class TriggerHandler { public class TriggerHandler {
private final Set<TriggerType> suppressedModes = Collections.synchronizedSet(EnumSet.noneOf(TriggerType.class)); private final Set<TriggerType> suppressedModes = Collections.synchronizedSet(EnumSet.noneOf(TriggerType.class));
@@ -127,10 +127,12 @@ public class TriggerHandler {
return TriggerHandler.parseTrigger(mapParams, host, intrinsic, sVarHolder); return TriggerHandler.parseTrigger(mapParams, host, intrinsic, sVarHolder);
} catch (Exception e) { } catch (Exception e) {
String msg = "TriggerHandler:parseTrigger failed to parse"; String msg = "TriggerHandler:parseTrigger failed to parse";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", host.getName()).withData("Trigger", trigParse).build() bread.setData("Card", host.getName());
); bread.setData("Trigger", trigParse);
Sentry.addBreadcrumb(bread, host);
//rethrow //rethrow
throw new RuntimeException("Error in Trigger for Card: " + host.getName(), e); throw new RuntimeException("Error in Trigger for Card: " + host.getName(), e);
} }
@@ -153,10 +155,12 @@ public class TriggerHandler {
} }
} catch (Exception e) { } catch (Exception e) {
String msg = "TriggerHandler:parseTrigger failed to parse"; String msg = "TriggerHandler:parseTrigger failed to parse";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg) Breadcrumb bread = new Breadcrumb(msg);
.withData("Card", host.getName()).withData("Params", mapParams.toString()).build() bread.setData("Card", host.getName());
); bread.setData("Params", mapParams.toString());
Sentry.addBreadcrumb(bread, host);
//rethrow //rethrow
throw new RuntimeException("Error in Trigger for Card: " + host.getName(), e); throw new RuntimeException("Error in Trigger for Card: " + host.getName(), e);
} }

View File

@@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="forge.app" package="forge.app"
android:versionCode="1" android:versionCode="1"
android:versionName="1.6.47" > <!-- versionName should be updated and it's used for Sentry releases tag --> android:versionName="1.6.49" > <!-- versionName should be updated and it's used for Sentry releases tag -->
<uses-sdk <uses-sdk
android:minSdkVersion="19" android:minSdkVersion="19"
@@ -30,5 +30,17 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".Exiter" android:theme="@android:style/Theme.NoDisplay"/> <activity android:name=".Exiter" android:theme="@android:style/Theme.NoDisplay"/>
<meta-data android:name="io.sentry.dsn" android:value="https://a0b8dbad9b8a49cfa51bf65d462e8dae:b3f27d7461224cb8836eb5c6050c666c@sentry.cardforge.org/2?buffer.enabled=false" />
<!-- manually added -->
<provider
android:name="io.sentry.android.core.SentryInitProvider"
android:authorities=".SentryInitProvider"
android:exported="false"/>
<provider
android:name="io.sentry.android.core.SentryPerformanceProvider"
android:authorities=".SentryPerformanceProvider"
android:initOrder="200"
android:exported="false"/>
</application> </application>
</manifest> </manifest>

View File

@@ -6,7 +6,7 @@
<packaging.type>jar</packaging.type> <packaging.type>jar</packaging.type>
<build.min.memory>-Xms1024m</build.min.memory> <build.min.memory>-Xms1024m</build.min.memory>
<build.max.memory>-Xmx1536m</build.max.memory> <build.max.memory>-Xmx1536m</build.max.memory>
<alpha-version>1.6.47.001</alpha-version> <alpha-version>1.6.49.001</alpha-version>
<sign.keystore>keystore</sign.keystore> <sign.keystore>keystore</sign.keystore>
<sign.alias>alias</sign.alias> <sign.alias>alias</sign.alias>
<sign.storepass>storepass</sign.storepass> <sign.storepass>storepass</sign.storepass>
@@ -45,7 +45,6 @@
</resources> </resources>
<finalName>forge-android-${alpha-version}</finalName> <finalName>forge-android-${alpha-version}</finalName>
</build> </build>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.google.android</groupId> <groupId>com.google.android</groupId>
@@ -104,7 +103,69 @@
<dependency> <dependency>
<groupId>io.sentry</groupId> <groupId>io.sentry</groupId>
<artifactId>sentry-android</artifactId> <artifactId>sentry-android</artifactId>
<version>1.7.30</version> <version>5.7.0</version>
<type>aar</type>
<exclusions>
<exclusion>
<groupId>io.sentry</groupId>
<artifactId>sentry-android-core</artifactId>
</exclusion>
<exclusion>
<groupId>io.sentry</groupId>
<artifactId>sentry-android-ndk</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- manual sentry-android dependencies because of Gradle Bug -->
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry-android-core</artifactId>
<version>5.7.0</version>
<type>aar</type>
<exclusions>
<exclusion>
<groupId>androidx.lifecycle</groupId>
<artifactId>lifecycle-process</artifactId>
</exclusion>
<exclusion>
<groupId>androidx.lifecycle</groupId>
<artifactId>lifecycle-common-java8</artifactId>
</exclusion>
<exclusion>
<groupId>androidx.core</groupId>
<artifactId>core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry-android-ndk</artifactId>
<version>5.7.0</version>
<type>aar</type>
<exclusions>
<exclusion>
<groupId>io.sentry</groupId>
<artifactId>sentry-android-core</artifactId>
</exclusion>
<exclusion>
<groupId>androidx.lifecycle</groupId>
<artifactId>lifecycle-process</artifactId>
</exclusion>
<exclusion>
<groupId>androidx.lifecycle</groupId>
<artifactId>lifecycle-common-java8</artifactId>
</exclusion>
<exclusion>
<groupId>androidx.core</groupId>
<artifactId>core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- runtime dependency of sentry -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -119,7 +180,19 @@
<plugin> <plugin>
<groupId>com.simpligility.maven.plugins</groupId> <groupId>com.simpligility.maven.plugins</groupId>
<artifactId>android-maven-plugin</artifactId> <artifactId>android-maven-plugin</artifactId>
<version>4.2.1</version> <dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>6.2.2</version>
</dependency>
</dependencies>
<version>4.6.0</version>
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<sign> <sign>
@@ -139,11 +212,21 @@
<config>${project.basedir}/proguard.cfg</config> <config>${project.basedir}/proguard.cfg</config>
</proguard> </proguard>
<release>true</release> <release>true</release>
<dex> <dexCompiler>d8</dexCompiler>
<d8>
<minApi>26</minApi>
<jvmArguments> <jvmArguments>
<argument>${build.min.memory}</argument> <argument>${build.min.memory}</argument>
<argument>${build.max.memory}</argument> <argument>${build.max.memory}</argument>
</jvmArguments> </jvmArguments>
</d8>
<dex>
<multi-dex>true</multi-dex>
<jvmArguments>
<argument>${build.min.memory}</argument>
<argument>${build.max.memory}</argument>
</jvmArguments>
<dexArguments>--min-sdk-version=26</dexArguments>
</dex> </dex>
</configuration> </configuration>
</plugin> </plugin>
@@ -160,7 +243,19 @@
<plugin> <plugin>
<groupId>com.simpligility.maven.plugins</groupId> <groupId>com.simpligility.maven.plugins</groupId>
<artifactId>android-maven-plugin</artifactId> <artifactId>android-maven-plugin</artifactId>
<version>4.2.1</version> <dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>6.2.2</version>
</dependency>
</dependencies>
<version>4.6.0</version>
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<sign> <sign>
@@ -183,11 +278,21 @@
<config>${project.basedir}/proguard.cfg</config> <config>${project.basedir}/proguard.cfg</config>
</proguard> </proguard>
<release>true</release> <release>true</release>
<dex> <dexCompiler>d8</dexCompiler>
<d8>
<minApi>26</minApi>
<jvmArguments> <jvmArguments>
<argument>${build.min.memory}</argument> <argument>${build.min.memory}</argument>
<argument>${build.max.memory}</argument> <argument>${build.max.memory}</argument>
</jvmArguments> </jvmArguments>
</d8>
<dex>
<multi-dex>true</multi-dex>
<jvmArguments>
<argument>${build.min.memory}</argument>
<argument>${build.max.memory}</argument>
</jvmArguments>
<dexArguments>--min-sdk-version=26</dexArguments>
</dex> </dex>
</configuration> </configuration>
</plugin> </plugin>
@@ -238,7 +343,19 @@
<plugin> <plugin>
<groupId>com.simpligility.maven.plugins</groupId> <groupId>com.simpligility.maven.plugins</groupId>
<artifactId>android-maven-plugin</artifactId> <artifactId>android-maven-plugin</artifactId>
<version>4.2.1</version> <dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>6.2.2</version>
</dependency>
</dependencies>
<version>4.6.0</version>
<inherited>true</inherited> <inherited>true</inherited>
<configuration> <configuration>
<sign> <sign>

View File

@@ -6,9 +6,13 @@
-verbose -verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable
-android
## Uncomment the line below and set it to the location of rt.jar in JDK if the Proguard step fails to find the libraries ## Uncomment the line below and set it to the location of rt.jar in JDK if the Proguard step fails to find the libraries
## and spits out a thousand-something Class Not Found errors ## and spits out a thousand-something Class Not Found errors
##-libraryjars /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar ##-libraryjars /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar
##-libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class)
##-libraryjars <java.home>/jmods/jdk.xml.dom.jmod(!**.jar;!module-info.class)
-dontwarn afu.org.checkerframework.** -dontwarn afu.org.checkerframework.**
-dontwarn io.netty.** -dontwarn io.netty.**
@@ -16,32 +20,55 @@
-dontwarn com.thoughtworks.xstream.** -dontwarn com.thoughtworks.xstream.**
-dontwarn com.badlogic.gdx.** -dontwarn com.badlogic.gdx.**
-dontwarn org.apache.commons.** -dontwarn org.apache.commons.**
-dontwarn org.apache.http.**
-dontwarn com.google.guava.** -dontwarn com.google.guava.**
-dontwarn com.google.common.** -dontwarn com.google.common.**
-dontwarn com.google.gson.**
-dontwarn org.checkerframework.** -dontwarn org.checkerframework.**
-dontwarn org.xmlpull.** -dontwarn org.xmlpull.**
-dontwarn org.apache.log4j.** -dontwarn org.apache.log4j.**
-dontwarn org.fourthline.cling.** -dontwarn org.fourthline.cling.**
-dontwarn org.seamless.http.** -dontwarn org.seamless.http.**
-dontwarn org.seamless.xhtml.**
-dontwarn org.seamless.xml.**
-dontwarn org.seamless.util.** -dontwarn org.seamless.util.**
-dontwarn org.seamless.swing.** -dontwarn org.seamless.swing.**
-dontwarn java.lang.management.** -dontwarn java.lang.management.**
-dontwarn java.awt.** -dontwarn java.awt.**
-dontwarn java.util.** -dontwarn java.util.**
-dontwarn java.lang.** -dontwarn java.lang.**
-dontwarn java.net.**
-dontwarn java.nio.**
-dontwarn java.io.**
-dontwarn org.slf4j.** -dontwarn org.slf4j.**
-dontwarn ch.qos.logback.**
-dontwarn javax.** -dontwarn javax.**
-dontwarn org.apache.logging.log4j.** -dontwarn org.apache.logging.log4j.**
-dontwarn module-info -dontwarn module-info
-dontwarn io.sentry.logback.*
-dontwarn io.sentry.**
-dontwarn net.jpountz.**
## Support library ## Support library
-dontwarn android.support.** -dontwarn android.**
-dontwarn androidx.**
-dontwarn forge.**
-keep class forge.** { *; } -keep class forge.** { *; }
-keep class com.thoughtworks.xstream.** { *; } -keep class com.thoughtworks.xstream.** { *; }
-keep class org.apache.commons.lang3.** { *; } -keep class org.apache.commons.lang3.** { *; }
-keep class com.google.guava.** { *; } -keep class com.google.guava.** { *; }
-keep class com.google.common.** { *; } -keep class com.google.common.** { *; }
-keep class com.google.gson.GsonBuilder
-keep class io.sentry.event.Event { *; } -keep class io.sentry.event.Event { *; }
-keep class io.sentry.android.core.SentryAndroidOptions
-keep class io.sentry.android.core.SentryAndroid
-keep class io.sentry.android.core.SentryInitProvider
-keep class io.sentry.android.core.SentryPerformanceProvider
-keep class io.sentry.android.ndk.SentryNdk
-keep class io.sentry.Sentry
-keep class io.netty.util.internal.logging.** { *; } -keep class io.netty.util.internal.logging.** { *; }
-keep class net.jpountz.** { *; } -keep class net.jpountz.** { *; }
-keep class com.ray3k.** { *; } -keep class com.ray3k.** { *; }

View File

@@ -53,9 +53,9 @@ import forge.localinstance.properties.ForgePreferences;
import forge.model.FModel; import forge.model.FModel;
import forge.util.FileUtil; import forge.util.FileUtil;
import forge.util.ThreadUtil; import forge.util.ThreadUtil;
import io.sentry.Breadcrumb;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.android.AndroidSentryClientFactory; //import io.sentry.android.core.SentryAndroid;
import io.sentry.event.BreadcrumbBuilder;
public class Main extends AndroidApplication { public class Main extends AndroidApplication {
AndroidAdapter Gadapter; AndroidAdapter Gadapter;
@@ -63,10 +63,10 @@ public class Main extends AndroidApplication {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Context ctx = this.getApplicationContext();
String sentryDsn = "https://a0b8dbad9b8a49cfa51bf65d462e8dae:b3f27d7461224cb8836eb5c6050c666c@sentry.cardforge.org/2?buffer.enabled=false";
//init Sentry //init Sentry
Sentry.init(sentryDsn, new AndroidSentryClientFactory(ctx)); //SentryAndroid.init(this);
//get total device RAM in mb //get total device RAM in mb
ActivityManager actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); ActivityManager actManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
@@ -217,9 +217,7 @@ public class Main extends AndroidApplication {
//fake init for error message //fake init for error message
//set current orientation //set current orientation
String message = getDeviceName()+"\n"+"Android "+AndroidRelease+"\n"+"RAM "+ totalRAM+"MB" +"\n"+"LibGDX "+ Version.VERSION+"\n"+"Can't access external storage"; String message = getDeviceName()+"\n"+"Android "+AndroidRelease+"\n"+"RAM "+ totalRAM+"MB" +"\n"+"LibGDX "+ Version.VERSION+"\n"+"Can't access external storage";
Sentry.getContext().recordBreadcrumb( Sentry.addBreadcrumb(new Breadcrumb(message));
new BreadcrumbBuilder().setMessage(message).build()
);
Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation); Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation);
initialize(Forge.getApp(new AndroidClipboard(), adapter, "", false, true, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName())); initialize(Forge.getApp(new AndroidClipboard(), adapter, "", false, true, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName()));
displayMessage(adapter, true, message); displayMessage(adapter, true, message);
@@ -232,9 +230,7 @@ public class Main extends AndroidApplication {
//fake init for error message //fake init for error message
//set current orientation //set current orientation
String message = getDeviceName()+"\n"+"Android "+AndroidRelease+"\n"+"RAM "+ totalRAM+"MB" +"\n"+"LibGDX "+ Version.VERSION+"\n"+"Can't access external storage\nPath: " + assetsDir; String message = getDeviceName()+"\n"+"Android "+AndroidRelease+"\n"+"RAM "+ totalRAM+"MB" +"\n"+"LibGDX "+ Version.VERSION+"\n"+"Can't access external storage\nPath: " + assetsDir;
Sentry.getContext().recordBreadcrumb( Sentry.addBreadcrumb(new Breadcrumb(message));
new BreadcrumbBuilder().setMessage(message).build()
);
Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation); Main.this.setRequestedOrientation(Main.this.getResources().getConfiguration().orientation);
initialize(Forge.getApp(new AndroidClipboard(), adapter, "", false, true, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName())); initialize(Forge.getApp(new AndroidClipboard(), adapter, "", false, true, totalRAM, isTabletDevice, AndroidAPI, AndroidRelease, getDeviceName()));
displayMessage(adapter, true, message); displayMessage(adapter, true, message);

View File

@@ -139,12 +139,6 @@
<artifactId>java-image-scaling</artifactId> <artifactId>java-image-scaling</artifactId>
<version>0.8.5</version> <version>0.8.5</version>
</dependency> </dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.9.10</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.powermock</groupId> <groupId>org.powermock</groupId>
<artifactId>powermock-module-testng-common</artifactId> <artifactId>powermock-module-testng-common</artifactId>
@@ -184,30 +178,30 @@
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>
<version>3.3.3</version> <version>3.12.4</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.bytebuddy</groupId> <groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId> <artifactId>byte-buddy</artifactId>
<version>1.10.5</version> <version>1.12.3</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.bytebuddy</groupId> <groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId> <artifactId>byte-buddy-agent</artifactId>
<version>1.10.5</version> <version>1.12.3</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.objenesis</groupId> <groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId> <artifactId>objenesis</artifactId>
<version>2.6</version> <version>3.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.freemarker</groupId> <groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId> <artifactId>freemarker</artifactId>
<version>2.3.20</version> <version>2.3.31</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.googlecode.soundlibs</groupId> <groupId>com.googlecode.soundlibs</groupId>
@@ -240,7 +234,7 @@
<plugin> <plugin>
<groupId>com.akathist.maven.plugins.launch4j</groupId> <groupId>com.akathist.maven.plugins.launch4j</groupId>
<artifactId>launch4j-maven-plugin</artifactId> <artifactId>launch4j-maven-plugin</artifactId>
<version>1.7.25</version> <version>2.1.2</version>
<executions> <executions>
<execution> <execution>
<id>l4j-gui</id> <id>l4j-gui</id>
@@ -405,7 +399,7 @@
<plugin> <plugin>
<groupId>com.akathist.maven.plugins.launch4j</groupId> <groupId>com.akathist.maven.plugins.launch4j</groupId>
<artifactId>launch4j-maven-plugin</artifactId> <artifactId>launch4j-maven-plugin</artifactId>
<version>1.7.25</version> <version>2.1.2</version>
<executions> <executions>
<execution> <execution>
<id>l4j-gui</id> <id>l4j-gui</id>

View File

@@ -24,7 +24,6 @@ import forge.gui.GuiBase;
import forge.gui.card.CardReaderExperiments; import forge.gui.card.CardReaderExperiments;
import forge.util.BuildInfo; import forge.util.BuildInfo;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.SentryClient;
/** /**
* Main class for Forge's swing application view. * Main class for Forge's swing application view.
@@ -34,11 +33,13 @@ public final class Main {
* Main entry point for Forge * Main entry point for Forge
*/ */
public static void main(final String[] args) { public static void main(final String[] args) {
Sentry.init();
SentryClient sentryClient = Sentry.getStoredClient(); Sentry.init(options -> {
sentryClient.setRelease(BuildInfo.getVersionString()); options.setEnableExternalConfiguration(true);
sentryClient.setEnvironment(System.getProperty("os.name")); options.setRelease(BuildInfo.getVersionString());
sentryClient.addTag("Java Version", System.getProperty("java.version")); options.setEnvironment(System.getProperty("os.name"));
options.setTag("Java Version", System.getProperty("java.version"));
}, true);
// HACK - temporary solution to "Comparison method violates it's general contract!" crash // HACK - temporary solution to "Comparison method violates it's general contract!" crash
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

View File

@@ -14,6 +14,7 @@ import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito; import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
import org.powermock.modules.testng.PowerMockTestCase; import org.powermock.modules.testng.PowerMockTestCase;
@@ -33,6 +34,7 @@ import java.util.ResourceBundle;
ImageCache.class, ImageIO.class, ImageKeys.class, ImageCache.class, ImageIO.class, ImageKeys.class,
ForgeConstants.class, Localizer.class}) ForgeConstants.class, Localizer.class})
@SuppressStaticInitializationFor({"forge.ImageCache", "forge.localinstance.properties.ForgeConstants"}) @SuppressStaticInitializationFor({"forge.ImageCache", "forge.localinstance.properties.ForgeConstants"})
@PowerMockIgnore({"javax.xml.*", "org.xml.sax.*", "com.sun.org.apache.xerces.*", "org.w3c.dom.*", "org.springframework.context.*", "org.apache.log4j.*"})
public class ForgeCardMockTestCase extends PowerMockTestCase { public class ForgeCardMockTestCase extends PowerMockTestCase {
public static final String MOCKED_LOCALISED_STRING = "any localised string"; public static final String MOCKED_LOCALISED_STRING = "any localised string";

View File

@@ -14,8 +14,8 @@ import forge.model.FModel;
import forge.util.Lang; import forge.util.Lang;
import forge.util.Localizer; import forge.util.Localizer;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.context.Context;
import org.powermock.api.mockito.PowerMockito; import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
import org.testng.Assert; import org.testng.Assert;
@@ -28,6 +28,7 @@ import java.util.ResourceBundle;
ImageCache.class, ImageIO.class, ImageKeys.class, ImageCache.class, ImageIO.class, ImageKeys.class,
ForgeConstants.class, Localizer.class, Sentry.class, GameLogFormatter.class}) ForgeConstants.class, Localizer.class, Sentry.class, GameLogFormatter.class})
@SuppressStaticInitializationFor({"forge.ImageCache", "forge.localinstance.properties.ForgeConstants"}) @SuppressStaticInitializationFor({"forge.ImageCache", "forge.localinstance.properties.ForgeConstants"})
@PowerMockIgnore({"javax.xml.*", "org.xml.sax.*", "com.sun.org.apache.xerces.*", "org.w3c.dom.*", "org.springframework.context.*", "org.apache.log4j.*"})
public class BaseGameSimulationTest extends ForgeCardMockTestCase { public class BaseGameSimulationTest extends ForgeCardMockTestCase {
@BeforeMethod @BeforeMethod
@@ -36,7 +37,7 @@ public class BaseGameSimulationTest extends ForgeCardMockTestCase {
super.initMocks(); super.initMocks();
PowerMockito.mockStatic(Sentry.class); PowerMockito.mockStatic(Sentry.class);
PowerMockito.mockStatic(GameLogFormatter.class); PowerMockito.mockStatic(GameLogFormatter.class);
PowerMockito.when(Sentry.getContext()).thenReturn(new Context()); //PowerMockito.when(Sentry.getContext()).thenReturn(new Context());
Lang.createInstance("en-US"); Lang.createInstance("en-US");
} }

View File

@@ -59,7 +59,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public class Forge implements ApplicationListener { public class Forge implements ApplicationListener {
public static final String CURRENT_VERSION = "1.6.47.001"; public static final String CURRENT_VERSION = "1.6.49.001";
private static ApplicationListener app = null; private static ApplicationListener app = null;
static Scene currentScene = null; static Scene currentScene = null;

View File

@@ -43,23 +43,23 @@
<dependency> <dependency>
<groupId>com.thoughtworks.xstream</groupId> <groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId> <artifactId>xstream</artifactId>
<version>1.4.18</version> <version>1.4.19</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-all</artifactId> <artifactId>netty-all</artifactId>
<version>4.1.48.Final</version> <version>4.1.71.Final</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.fourthline.cling</groupId> <groupId>org.fourthline.cling</groupId>
<artifactId>cling-support</artifactId> <artifactId>cling-support</artifactId>
<version>2.0.1</version> <version>2.1.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.lz4</groupId> <groupId>org.lz4</groupId>
<artifactId>lz4-java</artifactId> <artifactId>lz4-java</artifactId>
<version>1.7.1</version> <version>1.8.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.raeleus.TenPatch</groupId> <groupId>com.github.raeleus.TenPatch</groupId>

View File

@@ -31,7 +31,6 @@ import forge.localinstance.properties.ForgePreferences;
import forge.model.FModel; import forge.model.FModel;
import forge.util.Localizer; import forge.util.Localizer;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
/** /**
* The class ErrorViewer. Enables showing and saving error messages that * The class ErrorViewer. Enables showing and saving error messages that
@@ -71,9 +70,7 @@ public class BugReporter {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
if (null != message && !message.isEmpty()) { if (null != message && !message.isEmpty()) {
Sentry.getContext().recordBreadcrumb( Sentry.addBreadcrumb(message);
new BreadcrumbBuilder().setMessage(message).build()
);
sb.append(FThreads.debugGetCurrThreadId()).append(" > ").append(message).append("\n"); sb.append(FThreads.debugGetCurrThreadId()).append(" > ").append(message).append("\n");
} }
@@ -156,9 +153,9 @@ public class BugReporter {
public static void sendSentry() { public static void sendSentry() {
if (exception != null) { if (exception != null) {
Sentry.capture(exception); Sentry.captureException(exception);
} else if (message !=null) { } else if (message !=null) {
Sentry.capture(message); Sentry.captureMessage(message);
} }
} }

View File

@@ -34,6 +34,8 @@ import forge.itemmanager.ItemColumnConfig.SortState;
import forge.model.FModel; import forge.model.FModel;
import forge.util.CardTranslation; import forge.util.CardTranslation;
import forge.util.Localizer; import forge.util.Localizer;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -68,9 +70,9 @@ public enum ColumnDef {
public Comparable<?> apply(final Entry<InventoryItem, Integer> from) { public Comparable<?> apply(final Entry<InventoryItem, Integer> from) {
if (from.getKey() instanceof PaperCard) { if (from.getKey() instanceof PaperCard) {
String sortableName = ((PaperCard)from.getKey()).getSortableName(); String sortableName = ((PaperCard)from.getKey()).getSortableName();
return sortableName == null ? InventoryItem.toSortableName(from.getKey().getName()) : sortableName; return sortableName == null ? TextUtil.toSortableName(from.getKey().getName()) : sortableName;
} }
return InventoryItem.toSortableName(from.getKey().getName()); return TextUtil.toSortableName(from.getKey().getName());
} }
}, },
new Function<Entry<? extends InventoryItem, Integer>, Object>() { new Function<Entry<? extends InventoryItem, Integer>, Object>() {

View File

@@ -638,8 +638,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
public <T extends GameEntity> List<T> chooseEntitiesForEffect(final FCollectionView<T> optionList, final int min, final int max, public <T extends GameEntity> List<T> chooseEntitiesForEffect(final FCollectionView<T> optionList, final int min, final int max,
final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final Player targetedPlayer, Map<String, Object> params) { final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final Player targetedPlayer, Map<String, Object> params) {
// useful details for debugging problems with the mass select logic // useful details for debugging problems with the mass select logic
Sentry.getContext().addExtra("Card", sa.getCardView().toString()); Sentry.setExtra("Card", sa.getCardView().toString());
Sentry.getContext().addExtra("SpellAbility", sa.toString()); Sentry.setExtra("SpellAbility", sa.toString());
// Human is supposed to read the message and understand from it what to choose // Human is supposed to read the message and understand from it what to choose
if (optionList.isEmpty()) { if (optionList.isEmpty()) {

View File

@@ -317,12 +317,12 @@
<dependency> <dependency>
<groupId>ch.qos.logback</groupId> <groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId> <artifactId>logback-classic</artifactId>
<version>1.2.9</version> <version>1.2.11</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>ch.qos.logback</groupId> <groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId> <artifactId>logback-core</artifactId>
<version>1.2.9</version> <version>1.2.11</version>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>