diff --git a/src/main/java/net/wurstclient/SentryConfig.java b/src/main/java/net/wurstclient/SentryConfig.java new file mode 100644 index 00000000..e1e790fb --- /dev/null +++ b/src/main/java/net/wurstclient/SentryConfig.java @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2014 - 2020 | Alexander01998 | All rights reserved. + * + * This source code is subject to the terms of the GNU General Public + * License, version 3. If a copy of the GPL was not distributed with this + * file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt + */ +package net.wurstclient; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.mojang.blaze3d.platform.GlDebugInfo; + +import io.sentry.Breadcrumb; +import io.sentry.Sentry; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.metadata.ModMetadata; +import net.minecraft.SharedConstants; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.util.Window; +import net.minecraft.util.crash.CrashReport; +import net.wurstclient.hack.Hack; +import net.wurstclient.settings.Setting; + +public enum SentryConfig +{ + ; + + private static final String DSN = + "https://c01aef15a7cb466da7824ec5dac0d009@sentry.io/5464583"; + + public static void setupSentry() + { + FabricLoader fabricLoader = FabricLoader.getInstance(); + + Sentry.init(options -> { + options.setDsn(DSN); + options.setRelease(getRelease(fabricLoader)); + }); + + addVersions(fabricLoader); + addEnvironmentType(fabricLoader); + addOsInfo(); + addJavaInfo(); + addMods(fabricLoader); + } + + private static String getRelease(FabricLoader fabricLoader) + { + String modVersion = fabricLoader.getModContainer("wurst").get() + .getMetadata().getVersion().getFriendlyString(); + + if(modVersion != null && !modVersion.equals("${version}")) + return modVersion; + + return "v" + WurstClient.VERSION + "-MC" + WurstClient.MC_VERSION; + } + + private static void addVersions(FabricLoader fabricLoader) + { + Sentry.configureScope(scope -> { + scope.setTag("wurst.version", WurstClient.VERSION); + }); + + Sentry.configureScope(scope -> { + scope.setTag("mc.version", + SharedConstants.getGameVersion().getName()); + }); + + Sentry.configureScope(scope -> { + scope.setTag("fabric.api_version", + fabricLoader.getModContainer("fabric").get().getMetadata() + .getVersion().getFriendlyString()); + }); + + Sentry.configureScope(scope -> { + scope.setTag("fabric.loader_version", + fabricLoader.getModContainer("fabricloader").get().getMetadata() + .getVersion().getFriendlyString()); + }); + } + + private static void addEnvironmentType(FabricLoader fabricLoader) + { + Sentry.configureScope(scope -> { + boolean dev = fabricLoader.isDevelopmentEnvironment(); + scope.setTag("environment", dev ? "dev" : "prod"); + }); + } + + private static void addOsInfo() + { + Sentry.configureScope(scope -> { + + HashMap map = new HashMap<>(); + map.put("name", System.getProperty("os.name")); + scope.setContexts("os", map); + + scope.setTag("os.arch", System.getProperty("os.arch")); + }); + } + + private static void addJavaInfo() + { + Sentry.configureScope(scope -> { + + HashMap map = new HashMap<>(); + map.put("runtime", System.getProperty("java.runtime.name")); + map.put("version", System.getProperty("java.runtime.version")); + map.put("vendor", System.getProperty("java.vendor")); + map.put("vm", System.getProperty("java.vm.name") + " (" + + System.getProperty("java.vm.info") + ")"); + scope.setContexts("java", map); + + scope.setTag("java.version", System.getProperty("java.version")); + scope.setTag("java.vendor", System.getProperty("java.vendor")); + scope.setTag("java.vm", System.getProperty("java.vm.name")); + }); + } + + private static void addMods(FabricLoader fabricLoader) + { + Sentry.configureScope(scope -> { + + HashMap modMap = getModMap(fabricLoader); + scope.setContexts("mods", modMap); + + scope.setTag("other_mods", getOtherMods(modMap)); + }); + } + + private static HashMap getModMap(FabricLoader fabricLoader) + { + Stream modStream = + fabricLoader.getAllMods().stream().map(mod -> mod.getMetadata()); + + // filter out those Fabric API sub-mod things + modStream = modStream.filter(mod -> !mod.getId().startsWith("fabric-")); + + ArrayList modList = + modStream.collect(Collectors.toCollection(() -> new ArrayList<>())); + + // create a map of each mod's ID and version + HashMap modMap = new HashMap<>(); + for(ModMetadata mod : modList) + modMap.put(mod.getId(), mod.getVersion().getFriendlyString()); + + return modMap; + } + + /** + * Returns the number of installed mods that aren't part of Wurst, Fabric or + * Minecraft. + */ + private static String getOtherMods(HashMap modMap) + { + HashSet otherMods = new HashSet<>(modMap.keySet()); + otherMods.remove("minecraft"); + otherMods.remove("fabric"); + otherMods.remove("fabricloader"); + otherMods.remove("wurst"); + otherMods.remove("io_sentry_sentry"); + return "" + otherMods.size(); + } + + public static void addHackToggleBreadcrumb(Hack hack, boolean enabled) + { + Breadcrumb breadcrumb = new Breadcrumb(hack.getName()); + breadcrumb.setCategory("hack." + (enabled ? "enable" : "disable")); + + for(Entry e : hack.getSettings().entrySet()) + breadcrumb.setData(e.getValue().getName(), + e.getValue().toJson().toString()); + + Sentry.addBreadcrumb(breadcrumb); + } + + public static void addKeybindTriggerBreadcrumb(String keyName, String cmds) + { + Breadcrumb breadcrumb = new Breadcrumb(cmds); + breadcrumb.setCategory("keybind.trigger"); + breadcrumb.setData("key", keyName); + Sentry.addBreadcrumb(breadcrumb); + } + + public static void addScreenChangeBreadcrumb(Screen screen) + { + Breadcrumb breadcrumb = new Breadcrumb(); + breadcrumb.setType("navigation"); + breadcrumb.setCategory("screen.change"); + + Screen cs = WurstClient.MC.currentScreen; + String from = cs == null ? "none" : cs.getClass().getCanonicalName(); + breadcrumb.setData("from", from); + + String to = + screen == null ? "none" : screen.getClass().getCanonicalName(); + breadcrumb.setData("to", to); + + Sentry.addBreadcrumb(breadcrumb); + } + + public static void addDetailsOnCrash() + { + addCpuInfo(); + addGpuInfo(); + addLanguage(); + addFontType(); + addCurrentScreen(); + addWurstInfo(); + } + + private static void addCpuInfo() + { + Sentry.configureScope(scope -> { + HashMap map = new HashMap<>(); + map.put("name", GlDebugInfo.getCpuInfo()); + scope.setContexts("cpu", map); + }); + } + + private static void addGpuInfo() + { + Sentry.configureScope(scope -> { + + HashMap map = new HashMap<>(); + + map.put("name", GlDebugInfo.getRenderer()); + map.put("version", GlDebugInfo.getVersion()); + map.put("vendor_name", GlDebugInfo.getVendor()); + + Window window = WurstClient.MC.getWindow(); + map.put("framebuffer", window.getFramebufferWidth() + "x" + + window.getFramebufferHeight()); + + scope.setContexts("gpu", map); + }); + } + + private static void addLanguage() + { + Sentry.configureScope(scope -> { + scope.setTag("mc.lang", + WurstClient.MC.getLanguageManager().getLanguage().getCode()); + }); + } + + private static void addFontType() + { + Sentry.configureScope(scope -> { + scope.setTag("mc.font", + WurstClient.MC.forcesUnicodeFont() ? "unicode" : "default"); + }); + } + + private static void addCurrentScreen() + { + Sentry.configureScope(scope -> { + Screen cs = WurstClient.MC.currentScreen; + String screen = + cs == null ? "none" : cs.getClass().getCanonicalName(); + scope.setTag("mc.screen", screen); + }); + } + + private static void addWurstInfo() + { + Sentry.configureScope(scope -> { + HashMap map = new HashMap<>(); + map.put("enabled_hacks", getEnabledHax()); + map.put("settings", getSettingsMap()); + scope.setContexts("wurst", map); + }); + } + + private static ArrayList getEnabledHax() + { + return WurstClient.INSTANCE.getHax().getAllHax().stream() + .filter(Hack::isEnabled).map(Hack::getName) + .collect(Collectors.toCollection(() -> new ArrayList<>())); + } + + private static HashMap> getSettingsMap() + { + WurstClient wurst = WurstClient.INSTANCE; + + ArrayList features = new ArrayList<>(); + features.addAll(wurst.getHax().getAllHax()); + features.addAll(wurst.getCmds().getAllCmds()); + features.addAll(wurst.getOtfs().getAllOtfs()); + + HashMap> settingsMap = new HashMap<>(); + + for(Feature feature : features) + { + Collection ftSettings = feature.getSettings().values(); + if(ftSettings.isEmpty()) + continue; + + HashMap ftSettingsMap = new HashMap<>(); + for(Setting setting : ftSettings) + ftSettingsMap.put(setting.getName(), + setting.toJson().toString()); + + settingsMap.put(feature.getName(), ftSettingsMap); + } + + return settingsMap; + } + + public static void reportCrash(CrashReport report) + { + WurstClient wurst = WurstClient.INSTANCE; + + // don't report crash if the version is known to be outdated, but still + // report if the updater didn't get a chance to check before the crash + if(wurst.getUpdater() != null && wurst.getUpdater().isOutdated()) + return; + + Sentry.captureException(report.getCause()); + } +} diff --git a/src/main/java/net/wurstclient/WurstClient.java b/src/main/java/net/wurstclient/WurstClient.java index 18b55fb0..c61f105d 100644 --- a/src/main/java/net/wurstclient/WurstClient.java +++ b/src/main/java/net/wurstclient/WurstClient.java @@ -13,17 +13,12 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ArrayList; -import java.util.HashMap; import java.util.stream.Collectors; import java.util.stream.Stream; import org.lwjgl.glfw.GLFW; -import io.sentry.Sentry; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.metadata.ModMetadata; -import net.minecraft.SharedConstants; import net.minecraft.client.MinecraftClient; import net.minecraft.client.options.KeyBinding; import net.minecraft.client.util.InputUtil; @@ -91,7 +86,7 @@ public enum WurstClient { System.out.println("Starting Wurst Client..."); - setupSentry(); + SentryConfig.setupSentry(); wurstFolder = createWurstFolder(); String trackingID = "UA-52838431-5"; @@ -156,95 +151,6 @@ public enum WurstClient "Wurst " + VERSION + " MC" + MC_VERSION); } - private void setupSentry() - { - FabricLoader fabricLoader = FabricLoader.getInstance(); - - Sentry.init(options -> { - - options.setDsn( - "https://c01aef15a7cb466da7824ec5dac0d009@sentry.io/5464583"); - options.setDebug(true); - - String modVersion = fabricLoader.getModContainer("wurst").get() - .getMetadata().getVersion().getFriendlyString(); - - if(modVersion != null && !modVersion.equals("${version}")) - options.setRelease(modVersion); - else - options.setRelease("v" + VERSION + "-MC" + MC_VERSION); - }); - - Sentry.configureScope(scope -> { - scope.setTag("wurst.version", VERSION); - }); - - Sentry.configureScope(scope -> { - scope.setTag("mc.version", - SharedConstants.getGameVersion().getName()); - }); - - Sentry.configureScope(scope -> { - scope.setTag("fabric.api_version", - fabricLoader.getModContainer("fabric").get().getMetadata() - .getVersion().getFriendlyString()); - }); - - Sentry.configureScope(scope -> { - scope.setTag("fabric.loader_version", - fabricLoader.getModContainer("fabricloader").get().getMetadata() - .getVersion().getFriendlyString()); - }); - - boolean dev = fabricLoader.isDevelopmentEnvironment(); - Sentry.configureScope(scope -> { - scope.setTag("environment", dev ? "dev" : "prod"); - }); - - Sentry.configureScope(scope -> { - - HashMap map = new HashMap<>(); - map.put("name", System.getProperty("os.name")); - scope.setContexts("os", map); - - scope.setTag("os.arch", System.getProperty("os.arch")); - }); - - Sentry.configureScope(scope -> { - - HashMap map = new HashMap<>(); - map.put("runtime", System.getProperty("java.runtime.name")); - map.put("version", System.getProperty("java.runtime.version")); - map.put("vendor", System.getProperty("java.vendor")); - map.put("vm", System.getProperty("java.vm.name") + " (" - + System.getProperty("java.vm.info") + ")"); - scope.setContexts("java", map); - - scope.setTag("java.version", System.getProperty("java.version")); - scope.setTag("java.vendor", System.getProperty("java.vendor")); - scope.setTag("java.vm", System.getProperty("java.vm.name")); - }); - - Sentry.configureScope(scope -> { - - ArrayList mods = - fabricLoader.getAllMods().stream().map(mod -> mod.getMetadata()) - .filter(mod -> !mod.getId().startsWith("fabric-")) - .collect(Collectors.toCollection(() -> new ArrayList<>())); - - HashMap map = new HashMap<>(); - for(ModMetadata mod : mods) - map.put(mod.getId(), mod.getVersion().getFriendlyString()); - scope.setContexts("mods", map); - - // minecraft, fabric, fabricloader, wurst - // sentry is considered a mod in production, but not in dev - int wurstMods = dev ? 4 : 5; - - scope.setTag("other_mods", "" + (map.size() - wurstMods)); - }); - } - private Path createWurstFolder() { Path dotMinecraftFolder = MC.runDirectory.toPath().normalize(); diff --git a/src/main/java/net/wurstclient/hack/Hack.java b/src/main/java/net/wurstclient/hack/Hack.java index 4dbd44bc..f6b6a6c6 100644 --- a/src/main/java/net/wurstclient/hack/Hack.java +++ b/src/main/java/net/wurstclient/hack/Hack.java @@ -7,16 +7,13 @@ */ package net.wurstclient.hack; -import java.util.Map.Entry; import java.util.Objects; -import io.sentry.Breadcrumb; -import io.sentry.Sentry; import net.wurstclient.Category; import net.wurstclient.Feature; +import net.wurstclient.SentryConfig; import net.wurstclient.hacks.NavigatorHack; import net.wurstclient.hacks.TooManyHaxHack; -import net.wurstclient.settings.Setting; public abstract class Hack extends Feature { @@ -78,12 +75,7 @@ public abstract class Hack extends Feature if(enabled && tooManyHax.isEnabled() && tooManyHax.isBlocked(this)) return; - Breadcrumb breadcrumb = new Breadcrumb(name); - breadcrumb.setCategory("hack." + (enabled ? "enable" : "disable")); - for(Entry e : getSettings().entrySet()) - breadcrumb.setData(e.getValue().getName(), - e.getValue().toJson().toString()); - Sentry.addBreadcrumb(breadcrumb); + SentryConfig.addHackToggleBreadcrumb(this, enabled); this.enabled = enabled; diff --git a/src/main/java/net/wurstclient/keybinds/KeybindProcessor.java b/src/main/java/net/wurstclient/keybinds/KeybindProcessor.java index 22080218..6deaef79 100644 --- a/src/main/java/net/wurstclient/keybinds/KeybindProcessor.java +++ b/src/main/java/net/wurstclient/keybinds/KeybindProcessor.java @@ -9,10 +9,9 @@ package net.wurstclient.keybinds; import org.lwjgl.glfw.GLFW; -import io.sentry.Breadcrumb; -import io.sentry.Sentry; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.InputUtil; +import net.wurstclient.SentryConfig; import net.wurstclient.WurstClient; import net.wurstclient.clickgui.screens.ClickGuiScreen; import net.wurstclient.command.CmdProcessor; @@ -51,10 +50,7 @@ public final class KeybindProcessor implements KeyPressListener if(cmds == null) return; - Breadcrumb breadcrumb = new Breadcrumb(cmds); - breadcrumb.setCategory("keybind.trigger"); - breadcrumb.setData("key", keyName); - Sentry.addBreadcrumb(breadcrumb); + SentryConfig.addKeybindTriggerBreadcrumb(keyName, cmds); processCmds(cmds); } diff --git a/src/main/java/net/wurstclient/mixin/MinecraftClientMixin.java b/src/main/java/net/wurstclient/mixin/MinecraftClientMixin.java index bbace940..8a5e1935 100644 --- a/src/main/java/net/wurstclient/mixin/MinecraftClientMixin.java +++ b/src/main/java/net/wurstclient/mixin/MinecraftClientMixin.java @@ -7,11 +7,6 @@ */ package net.wurstclient.mixin; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.stream.Collectors; - import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; @@ -22,32 +17,25 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import com.mojang.blaze3d.platform.GlDebugInfo; - -import io.sentry.Breadcrumb; -import io.sentry.Sentry; import net.minecraft.client.MinecraftClient; import net.minecraft.client.WindowEventHandler; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.network.ClientPlayerInteractionManager; import net.minecraft.client.util.Session; -import net.minecraft.client.util.Window; import net.minecraft.entity.Entity; import net.minecraft.util.crash.CrashReport; import net.minecraft.util.hit.EntityHitResult; import net.minecraft.util.hit.HitResult; import net.minecraft.util.snooper.SnooperListener; import net.minecraft.util.thread.ReentrantThreadExecutor; -import net.wurstclient.Feature; +import net.wurstclient.SentryConfig; import net.wurstclient.WurstClient; import net.wurstclient.events.LeftClickListener.LeftClickEvent; import net.wurstclient.events.RightClickListener.RightClickEvent; -import net.wurstclient.hack.Hack; import net.wurstclient.mixinterface.IClientPlayerEntity; import net.wurstclient.mixinterface.IClientPlayerInteractionManager; import net.wurstclient.mixinterface.IMinecraftClient; -import net.wurstclient.settings.Setting; @Mixin(MinecraftClient.class) public abstract class MinecraftClientMixin @@ -139,105 +127,21 @@ public abstract class MinecraftClientMixin private void onAddDetailsToCrashReport(CrashReport report, CallbackInfoReturnable cir) { - Sentry.configureScope(scope -> { - HashMap map = new HashMap<>(); - map.put("name", GlDebugInfo.getCpuInfo()); - scope.setContexts("cpu", map); - }); - - Sentry.configureScope(scope -> { - - HashMap map = new HashMap<>(); - - map.put("name", GlDebugInfo.getRenderer()); - map.put("version", GlDebugInfo.getVersion()); - map.put("vendor_name", GlDebugInfo.getVendor()); - - Window window = WurstClient.MC.getWindow(); - map.put("framebuffer", window.getFramebufferWidth() + "x" - + window.getFramebufferHeight()); - - scope.setContexts("gpu", map); - }); - - Sentry.configureScope(scope -> { - - scope.setTag("mc.lang", - WurstClient.MC.getLanguageManager().getLanguage().getCode()); - - scope.setTag("mc.font", - WurstClient.MC.forcesUnicodeFont() ? "unicode" : "default"); - - Screen cs = WurstClient.MC.currentScreen; - String screen = - cs == null ? "none" : cs.getClass().getCanonicalName(); - scope.setTag("mc.screen", screen); - }); - - Sentry.configureScope(scope -> { - - HashMap map = new HashMap<>(); - - ArrayList enabledHax = WurstClient.INSTANCE.getHax() - .getAllHax().stream().filter(Hack::isEnabled).map(Hack::getName) - .collect(Collectors.toCollection(() -> new ArrayList<>())); - - map.put("enabled_hacks", enabledHax); - - ArrayList features = new ArrayList<>(); - features.addAll(WurstClient.INSTANCE.getHax().getAllHax()); - features.addAll(WurstClient.INSTANCE.getCmds().getAllCmds()); - features.addAll(WurstClient.INSTANCE.getOtfs().getAllOtfs()); - - HashMap> map2 = new HashMap<>(); - for(Feature feature : features) - { - Collection settings = feature.getSettings().values(); - if(settings.isEmpty()) - continue; - - HashMap map3 = new HashMap<>(); - for(Setting setting : settings) - map3.put(setting.getName(), setting.toJson().toString()); - map2.put(feature.getName(), map3); - } - map.put("settings", map2); - - scope.setContexts("wurst", map); - }); + SentryConfig.addDetailsOnCrash(); } @Inject(at = {@At("HEAD")}, method = {"printCrashReport(Lnet/minecraft/util/crash/CrashReport;)V"}) private static void onPrintCrashReport(CrashReport report, CallbackInfo ci) { - WurstClient wurst = WurstClient.INSTANCE; - - // don't report crash if the version is known to be outdated, but still - // report if the updater didn't get a chance to check before the crash - if(wurst.getUpdater() != null && wurst.getUpdater().isOutdated()) - return; - - Sentry.captureException(report.getCause()); + SentryConfig.reportCrash(report); } @Inject(at = {@At("HEAD")}, method = {"openScreen(Lnet/minecraft/client/gui/screen/Screen;)V"}) private void onOpenScreen(@Nullable Screen screen, CallbackInfo ci) { - Breadcrumb breadcrumb = new Breadcrumb(); - breadcrumb.setType("navigation"); - breadcrumb.setCategory("screen.change"); - - Screen cs = WurstClient.MC.currentScreen; - String from = cs == null ? "none" : cs.getClass().getCanonicalName(); - breadcrumb.setData("from", from); - - String to = - screen == null ? "none" : screen.getClass().getCanonicalName(); - breadcrumb.setData("to", to); - - Sentry.addBreadcrumb(breadcrumb); + SentryConfig.addScreenChangeBreadcrumb(screen); } @Override