addon funnies

This commit is contained in:
0x3C50 2022-04-03 18:38:04 +02:00
parent 9370619e71
commit a05fdfde2d
17 changed files with 412 additions and 70 deletions

View file

@ -4,6 +4,7 @@
package net.shadow.client.feature.addon;
import net.minecraft.util.Identifier;
import net.shadow.client.feature.command.Command;
import net.shadow.client.feature.module.AddonModule;
@ -14,14 +15,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
@SuppressWarnings("unused")
public abstract class Addon {
private final AtomicBoolean isEnabled = new AtomicBoolean(false);
public final String name;
public final String description;
public final String[] developers;
public Addon(String name, String description, String[] developers) {
this.name = name;
this.description = description;
this.developers = developers;
}
public abstract String getName();
public abstract String getDescription();
public abstract BufferedImage getIcon();
public abstract String[] getAuthors();
public abstract Identifier getIcon();
public abstract List<AddonModule> getAdditionalModules();

View file

@ -4,20 +4,24 @@
package net.shadow.client.feature.addon;
import net.minecraft.entity.passive.AbstractDonkeyEntity;
import net.shadow.client.ShadowMain;
import net.shadow.client.feature.command.Command;
import net.shadow.client.feature.command.CommandRegistry;
import net.shadow.client.feature.config.ModuleConfig;
import net.shadow.client.feature.config.SettingBase;
import net.shadow.client.feature.gui.clickgui.ClickGUI;
import net.shadow.client.feature.gui.clickgui.theme.impl.Shadow;
import net.shadow.client.feature.module.AddonModule;
import net.shadow.client.feature.module.Module;
import net.shadow.client.feature.module.ModuleRegistry;
import net.shadow.client.helper.ClassLoaderAddendum;
import org.apache.logging.log4j.Level;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
@ -28,8 +32,8 @@ public class AddonManager {
0xCA, 0xFE, 0xBA, 0xBE
};
public static AddonManager INSTANCE;
private final ClassLoaderAddendum classLoader = new ClassLoaderAddendum(AddonManager.class.getClassLoader());
private final List<Addon> loadedAddons = new ArrayList<>();
record AddonEntry(File sourceFile, String name, String description, String[] devs, Addon registeredAddon) {}
private final List<AddonEntry> loadedAddons = new ArrayList<>();
@SuppressWarnings("ResultOfMethodCallIgnored")
private AddonManager() {
@ -39,6 +43,10 @@ public class AddonManager {
initializeAddons();
}
public List<Addon> getLoadedAddons() {
return loadedAddons.stream().map(addonEntry -> addonEntry.registeredAddon).toList();
}
public static void init() {
new AddonManager();
}
@ -46,28 +54,34 @@ public class AddonManager {
void initializeAddons() {
for (File file : Objects.requireNonNull(ADDON_DIRECTORY.listFiles())) {
if (file.getName().endsWith(".jar")) {
ShadowMain.log(Level.INFO, "Attempting to load addon " + file.getName());
try {
loadAddon(file);
} catch (Throwable e) {
ShadowMain.log(Level.ERROR, "Failed to load " + file.getName());
e.printStackTrace();
if (e instanceof NoClassDefFoundError noClassDefFoundError) {
ShadowMain.log(Level.INFO, "This error is in releation to the class file being remapped for the wrong dev environment. If you're running this in a dev environment, this is on you. In this case, please ask the developer(s) for a \"dev\" jar, and use that instead. If not, please report this error to the addon developer(s).");
ShadowMain.log(Level.INFO, "(Some additional information about the error: ERR:CLASS_MISSING, class " + noClassDefFoundError.getMessage() + " not found)");
}
if (e instanceof IncompatibleClassChangeError) {
ShadowMain.log(Level.INFO, "This error either occurs because the addon is heavily obfuscated and the obfuscator is bad, or because the addon is built on an outdated shadow SDK. Please report this error to the addon developer(s).");
}
if (e instanceof ClassCastException) {
ShadowMain.log(Level.INFO, "This error probably occurs because of an outdated shadow SDK. Please report this error to the addon developer(s).");
}
}
safeLoadAddon(file);
}
}
dispatchEnable();
}
Addon safeLoadAddon(File file) {
ShadowMain.log(Level.INFO, "Attempting to load addon " + file.getName());
try {
return loadAddon(file);
} catch (Throwable e) {
ShadowMain.log(Level.ERROR, "Failed to load " + file.getName());
e.printStackTrace();
if (e instanceof NoClassDefFoundError noClassDefFoundError) {
ShadowMain.log(Level.INFO, "This error is in releation to the class file being remapped for the wrong dev environment. If you're running this in a dev environment, this is on you. In this case, please ask the developer(s) for a \"dev\" jar, and use that instead. If not, please report this error to the addon developer(s).");
ShadowMain.log(Level.INFO, "(Some additional information about the error: ERR:CLASS_MISSING, class " + noClassDefFoundError.getMessage() + " not found)");
}
if (e instanceof IncompatibleClassChangeError) {
ShadowMain.log(Level.INFO, "This error either occurs because the addon is heavily obfuscated and the obfuscator is bad, or because the addon is built on an outdated shadow SDK. Please report this error to the addon developer(s).");
}
if (e instanceof ClassCastException) {
ShadowMain.log(Level.INFO, "This error probably occurs because of an outdated shadow SDK. Please report this error to the addon developer(s).");
}
}
return null;
}
public void reload() {
dispatchReload();
dispatchDisable();
@ -75,9 +89,65 @@ public class AddonManager {
initializeAddons();
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public void discoverNewAddons() {
for (File file : Objects.requireNonNull(ADDON_DIRECTORY.listFiles())) {
if (loadedAddons.stream().anyMatch(addonEntry -> addonEntry.sourceFile.getAbsoluteFile().equals(file.getAbsoluteFile()))) continue;
if (file.getName().endsWith(".jar")) {
if (safeLoadAddon(file) == null) {
ShadowMain.log(Level.WARN, "Renaming addon to prevent re-discovery because it failed to load");
file.renameTo(new File(file.getAbsolutePath()+".disabled"));
}
}
}
}
public void reload(Addon addon) {
addon.reloaded();
Map<String, ModuleConfig> storedConfig = new ConcurrentHashMap<>();
for (ModuleRegistry.AddonModuleEntry customModule : ModuleRegistry.getCustomModules()) {
if (customModule.addon() == addon) {
storedConfig.put(customModule.module().getName(), customModule.module().config);
}
}
// if (addon.getAdditionalModules() != null) for (AddonModule additionalModule : addon.getAdditionalModules()) {
// storedConfig.put(additionalModule.getName(), additionalModule.config);
// }
if (addon.isEnabled()) disableAddon(addon);
AddonEntry meant = null;
for (AddonEntry loadedAddon : loadedAddons) {
if (loadedAddon.registeredAddon == addon) {
meant = loadedAddon;
}
}
if (meant != null) {
loadedAddons.remove(meant);
Addon loadedAddon = safeLoadAddon(meant.sourceFile);
if (loadedAddon != null) {
enableAddon(loadedAddon);
for (ModuleRegistry.AddonModuleEntry customModule : ModuleRegistry.getCustomModules()) {
if (customModule.addon() == loadedAddon) {
Module additionalModule = customModule.module();
if (storedConfig.containsKey(additionalModule.getName())) {
List<SettingBase<?>> amog = additionalModule.config.getSettings(); // new config
for (SettingBase<?> setting : storedConfig.get(additionalModule.getName()).getSettings()) { // old saved config
for (SettingBase<?> settingBase : amog) { // merge
if (settingBase.name.equals(setting.name)) { // if new name equals old name of setting
settingBase.accept(setting.getConfigSave()); // set val
break;
}
}
}
}
}
}
}
}
}
void dispatchReload() {
for (Addon loadedAddon : loadedAddons) {
loadedAddon.reloaded();
for (AddonEntry loadedAddon : loadedAddons) {
loadedAddon.registeredAddon.reloaded();
}
}
@ -94,33 +164,36 @@ public class AddonManager {
List<AddonModule> customModules = addon.getAdditionalModules();
List<Command> customCommands = addon.getAdditionalCommands();
if (customModules != null) for (AddonModule additionalModule : customModules) {
ShadowMain.log(Level.INFO, "Loading module " + additionalModule.getName() + " from addon " + addon.getName());
ShadowMain.log(Level.INFO, "Loading module " + additionalModule.getName() + " from addon " + addon.name);
ModuleRegistry.registerAddonModule(addon, additionalModule);
}
if (customCommands != null) for (Command customCommand : customCommands) {
ShadowMain.log(Level.INFO, "Loading command " + customCommand.getName() + " from addon " + addon.getName());
ShadowMain.log(Level.INFO, "Loading command " + customCommand.getName() + " from addon " + addon.name);
CommandRegistry.registerCustomCommand(addon, customCommand);
}
}
void dispatchDisable() {
for (Addon loadedAddon : loadedAddons) {
disableAddon(loadedAddon);
for (AddonEntry loadedAddon : loadedAddons) {
disableAddon(loadedAddon.registeredAddon);
}
ClickGUI.reInit();
}
void dispatchEnable() {
for (Addon loadedAddon : loadedAddons) {
enableAddon(loadedAddon);
for (AddonEntry loadedAddon : loadedAddons) {
enableAddon(loadedAddon.registeredAddon);
}
ClickGUI.reInit();
}
void loadAddon(File location) throws Exception {
Addon loadAddon(File location) throws Exception {
ClassLoaderAddendum classLoader = new ClassLoaderAddendum(AddonManager.class.getClassLoader());
JarFile jf = new JarFile(location);
Addon mainClass = null;
for (JarEntry jarEntry : jf.stream().toList()) {
if (jarEntry.getName().endsWith(".class")) {
System.out.println(jarEntry.getName());
// System.out.println(jarEntry.getName());
InputStream stream = jf.getInputStream(jarEntry);
byte[] classBytes = stream.readAllBytes();
stream.close();
@ -142,16 +215,21 @@ public class AddonManager {
if (Addon.class.isAssignableFrom(loadedClass)) {
if (mainClass != null)
throw new IllegalStateException("Jarfile " + location.getName() + " has multiple main classes");
mainClass = (Addon) loadedClass.getDeclaredConstructor().newInstance();
System.out.println("Found main class " + loadedClass.getName());
try {
mainClass = (Addon) loadedClass.getDeclaredConstructor().newInstance();
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Jarfile "+location.getName()+" has invalid main class: No constructor without arguments");
}
// System.out.println("Found main class " + loadedClass.getName());
}
}
}
if (mainClass == null)
throw new IllegalStateException("Jarfile " + location.getName() + " does not have a main class");
System.out.println("Discovered addon " + mainClass.getName() + " by " + String.join(", ", mainClass.getAuthors()));
loadedAddons.add(mainClass);
ShadowMain.log(Level.INFO, "Discovered addon " + mainClass.name + " by " + String.join(", ", mainClass.developers));
loadedAddons.add(new AddonEntry(location,mainClass.name,mainClass.description,mainClass.developers,mainClass));
return mainClass;
}
}

View file

@ -89,6 +89,7 @@ public abstract class SettingBase<V> {
* @param value The new value
*/
public void setValue(V value) {
// System.out.println("SET "+this.value+" -> "+value);
this.value = value;
if (this.onChanged != null) this.onChanged.accept(value);
}

View file

@ -62,6 +62,10 @@ public class ClickGUI extends Screen implements FastTickable {
return instance;
}
public static void reInit() {
if (instance != null) instance.initElements();
}
@Override
protected void init() {

View file

@ -17,8 +17,9 @@ public class StringSettingEditor extends ConfigBase<StringSetting> {
super(x, y, width, 0, configValue);
double h = FontRenderers.getRenderer().getFontHeight() + 2;
input = new RoundTextFieldWidget(x, y, width, h, configValue.getName());
input.changeListener = () -> configValue.setValue(input.get());
input.setText(configValue.getValue());
input.changeListener = () -> configValue.setValue(input.get());
this.height = h + FontRenderers.getRenderer().getMarginHeight() + 1;
}

View file

@ -0,0 +1,183 @@
/*
* Copyright (c) Shadow client, 0x150, Saturn5VFive 2022. All rights reserved.
*/
package net.shadow.client.feature.gui.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
import net.shadow.client.ShadowMain;
import net.shadow.client.feature.addon.Addon;
import net.shadow.client.feature.addon.AddonManager;
import net.shadow.client.feature.gui.FastTickable;
import net.shadow.client.feature.gui.clickgui.ClickGUI;
import net.shadow.client.feature.gui.widget.RoundButton;
import net.shadow.client.helper.GameTexture;
import net.shadow.client.helper.Texture;
import net.shadow.client.helper.Timer;
import net.shadow.client.helper.font.FontRenderers;
import net.shadow.client.helper.font.adapter.FontAdapter;
import net.shadow.client.helper.render.ClipStack;
import net.shadow.client.helper.render.Rectangle;
import net.shadow.client.helper.render.Renderer;
import net.shadow.client.helper.render.Scroller;
import net.shadow.client.helper.util.Utils;
import org.lwjgl.opengl.GL40C;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
public class AddonManagerScreen extends ClientScreen implements FastTickable {
Timer discoverTimer = new Timer();
Scroller scroller = new Scroller(0);
@Override
public void onFastTick() {
scroller.tick();
for (AddonViewer addonViewer : viewerList) {
addonViewer.onFastTick();
}
if (discoverTimer.hasExpired(5000)) {
discoverTimer.reset();
AddonManager.INSTANCE.discoverNewAddons();
for (Addon loadedAddon : AddonManager.INSTANCE.getLoadedAddons()) {
if (viewerList.stream().noneMatch(addonViewer -> addonViewer.addon == loadedAddon)) {
viewerList.add(new AddonViewer(loadedAddon, WIDGET_WIDTH-10));
}
}
}
}
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
if (new Rectangle(width/2d-WIDGET_WIDTH/2d,height/2d-WIDGET_HEIGHT/2d,width/2d+WIDGET_WIDTH/2d,height/2d+WIDGET_HEIGHT/2d).contains(mouseX,mouseY)) {
double contentHeight = viewerList.stream().map(addonViewer -> addonViewer.getHeight()+5).reduce(Double::sum).orElse(0d)+5;
double entitledScroll = Math.max(0, contentHeight-WIDGET_HEIGHT);
scroller.setBounds(0,entitledScroll);
scroller.scroll(amount);
}
return super.mouseScrolled(mouseX, mouseY, amount);
}
double WIDGET_WIDTH = 600;
double WIDGET_HEIGHT = 300;
List<AddonViewer> viewerList = new ArrayList<>();
@Override
protected void init() {
reInitViewers();
}
void reInitViewers() {
viewerList.clear();
for (Addon loadedAddon : AddonManager.INSTANCE.getLoadedAddons()) {
viewerList.add(new AddonViewer(loadedAddon, WIDGET_WIDTH-10));
}
}
@Override
public void renderInternal(MatrixStack stack, int mouseX, int mouseY, float delta) {
renderBackground(stack);
Renderer.R2D.renderRoundedQuad(stack,new Color(20,20,20),width/2d-WIDGET_WIDTH/2d,height/2d-WIDGET_HEIGHT/2d,width/2d+WIDGET_WIDTH/2d,height/2d+WIDGET_HEIGHT/2d,5,20);
ClipStack.globalInstance.addWindow(stack, new Rectangle(width/2d-WIDGET_WIDTH/2d,height/2d-WIDGET_HEIGHT/2d,width/2d+WIDGET_WIDTH/2d,height/2d+WIDGET_HEIGHT/2d));
double yOffset = 0;
double xRoot = width/2d-WIDGET_WIDTH/2d+5;
double yRoot = height/2d-WIDGET_HEIGHT/2d+5;
for (AddonViewer addonViewer : viewerList) {
addonViewer.render(stack,xRoot,yRoot+yOffset+scroller.getScroll(),mouseX,mouseY);
yOffset += addonViewer.getHeight()+5;
}
ClipStack.globalInstance.popWindow();
super.renderInternal(stack, mouseX, mouseY, delta);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
for (AddonViewer addonViewer : new ArrayList<>(viewerList)) {
addonViewer.clicked(mouseX, mouseY, button);
}
return super.mouseClicked(mouseX, mouseY, button);
}
class AddonViewer implements FastTickable {
Addon addon;
double width;
static final double iconDimensions = 64;
static final double padding = 5;
double lastX, lastY;
RoundButton disable, reload;
public AddonViewer(Addon addon, double width) {
this.addon = addon;
this.width = width;
disable = new RoundButton(RoundButton.STANDARD,0,0,60,20,addon.isEnabled()?"Disable":"Enable", () -> {
if (addon.isEnabled()) AddonManager.INSTANCE.disableAddon(addon);
else AddonManager.INSTANCE.enableAddon(addon);
disable.setText(addon.isEnabled()?"Disable":"Enable");
ClickGUI.reInit();
});
reload = new RoundButton(RoundButton.STANDARD,0,0,60,20,"Reload",() -> {
AddonManager.INSTANCE.reload(addon);
reInitViewers();
ClickGUI.reInit();
});
}
public void render(MatrixStack stack, double x, double y, int mouseX, int mouseY) {
lastX = x;
lastY = y;
Color background = new Color(30,30,30);
Renderer.R2D.renderRoundedQuad(stack,background,x,y,x+width,y+getHeight(),5,20);
RenderSystem.enableBlend();
RenderSystem.colorMask(false, false, false, true);
RenderSystem.clearColor(0.0F, 0.0F, 0.0F, 0.0F);
RenderSystem.clear(GL40C.GL_COLOR_BUFFER_BIT, false);
RenderSystem.colorMask(true, true, true, true);
RenderSystem.setShader(GameRenderer::getPositionColorShader);
Renderer.R2D.renderRoundedQuadInternal(stack.peek().getPositionMatrix(), background.getRed()/255f, background.getGreen()/255f, background.getBlue()/255f, 1, x + padding, y + padding, x + padding + iconDimensions, y + padding + iconDimensions, 6, 10);
RenderSystem.blendFunc(GL40C.GL_DST_ALPHA, GL40C.GL_ONE_MINUS_DST_ALPHA);
Identifier icon = addon.getIcon();
if (icon == null) icon = GameTexture.ICONS_ADDON_PROVIDED.getWhere();
RenderSystem.setShaderTexture(0, addon.getIcon());
if (!addon.isEnabled()) RenderSystem.setShaderColor(0.6f,0.6f,0.6f,1f);
Renderer.R2D.renderTexture(stack, x + padding, y + padding, iconDimensions, iconDimensions, 0, 0, iconDimensions, iconDimensions, iconDimensions, iconDimensions);
RenderSystem.defaultBlendFunc();
RenderSystem.setShaderColor(1f,1f,1f,1f);
FontAdapter title = FontRenderers.getCustomSize(30);
FontAdapter normal = FontRenderers.getRenderer();
double entireHeight = title.getFontHeight()+normal.getFontHeight()*2d;
if (addon.isEnabled()) title.drawString(stack,addon.name, (float) (x+padding+iconDimensions+padding), (float) (y+getHeight()/2d-entireHeight/2d),0xFFFFFF);
else title.drawString(stack,addon.name, (float) (x+padding+iconDimensions+padding), (float) (y+getHeight()/2d-entireHeight/2d),0.6f,0.6f,0.6f,1f);
normal.drawString(stack,addon.description, (float) (x+padding+iconDimensions+padding), (float) (y+getHeight()/2d-entireHeight/2d+title.getFontHeight()),0.6f,0.6f,0.6f,1f);
normal.drawString(stack,"Developer(s): "+String.join(", ", addon.developers), (float) (x+padding+iconDimensions+padding), (float) (y+getHeight()/2d-entireHeight/2d+title.getFontHeight()+normal.getFontHeight()),0.6f,0.6f,0.6f,1f);
double buttonRowHeight = disable.getHeight()+padding+reload.getHeight();
disable.setX(x+width-disable.getWidth()-padding);
disable.setY(y+getHeight()/2d-buttonRowHeight/2d);
disable.render(stack,mouseX,mouseY,0);
reload.setX(x+width-disable.getWidth()-padding);
reload.setY(y+getHeight()/2d-buttonRowHeight/2d+disable.getHeight()+padding);
reload.render(stack,mouseX,mouseY,0);
}
public void clicked(double mouseX, double mouseY,int button) {
disable.mouseClicked(mouseX,mouseY,button);
reload.mouseClicked(mouseX, mouseY, button);
}
@Override
public void onFastTick() {
disable.onFastTick();
reload.onFastTick();
}
public double getHeight() {
return iconDimensions +padding*2;
}
}
}

View file

@ -114,7 +114,10 @@ public class HomeScreen extends ClientScreen implements FastTickable {
buttonsMap.add(new AbstractMap.SimpleEntry<>("Singleplayer", () -> ShadowMain.client.setScreen(new SelectWorldScreen(this))));
buttonsMap.add(new AbstractMap.SimpleEntry<>("Multiplayer", () -> ShadowMain.client.setScreen(new MultiplayerScreen(this))));
buttonsMap.add(new AbstractMap.SimpleEntry<>("Realms", () -> ShadowMain.client.setScreen(new RealmsMainScreen(this))));
buttonsMap.add(new AbstractMap.SimpleEntry<>("Alts", () -> ShadowMain.client.setScreen(AltManagerScreen.instance())));
buttonsMap.add(new AbstractMap.SimpleEntry<>("Alts", () -> ShadowMain.client.setScreen(
// AltManagerScreen.instance()
new AddonManagerScreen()
)));
buttonsMap.add(new AbstractMap.SimpleEntry<>("Settings", () -> ShadowMain.client.setScreen(new OptionsScreen(this, ShadowMain.client.options))));
widgetsHeight = buttonsMap.size() * (widgetHeight + widPad) - widPad;
double xOffset = -innerBottomPadding(); // dont question it

View file

@ -19,11 +19,18 @@ import net.shadow.client.feature.module.impl.world.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ModuleRegistry {
static final List<Module> vanillaModules = new ArrayList<>();
static final List<AddonModuleEntry> customModules = new ArrayList<>();
static final List<Module> sharedModuleList = new ArrayList<>();
static final AtomicBoolean reloadInProgress = new AtomicBoolean(false);
public static List<AddonModuleEntry> getCustomModules() {
return customModules;
}
public static void registerAddonModule(Addon source, Module module) {
for (AddonModuleEntry customModule : customModules) {
@ -37,16 +44,21 @@ public class ModuleRegistry {
static final AtomicBoolean initialized = new AtomicBoolean(false);
public static void clearCustomModules(Addon addon) {
for (AddonModuleEntry customModule : customModules) {
if (customModule.addon == addon && customModule.module.isEnabled()) customModule.module.setEnabled(false);
}
customModules.removeIf(addonModuleEntry -> addonModuleEntry.addon == addon);
rebuildSharedModuleList();
}
private static void rebuildSharedModuleList() {
reloadInProgress.set(true);
sharedModuleList.clear();
sharedModuleList.addAll(vanillaModules);
for (AddonModuleEntry customModule : customModules) {
sharedModuleList.add(customModule.module);
}
reloadInProgress.set(false);
}
public static void init() {
@ -174,7 +186,13 @@ public class ModuleRegistry {
return sharedModuleList;
}
record AddonModuleEntry(Addon addon, Module module) {
public record AddonModuleEntry(Addon addon, Module module) {
}
private static void awaitLockOpen() {
while(reloadInProgress.get()) {
Thread.onSpinWait();
}
}
@SuppressWarnings("unchecked")
@ -182,6 +200,7 @@ public class ModuleRegistry {
if (!initialized.get()) {
init();
}
awaitLockOpen();
for (Module module : getModules()) {
if (module.getClass() == clazz) {
return (T) module;
@ -194,6 +213,7 @@ public class ModuleRegistry {
if (!initialized.get()) {
init();
}
awaitLockOpen();
for (Module module : getModules()) {
if (module.getName().equalsIgnoreCase(n)) {
return module;

View file

@ -14,7 +14,7 @@ public enum ModuleType {
WORLD("World", GameTexture.ICONS_WORLD.getWhere()),
EXPLOIT("Exploit", GameTexture.ICONS_EXPLOIT.getWhere()),
CRASH("Crash", GameTexture.ICONS_CRASH.getWhere()),
ADDON_PROVIDED("Addons", GameTexture.ICONS_ITEMS.getWhere()),
ADDON_PROVIDED("Addons", GameTexture.ICONS_ADDON_PROVIDED.getWhere()),
GRIEF("Grief", GameTexture.ICONS_GRIEF.getWhere()),
COMBAT("Combat", GameTexture.ICONS_COMBAT.getWhere());

View file

@ -9,6 +9,7 @@ import net.minecraft.network.Packet;
import net.minecraft.network.packet.c2s.play.ButtonClickC2SPacket;
import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
import net.minecraft.screen.slot.SlotActionType;
import net.shadow.client.feature.gui.notifications.Notification;
import net.shadow.client.feature.module.Module;
import net.shadow.client.feature.module.ModuleType;
@ -62,6 +63,6 @@ public class Test extends Module {
@Override
public void tick() {
client.interactionManager.clickSlot(0,0,0, SlotActionType.QUICK_MOVE,client.player);
}
}

View file

@ -4,7 +4,11 @@
package net.shadow.client.feature.module.impl.movement;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.impl.FabricLoaderImpl;
import net.fabricmc.loader.impl.launch.FabricLauncher;
import net.minecraft.client.util.math.MatrixStack;
import net.shadow.client.feature.gui.notifications.Notification;
import net.shadow.client.feature.module.Module;
import net.shadow.client.feature.module.ModuleType;
@ -21,7 +25,10 @@ public class NoLevitation extends Module {
@Override
public void enable() {
if (FabricLoader.getInstance().isModLoaded("meteor-client")) {
Notification.create(4000,"NoLevitation", Notification.Type.ERROR, "Meteor is currently loaded and prevents this from working. Use meteor's NoLevitation");
setEnabled(false);
}
}
@Override

View file

@ -5,6 +5,7 @@
package net.shadow.client.feature.module.impl.render;
import com.mojang.blaze3d.systems.RenderSystem;
import lombok.val;
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.network.packet.s2c.play.WorldTimeUpdateS2CPacket;
@ -34,10 +35,8 @@ import net.shadow.client.mixin.IInGameHudAccessor;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class Hud extends Module {
public static double currentTps = 0;
@ -48,7 +47,8 @@ public class Hud extends Module {
final BooleanSetting coords = this.config.create(new BooleanSetting.Builder(true).name("Coordinates").description("Whether to show current coordinates").get());
final BooleanSetting ping = this.config.create(new BooleanSetting.Builder(true).name("Ping").description("Whether to show current ping").get());
final BooleanSetting modules = this.config.create(new BooleanSetting.Builder(true).name("Array list").description("Whether to show currently enabled modules").get());
final List<ModuleEntry> moduleList = new ArrayList<>();
Map<Module, ModuleEntry> entryList = new ConcurrentHashMap<>();
// final List<ModuleEntry> moduleList = new ArrayList<>();
final Timer tpsUpdateTimer = new Timer();
final List<Double> last5SecondTpsAverage = new ArrayList<>();
long lastTimePacketReceived;
@ -116,7 +116,7 @@ public class Hud extends Module {
@Override
public void postInit() {
makeSureIsInitialized();
super.postInit();
}
@ -128,6 +128,7 @@ public class Hud extends Module {
if (ShadowMain.client.player == null) {
return;
}
makeSureIsInitialized();
MatrixStack ms = Renderer.R3D.getEmptyMatrixStack();
double heightOffsetLeft = 0, heightOffsetRight = 0;
if (ShadowMain.client.options.debugEnabled) {
@ -214,23 +215,23 @@ public class Hud extends Module {
void drawModuleList(MatrixStack ms) {
double width = ShadowMain.client.getWindow().getScaledWidth();
double y = 0;
for (ModuleEntry moduleEntry : moduleList.stream().sorted(Comparator.comparingDouble(value -> -value.getRenderWidth())).toList()) {
double prog = moduleEntry.getAnimProg() * 2;
for (Map.Entry<Module, ModuleEntry> moduleEntry : this.entryList.entrySet().stream().sorted(Comparator.comparingDouble(value -> -value.getValue().getRenderWidth())).toList()) {
double prog = moduleEntry.getValue().getAnimProg() * 2;
if (prog == 0) {
continue;
}
double expandProg = MathHelper.clamp(prog, 0, 1); // 0-1 as 0-1 from 0-2
double slideProg = MathHelper.clamp(prog - 1, 0, 1); // 1-2 as 0-1 from 0-2
double hei = (FontRenderers.getRenderer().getMarginHeight() + 2);
double wid = moduleEntry.getRenderWidth() + 2;
double wid = moduleEntry.getValue().getRenderWidth() + 2;
Renderer.R2D.renderQuad(ms, ThemeManager.getMainTheme().getActive(), width - (wid + 1), y, width, y + hei * expandProg);
ms.push();
ms.translate((1 - slideProg) * wid, 0, 0);
Renderer.R2D.renderQuad(ms, ThemeManager.getMainTheme().getModule(), width - wid, y, width, y + hei * expandProg);
double nameW = FontRenderers.getRenderer().getStringWidth(moduleEntry.module.getName());
FontRenderers.getRenderer().drawString(ms, moduleEntry.module.getName(), width - wid + 1, y + 1, 0xFFFFFF);
if (moduleEntry.module.getContext() != null && !moduleEntry.module.getContext().isEmpty()) {
FontRenderers.getRenderer().drawString(ms, " " + moduleEntry.module.getContext(), width - wid + 1 + nameW, y + 1, 0xAAAAAA);
double nameW = FontRenderers.getRenderer().getStringWidth(moduleEntry.getKey().getName());
FontRenderers.getRenderer().drawString(ms, moduleEntry.getKey().getName(), width - wid + 1, y + 1, 0xFFFFFF);
if (moduleEntry.getKey().getContext() != null && !moduleEntry.getKey().getContext().isEmpty()) {
FontRenderers.getRenderer().drawString(ms, " " + moduleEntry.getKey().getContext(), width - wid + 1 + nameW, y + 1, 0xAAAAAA);
}
ms.pop();
y += hei * expandProg;
@ -239,13 +240,17 @@ public class Hud extends Module {
}
void makeSureIsInitialized() {
if (moduleList.isEmpty()) {
for (Module module : ModuleRegistry.getModules()) {
for (Module module : ModuleRegistry.getModules()) {
if (!entryList.containsKey(module)) {
ModuleEntry me = new ModuleEntry();
me.module = module;
moduleList.add(me);
entryList.put(module, me);
}
}
for (Map.Entry<Module, ModuleEntry> moduleModuleEntryEntry : entryList.entrySet()) {
if (!ModuleRegistry.getModules().contains(moduleModuleEntryEntry.getKey()) && moduleModuleEntryEntry.getValue().animationProgress == 0) {
entryList.remove(moduleModuleEntryEntry.getKey());
}
moduleList.sort(Comparator.comparingDouble(value -> -FontRenderers.getRenderer().getStringWidth(value.module.getName())));
}
}
@ -253,7 +258,7 @@ public class Hud extends Module {
public void onFastTick() {
rNoConnectionPosY = Transitions.transition(rNoConnectionPosY, shouldNoConnectionDropDown() ? 10 : -10, 10);
HudRenderer.getInstance().fastTick();
for (ModuleEntry moduleEntry : new ArrayList<>(moduleList)) {
for (ModuleEntry moduleEntry : entryList.values()) {
moduleEntry.animate();
}
}

View file

@ -10,6 +10,7 @@ public enum GameTexture {
TEXTURE_ICON(new Texture("tex/icon"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/icon.png"),
TEXTURE_BACKGROUND(new Texture("tex/background"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/background.jpg?inline=false"),
TEXTURE_LOGO(new Texture("tex/logo"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/shadow_logo.png"),
TEXTURE_ICON_FULL(new Texture("tex/iconFull"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/shadowLogoFull.png?inline=false"),
NOTIF_ERROR(new Texture("notif/error"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/error.png"),
NOTIF_INFO(new Texture("notif/info"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/info.png"),
@ -19,7 +20,7 @@ public enum GameTexture {
ICONS_RENDER(new Texture("icons/render"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/render.png"),
ICONS_CRASH(new Texture("icons/crash"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/crash.png"),
ICONS_GRIEF(new Texture("icons/grief"), "https://github.com/Saturn5Vfive/shadow-fs/blob/main/grief.png?raw=true"),
ICONS_ITEMS(new Texture("icons/item"), "https://github.com/Saturn5Vfive/shadow-fs/blob/main/items.png?raw=true"),
ICONS_ADDON_PROVIDED(new Texture("icons/item"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/addons.png"),
ICONS_MOVE(new Texture("icons/move"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/movement.png"),
ICONS_MISC(new Texture("icons/misc"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/misc.png"),
ICONS_WORLD(new Texture("icons/world"), "https://gitlab.com/0x151/coffee-fs/-/raw/main/world.png"),

View file

@ -13,4 +13,8 @@ public class Rectangle {
@Getter
@Setter
private double x, y, x1, y1;
public boolean contains(double x, double y) {
return x >= this.x && x <= this.x1 && y >= this.y && y <= this.y1;
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) Shadow client, 0x150, Saturn5VFive 2022. All rights reserved.
*/
package net.shadow.client.mixin;
import net.minecraft.client.gui.screen.GameMenuScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;
import net.shadow.client.feature.gui.screen.AddonManagerScreen;
import net.shadow.client.feature.gui.widget.RoundButton;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GameMenuScreen.class)
public class GameMenuMixin extends Screen {
protected GameMenuMixin(Text title) {
super(title);
}
@Inject(method="initWidgets",at=@At("RETURN"))
void addAddons(CallbackInfo ci) {
addDrawableChild(new RoundButton(RoundButton.STANDARD,5,5,60,20,"Addons",() -> {
assert client != null;
client.setScreen(new AddonManagerScreen());
}));
}
}

View file

@ -52,7 +52,7 @@ public class LivingEntityMixin {
}
}
@Redirect(method = "travel", at = @At(value = "INVOKE", target = "net/minecraft/entity/LivingEntity.hasStatusEffect(Lnet/minecraft/entity/effect/StatusEffect;)Z"))
@Redirect(method = "travel", at = @At(value = "INVOKE", target = "net/minecraft/entity/LivingEntity.hasStatusEffect(Lnet/minecraft/entity/effect/StatusEffect;)Z"),require = 0)
boolean atomic_stopLevitationEffect(LivingEntity instance, StatusEffect effect) {
if (instance.equals(ShadowMain.client.player) && ModuleRegistry.getByClass(NoLevitation.class).isEnabled() && effect == StatusEffects.LEVITATION) {
return false;

View file

@ -25,6 +25,7 @@
"EntityRenderDispatcherMixin",
"EntityRendererMixin",
"EntryListWidgetMixin",
"GameMenuMixin",
"GameRendererMixin",
"IClientPlayerInteractionManagerAccessor",
"ICustomPayloadC2SPacketAccessor",