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.RestartUtil;
import io.sentry.Sentry;
import io.sentry.SentryClient;
import javax.imageio.ImageIO;
import java.awt.*;
@@ -35,11 +34,12 @@ public class Main {
public static void main(String[] args) {
Sentry.init();
SentryClient sentryClient = Sentry.getStoredClient();
sentryClient.setRelease(BuildInfo.getVersionString());
sentryClient.setEnvironment(System.getProperty("os.name"));
sentryClient.addTag("Java Version", System.getProperty("java.version"));
Sentry.init(options -> {
options.setEnableExternalConfiguration(true);
options.setRelease(BuildInfo.getVersionString());
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
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

View File

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

View File

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

View File

@@ -26,51 +26,4 @@ import forge.util.IHasName;
public interface InventoryItem extends IHasName {
String getItemType();
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;
// 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
sortableName = InventoryItem.toSortableName(CardTranslation.getTranslatedName(rules0.getName()));
sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(rules0.getName()));
}
// 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 "{"+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>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<version>4.13.2</version>
<scope>test</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry-logback</artifactId>
<version>1.7.30</version>
<version>5.7.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -35,8 +35,8 @@ import forge.game.cost.Cost;
import forge.game.spellability.*;
import forge.game.zone.ZoneType;
import forge.util.FileSection;
import io.sentry.Breadcrumb;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
/**
* <p>
@@ -145,10 +145,12 @@ public final class AbilityFactory {
return getAbility(mapParams, type, state, sVarHolder);
} catch (Error | Exception ex) {
String msg = "AbilityFactory:getAbility: crash when trying to create ability ";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg)
.withData("Card", state.getName()).withData("Ability", abString).build()
);
Breadcrumb bread = new Breadcrumb(msg);
bread.setData("Card", state.getName());
bread.setData("Ability", abString);
Sentry.addBreadcrumb(bread);
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.collect.FCollection;
import forge.util.collect.FCollectionView;
import io.sentry.Breadcrumb;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
public class AbilityUtils {
@@ -1428,11 +1428,11 @@ public class AbilityUtils {
final Card card = sa.getHostCard();
String msg = "AbilityUtils:resolveApiAbility: try to resolve API ability";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg)
.withData("Api", sa.getApi().toString())
.withData("Card", card.getName()).withData("SA", sa.toString()).build()
);
Breadcrumb bread = new Breadcrumb(msg);
bread.setData("Api", sa.getApi().toString());
bread.setData("Card", card.getName());
bread.setData("SA", sa.toString());
Sentry.addBreadcrumb(bread);
// check conditions
if (sa.metConditions()) {

View File

@@ -23,8 +23,8 @@ import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
import io.sentry.Breadcrumb;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
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
if (mana.isEmpty()) {
String msg = "AbilityFactoryMana::manaResolve() - special mana effect is empty for";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg)
.withData("Card", card.getName()).withData("SA", sa.toString()).build()
);
Breadcrumb bread = new Breadcrumb(msg);
bread.setData("Card", card.getName());
bread.setData("SA", sa.toString());
Sentry.addBreadcrumb(bread, sa);
continue;
}

View File

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

View File

@@ -74,8 +74,8 @@ import forge.game.trigger.TriggerHandler;
import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.TextUtil;
import io.sentry.Breadcrumb;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
/**
* <p>
@@ -599,10 +599,11 @@ public class CardFactoryUtil {
intrinsicAbility.setCardState(card.getCurrentState());
} catch (Exception e) {
String msg = "CardFactoryUtil:addAbilityFactoryAbilities: crash in raw Ability";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg)
.withData("Card", card.getName()).withData("Ability", rawAbility).build()
);
Breadcrumb bread = new Breadcrumb(msg);
bread.setData("Card", card.getName());
bread.setData("Ability", rawAbility);
Sentry.addBreadcrumb(bread, card);
// rethrow the exception with card Name for the user
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.util.collect.FCollection;
import forge.util.collect.FCollectionView;
import io.sentry.Breadcrumb;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
public class CardState extends GameObject implements IHasSVars {
private String name = "";
@@ -270,10 +270,11 @@ public class CardState extends GameObject implements IHasSVars {
inst = intrinsicKeywords.add(s);
} catch (Exception e) {
String msg = "CardState:addIntrinsicKeyword: failed to parse Keyword";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg)
.withData("Card", card.getName()).withData("Keyword", s).build()
);
Breadcrumb bread = new Breadcrumb(msg);
bread.setData("Card", card.getName());
bread.setData("Keyword", s);
Sentry.addBreadcrumb(bread, this);
//rethrow
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.util.TextUtil;
import forge.util.collect.FCollection;
import io.sentry.Breadcrumb;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
public final class CardUtil {
// disable instantiation
@@ -190,13 +190,12 @@ public final class CardUtil {
return cachedCard;
}
String msg = "CardUtil:getLKICopy copy object";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg)
.withData("Card", in.getName())
.withData("CardState", in.getCurrentStateName().toString())
.withData("Player", in.getController().getName())
.build()
);
Breadcrumb bread = new Breadcrumb(msg);
bread.setData("Card", in.getName());
bread.setData("CardState", in.getCurrentStateName().toString());
bread.setData("Player", in.getController().getName());
Sentry.addBreadcrumb(bread, in);
final Card newCopy = new Card(in.getId(), in.getPaperCard(), in.getGame(), null);
cachedMap.put(in.getId(), newCopy);

View File

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

View File

@@ -40,8 +40,8 @@ import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.FileSection;
import forge.util.Visitor;
import io.sentry.Breadcrumb;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
public class TriggerHandler {
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);
} catch (Exception e) {
String msg = "TriggerHandler:parseTrigger failed to parse";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg)
.withData("Card", host.getName()).withData("Trigger", trigParse).build()
);
Breadcrumb bread = new Breadcrumb(msg);
bread.setData("Card", host.getName());
bread.setData("Trigger", trigParse);
Sentry.addBreadcrumb(bread, host);
//rethrow
throw new RuntimeException("Error in Trigger for Card: " + host.getName(), e);
}
@@ -153,10 +155,12 @@ public class TriggerHandler {
}
} catch (Exception e) {
String msg = "TriggerHandler:parseTrigger failed to parse";
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(msg)
.withData("Card", host.getName()).withData("Params", mapParams.toString()).build()
);
Breadcrumb bread = new Breadcrumb(msg);
bread.setData("Card", host.getName());
bread.setData("Params", mapParams.toString());
Sentry.addBreadcrumb(bread, host);
//rethrow
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"
package="forge.app"
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
android:minSdkVersion="19"
@@ -30,5 +30,17 @@
</intent-filter>
</activity>
<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>
</manifest>

View File

@@ -6,7 +6,7 @@
<packaging.type>jar</packaging.type>
<build.min.memory>-Xms1024m</build.min.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.alias>alias</sign.alias>
<sign.storepass>storepass</sign.storepass>
@@ -45,7 +45,6 @@
</resources>
<finalName>forge-android-${alpha-version}</finalName>
</build>
<dependencies>
<dependency>
<groupId>com.google.android</groupId>
@@ -104,7 +103,69 @@
<dependency>
<groupId>io.sentry</groupId>
<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>
</dependencies>
@@ -119,7 +180,19 @@
<plugin>
<groupId>com.simpligility.maven.plugins</groupId>
<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>
<configuration>
<sign>
@@ -139,11 +212,21 @@
<config>${project.basedir}/proguard.cfg</config>
</proguard>
<release>true</release>
<dex>
<dexCompiler>d8</dexCompiler>
<d8>
<minApi>26</minApi>
<jvmArguments>
<argument>${build.min.memory}</argument>
<argument>${build.max.memory}</argument>
</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>
</configuration>
</plugin>
@@ -160,7 +243,19 @@
<plugin>
<groupId>com.simpligility.maven.plugins</groupId>
<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>
<configuration>
<sign>
@@ -183,11 +278,21 @@
<config>${project.basedir}/proguard.cfg</config>
</proguard>
<release>true</release>
<dex>
<dexCompiler>d8</dexCompiler>
<d8>
<minApi>26</minApi>
<jvmArguments>
<argument>${build.min.memory}</argument>
<argument>${build.max.memory}</argument>
</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>
</configuration>
</plugin>
@@ -238,7 +343,19 @@
<plugin>
<groupId>com.simpligility.maven.plugins</groupId>
<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>
<configuration>
<sign>

View File

@@ -6,9 +6,13 @@
-verbose
-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
## and spits out a thousand-something Class Not Found errors
##-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 io.netty.**
@@ -16,32 +20,55 @@
-dontwarn com.thoughtworks.xstream.**
-dontwarn com.badlogic.gdx.**
-dontwarn org.apache.commons.**
-dontwarn org.apache.http.**
-dontwarn com.google.guava.**
-dontwarn com.google.common.**
-dontwarn com.google.gson.**
-dontwarn org.checkerframework.**
-dontwarn org.xmlpull.**
-dontwarn org.apache.log4j.**
-dontwarn org.fourthline.cling.**
-dontwarn org.seamless.http.**
-dontwarn org.seamless.xhtml.**
-dontwarn org.seamless.xml.**
-dontwarn org.seamless.util.**
-dontwarn org.seamless.swing.**
-dontwarn java.lang.management.**
-dontwarn java.awt.**
-dontwarn java.util.**
-dontwarn java.lang.**
-dontwarn java.net.**
-dontwarn java.nio.**
-dontwarn java.io.**
-dontwarn org.slf4j.**
-dontwarn ch.qos.logback.**
-dontwarn javax.**
-dontwarn org.apache.logging.log4j.**
-dontwarn module-info
-dontwarn io.sentry.logback.*
-dontwarn io.sentry.**
-dontwarn net.jpountz.**
## Support library
-dontwarn android.support.**
-dontwarn android.**
-dontwarn androidx.**
-dontwarn forge.**
-keep class forge.** { *; }
-keep class com.thoughtworks.xstream.** { *; }
-keep class org.apache.commons.lang3.** { *; }
-keep class com.google.guava.** { *; }
-keep class com.google.common.** { *; }
-keep class com.google.gson.GsonBuilder
-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 net.jpountz.** { *; }
-keep class com.ray3k.** { *; }

View File

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

View File

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

View File

@@ -24,7 +24,6 @@ import forge.gui.GuiBase;
import forge.gui.card.CardReaderExperiments;
import forge.util.BuildInfo;
import io.sentry.Sentry;
import io.sentry.SentryClient;
/**
* Main class for Forge's swing application view.
@@ -34,11 +33,13 @@ public final class Main {
* Main entry point for Forge
*/
public static void main(final String[] args) {
Sentry.init();
SentryClient sentryClient = Sentry.getStoredClient();
sentryClient.setRelease(BuildInfo.getVersionString());
sentryClient.setEnvironment(System.getProperty("os.name"));
sentryClient.addTag("Java Version", System.getProperty("java.version"));
Sentry.init(options -> {
options.setEnableExternalConfiguration(true);
options.setRelease(BuildInfo.getVersionString());
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
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.mockito.Mockito;
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.SuppressStaticInitializationFor;
import org.powermock.modules.testng.PowerMockTestCase;
@@ -33,6 +34,7 @@ import java.util.ResourceBundle;
ImageCache.class, ImageIO.class, ImageKeys.class,
ForgeConstants.class, Localizer.class})
@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 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.Localizer;
import io.sentry.Sentry;
import io.sentry.context.Context;
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.SuppressStaticInitializationFor;
import org.testng.Assert;
@@ -28,6 +28,7 @@ import java.util.ResourceBundle;
ImageCache.class, ImageIO.class, ImageKeys.class,
ForgeConstants.class, Localizer.class, Sentry.class, GameLogFormatter.class})
@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 {
@BeforeMethod
@@ -36,7 +37,7 @@ public class BaseGameSimulationTest extends ForgeCardMockTestCase {
super.initMocks();
PowerMockito.mockStatic(Sentry.class);
PowerMockito.mockStatic(GameLogFormatter.class);
PowerMockito.when(Sentry.getContext()).thenReturn(new Context());
//PowerMockito.when(Sentry.getContext()).thenReturn(new Context());
Lang.createInstance("en-US");
}

View File

@@ -59,7 +59,7 @@ import java.util.List;
import java.util.Map;
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;
static Scene currentScene = null;

View File

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

View File

@@ -31,7 +31,6 @@ import forge.localinstance.properties.ForgePreferences;
import forge.model.FModel;
import forge.util.Localizer;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
/**
* The class ErrorViewer. Enables showing and saving error messages that
@@ -71,9 +70,7 @@ public class BugReporter {
final StringBuilder sb = new StringBuilder();
if (null != message && !message.isEmpty()) {
Sentry.getContext().recordBreadcrumb(
new BreadcrumbBuilder().setMessage(message).build()
);
Sentry.addBreadcrumb(message);
sb.append(FThreads.debugGetCurrThreadId()).append(" > ").append(message).append("\n");
}
@@ -156,9 +153,9 @@ public class BugReporter {
public static void sendSentry() {
if (exception != null) {
Sentry.capture(exception);
Sentry.captureException(exception);
} 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.util.CardTranslation;
import forge.util.Localizer;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
@@ -68,9 +70,9 @@ public enum ColumnDef {
public Comparable<?> apply(final Entry<InventoryItem, Integer> from) {
if (from.getKey() instanceof PaperCard) {
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>() {

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,
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
Sentry.getContext().addExtra("Card", sa.getCardView().toString());
Sentry.getContext().addExtra("SpellAbility", sa.toString());
Sentry.setExtra("Card", sa.getCardView().toString());
Sentry.setExtra("SpellAbility", sa.toString());
// Human is supposed to read the message and understand from it what to choose
if (optionList.isEmpty()) {

View File

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