/*
* Skytils - Hypixel Skyblock Quality of Life Mod
* Copyright (C) 2021 Skytils
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package skytils.skytilsmod.tweaker;
import kotlin.KotlinVersion;
import kotlin.text.StringsKt;
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;
@IFMLLoadingPlugin.Name("Skytils On Top")
@IFMLLoadingPlugin.SortingIndex(69)
public class SkytilsLoadingPlugin implements IFMLLoadingPlugin {
public static final String missingDependency =
"
" +
"Skytils has detected a possible missing dependency
" +
"The most likely reason is Essential failed to load.
" +
"Essential might also not work in your country.
" +
"Check the Skytils Discord for any announcements, and
" +
"if there are none, ask for support." +
"
";
public static final String kotlinErrorMessage =
"" +
"Skytils has detected a mod with an older version of Kotlin.
" +
"The most common culprit is the ChatTriggers mod.
" +
"If you do have ChatTriggers, you can update to 1.3.2
" +
"or later to fix the issue. https://www.chattriggers.com/
" +
"In order to resolve this conflict you must
" +
"deleted the outdated mods.
" +
"If you have already done this and are still getting this error,
" +
"or need assistance, ask for support in the Discord.";
public static final String badMixinVersionMessage =
"
" +
"Skytils has detected an older version of Mixin.
" +
"Many of my features require Mixin 0.7 or later!
" +
"In order to resolve this conflict you must remove
" +
"any mods with a Mixin version below 0.7.
" +
"You can also try to rename Skytils be above other mods alphabetically
" +
"by changing Skytils.jar to !Skytils.jar
" +
"If you have already done this and are still getting this error,
" +
"ask for support in the Discord.";
public static final String liteloaderUserMessage =
"
" +
"Skytils has detected that you are using LiteLoader.
" +
"LiteLoader bundles an older, incompatible version of Mixin.
" +
"In order to resolve this conflict you must launch
" +
"Minecraft without LiteLoader.
" +
"If you have already done this and are still getting this error,
" +
"ask for support in the Discord." +
"
";
private static final String voidChatMessage =
"" +
"Skytils has detected that you are using VoidChat.
" +
"VoidChat breaks many of my features!
" +
"In order to resolve this conflict you must remove
" +
"VoidChat from your Minecraft mods folder.
" +
"A good alternative is Patcher at https://sk1er.club/mods/Patcher.
" +
"If you have already done this and are still getting this error,
" +
"ask for support in the Discord." +
"
";
private static final String betterFPSMessage =
"" +
"Skytils has detected that you are using BetterFPS.
" +
"BetterFPS breaks my core plugins, and also breaks the game!
" +
"In order to resolve this conflict you must remove
" +
"BetterFPS from your Minecraft mods folder.
" +
"You probably will not notice a change in your FPS.
" +
"Video showcasing breaking changes: https://streamable.com/q4ip5u.
" +
"If you have already done this and are still getting this error,
" +
"ask for support in the Discord." +
"
";
private final SkytilsLoadingPluginKt kotlinPlugin;
public SkytilsLoadingPlugin() throws URISyntaxException {
if (System.getProperty("skytils.skipStartChecks") == null) {
if (!checkForClass("kotlin.KotlinVersion") || !checkForClass("gg.essential.api.EssentialAPI")) {
showMessage(missingDependency);
exit();
}
if (!KotlinVersion.CURRENT.isAtLeast(1, 5, 0)) {
final File file = new File(KotlinVersion.class.getProtectionDomain().getCodeSource().getLocation().toURI());
File realFile = file;
for (int i = 0; i < 5; i++) {
if (realFile == null) {
realFile = file;
break;
}
if (!realFile.getName().endsWith(".jar!") && !realFile.getName().endsWith(".jar")) {
realFile = realFile.getParentFile();
} else break;
}
String name = realFile.getName().contains(".jar") ? realFile.getName() : StringsKt.substringAfterLast(StringsKt.substringBeforeLast(file.getAbsolutePath(), ".jar", "unknown"), "/", "Unknown");
if (name.endsWith("!")) name = name.substring(0, name.length() - 1);
showMessage(kotlinErrorMessage + "
The culprit seems to be " + name + "
It bundles version " + KotlinVersion.CURRENT + "");
exit();
}
if (checkForClass("com.sky.voidchat.EDFMLLoadingPlugin")) {
showMessage(voidChatMessage);
exit();
}
if (checkForClass("me.guichaguri.betterfps.BetterFpsHelper")) {
showMessage(betterFPSMessage);
exit();
}
}
kotlinPlugin = new SkytilsLoadingPluginKt();
}
private boolean checkForClass(String className) {
try {
Class.forName(className, false, getClass().getClassLoader());
return true;
} catch (ClassNotFoundException ignored) {
return false;
}
}
private void showMessage(String errorMessage) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
// This makes the JOptionPane show on taskbar and stay on top
JFrame frame = new JFrame();
frame.setUndecorated(true);
frame.setAlwaysOnTop(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Icon icon = null;
try {
URL url = SkytilsLoadingPlugin.class.getResource("/assets/skytils/sychicpet.gif");
if (url != null) {
icon = new ImageIcon(Toolkit.getDefaultToolkit().createImage(url).getScaledInstance(50, 50, Image.SCALE_DEFAULT));
}
} catch (Exception e) {
e.printStackTrace();
}
JButton discordLink = new JButton("Join the Discord");
discordLink.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent event) {
try {
Desktop.getDesktop().browse(new URI("https://discord.gg/skytils"));
} catch (Exception e) {
e.printStackTrace();
}
}
});
JButton close = new JButton("Close");
close.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
exit();
}
});
Object[] options = new Object[]{discordLink, close};
JOptionPane.showOptionDialog(
frame,
errorMessage,
"Skytils Error",
JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE,
icon,
options,
options[0]
);
exit();
}
/**
* Bypasses forges security manager to exit the jvm
*/
public static void exit() {
try {
Class> clazz = Class.forName("java.lang.Shutdown");
Method m_exit = clazz.getDeclaredMethod("exit", int.class);
m_exit.setAccessible(true);
m_exit.invoke(null, 0);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
@Override
public String[] getASMTransformerClass() {
return kotlinPlugin.getASMTransformerClass();
}
@Override
public String getModContainerClass() {
return kotlinPlugin.getModContainerClass();
}
@Override
public String getSetupClass() {
return kotlinPlugin.getSetupClass();
}
@Override
public void injectData(Map data) {
kotlinPlugin.injectData(data);
}
@Override
public String getAccessTransformerClass() {
return kotlinPlugin.getAccessTransformerClass();
}
}