mirror of
https://github.com/AutismDevelopment/Autism-Client.git
synced 2026-10-28 19:39:48 +00:00
Release the tag update
This commit is contained in:
commit
9e00f40996
977 changed files with 219163 additions and 0 deletions
16
src/main/java/autismclient/api/AddonRegistrationResult.java
Normal file
16
src/main/java/autismclient/api/AddonRegistrationResult.java
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package autismclient.api;
|
||||
|
||||
public record AddonRegistrationResult(boolean accepted, String kind, String id, String reason) {
|
||||
|
||||
public static AddonRegistrationResult accepted(String kind, String id) {
|
||||
return new AddonRegistrationResult(true, clean(kind), clean(id), "Accepted");
|
||||
}
|
||||
|
||||
public static AddonRegistrationResult rejected(String kind, String id, String reason) {
|
||||
return new AddonRegistrationResult(false, clean(kind), clean(id), clean(reason));
|
||||
}
|
||||
|
||||
private static String clean(String value) {
|
||||
return value == null || value.isBlank() ? "" : value.trim();
|
||||
}
|
||||
}
|
||||
8
src/main/java/autismclient/api/ApiVersion.java
Normal file
8
src/main/java/autismclient/api/ApiVersion.java
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
package autismclient.api;
|
||||
|
||||
public final class ApiVersion {
|
||||
|
||||
public static final int CURRENT = 3;
|
||||
|
||||
private ApiVersion() {}
|
||||
}
|
||||
20
src/main/java/autismclient/api/AutismAddon.java
Normal file
20
src/main/java/autismclient/api/AutismAddon.java
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package autismclient.api;
|
||||
|
||||
public abstract class AutismAddon {
|
||||
|
||||
public String name = "";
|
||||
|
||||
public String authors = "";
|
||||
|
||||
public int color = 0xFFFFFFFF;
|
||||
|
||||
public abstract int apiVersion();
|
||||
|
||||
public void onRegisterCategories() {}
|
||||
|
||||
public abstract void onInitialize();
|
||||
|
||||
public void onUnload() {}
|
||||
|
||||
public abstract String getPackage();
|
||||
}
|
||||
162
src/main/java/autismclient/api/AutismAddons.java
Normal file
162
src/main/java/autismclient/api/AutismAddons.java
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
package autismclient.api;
|
||||
|
||||
import autismclient.addons.AddonManager;
|
||||
import autismclient.api.event.AddonEvents;
|
||||
import autismclient.api.custommenu.CustomMenuAdapter;
|
||||
import autismclient.api.custommenu.CustomMenuAdapterRegistry;
|
||||
import autismclient.api.hud.HudElementProvider;
|
||||
import autismclient.api.hud.HudElements;
|
||||
import autismclient.api.macro.MacroActionEntry;
|
||||
import autismclient.api.macro.MacroActionRegistry;
|
||||
import autismclient.api.macro.MacroPresetRegistry;
|
||||
import autismclient.commands.Command;
|
||||
import autismclient.modules.Module;
|
||||
import autismclient.modules.ModuleCategory;
|
||||
import autismclient.modules.ModuleRegistry;
|
||||
import autismclient.util.macro.MacroAction;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class AutismAddons {
|
||||
private AutismAddons() {}
|
||||
|
||||
public static Modules modules() { return Modules.INSTANCE; }
|
||||
|
||||
public static Commands commands() { return Commands.INSTANCE; }
|
||||
|
||||
public static MacroActions macroActions() { return MacroActions.INSTANCE; }
|
||||
|
||||
public static Presets presets() { return Presets.INSTANCE; }
|
||||
|
||||
public static Hud hud() { return Hud.INSTANCE; }
|
||||
|
||||
public static Events events() { return Events.INSTANCE; }
|
||||
|
||||
public static CustomMenus customMenus() { return CustomMenus.INSTANCE; }
|
||||
|
||||
public static List<AutismAddon> list() { return AddonManager.loaded(); }
|
||||
|
||||
public static String id(String localId) { return AddonManager.scopedId(localId); }
|
||||
|
||||
public static int apiVersion() { return ApiVersion.CURRENT; }
|
||||
|
||||
public static final class Modules {
|
||||
static final Modules INSTANCE = new Modules();
|
||||
private Modules() {}
|
||||
|
||||
public boolean register(Module module) {
|
||||
return ModuleRegistry.registerAddonModule(module, AddonManager.currentAddonId());
|
||||
}
|
||||
|
||||
public AddonRegistrationResult registerDetailed(Module module) {
|
||||
return ModuleRegistry.registerAddonModuleDetailed(module, AddonManager.currentAddonId());
|
||||
}
|
||||
|
||||
public ModuleCategory autoCategory() {
|
||||
return ModuleCategory.registerAddon(AddonManager.currentAddonId(),
|
||||
AddonManager.scopedCategoryLabel(null));
|
||||
}
|
||||
|
||||
public ModuleCategory registerCategory(String label) {
|
||||
return ModuleCategory.registerAddon(AddonManager.currentAddonId(),
|
||||
AddonManager.scopedCategoryLabel(label));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Commands {
|
||||
static final Commands INSTANCE = new Commands();
|
||||
private Commands() {}
|
||||
|
||||
public void register(Command command) {
|
||||
autismclient.commands.AutismCommands.registerAddonCommand(command, AddonManager.currentAddonId());
|
||||
}
|
||||
|
||||
public AddonRegistrationResult registerDetailed(Command command) {
|
||||
return autismclient.commands.AutismCommands.registerAddonCommandDetailed(command, AddonManager.currentAddonId());
|
||||
}
|
||||
}
|
||||
|
||||
public static final class MacroActions {
|
||||
static final MacroActions INSTANCE = new MacroActions();
|
||||
private MacroActions() {}
|
||||
|
||||
public boolean register(MacroActionEntry entry) {
|
||||
return MacroActionRegistry.register(entry);
|
||||
}
|
||||
|
||||
public AddonRegistrationResult registerDetailed(MacroActionEntry entry) {
|
||||
return MacroActionRegistry.registerDetailed(entry);
|
||||
}
|
||||
|
||||
public void registerCategory(String id, String label, int color) {
|
||||
MacroActionRegistry.registerScopedCategory(id, label, color);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class CustomMenus {
|
||||
static final CustomMenus INSTANCE = new CustomMenus();
|
||||
private CustomMenus() {}
|
||||
|
||||
public boolean register(CustomMenuAdapter adapter) {
|
||||
return CustomMenuAdapterRegistry.register(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Presets {
|
||||
static final Presets INSTANCE = new Presets();
|
||||
private Presets() {}
|
||||
|
||||
public void registerCategory(String id, String label) {
|
||||
MacroPresetRegistry.registerScopedCategory(id, label);
|
||||
}
|
||||
|
||||
public void register(String label, String tip, Supplier<List<MacroAction>> builder) {
|
||||
MacroPresetRegistry.register(MacroPresetRegistry.ensureScopedCategory(null), label, tip, builder);
|
||||
}
|
||||
|
||||
public AddonRegistrationResult registerDetailed(String label, String tip, Supplier<List<MacroAction>> builder) {
|
||||
return MacroPresetRegistry.registerDetailed(MacroPresetRegistry.ensureScopedCategory(null), label, tip, builder);
|
||||
}
|
||||
|
||||
public void register(String categoryId, String label, String tip, Supplier<List<MacroAction>> builder) {
|
||||
MacroPresetRegistry.register(MacroPresetRegistry.ensureScopedCategory(categoryId), label, tip, builder);
|
||||
}
|
||||
|
||||
public AddonRegistrationResult registerDetailed(String categoryId, String label, String tip, Supplier<List<MacroAction>> builder) {
|
||||
return MacroPresetRegistry.registerDetailed(MacroPresetRegistry.ensureScopedCategory(categoryId), label, tip, builder);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Hud {
|
||||
static final Hud INSTANCE = new Hud();
|
||||
private Hud() {}
|
||||
|
||||
public boolean register(HudElementProvider provider) {
|
||||
return HudElements.register(provider);
|
||||
}
|
||||
|
||||
public AddonRegistrationResult registerDetailed(HudElementProvider provider) {
|
||||
return HudElements.registerDetailed(provider);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Events {
|
||||
static final Events INSTANCE = new Events();
|
||||
private Events() {}
|
||||
|
||||
public void onTick(Consumer<Minecraft> listener) { AddonEvents.onTick(listener); }
|
||||
|
||||
public void onPacketSend(Predicate<Packet<?>> listener) { AddonEvents.onPacketSend(listener); }
|
||||
|
||||
public void onPacketReceive(Consumer<Packet<?>> listener) { AddonEvents.onPacketReceive(listener); }
|
||||
|
||||
public void onGameJoin(Runnable listener) { AddonEvents.onGameJoin(listener); }
|
||||
|
||||
public void onGameLeft(Runnable listener) { AddonEvents.onGameLeft(listener); }
|
||||
}
|
||||
}
|
||||
94
src/main/java/autismclient/api/SimpleAddon.java
Normal file
94
src/main/java/autismclient/api/SimpleAddon.java
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
package autismclient.api;
|
||||
|
||||
import autismclient.api.macro.MacroActionEntry;
|
||||
import autismclient.api.macro.MacroPresetRegistry;
|
||||
import autismclient.api.macro.SimpleAction;
|
||||
import autismclient.api.macro.SimpleCondition;
|
||||
import autismclient.modules.Module;
|
||||
import autismclient.util.macro.MacroAction;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class SimpleAddon extends AutismAddon {
|
||||
private final int apiVersion;
|
||||
private final String rootPackage;
|
||||
|
||||
protected SimpleAddon(int apiVersion, String rootPackage) {
|
||||
this.apiVersion = apiVersion;
|
||||
this.rootPackage = rootPackage == null ? "" : rootPackage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int apiVersion() {
|
||||
return apiVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPackage() {
|
||||
return rootPackage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onInitialize() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
protected abstract void initialize();
|
||||
|
||||
protected final String id(String localId) {
|
||||
return AutismAddons.id(localId);
|
||||
}
|
||||
|
||||
protected final AddonRegistrationResult registerModule(Module module) {
|
||||
return AutismAddons.modules().registerDetailed(module);
|
||||
}
|
||||
|
||||
protected final AddonRegistrationResult registerAction(MacroActionEntry entry) {
|
||||
return AutismAddons.macroActions().registerDetailed(entry);
|
||||
}
|
||||
|
||||
protected final AddonRegistrationResult registerPreset(String label, String tip, Supplier<List<MacroAction>> builder) {
|
||||
return AutismAddons.presets().registerDetailed(label, tip, builder);
|
||||
}
|
||||
|
||||
protected final AddonRegistrationResult registerSimpleAction(
|
||||
String localId, String label, String tip, String icon, Consumer<Minecraft> runner) {
|
||||
return registerAction(simpleAction(localId, label, tip, icon, runner));
|
||||
}
|
||||
|
||||
protected final AddonRegistrationResult registerSimpleCondition(
|
||||
String localId, String label, String tip, String status, String icon, Predicate<Minecraft> predicate) {
|
||||
return registerAction(simpleCondition(localId, label, tip, status, icon, predicate));
|
||||
}
|
||||
|
||||
protected final MacroActionEntry simpleAction(
|
||||
String localId,
|
||||
String label,
|
||||
String tip,
|
||||
String icon,
|
||||
Consumer<Minecraft> runner
|
||||
) {
|
||||
String typeId = id(localId);
|
||||
return MacroActionEntry.builder(typeId, () -> new SimpleAction(typeId, label, icon, runner))
|
||||
.picker(label, tip)
|
||||
.build();
|
||||
}
|
||||
|
||||
protected final MacroActionEntry simpleCondition(
|
||||
String localId,
|
||||
String label,
|
||||
String tip,
|
||||
String status,
|
||||
String icon,
|
||||
Predicate<Minecraft> predicate
|
||||
) {
|
||||
String typeId = id(localId);
|
||||
return MacroActionEntry.builder(typeId, () -> new SimpleCondition(typeId, label, status, icon, predicate))
|
||||
.condition(label, tip)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package autismclient.api.custommenu;
|
||||
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
|
||||
public interface CustomMenuAdapter {
|
||||
String id();
|
||||
|
||||
CustomMenuEvent inspectInbound(Packet<?> packet, String phase);
|
||||
|
||||
CustomMenuSubmitResult submit(CustomMenuSnapshot snapshot, CustomMenuSubmission submission);
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package autismclient.api.custommenu;
|
||||
|
||||
import autismclient.AutismClientAddon;
|
||||
import autismclient.addons.AddonManager;
|
||||
import autismclient.util.custommenu.VanillaDialogAdapter;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class CustomMenuAdapterRegistry {
|
||||
private record Registered(CustomMenuAdapter adapter, String owner) {}
|
||||
private static final Map<String, Registered> ADAPTERS = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
ADAPTERS.put(VanillaDialogAdapter.ID, new Registered(new VanillaDialogAdapter(), "autismclient"));
|
||||
}
|
||||
|
||||
private CustomMenuAdapterRegistry() {}
|
||||
|
||||
public static synchronized boolean register(CustomMenuAdapter adapter) {
|
||||
if (adapter == null || adapter.id() == null || adapter.id().isBlank()) return false;
|
||||
String id = adapter.id().trim().toLowerCase(java.util.Locale.ROOT);
|
||||
if (ADAPTERS.containsKey(id)) return false;
|
||||
ADAPTERS.put(id, new Registered(adapter, AddonManager.currentAddonId()));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static synchronized void unregisterAddon(String addonId) {
|
||||
if (addonId == null || addonId.isBlank()) return;
|
||||
ADAPTERS.entrySet().removeIf(entry -> addonId.equals(entry.getValue().owner()));
|
||||
}
|
||||
|
||||
public static CustomMenuEvent inspect(Packet<?> packet, String phase) {
|
||||
List<Registered> snapshot;
|
||||
synchronized (CustomMenuAdapterRegistry.class) {
|
||||
snapshot = new ArrayList<>(ADAPTERS.values());
|
||||
}
|
||||
for (Registered registered : snapshot) {
|
||||
try {
|
||||
CustomMenuEvent event = registered.adapter().inspectInbound(packet, phase);
|
||||
if (event != null && event.type() != CustomMenuEvent.Type.NONE) return event;
|
||||
} catch (Throwable error) {
|
||||
AutismClientAddon.LOG.warn("[CustomMenus] Adapter '{}' failed while reading a packet", registered.adapter().id(), error);
|
||||
}
|
||||
}
|
||||
return CustomMenuEvent.NONE;
|
||||
}
|
||||
|
||||
public static CustomMenuSubmitResult submit(CustomMenuSnapshot snapshot, CustomMenuSubmission submission) {
|
||||
if (snapshot == null) return CustomMenuSubmitResult.failure("No custom menu is open");
|
||||
Registered registered;
|
||||
synchronized (CustomMenuAdapterRegistry.class) {
|
||||
registered = ADAPTERS.get(snapshot.adapterId().toLowerCase(java.util.Locale.ROOT));
|
||||
}
|
||||
if (registered == null) return CustomMenuSubmitResult.failure("Custom menu adapter is unavailable");
|
||||
try {
|
||||
CustomMenuSubmitResult result = registered.adapter().submit(snapshot, submission);
|
||||
return result == null ? CustomMenuSubmitResult.failure("Custom menu adapter returned no result") : result;
|
||||
} catch (Throwable error) {
|
||||
|
||||
AutismClientAddon.LOG.warn("[CustomMenus] Adapter '{}' failed while submitting a form ({})",
|
||||
registered.adapter().id(), error.getClass().getSimpleName());
|
||||
return CustomMenuSubmitResult.failure("Custom menu adapter failed");
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized List<String> ids() {
|
||||
return List.copyOf(ADAPTERS.keySet());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package autismclient.api.custommenu;
|
||||
|
||||
public record CustomMenuButton(int index, String label, String actionId, Kind kind) {
|
||||
public enum Kind { CUSTOM, COMMAND, DIALOG, URL, CLIPBOARD, OTHER, EMPTY }
|
||||
|
||||
public CustomMenuButton {
|
||||
label = label == null ? "" : label;
|
||||
actionId = actionId == null ? "" : actionId;
|
||||
kind = kind == null ? Kind.OTHER : kind;
|
||||
}
|
||||
|
||||
public boolean serverRelevant() {
|
||||
return kind == Kind.CUSTOM || kind == Kind.COMMAND || kind == Kind.DIALOG;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package autismclient.api.custommenu;
|
||||
|
||||
public record CustomMenuEvent(Type type, CustomMenuSnapshot snapshot) {
|
||||
public enum Type { NONE, OPEN, CLEAR }
|
||||
|
||||
public static final CustomMenuEvent NONE = new CustomMenuEvent(Type.NONE, null);
|
||||
public static final CustomMenuEvent CLEAR = new CustomMenuEvent(Type.CLEAR, null);
|
||||
|
||||
public static CustomMenuEvent open(CustomMenuSnapshot snapshot) {
|
||||
return new CustomMenuEvent(Type.OPEN, snapshot);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package autismclient.api.custommenu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record CustomMenuInput(
|
||||
int index,
|
||||
String key,
|
||||
String label,
|
||||
Kind kind,
|
||||
String initialValue,
|
||||
int maxLength,
|
||||
double min,
|
||||
double max,
|
||||
double step,
|
||||
List<String> options
|
||||
) {
|
||||
public enum Kind { TEXT, BOOLEAN, NUMBER, OPTION }
|
||||
|
||||
public CustomMenuInput {
|
||||
key = key == null ? "" : key;
|
||||
label = label == null ? "" : label;
|
||||
kind = kind == null ? Kind.TEXT : kind;
|
||||
initialValue = initialValue == null ? "" : initialValue;
|
||||
options = options == null ? List.of() : List.copyOf(options);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package autismclient.api.custommenu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record CustomMenuSnapshot(
|
||||
String adapterId,
|
||||
String phase,
|
||||
long generation,
|
||||
String title,
|
||||
List<CustomMenuInput> inputs,
|
||||
List<CustomMenuButton> buttons,
|
||||
Object adapterState
|
||||
) {
|
||||
public CustomMenuSnapshot {
|
||||
adapterId = adapterId == null ? "" : adapterId;
|
||||
phase = phase == null ? "" : phase;
|
||||
title = title == null ? "" : title;
|
||||
inputs = inputs == null ? List.of() : List.copyOf(inputs);
|
||||
buttons = buttons == null ? List.of() : List.copyOf(buttons);
|
||||
}
|
||||
|
||||
public CustomMenuSnapshot withConnectionState(String newPhase, long newGeneration) {
|
||||
return new CustomMenuSnapshot(adapterId, newPhase, newGeneration, title, inputs, buttons, adapterState);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package autismclient.api.custommenu;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record CustomMenuSubmission(Map<String, String> values, CustomMenuButton button) {
|
||||
public CustomMenuSubmission {
|
||||
values = values == null ? Map.of() : Map.copyOf(values);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package autismclient.api.custommenu;
|
||||
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import java.util.List;
|
||||
|
||||
public record CustomMenuSubmitResult(
|
||||
boolean success,
|
||||
String error,
|
||||
List<Packet<?>> packets,
|
||||
CustomMenuSnapshot replacement,
|
||||
ClickEvent clientAction
|
||||
) {
|
||||
public CustomMenuSubmitResult {
|
||||
error = error == null ? "" : error;
|
||||
packets = packets == null ? List.of() : List.copyOf(packets);
|
||||
}
|
||||
|
||||
public static CustomMenuSubmitResult failure(String error) {
|
||||
return new CustomMenuSubmitResult(false, error, List.of(), null, null);
|
||||
}
|
||||
|
||||
public static CustomMenuSubmitResult packets(List<Packet<?>> packets) {
|
||||
return new CustomMenuSubmitResult(true, "", packets, null, null);
|
||||
}
|
||||
|
||||
public static CustomMenuSubmitResult replacement(CustomMenuSnapshot replacement, ClickEvent clientAction) {
|
||||
return new CustomMenuSubmitResult(true, "", List.of(), replacement, clientAction);
|
||||
}
|
||||
}
|
||||
153
src/main/java/autismclient/api/event/AddonEvents.java
Normal file
153
src/main/java/autismclient/api/event/AddonEvents.java
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
package autismclient.api.event;
|
||||
|
||||
import autismclient.AutismClientAddon;
|
||||
import autismclient.addons.AddonManager;
|
||||
import autismclient.modules.PackHideState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class AddonEvents {
|
||||
private static final List<OwnedConsumer<Minecraft>> TICK = new CopyOnWriteArrayList<>();
|
||||
private static final List<OwnedPredicate<Packet<?>>> PACKET_SEND = new CopyOnWriteArrayList<>();
|
||||
private static final List<OwnedConsumer<Packet<?>>> PACKET_RECEIVE = new CopyOnWriteArrayList<>();
|
||||
private static final List<OwnedRunnable> GAME_JOIN = new CopyOnWriteArrayList<>();
|
||||
private static final List<OwnedRunnable> GAME_LEFT = new CopyOnWriteArrayList<>();
|
||||
|
||||
private static final long ERROR_LOG_INTERVAL_MS = 5_000L;
|
||||
private static final Map<String, Long> LAST_ERROR_LOG_MS = new ConcurrentHashMap<>();
|
||||
|
||||
private AddonEvents() {}
|
||||
|
||||
public static void onTick(Consumer<Minecraft> listener) {
|
||||
String owner = ownerOrReject("tick");
|
||||
if (owner != null && listener != null) {
|
||||
TICK.add(new OwnedConsumer<>(owner, listener));
|
||||
AddonManager.recordAcceptedRegistration("event", "tick");
|
||||
}
|
||||
}
|
||||
|
||||
public static void onPacketSend(Predicate<Packet<?>> listener) {
|
||||
String owner = ownerOrReject("packetSend");
|
||||
if (owner != null && listener != null) {
|
||||
PACKET_SEND.add(new OwnedPredicate<>(owner, listener));
|
||||
AddonManager.recordAcceptedRegistration("event", "packetSend");
|
||||
}
|
||||
}
|
||||
|
||||
public static void onPacketReceive(Consumer<Packet<?>> listener) {
|
||||
String owner = ownerOrReject("packetReceive");
|
||||
if (owner != null && listener != null) {
|
||||
PACKET_RECEIVE.add(new OwnedConsumer<>(owner, listener));
|
||||
AddonManager.recordAcceptedRegistration("event", "packetReceive");
|
||||
}
|
||||
}
|
||||
|
||||
public static void onGameJoin(Runnable listener) {
|
||||
String owner = ownerOrReject("gameJoin");
|
||||
if (owner != null && listener != null) {
|
||||
GAME_JOIN.add(new OwnedRunnable(owner, listener));
|
||||
AddonManager.recordAcceptedRegistration("event", "gameJoin");
|
||||
}
|
||||
}
|
||||
|
||||
public static void onGameLeft(Runnable listener) {
|
||||
String owner = ownerOrReject("gameLeft");
|
||||
if (owner != null && listener != null) {
|
||||
GAME_LEFT.add(new OwnedRunnable(owner, listener));
|
||||
AddonManager.recordAcceptedRegistration("event", "gameLeft");
|
||||
}
|
||||
}
|
||||
|
||||
private static String ownerOrReject(String event) {
|
||||
String owner = AddonManager.currentAddonId();
|
||||
if (owner == null || owner.isBlank()) {
|
||||
AutismClientAddon.LOG.warn("[Addons] Rejecting {} listener outside an addon lifecycle", event);
|
||||
AddonManager.recordRejectedRegistration(owner, "event", event, "registration outside an addon lifecycle - register from onInitialize() or onRegisterCategories()");
|
||||
return null;
|
||||
}
|
||||
return owner;
|
||||
}
|
||||
|
||||
public static void unregisterAddon(String addonId) {
|
||||
if (addonId == null || addonId.isBlank()) return;
|
||||
TICK.removeIf(listener -> addonId.equals(listener.owner()));
|
||||
PACKET_SEND.removeIf(listener -> addonId.equals(listener.owner()));
|
||||
PACKET_RECEIVE.removeIf(listener -> addonId.equals(listener.owner()));
|
||||
GAME_JOIN.removeIf(listener -> addonId.equals(listener.owner()));
|
||||
GAME_LEFT.removeIf(listener -> addonId.equals(listener.owner()));
|
||||
LAST_ERROR_LOG_MS.keySet().removeIf(key -> key.startsWith(addonId + ":"));
|
||||
}
|
||||
|
||||
public static void fireTick(Minecraft mc) {
|
||||
if (PackHideState.isHardLocked()) return;
|
||||
if (TICK.isEmpty()) return;
|
||||
for (OwnedConsumer<Minecraft> l : TICK) {
|
||||
try { l.listener().accept(mc); } catch (Throwable t) { logThrottled(l.owner(), "tick", t); }
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasTickListeners() {
|
||||
if (PackHideState.isHardLocked()) return false;
|
||||
return !TICK.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean hasPacketListeners() {
|
||||
if (PackHideState.isHardLocked()) return false;
|
||||
return !PACKET_SEND.isEmpty() || !PACKET_RECEIVE.isEmpty();
|
||||
}
|
||||
|
||||
public static boolean firePacketSend(Packet<?> packet) {
|
||||
if (PackHideState.isHardLocked()) return false;
|
||||
if (PACKET_SEND.isEmpty()) return false;
|
||||
boolean cancel = false;
|
||||
for (OwnedPredicate<Packet<?>> l : PACKET_SEND) {
|
||||
try { cancel |= l.listener().test(packet); } catch (Throwable t) { logThrottled(l.owner(), "packetSend", t); }
|
||||
}
|
||||
return cancel;
|
||||
}
|
||||
|
||||
public static void firePacketReceive(Packet<?> packet) {
|
||||
if (PackHideState.isHardLocked()) return;
|
||||
if (PACKET_RECEIVE.isEmpty()) return;
|
||||
for (OwnedConsumer<Packet<?>> l : PACKET_RECEIVE) {
|
||||
try { l.listener().accept(packet); } catch (Throwable t) { logThrottled(l.owner(), "packetReceive", t); }
|
||||
}
|
||||
}
|
||||
|
||||
public static void fireGameJoin() {
|
||||
if (PackHideState.isHardLocked()) return;
|
||||
if (GAME_JOIN.isEmpty()) return;
|
||||
for (OwnedRunnable l : GAME_JOIN) {
|
||||
try { l.listener().run(); } catch (Throwable t) { logThrottled(l.owner(), "gameJoin", t); }
|
||||
}
|
||||
}
|
||||
|
||||
public static void fireGameLeft() {
|
||||
if (PackHideState.isHardLocked()) return;
|
||||
if (GAME_LEFT.isEmpty()) return;
|
||||
for (OwnedRunnable l : GAME_LEFT) {
|
||||
try { l.listener().run(); } catch (Throwable t) { logThrottled(l.owner(), "gameLeft", t); }
|
||||
}
|
||||
}
|
||||
|
||||
private static void logThrottled(String owner, String event, Throwable t) {
|
||||
long now = System.currentTimeMillis();
|
||||
String key = owner + ":" + event + ":" + t.getClass().getName();
|
||||
Long last = LAST_ERROR_LOG_MS.get(key);
|
||||
if (last != null && now - last < ERROR_LOG_INTERVAL_MS) return;
|
||||
LAST_ERROR_LOG_MS.put(key, now);
|
||||
AddonManager.recordRuntimeError(owner, event + " listener threw " + t.getClass().getSimpleName());
|
||||
AutismClientAddon.LOG.warn("[Addons] Addon '{}' {} event listener threw", owner, event, t);
|
||||
}
|
||||
|
||||
private record OwnedConsumer<T>(String owner, Consumer<T> listener) {}
|
||||
private record OwnedPredicate<T>(String owner, Predicate<T> listener) {}
|
||||
private record OwnedRunnable(String owner, Runnable listener) {}
|
||||
}
|
||||
27
src/main/java/autismclient/api/hud/HudElementProvider.java
Normal file
27
src/main/java/autismclient/api/hud/HudElementProvider.java
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package autismclient.api.hud;
|
||||
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiGraphicsExtractor;
|
||||
|
||||
public interface HudElementProvider {
|
||||
|
||||
String id();
|
||||
|
||||
String label();
|
||||
|
||||
default String description() { return ""; }
|
||||
|
||||
int width();
|
||||
|
||||
int height();
|
||||
|
||||
void render(GuiGraphicsExtractor ctx, Font font, int x, int y, float alpha);
|
||||
|
||||
default boolean defaultEnabled() { return false; }
|
||||
|
||||
default String defaultAnchor() { return "TOP_LEFT"; }
|
||||
|
||||
default int defaultX() { return 0; }
|
||||
|
||||
default int defaultY() { return 0; }
|
||||
}
|
||||
104
src/main/java/autismclient/api/hud/HudElements.java
Normal file
104
src/main/java/autismclient/api/hud/HudElements.java
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
package autismclient.api.hud;
|
||||
|
||||
import autismclient.AutismClientAddon;
|
||||
import autismclient.api.AddonRegistrationResult;
|
||||
import autismclient.addons.AddonManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public final class HudElements {
|
||||
private static final Map<String, HudElementProvider> PROVIDERS = new LinkedHashMap<>();
|
||||
private static final Map<String, String> OWNERS = new LinkedHashMap<>();
|
||||
private static int revision;
|
||||
|
||||
private HudElements() {}
|
||||
|
||||
public static int revision() {
|
||||
return revision;
|
||||
}
|
||||
|
||||
public static boolean register(HudElementProvider provider) {
|
||||
return registerDetailed(provider).accepted();
|
||||
}
|
||||
|
||||
public static AddonRegistrationResult registerDetailed(HudElementProvider provider) {
|
||||
if (provider == null) return AddonRegistrationResult.rejected("hud", "", "provider was null");
|
||||
String ownerAddonId = AddonManager.currentAddonId();
|
||||
if (ownerAddonId == null || ownerAddonId.isBlank()) {
|
||||
return reject(ownerAddonId, "", "registration outside an addon lifecycle - register from onInitialize() or onRegisterCategories()");
|
||||
}
|
||||
String id = provider.id();
|
||||
if (id == null || !id.contains(":")) {
|
||||
return reject(ownerAddonId, id, "non-namespaced id - scope it with AutismAddons.id(...) so it becomes addonId:localId");
|
||||
}
|
||||
if (!id.startsWith(ownerAddonId + ":")) {
|
||||
return reject(ownerAddonId, id, "foreign namespace - the id must start with your addon id; scope it with AutismAddons.id(...)");
|
||||
}
|
||||
if (PROVIDERS.containsKey(id)) {
|
||||
return reject(ownerAddonId, id, "duplicate id");
|
||||
}
|
||||
AddonRegistrationResult sizeCheck = validateSize(ownerAddonId, id, provider);
|
||||
if (!sizeCheck.accepted()) return sizeCheck;
|
||||
PROVIDERS.put(id, provider);
|
||||
OWNERS.put(id, ownerAddonId);
|
||||
revision++;
|
||||
AddonManager.recordAcceptedRegistration("hud", id);
|
||||
return AddonRegistrationResult.accepted("hud", id);
|
||||
}
|
||||
|
||||
private static AddonRegistrationResult validateSize(String ownerAddonId, String id, HudElementProvider provider) {
|
||||
int width;
|
||||
int height;
|
||||
try {
|
||||
width = provider.width();
|
||||
height = provider.height();
|
||||
} catch (Throwable t) {
|
||||
AutismClientAddon.LOG.warn("[Hud] Rejecting HUD element '{}': sizing threw", id, t);
|
||||
AddonManager.recordRejectedRegistration(ownerAddonId, "hud", id, "sizing threw " + t.getClass().getSimpleName());
|
||||
return AddonRegistrationResult.rejected("hud", id, "sizing threw " + t.getClass().getSimpleName());
|
||||
}
|
||||
if (width <= 0) return reject(ownerAddonId, id, "width must be positive");
|
||||
if (height <= 0) return reject(ownerAddonId, id, "height must be positive");
|
||||
return AddonRegistrationResult.accepted("hud", id);
|
||||
}
|
||||
|
||||
private static AddonRegistrationResult reject(String ownerAddonId, String id, String reason) {
|
||||
AutismClientAddon.LOG.warn("[Hud] Rejecting HUD element '{}': {}", id, reason);
|
||||
AddonManager.recordRejectedRegistration(ownerAddonId, "hud", id, reason);
|
||||
return AddonRegistrationResult.rejected("hud", id, reason);
|
||||
}
|
||||
|
||||
public static void unregisterAddon(String addonId) {
|
||||
if (addonId == null || addonId.isBlank()) return;
|
||||
List<String> remove = new ArrayList<>();
|
||||
for (Map.Entry<String, String> owner : OWNERS.entrySet()) {
|
||||
if (addonId.equals(owner.getValue())) remove.add(owner.getKey());
|
||||
}
|
||||
if (remove.isEmpty()) return;
|
||||
for (String id : remove) {
|
||||
PROVIDERS.remove(id);
|
||||
OWNERS.remove(id);
|
||||
}
|
||||
revision++;
|
||||
}
|
||||
|
||||
public static HudElementProvider get(String id) {
|
||||
return id == null ? null : PROVIDERS.get(id);
|
||||
}
|
||||
|
||||
public static boolean isAddon(String id) {
|
||||
return id != null && PROVIDERS.containsKey(id);
|
||||
}
|
||||
|
||||
public static List<String> ids() {
|
||||
return Collections.unmodifiableList(new ArrayList<>(PROVIDERS.keySet()));
|
||||
}
|
||||
|
||||
public static boolean isEmpty() {
|
||||
return PROVIDERS.isEmpty();
|
||||
}
|
||||
}
|
||||
83
src/main/java/autismclient/api/macro/ActionSchema.java
Normal file
83
src/main/java/autismclient/api/macro/ActionSchema.java
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import autismclient.gui.macro.editor.ActionFieldSchema;
|
||||
|
||||
public final class ActionSchema {
|
||||
private final ActionFieldSchema internal;
|
||||
|
||||
private ActionSchema(ActionFieldSchema internal) {
|
||||
this.internal = internal;
|
||||
}
|
||||
|
||||
public ActionFieldSchema internal() {
|
||||
return internal;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private final ActionFieldSchema.Builder delegate = ActionFieldSchema.builder();
|
||||
|
||||
private Builder() {}
|
||||
|
||||
public Builder toggle(String key, String label) { delegate.toggle(key, label); return this; }
|
||||
|
||||
public Builder number(String key, String label) { delegate.number(key, label); return this; }
|
||||
|
||||
public Builder decimal(String key, String label) { delegate.decimal(key, label); return this; }
|
||||
|
||||
public Builder text(String key, String label) { delegate.text(key, label); return this; }
|
||||
|
||||
public Builder macroSelect(String key, String label) { delegate.macroSelect(key, label); return this; }
|
||||
|
||||
public Builder enumField(String key, String label, String... options) { delegate.enumField(key, label, options); return this; }
|
||||
|
||||
public Builder stringList(String key, String label) { delegate.stringList(key, label); return this; }
|
||||
|
||||
public Builder slot(String key, String label) { delegate.slot(key, label); return this; }
|
||||
|
||||
public Builder targetSummary(String key, String label) { delegate.targetSummary(key, label); return this; }
|
||||
|
||||
public Builder capturePacketClick(String key, String label) { delegate.capturePacketClick(key, label); return this; }
|
||||
|
||||
public Builder blockPos(String key, String label) { delegate.blockPos(key, label); return this; }
|
||||
|
||||
public Builder range(int min, int max) { delegate.range(min, max); return this; }
|
||||
|
||||
public Builder decRange(double min, double max) { delegate.decRange(min, max); return this; }
|
||||
|
||||
public Builder showWhen(String key) { delegate.showWhen(key); return this; }
|
||||
|
||||
public Builder hideWhen(String key) { delegate.hideWhen(key); return this; }
|
||||
|
||||
public Builder showWhenEnum(String key, String value) { delegate.showWhenEnum(key, value); return this; }
|
||||
|
||||
public Builder hideWhenEnum(String key, String value) { delegate.hideWhenEnum(key, value); return this; }
|
||||
|
||||
public Builder addLabel(String label) { delegate.addLabel(label); return this; }
|
||||
|
||||
public Builder xyzKeys(String... keys) { delegate.xyzKeys(keys); return this; }
|
||||
|
||||
public Builder xyzDouble(boolean value) { delegate.xyzDouble(value); return this; }
|
||||
|
||||
public Builder captureBlock() { delegate.captureBlock(); return this; }
|
||||
|
||||
public Builder captureEntity() { delegate.captureEntity(); return this; }
|
||||
|
||||
public Builder captureCatalog() { delegate.captureCatalog(); return this; }
|
||||
|
||||
public Builder captureItemSlot() { delegate.captureItemSlot(); return this; }
|
||||
|
||||
public Builder capturePacketName() { delegate.capturePacketName(); return this; }
|
||||
|
||||
public Builder exclusiveWith(String... keys) { delegate.exclusiveWith(keys); return this; }
|
||||
|
||||
public Builder dynamic() { delegate.dynamic(); return this; }
|
||||
|
||||
public ActionSchema build() {
|
||||
return new ActionSchema(delegate.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
61
src/main/java/autismclient/api/macro/AddonAction.java
Normal file
61
src/main/java/autismclient/api/macro/AddonAction.java
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import autismclient.util.macro.MacroAction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
public abstract class AddonAction implements MacroAction {
|
||||
private final String typeId;
|
||||
|
||||
protected AddonAction(String typeId) {
|
||||
this.typeId = typeId;
|
||||
}
|
||||
|
||||
protected abstract void run(net.minecraft.client.Minecraft mc);
|
||||
|
||||
protected void save(CompoundTag tag) {}
|
||||
|
||||
protected void load(CompoundTag tag) {}
|
||||
|
||||
protected ActionSchema schema() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute(net.minecraft.client.Minecraft mc) {
|
||||
run(mc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getTypeId() {
|
||||
return typeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CompoundTag toTag() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putString("type", typeId);
|
||||
save(tag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void fromTag(CompoundTag tag) {
|
||||
load(tag);
|
||||
}
|
||||
|
||||
protected static void putString(CompoundTag tag, String key, String value) { tag.putString(key, value == null ? "" : value); }
|
||||
protected static void putInt(CompoundTag tag, String key, int value) { tag.putInt(key, value); }
|
||||
protected static void putDouble(CompoundTag tag, String key, double value) { tag.putDouble(key, value); }
|
||||
protected static void putBool(CompoundTag tag, String key, boolean value) { tag.putBoolean(key, value); }
|
||||
|
||||
protected static String getString(CompoundTag tag, String key, String def) { return tag.getStringOr(key, def); }
|
||||
protected static int getInt(CompoundTag tag, String key, int def) { return tag.getIntOr(key, def); }
|
||||
protected static double getDouble(CompoundTag tag, String key, double def) { return tag.getDoubleOr(key, def); }
|
||||
protected static boolean getBool(CompoundTag tag, String key, boolean def) { return tag.getBooleanOr(key, def); }
|
||||
|
||||
public static ActionSchema schemaOf(MacroAction action) {
|
||||
return action instanceof AddonAction a ? a.schema()
|
||||
: action instanceof AddonContextAction c ? c.schemaInternal()
|
||||
: null;
|
||||
}
|
||||
}
|
||||
10
src/main/java/autismclient/api/macro/AddonCondition.java
Normal file
10
src/main/java/autismclient/api/macro/AddonCondition.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
public abstract class AddonCondition {
|
||||
|
||||
public abstract boolean check(Minecraft mc);
|
||||
|
||||
public void onComplete() {}
|
||||
}
|
||||
51
src/main/java/autismclient/api/macro/AddonContextAction.java
Normal file
51
src/main/java/autismclient/api/macro/AddonContextAction.java
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
public abstract class AddonContextAction implements ContextMacroAction {
|
||||
private final String typeId;
|
||||
|
||||
protected AddonContextAction(String typeId) {
|
||||
this.typeId = typeId;
|
||||
}
|
||||
|
||||
protected void save(CompoundTag tag) {}
|
||||
|
||||
protected void load(CompoundTag tag) {}
|
||||
|
||||
protected ActionSchema schema() {
|
||||
return null;
|
||||
}
|
||||
|
||||
ActionSchema schemaInternal() {
|
||||
return schema();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getTypeId() {
|
||||
return typeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CompoundTag toTag() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putString("type", typeId);
|
||||
save(tag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void fromTag(CompoundTag tag) {
|
||||
load(tag);
|
||||
}
|
||||
|
||||
protected static void putString(CompoundTag tag, String key, String value) { tag.putString(key, value == null ? "" : value); }
|
||||
protected static void putInt(CompoundTag tag, String key, int value) { tag.putInt(key, value); }
|
||||
protected static void putDouble(CompoundTag tag, String key, double value) { tag.putDouble(key, value); }
|
||||
protected static void putBool(CompoundTag tag, String key, boolean value) { tag.putBoolean(key, value); }
|
||||
|
||||
protected static String getString(CompoundTag tag, String key, String def) { return tag.getStringOr(key, def); }
|
||||
protected static int getInt(CompoundTag tag, String key, int def) { return tag.getIntOr(key, def); }
|
||||
protected static double getDouble(CompoundTag tag, String key, double def) { return tag.getDoubleOr(key, def); }
|
||||
protected static boolean getBool(CompoundTag tag, String key, boolean def) { return tag.getBooleanOr(key, def); }
|
||||
}
|
||||
14
src/main/java/autismclient/api/macro/ContextMacroAction.java
Normal file
14
src/main/java/autismclient/api/macro/ContextMacroAction.java
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import autismclient.util.macro.MacroAction;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
public interface ContextMacroAction extends MacroAction {
|
||||
|
||||
void run(MacroExecutionContext ctx) throws InterruptedException;
|
||||
|
||||
@Override
|
||||
default void execute(Minecraft mc) {
|
||||
|
||||
}
|
||||
}
|
||||
103
src/main/java/autismclient/api/macro/MacroActionEntry.java
Normal file
103
src/main/java/autismclient/api/macro/MacroActionEntry.java
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import autismclient.addons.AddonManager;
|
||||
import autismclient.gui.macro.editor.ActionFieldSchema;
|
||||
import autismclient.util.macro.MacroAction;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class MacroActionEntry {
|
||||
|
||||
public enum Kind { ACTION, CONDITION }
|
||||
|
||||
private final String typeId;
|
||||
private final Supplier<MacroAction> factory;
|
||||
private final ActionFieldSchema schema;
|
||||
private String pickerCategory;
|
||||
private final String pickerLabel;
|
||||
private final String pickerTip;
|
||||
private final Kind kind;
|
||||
|
||||
private MacroActionEntry(Builder b) {
|
||||
this.typeId = b.typeId;
|
||||
this.factory = b.factory;
|
||||
this.schema = b.schema;
|
||||
this.pickerCategory = b.pickerCategory;
|
||||
this.pickerLabel = b.pickerLabel;
|
||||
this.pickerTip = b.pickerTip;
|
||||
this.kind = b.kind;
|
||||
}
|
||||
|
||||
public String typeId() { return typeId; }
|
||||
public Supplier<MacroAction> factory() { return factory; }
|
||||
public ActionFieldSchema schema() { return schema; }
|
||||
|
||||
public boolean hasPicker() { return pickerCategory != null && pickerLabel != null; }
|
||||
|
||||
boolean wantsPicker() { return pickerLabel != null; }
|
||||
public String pickerCategory() { return pickerCategory; }
|
||||
public String pickerLabel() { return pickerLabel; }
|
||||
public String pickerTip() { return pickerTip == null ? "" : pickerTip; }
|
||||
public Kind kind() { return kind; }
|
||||
public boolean isCondition() { return kind == Kind.CONDITION; }
|
||||
|
||||
void setPickerCategory(String categoryId) {
|
||||
this.pickerCategory = categoryId;
|
||||
}
|
||||
|
||||
public static Builder builder(String typeId, Supplier<MacroAction> factory) {
|
||||
return new Builder(typeId, factory);
|
||||
}
|
||||
|
||||
public static Builder local(String localId, Supplier<MacroAction> factory) {
|
||||
return new Builder(AddonManager.scopedId(localId), factory);
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private final String typeId;
|
||||
private final Supplier<MacroAction> factory;
|
||||
private ActionFieldSchema schema;
|
||||
private String pickerCategory;
|
||||
private String pickerLabel;
|
||||
private String pickerTip;
|
||||
private Kind kind = Kind.ACTION;
|
||||
|
||||
private Builder(String typeId, Supplier<MacroAction> factory) {
|
||||
this.typeId = typeId;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public Builder schema(ActionSchema schema) {
|
||||
this.schema = schema == null ? null : schema.internal();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder picker(String label, String tip) {
|
||||
return picker(null, label, tip);
|
||||
}
|
||||
|
||||
public Builder picker(String categoryId, String label, String tip) {
|
||||
this.pickerCategory = categoryId;
|
||||
this.pickerLabel = label;
|
||||
this.pickerTip = tip;
|
||||
this.kind = Kind.ACTION;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder condition(String label, String tip) {
|
||||
return condition(null, label, tip);
|
||||
}
|
||||
|
||||
public Builder condition(String categoryId, String label, String tip) {
|
||||
this.pickerCategory = categoryId;
|
||||
this.pickerLabel = label;
|
||||
this.pickerTip = tip;
|
||||
this.kind = Kind.CONDITION;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MacroActionEntry build() {
|
||||
return new MacroActionEntry(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
230
src/main/java/autismclient/api/macro/MacroActionRegistry.java
Normal file
230
src/main/java/autismclient/api/macro/MacroActionRegistry.java
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import autismclient.AutismClientAddon;
|
||||
import autismclient.api.AddonRegistrationResult;
|
||||
import autismclient.addons.AddonManager;
|
||||
import autismclient.gui.macro.editor.ActionFieldSchema;
|
||||
import autismclient.util.macro.MacroAction;
|
||||
import autismclient.util.macro.MacroActionType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class MacroActionRegistry {
|
||||
private static final Map<String, MacroActionEntry> ENTRIES = new LinkedHashMap<>();
|
||||
private static final Map<String, ActionCategory> CATEGORIES = new LinkedHashMap<>();
|
||||
private static final Map<String, String> ENTRY_OWNERS = new LinkedHashMap<>();
|
||||
private static final Map<String, String> CATEGORY_OWNERS = new LinkedHashMap<>();
|
||||
|
||||
private static final Map<String, ActionFieldSchema> RESOLVED_SCHEMAS = new LinkedHashMap<>();
|
||||
|
||||
public record ActionCategory(String id, String label, int color) {}
|
||||
|
||||
public static final int ADDON_AUTO_CATEGORY_COLOR = 0xFFAA66FF;
|
||||
|
||||
private static final String ADDON_CAT_PREFIX = "addon:";
|
||||
|
||||
private MacroActionRegistry() {}
|
||||
|
||||
public static String scopeCategoryId(String rawId) {
|
||||
if (AddonManager.isLifecycleActive()) {
|
||||
String addonId = AddonManager.currentAddonId();
|
||||
return ADDON_CAT_PREFIX + (addonId == null || addonId.isBlank() ? "shared" : addonId);
|
||||
}
|
||||
if (rawId != null && rawId.startsWith(ADDON_CAT_PREFIX)) return rawId;
|
||||
String addonId = AddonManager.currentAddonId();
|
||||
String base = addonId == null || addonId.isBlank() ? "shared" : addonId;
|
||||
return rawId == null || rawId.isBlank()
|
||||
? ADDON_CAT_PREFIX + base
|
||||
: ADDON_CAT_PREFIX + base + "/" + rawId;
|
||||
}
|
||||
|
||||
public static String ensureScopedCategory(String rawId) {
|
||||
String scopedId = scopeCategoryId(rawId);
|
||||
if (!CATEGORIES.containsKey(scopedId)) {
|
||||
registerCategoryInternal(scopedId, AddonManager.scopedCategoryLabel(null), ADDON_AUTO_CATEGORY_COLOR,
|
||||
AddonManager.currentAddonId());
|
||||
}
|
||||
return scopedId;
|
||||
}
|
||||
|
||||
public static void registerScopedCategory(String rawId, String label, int color) {
|
||||
String visible = AddonManager.isLifecycleActive() ? AddonManager.scopedCategoryLabel(null) : label;
|
||||
registerCategoryInternal(scopeCategoryId(rawId), visible, color,
|
||||
AddonManager.currentAddonId());
|
||||
}
|
||||
|
||||
public static void registerCategory(String id, String label, int color) {
|
||||
registerCategoryInternal(id, label, color, null);
|
||||
}
|
||||
|
||||
private static void registerCategoryInternal(String id, String label, int color, String ownerAddonId) {
|
||||
if (id == null || id.isBlank()) return;
|
||||
CATEGORIES.put(id, new ActionCategory(id, label == null || label.isBlank() ? id : label, color));
|
||||
if (ownerAddonId != null && !ownerAddonId.isBlank()) CATEGORY_OWNERS.put(id, ownerAddonId);
|
||||
}
|
||||
|
||||
public static ActionCategory category(String id) {
|
||||
return id == null ? null : CATEGORIES.get(id);
|
||||
}
|
||||
|
||||
public static boolean register(MacroActionEntry entry) {
|
||||
return registerDetailed(entry).accepted();
|
||||
}
|
||||
|
||||
public static AddonRegistrationResult registerDetailed(MacroActionEntry entry) {
|
||||
if (entry == null) return AddonRegistrationResult.rejected("macro action", "", "entry was null");
|
||||
String ownerAddonId = AddonManager.currentAddonId();
|
||||
if (ownerAddonId == null || ownerAddonId.isBlank()) {
|
||||
return reject(ownerAddonId, "macro action", "", "registration outside an addon lifecycle - register from onInitialize() or onRegisterCategories()");
|
||||
}
|
||||
|
||||
String typeId = entry.typeId();
|
||||
if (typeId == null || !typeId.contains(":")) {
|
||||
return reject(ownerAddonId, "macro action", typeId, "non-namespaced type id - scope it with AutismAddons.id(...) so it becomes addonId:localId");
|
||||
}
|
||||
if (!typeId.startsWith(ownerAddonId + ":")) {
|
||||
return reject(ownerAddonId, "macro action", typeId, "foreign namespace - the id must start with your addon id; scope it with AutismAddons.id(...)");
|
||||
}
|
||||
if (entry.factory() == null) {
|
||||
return reject(ownerAddonId, "macro action", typeId, "missing factory");
|
||||
}
|
||||
if (isBuiltinName(typeId)) {
|
||||
return reject(ownerAddonId, "macro action", typeId, "collides with a built-in type");
|
||||
}
|
||||
if (ENTRIES.containsKey(typeId)) {
|
||||
return reject(ownerAddonId, "macro action", typeId, "duplicate type id");
|
||||
}
|
||||
|
||||
if (entry.wantsPicker()) {
|
||||
entry.setPickerCategory(ensureScopedCategory(entry.pickerCategory()));
|
||||
}
|
||||
|
||||
ActionFieldSchema effectiveSchema = entry.schema();
|
||||
MacroAction probe;
|
||||
try {
|
||||
probe = entry.factory().get();
|
||||
} catch (Throwable t) {
|
||||
AutismClientAddon.LOG.warn("[MacroActions] Rejecting action '{}' because its factory threw during validation", typeId, t);
|
||||
return reject(ownerAddonId, "macro action", typeId, "factory threw: " + errorName(t));
|
||||
}
|
||||
if (probe == null) {
|
||||
return reject(ownerAddonId, "macro action", typeId, "factory returned null");
|
||||
}
|
||||
if (effectiveSchema == null) {
|
||||
ActionSchema declared = AddonAction.schemaOf(probe);
|
||||
if (declared != null) effectiveSchema = declared.internal();
|
||||
}
|
||||
String validationError = validateProbe(typeId, entry, probe, effectiveSchema);
|
||||
if (validationError != null) return reject(ownerAddonId, "macro action", typeId, validationError);
|
||||
|
||||
ENTRIES.put(typeId, entry);
|
||||
ENTRY_OWNERS.put(typeId, ownerAddonId);
|
||||
if (effectiveSchema != null) RESOLVED_SCHEMAS.put(typeId, effectiveSchema);
|
||||
AddonManager.recordAcceptedRegistration("macro action", typeId);
|
||||
return AddonRegistrationResult.accepted("macro action", typeId);
|
||||
}
|
||||
|
||||
private static AddonRegistrationResult reject(String ownerAddonId, String kind, String id, String reason) {
|
||||
AutismClientAddon.LOG.warn("[MacroActions] Rejecting {} '{}': {}", kind, id, reason);
|
||||
AddonManager.recordRejectedRegistration(ownerAddonId, kind, id, reason);
|
||||
return AddonRegistrationResult.rejected(kind, id, reason);
|
||||
}
|
||||
|
||||
private static String validateProbe(String typeId, MacroActionEntry entry, MacroAction probe, ActionFieldSchema schema) {
|
||||
String writtenType;
|
||||
net.minecraft.nbt.CompoundTag tag;
|
||||
try {
|
||||
tag = probe.toTag();
|
||||
writtenType = tag.getStringOr("type", "");
|
||||
} catch (Throwable t) {
|
||||
AutismClientAddon.LOG.warn("[MacroActions] Rejecting '{}' because toTag() threw", typeId, t);
|
||||
return "toTag() threw: " + errorName(t);
|
||||
}
|
||||
if (!typeId.equals(writtenType)) {
|
||||
return "writes type=\"" + writtenType + "\" instead of \"" + typeId + "\"";
|
||||
}
|
||||
if (schema != null) {
|
||||
for (autismclient.gui.macro.editor.FieldDef field : schema.fields()) {
|
||||
String key = field.key();
|
||||
if (field.type() == autismclient.gui.macro.editor.FieldType.BLOCK_POS) {
|
||||
for (String axisKey : field.xyzKeys()) {
|
||||
if (axisKey != null && !axisKey.isEmpty() && !tag.contains(axisKey)) {
|
||||
return "schema field '" + axisKey + "' is not written by toTag()/save()";
|
||||
}
|
||||
}
|
||||
} else if (key != null && !key.isEmpty() && !tag.contains(key)) {
|
||||
return "schema field '" + key + "' is not written by toTag()/save()";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entry.isCondition() && !(probe instanceof ContextMacroAction)) {
|
||||
return "conditions must implement ContextMacroAction";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void unregisterAddon(String addonId) {
|
||||
if (addonId == null || addonId.isBlank()) return;
|
||||
List<String> removeTypes = new ArrayList<>();
|
||||
for (Map.Entry<String, String> owner : ENTRY_OWNERS.entrySet()) {
|
||||
if (addonId.equals(owner.getValue())) removeTypes.add(owner.getKey());
|
||||
}
|
||||
for (String typeId : removeTypes) {
|
||||
ENTRIES.remove(typeId);
|
||||
RESOLVED_SCHEMAS.remove(typeId);
|
||||
ENTRY_OWNERS.remove(typeId);
|
||||
}
|
||||
|
||||
List<String> removeCategories = new ArrayList<>();
|
||||
for (Map.Entry<String, String> owner : CATEGORY_OWNERS.entrySet()) {
|
||||
if (addonId.equals(owner.getValue())) removeCategories.add(owner.getKey());
|
||||
}
|
||||
for (String categoryId : removeCategories) {
|
||||
CATEGORIES.remove(categoryId);
|
||||
CATEGORY_OWNERS.remove(categoryId);
|
||||
}
|
||||
}
|
||||
|
||||
public static Supplier<MacroAction> factory(String typeId) {
|
||||
MacroActionEntry e = typeId == null ? null : ENTRIES.get(typeId);
|
||||
return e == null ? null : e.factory();
|
||||
}
|
||||
|
||||
public static ActionFieldSchema schema(String typeId) {
|
||||
return typeId == null ? null : RESOLVED_SCHEMAS.get(typeId);
|
||||
}
|
||||
|
||||
public static boolean isCondition(String typeId) {
|
||||
MacroActionEntry e = typeId == null ? null : ENTRIES.get(typeId);
|
||||
return e != null && e.isCondition();
|
||||
}
|
||||
|
||||
public static String ownerOf(String typeId) {
|
||||
return typeId == null ? null : ENTRY_OWNERS.get(typeId);
|
||||
}
|
||||
|
||||
public static List<MacroActionEntry> entries() {
|
||||
return Collections.unmodifiableList(new ArrayList<>(ENTRIES.values()));
|
||||
}
|
||||
|
||||
private static boolean isBuiltinName(String typeId) {
|
||||
try {
|
||||
MacroActionType.valueOf(typeId.toUpperCase(Locale.ROOT));
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static String errorName(Throwable t) {
|
||||
if (t == null) return "unknown";
|
||||
String message = t.getMessage();
|
||||
return message == null || message.isBlank() ? t.getClass().getSimpleName() : t.getClass().getSimpleName() + ": " + message;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import autismclient.util.macro.MacroTemplate;
|
||||
import autismclient.util.macro.MacroValue;
|
||||
|
||||
public interface MacroExecutionContext {
|
||||
|
||||
Minecraft mc();
|
||||
|
||||
void runOnClientThread(Runnable r);
|
||||
|
||||
<T> T callOnClientThread(Supplier<T> s);
|
||||
|
||||
void waitTicks(int ticks);
|
||||
|
||||
void awaitCondition(CompletableFuture<Void> future);
|
||||
|
||||
void awaitCondition(AddonCondition condition);
|
||||
|
||||
boolean isActive();
|
||||
|
||||
void setStatus(String status);
|
||||
|
||||
void sendPacket(Packet<?> packet);
|
||||
|
||||
Optional<MacroValue> variable(String name);
|
||||
|
||||
void setVariable(String name, MacroValue value);
|
||||
|
||||
default void setVariable(String name, Object value) {
|
||||
setVariable(name, MacroValue.text(value));
|
||||
}
|
||||
|
||||
void removeVariable(String name);
|
||||
|
||||
Map<String, MacroValue> variables();
|
||||
|
||||
MacroTemplate.Resolution resolveTemplate(String template);
|
||||
|
||||
default void captureResult(String name, MacroValue value) {
|
||||
setVariable(name, value);
|
||||
}
|
||||
|
||||
default void captureResults(Map<String, MacroValue> values) {
|
||||
if (values != null) values.forEach(this::setVariable);
|
||||
}
|
||||
|
||||
default Optional<Integer> resolveInt(String template) {
|
||||
MacroTemplate.Resolution resolved = resolveTemplate(template);
|
||||
if (!resolved.success()) return Optional.empty();
|
||||
try { return Optional.of(Integer.parseInt(resolved.value().trim())); }
|
||||
catch (NumberFormatException ignored) { return Optional.empty(); }
|
||||
}
|
||||
|
||||
default Optional<Double> resolveDouble(String template) {
|
||||
MacroTemplate.Resolution resolved = resolveTemplate(template);
|
||||
if (!resolved.success()) return Optional.empty();
|
||||
try { return Optional.of(Double.parseDouble(resolved.value().trim())); }
|
||||
catch (NumberFormatException ignored) { return Optional.empty(); }
|
||||
}
|
||||
|
||||
default <E extends Enum<E>> Optional<E> resolveEnum(String template, Class<E> type) {
|
||||
if (type == null) return Optional.empty();
|
||||
MacroTemplate.Resolution resolved = resolveTemplate(template);
|
||||
if (!resolved.success()) return Optional.empty();
|
||||
for (E value : type.getEnumConstants()) {
|
||||
if (value.name().equalsIgnoreCase(resolved.value().trim())) return Optional.of(value);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
115
src/main/java/autismclient/api/macro/MacroPresetRegistry.java
Normal file
115
src/main/java/autismclient/api/macro/MacroPresetRegistry.java
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import autismclient.AutismClientAddon;
|
||||
import autismclient.api.AddonRegistrationResult;
|
||||
import autismclient.addons.AddonManager;
|
||||
import autismclient.util.macro.MacroAction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class MacroPresetRegistry {
|
||||
|
||||
public record PresetEntry(String categoryId, String label, String tip, Supplier<List<MacroAction>> builder) {}
|
||||
|
||||
private static final List<PresetEntry> ENTRIES = new ArrayList<>();
|
||||
private static final Map<PresetEntry, String> ENTRY_OWNERS = new IdentityHashMap<>();
|
||||
private static final Map<String, String> CATEGORY_LABELS = new LinkedHashMap<>();
|
||||
private static final Map<String, String> CATEGORY_OWNERS = new LinkedHashMap<>();
|
||||
|
||||
private MacroPresetRegistry() {}
|
||||
|
||||
public static void registerCategory(String id, String label) {
|
||||
registerCategory(id, label, AddonManager.currentAddonId());
|
||||
}
|
||||
|
||||
public static String ensureScopedCategory(String rawId) {
|
||||
String scopedId = MacroActionRegistry.scopeCategoryId(rawId);
|
||||
if (!CATEGORY_LABELS.containsKey(scopedId)) {
|
||||
registerCategory(scopedId, AddonManager.scopedCategoryLabel(null), AddonManager.currentAddonId());
|
||||
}
|
||||
return scopedId;
|
||||
}
|
||||
|
||||
public static void registerScopedCategory(String rawId, String label) {
|
||||
String visible = AddonManager.isLifecycleActive() ? AddonManager.scopedCategoryLabel(null) : label;
|
||||
registerCategory(MacroActionRegistry.scopeCategoryId(rawId), visible,
|
||||
AddonManager.currentAddonId());
|
||||
}
|
||||
|
||||
private static void registerCategory(String id, String label, String ownerAddonId) {
|
||||
if (id == null || id.isBlank()) return;
|
||||
CATEGORY_LABELS.put(id, label == null || label.isBlank() ? id : label);
|
||||
if (ownerAddonId != null && !ownerAddonId.isBlank()) CATEGORY_OWNERS.put(id, ownerAddonId);
|
||||
}
|
||||
|
||||
public static void register(String categoryId, String label, String tip, Supplier<List<MacroAction>> builder) {
|
||||
registerDetailed(categoryId, label, tip, builder);
|
||||
}
|
||||
|
||||
public static AddonRegistrationResult registerDetailed(String categoryId, String label, String tip, Supplier<List<MacroAction>> builder) {
|
||||
String ownerAddonId = AddonManager.currentAddonId();
|
||||
if (ownerAddonId == null || ownerAddonId.isBlank()) {
|
||||
return reject(ownerAddonId, label, "registration outside an addon lifecycle - register from onInitialize() or onRegisterCategories()");
|
||||
}
|
||||
if (categoryId == null || categoryId.isBlank()) return reject(ownerAddonId, label, "missing category");
|
||||
if (label == null || label.isBlank()) return reject(ownerAddonId, label, "missing label");
|
||||
if (builder == null) return reject(ownerAddonId, label, "missing builder");
|
||||
AddonRegistrationResult validation = validateBuilder(ownerAddonId, label, builder);
|
||||
if (!validation.accepted()) return validation;
|
||||
PresetEntry entry = new PresetEntry(categoryId, label, tip == null ? "" : tip, builder);
|
||||
ENTRIES.add(entry);
|
||||
ENTRY_OWNERS.put(entry, ownerAddonId);
|
||||
AddonManager.recordAcceptedRegistration("preset", label);
|
||||
return AddonRegistrationResult.accepted("preset", label);
|
||||
}
|
||||
|
||||
private static AddonRegistrationResult validateBuilder(String ownerAddonId, String label, Supplier<List<MacroAction>> builder) {
|
||||
List<MacroAction> actions;
|
||||
try {
|
||||
actions = builder.get();
|
||||
} catch (Throwable t) {
|
||||
AutismClientAddon.LOG.warn("[MacroPresets] Rejecting preset '{}': builder threw", label, t);
|
||||
AddonManager.recordRejectedRegistration(ownerAddonId, "preset", label, "builder threw " + t.getClass().getSimpleName());
|
||||
return AddonRegistrationResult.rejected("preset", label, "builder threw " + t.getClass().getSimpleName());
|
||||
}
|
||||
if (actions == null) return reject(ownerAddonId, label, "builder returned null");
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
if (actions.get(i) == null) {
|
||||
return reject(ownerAddonId, label, "builder returned null action at index " + i);
|
||||
}
|
||||
}
|
||||
return AddonRegistrationResult.accepted("preset", label);
|
||||
}
|
||||
|
||||
private static AddonRegistrationResult reject(String ownerAddonId, String label, String reason) {
|
||||
AutismClientAddon.LOG.warn("[MacroPresets] Rejecting preset '{}': {}", label, reason);
|
||||
AddonManager.recordRejectedRegistration(ownerAddonId, "preset", label, reason);
|
||||
return AddonRegistrationResult.rejected("preset", label, reason);
|
||||
}
|
||||
|
||||
public static void unregisterAddon(String addonId) {
|
||||
if (addonId == null || addonId.isBlank()) return;
|
||||
List<PresetEntry> remove = new ArrayList<>();
|
||||
for (PresetEntry entry : ENTRIES) {
|
||||
if (addonId.equals(ENTRY_OWNERS.get(entry))) remove.add(entry);
|
||||
}
|
||||
ENTRIES.removeAll(remove);
|
||||
for (PresetEntry entry : remove) ENTRY_OWNERS.remove(entry);
|
||||
CATEGORY_LABELS.entrySet().removeIf(entry -> addonId.equals(CATEGORY_OWNERS.get(entry.getKey())));
|
||||
CATEGORY_OWNERS.entrySet().removeIf(entry -> addonId.equals(entry.getValue()));
|
||||
}
|
||||
|
||||
public static List<PresetEntry> entries() {
|
||||
return Collections.unmodifiableList(ENTRIES);
|
||||
}
|
||||
|
||||
public static String categoryLabel(String id) {
|
||||
return CATEGORY_LABELS.get(id);
|
||||
}
|
||||
}
|
||||
33
src/main/java/autismclient/api/macro/SimpleAction.java
Normal file
33
src/main/java/autismclient/api/macro/SimpleAction.java
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class SimpleAction extends AddonAction {
|
||||
private final String displayName;
|
||||
private final String icon;
|
||||
private final Consumer<Minecraft> runner;
|
||||
|
||||
public SimpleAction(String typeId, String displayName, String icon, Consumer<Minecraft> runner) {
|
||||
super(typeId);
|
||||
this.displayName = displayName == null || displayName.isBlank() ? typeId : displayName;
|
||||
this.icon = icon == null || icon.isBlank() ? "*" : icon;
|
||||
this.runner = runner;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(Minecraft mc) {
|
||||
if (runner != null) runner.accept(mc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
41
src/main/java/autismclient/api/macro/SimpleCondition.java
Normal file
41
src/main/java/autismclient/api/macro/SimpleCondition.java
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package autismclient.api.macro;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class SimpleCondition extends AddonContextAction {
|
||||
private final String displayName;
|
||||
private final String status;
|
||||
private final String icon;
|
||||
private final Predicate<Minecraft> predicate;
|
||||
|
||||
public SimpleCondition(String typeId, String displayName, String status, String icon, Predicate<Minecraft> predicate) {
|
||||
super(typeId);
|
||||
this.displayName = displayName == null || displayName.isBlank() ? typeId : displayName;
|
||||
this.status = status == null || status.isBlank() ? this.displayName : status;
|
||||
this.icon = icon == null || icon.isBlank() ? "?" : icon;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(MacroExecutionContext ctx) {
|
||||
ctx.setStatus(status);
|
||||
ctx.awaitCondition(new AddonCondition() {
|
||||
@Override
|
||||
public boolean check(Minecraft mc) {
|
||||
return predicate != null && predicate.test(mc);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
29
src/main/java/autismclient/api/module/ActionSetting.java
Normal file
29
src/main/java/autismclient/api/module/ActionSetting.java
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public final class ActionSetting extends Setting<Void, ActionSetting> {
|
||||
private String buttonLabel = "Run";
|
||||
|
||||
public ActionSetting(String name, String title, Runnable action) {
|
||||
super(Kind.ACTION, name, title, null);
|
||||
setAction(action);
|
||||
}
|
||||
|
||||
public ActionSetting buttonLabel(String buttonLabel) {
|
||||
this.buttonLabel = buttonLabel == null || buttonLabel.isBlank() ? "Run" : buttonLabel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String buttonLabel() {
|
||||
return buttonLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void decode(String raw) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String encode(Void value) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
10
src/main/java/autismclient/api/module/Availability.java
Normal file
10
src/main/java/autismclient/api/module/Availability.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public enum Availability {
|
||||
|
||||
ALWAYS,
|
||||
|
||||
IN_WORLD,
|
||||
|
||||
IN_CONTAINER
|
||||
}
|
||||
17
src/main/java/autismclient/api/module/BoolSetting.java
Normal file
17
src/main/java/autismclient/api/module/BoolSetting.java
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public final class BoolSetting extends Setting<Boolean, BoolSetting> {
|
||||
public BoolSetting(String name, String title, boolean defaultValue) {
|
||||
super(Kind.BOOLEAN, name, title, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean decode(String raw) {
|
||||
return raw != null && Boolean.parseBoolean(raw.trim());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String encode(Boolean value) {
|
||||
return Boolean.toString(value != null && value);
|
||||
}
|
||||
}
|
||||
39
src/main/java/autismclient/api/module/ChoiceSetting.java
Normal file
39
src/main/java/autismclient/api/module/ChoiceSetting.java
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class ChoiceSetting extends Setting<String, ChoiceSetting> {
|
||||
public ChoiceSetting(String name, String title, String defaultValue, String... choices) {
|
||||
super(Kind.ENUM, name, title, defaultValue == null ? "" : defaultValue);
|
||||
setChoices(choices == null ? List.of() : Arrays.asList(choices));
|
||||
}
|
||||
|
||||
public ChoiceSetting(String name, String title, String defaultValue, List<String> choices) {
|
||||
super(Kind.ENUM, name, title, defaultValue == null ? "" : defaultValue);
|
||||
setChoices(choices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String decode(String raw) {
|
||||
if (raw == null) return defaultValueTyped();
|
||||
String needle = raw.trim();
|
||||
List<String> options = choices();
|
||||
if (options.isEmpty()) return needle;
|
||||
for (String choice : options) {
|
||||
if (choice.equalsIgnoreCase(needle)) return choice;
|
||||
}
|
||||
return defaultValueTyped();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String encode(String value) {
|
||||
if (value == null) return defaultValueTyped();
|
||||
List<String> options = choices();
|
||||
if (options.isEmpty()) return value;
|
||||
for (String choice : options) {
|
||||
if (choice.equalsIgnoreCase(value)) return choice;
|
||||
}
|
||||
return defaultValueTyped();
|
||||
}
|
||||
}
|
||||
36
src/main/java/autismclient/api/module/ColorSetting.java
Normal file
36
src/main/java/autismclient/api/module/ColorSetting.java
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public final class ColorSetting extends Setting<Integer, ColorSetting> {
|
||||
public ColorSetting(String name, String title, int defaultArgb) {
|
||||
super(Kind.COLOR, name, title, defaultArgb);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer decode(String raw) {
|
||||
Integer parsed = parseColor(raw);
|
||||
return parsed == null ? defaultValueTyped() : parsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String encode(Integer value) {
|
||||
int argb = value == null ? defaultValueTyped() : value;
|
||||
return String.format(Locale.ROOT, "%08X", argb);
|
||||
}
|
||||
|
||||
static Integer parseColor(String value) {
|
||||
if (value == null) return null;
|
||||
String text = value.trim();
|
||||
if (text.isEmpty()) return null;
|
||||
if (text.startsWith("#")) text = text.substring(1);
|
||||
else if (text.startsWith("0x") || text.startsWith("0X")) text = text.substring(2);
|
||||
try {
|
||||
long parsed = Long.parseUnsignedLong(text, 16);
|
||||
if (text.length() <= 6) parsed |= 0xFF000000L;
|
||||
return (int) parsed;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/main/java/autismclient/api/module/DisplayMode.java
Normal file
20
src/main/java/autismclient/api/module/DisplayMode.java
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public enum DisplayMode {
|
||||
|
||||
DEFAULT,
|
||||
|
||||
READONLY_SUMMARY,
|
||||
|
||||
NUMERIC_TEXT_FIELD,
|
||||
|
||||
FILE_PICKER,
|
||||
|
||||
PLAYER_NAME_LIST,
|
||||
|
||||
RANK_TAG_LIST,
|
||||
|
||||
MACRO_PICKER,
|
||||
|
||||
CONDITIONAL_MACRO_PICKER
|
||||
}
|
||||
42
src/main/java/autismclient/api/module/DoubleSetting.java
Normal file
42
src/main/java/autismclient/api/module/DoubleSetting.java
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public final class DoubleSetting extends Setting<Double, DoubleSetting> {
|
||||
public DoubleSetting(String name, String title, double defaultValue, double min, double max, double step) {
|
||||
super(Kind.DOUBLE, name, title, clamp(defaultValue, min, Math.max(min, max)));
|
||||
setRange(min, max);
|
||||
setSliderRange(min, max);
|
||||
setStep(step <= 0 ? 0.1 : step);
|
||||
}
|
||||
|
||||
public DoubleSetting sliderRange(double min, double max) {
|
||||
setSliderRange(min, max);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Double decode(String raw) {
|
||||
if (raw == null) return defaultValueTyped();
|
||||
try {
|
||||
return clamp(Double.parseDouble(raw.trim()), min(), max());
|
||||
} catch (Exception e) {
|
||||
return defaultValueTyped();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String encode(Double value) {
|
||||
double v = value == null ? defaultValueTyped() : value;
|
||||
return Double.toString(clamp(v, min(), max()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Double sanitizeTyped(Double value) {
|
||||
double v = value == null ? defaultValueTyped() : value;
|
||||
return clamp(v, min(), max());
|
||||
}
|
||||
|
||||
private static double clamp(double value, double min, double max) {
|
||||
if (Double.isNaN(value)) return min;
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
}
|
||||
70
src/main/java/autismclient/api/module/EnumSetting.java
Normal file
70
src/main/java/autismclient/api/module/EnumSetting.java
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class EnumSetting<E extends Enum<E>> extends Setting<E, EnumSetting<E>> {
|
||||
private final E[] values;
|
||||
private final Function<E, String> tokenizer;
|
||||
|
||||
public EnumSetting(String name, String title, E defaultValue, E[] values, Function<E, String> tokenizer) {
|
||||
super(Kind.ENUM, name, title, defaultValue);
|
||||
this.values = values == null ? newArray(defaultValue) : values;
|
||||
this.tokenizer = tokenizer == null ? Enum::name : tokenizer;
|
||||
List<String> labels = new ArrayList<>();
|
||||
for (E value : this.values) labels.add(token(value));
|
||||
setChoices(labels);
|
||||
}
|
||||
|
||||
public EnumSetting(String name, String title, E defaultValue, E[] values) {
|
||||
this(name, title, defaultValue, values, EnumSetting::titleCase);
|
||||
}
|
||||
|
||||
private String token(E value) {
|
||||
if (value == null) return "";
|
||||
try {
|
||||
String label = tokenizer.apply(value);
|
||||
return label == null || label.isBlank() ? value.name() : label;
|
||||
} catch (Throwable t) {
|
||||
return value.name();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected E decode(String raw) {
|
||||
if (raw == null) return defaultValueTyped();
|
||||
String needle = raw.trim();
|
||||
if (needle.isEmpty()) return defaultValueTyped();
|
||||
for (E value : values) {
|
||||
if (token(value).equalsIgnoreCase(needle)) return value;
|
||||
}
|
||||
for (E value : values) {
|
||||
if (value.name().equalsIgnoreCase(needle)) return value;
|
||||
}
|
||||
return defaultValueTyped();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String encode(E value) {
|
||||
return token(value == null ? defaultValueTyped() : value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <E extends Enum<E>> E[] newArray(E single) {
|
||||
E[] array = (E[]) java.lang.reflect.Array.newInstance(single.getClass(), 1);
|
||||
array[0] = single;
|
||||
return array;
|
||||
}
|
||||
|
||||
public static String titleCase(Enum<?> value) {
|
||||
String[] words = value.name().toLowerCase(java.util.Locale.ROOT).split("_");
|
||||
StringBuilder out = new StringBuilder();
|
||||
for (String word : words) {
|
||||
if (word.isEmpty()) continue;
|
||||
if (out.length() > 0) out.append(' ');
|
||||
out.append(Character.toUpperCase(word.charAt(0))).append(word.substring(1));
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
}
|
||||
45
src/main/java/autismclient/api/module/IntSetting.java
Normal file
45
src/main/java/autismclient/api/module/IntSetting.java
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public final class IntSetting extends Setting<Integer, IntSetting> {
|
||||
public IntSetting(String name, String title, int defaultValue, int min, int max, int step) {
|
||||
super(Kind.INTEGER, name, title, clampStatic(defaultValue, min, Math.max(min, max)));
|
||||
setRange(min, max);
|
||||
setSliderRange(min, max);
|
||||
setStep(Math.max(1, step));
|
||||
}
|
||||
|
||||
public IntSetting sliderRange(double min, double max) {
|
||||
setSliderRange(min, max);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer decode(String raw) {
|
||||
if (raw == null) return defaultValueTyped();
|
||||
try {
|
||||
return (int) clampStatic((long) Double.parseDouble(raw.trim()), (long) min(), (long) max());
|
||||
} catch (Exception e) {
|
||||
return defaultValueTyped();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String encode(Integer value) {
|
||||
int v = value == null ? defaultValueTyped() : value;
|
||||
return Integer.toString((int) clampStatic(v, (long) min(), (long) max()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer sanitizeTyped(Integer value) {
|
||||
int v = value == null ? defaultValueTyped() : value;
|
||||
return (int) clampStatic(v, (long) min(), (long) max());
|
||||
}
|
||||
|
||||
private static int clampStatic(int value, int min, int max) {
|
||||
return (int) clampStatic((long) value, (long) min, (long) max);
|
||||
}
|
||||
|
||||
private static long clampStatic(long value, long min, long max) {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
}
|
||||
22
src/main/java/autismclient/api/module/KeybindSetting.java
Normal file
22
src/main/java/autismclient/api/module/KeybindSetting.java
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public final class KeybindSetting extends Setting<Integer, KeybindSetting> {
|
||||
public KeybindSetting(String name, String title, int defaultKey) {
|
||||
super(Kind.KEYBIND, name, title, defaultKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer decode(String raw) {
|
||||
if (raw == null) return defaultValueTyped();
|
||||
try {
|
||||
return Integer.parseInt(raw.trim());
|
||||
} catch (Exception e) {
|
||||
return defaultValueTyped();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String encode(Integer value) {
|
||||
return Integer.toString(value == null ? defaultValueTyped() : value);
|
||||
}
|
||||
}
|
||||
19
src/main/java/autismclient/api/module/Kind.java
Normal file
19
src/main/java/autismclient/api/module/Kind.java
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public enum Kind {
|
||||
BOOLEAN,
|
||||
INTEGER,
|
||||
DOUBLE,
|
||||
ENUM,
|
||||
STRING,
|
||||
STRING_LIST,
|
||||
PACKET_LIST,
|
||||
ITEM_LIST,
|
||||
BLOCK_LIST,
|
||||
ENTITY_TYPE_LIST,
|
||||
SOUND_EVENT_LIST,
|
||||
STORAGE_LIST,
|
||||
COLOR,
|
||||
KEYBIND,
|
||||
ACTION
|
||||
}
|
||||
47
src/main/java/autismclient/api/module/ListSetting.java
Normal file
47
src/main/java/autismclient/api/module/ListSetting.java
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
abstract class ListSetting<S extends ListSetting<S>> extends Setting<List<String>, S> {
|
||||
protected ListSetting(Kind kind, String name, String title, List<String> defaultValue) {
|
||||
super(kind, name, title, defaultValue == null ? List.of() : List.copyOf(defaultValue));
|
||||
}
|
||||
|
||||
protected ListSetting(Kind kind, String name, String title, String defaultRaw) {
|
||||
super(kind, name, title, parseRaw(defaultRaw));
|
||||
}
|
||||
|
||||
static List<String> parseRaw(String raw) {
|
||||
if (raw == null || raw.isBlank()) return List.of();
|
||||
List<String> out = new ArrayList<>();
|
||||
for (String part : raw.split("\\|")) {
|
||||
String trimmed = part.trim();
|
||||
if (!trimmed.isEmpty()) out.add(trimmed);
|
||||
}
|
||||
return List.copyOf(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> decode(String raw) {
|
||||
if (raw == null || raw.isBlank()) return List.of();
|
||||
List<String> out = new ArrayList<>();
|
||||
for (String part : raw.split("\\|")) {
|
||||
String item = part.trim();
|
||||
if (!item.isEmpty()) out.add(item);
|
||||
}
|
||||
return List.copyOf(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String encode(List<String> value) {
|
||||
if (value == null || value.isEmpty()) return "";
|
||||
List<String> out = new ArrayList<>();
|
||||
for (String item : value) {
|
||||
if (item == null) continue;
|
||||
String trimmed = item.trim();
|
||||
if (!trimmed.isEmpty()) out.add(trimmed);
|
||||
}
|
||||
return String.join("|", out);
|
||||
}
|
||||
}
|
||||
17
src/main/java/autismclient/api/module/PacketListSetting.java
Normal file
17
src/main/java/autismclient/api/module/PacketListSetting.java
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class PacketListSetting extends ListSetting<PacketListSetting> {
|
||||
public PacketListSetting(String name, String title) {
|
||||
super(Kind.PACKET_LIST, name, title, List.of());
|
||||
}
|
||||
|
||||
public PacketListSetting(String name, String title, List<String> defaultValue) {
|
||||
super(Kind.PACKET_LIST, name, title, defaultValue);
|
||||
}
|
||||
|
||||
public PacketListSetting(String name, String title, String defaultValue) {
|
||||
super(Kind.PACKET_LIST, name, title, defaultValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class RegistryListSetting extends ListSetting<RegistryListSetting> {
|
||||
private RegistryListSetting(Kind kind, String name, String title, String defaultValue) {
|
||||
super(registryKindOrDefault(kind), name, title, parseDefault(defaultValue));
|
||||
}
|
||||
|
||||
public static RegistryListSetting items(String name, String title) {
|
||||
return items(name, title, "");
|
||||
}
|
||||
|
||||
public static RegistryListSetting items(String name, String title, String defaultValue) {
|
||||
return new RegistryListSetting(Kind.ITEM_LIST, name, title, defaultValue);
|
||||
}
|
||||
|
||||
public static RegistryListSetting blocks(String name, String title) {
|
||||
return blocks(name, title, "");
|
||||
}
|
||||
|
||||
public static RegistryListSetting blocks(String name, String title, String defaultValue) {
|
||||
return new RegistryListSetting(Kind.BLOCK_LIST, name, title, defaultValue);
|
||||
}
|
||||
|
||||
public static RegistryListSetting entityTypes(String name, String title) {
|
||||
return entityTypes(name, title, "");
|
||||
}
|
||||
|
||||
public static RegistryListSetting entityTypes(String name, String title, String defaultValue) {
|
||||
return new RegistryListSetting(Kind.ENTITY_TYPE_LIST, name, title, defaultValue);
|
||||
}
|
||||
|
||||
public static RegistryListSetting soundEvents(String name, String title) {
|
||||
return soundEvents(name, title, "");
|
||||
}
|
||||
|
||||
public static RegistryListSetting soundEvents(String name, String title, String defaultValue) {
|
||||
return new RegistryListSetting(Kind.SOUND_EVENT_LIST, name, title, defaultValue);
|
||||
}
|
||||
|
||||
public static RegistryListSetting storages(String name, String title) {
|
||||
return storages(name, title, "");
|
||||
}
|
||||
|
||||
public static RegistryListSetting storages(String name, String title, String defaultValue) {
|
||||
return new RegistryListSetting(Kind.STORAGE_LIST, name, title, defaultValue);
|
||||
}
|
||||
|
||||
private static List<String> parseDefault(String raw) {
|
||||
if (raw == null || raw.isBlank()) return List.of();
|
||||
List<String> out = new ArrayList<>();
|
||||
for (String part : raw.split("\\|")) {
|
||||
String trimmed = part.trim();
|
||||
if (!trimmed.isEmpty()) out.add(trimmed);
|
||||
}
|
||||
return List.copyOf(out);
|
||||
}
|
||||
|
||||
private static Kind registryKindOrDefault(Kind kind) {
|
||||
return switch (kind == null ? Kind.ITEM_LIST : kind) {
|
||||
case ITEM_LIST, BLOCK_LIST, ENTITY_TYPE_LIST, SOUND_EVENT_LIST, STORAGE_LIST -> kind;
|
||||
default -> Kind.ITEM_LIST;
|
||||
};
|
||||
}
|
||||
}
|
||||
303
src/main/java/autismclient/api/module/Setting.java
Normal file
303
src/main/java/autismclient/api/module/Setting.java
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class Setting<T, S extends Setting<T, S>> {
|
||||
private final Kind kind;
|
||||
private final String name;
|
||||
private final T def;
|
||||
private String title;
|
||||
private String description = "";
|
||||
private String group = "General";
|
||||
private String unit = "";
|
||||
private DisplayMode displayMode = DisplayMode.DEFAULT;
|
||||
private Availability availability;
|
||||
private BooleanSupplier visible;
|
||||
private Function<String, String> formatter;
|
||||
private Runnable action;
|
||||
private String linkedActionId = "";
|
||||
private double min;
|
||||
private double max;
|
||||
private double sliderMin;
|
||||
private double sliderMax;
|
||||
private double step = 1.0;
|
||||
private List<String> choices = List.of();
|
||||
|
||||
private SettingOwner owner;
|
||||
private transient boolean cached;
|
||||
private transient String cachedRaw;
|
||||
private transient T cachedValue;
|
||||
|
||||
protected Setting(Kind kind, String name, String title, T def) {
|
||||
this.kind = kind == null ? Kind.STRING : kind;
|
||||
this.name = name == null ? "" : name;
|
||||
this.title = title == null || title.isBlank() ? this.name : title;
|
||||
this.def = def;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected final S self() {
|
||||
return (S) this;
|
||||
}
|
||||
|
||||
protected abstract T decode(String raw);
|
||||
|
||||
protected abstract String encode(T value);
|
||||
|
||||
protected T sanitizeTyped(T value) {
|
||||
return value == null ? def : value;
|
||||
}
|
||||
|
||||
public final void attach(SettingOwner owner) {
|
||||
this.owner = owner;
|
||||
this.cached = false;
|
||||
}
|
||||
|
||||
private String stored() {
|
||||
if (owner == null) return defaultValue();
|
||||
String raw = owner.settingValue(name);
|
||||
return raw == null ? defaultValue() : raw;
|
||||
}
|
||||
|
||||
public final T get() {
|
||||
String raw = stored();
|
||||
if (cached && Objects.equals(raw, cachedRaw)) return cachedValue;
|
||||
T value = decode(raw);
|
||||
cachedRaw = raw;
|
||||
cachedValue = value;
|
||||
cached = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
public final void set(T value) {
|
||||
if (owner != null) owner.putSettingValue(name, encode(sanitizeTyped(value)));
|
||||
}
|
||||
|
||||
public final T defaultValueTyped() {
|
||||
return def;
|
||||
}
|
||||
|
||||
public final S description(String description) {
|
||||
this.description = description == null ? "" : description;
|
||||
return self();
|
||||
}
|
||||
|
||||
public final S group(String group) {
|
||||
this.group = group == null || group.isBlank() ? "General" : group;
|
||||
return self();
|
||||
}
|
||||
|
||||
public final S unit(String unit) {
|
||||
this.unit = unit == null ? "" : unit;
|
||||
return self();
|
||||
}
|
||||
|
||||
public final S visibleWhen(BooleanSupplier visible) {
|
||||
this.visible = visible;
|
||||
return self();
|
||||
}
|
||||
|
||||
public final S formatter(Function<String, String> formatter) {
|
||||
this.formatter = formatter;
|
||||
return self();
|
||||
}
|
||||
|
||||
public final S displayMode(DisplayMode displayMode) {
|
||||
this.displayMode = displayMode == null ? DisplayMode.DEFAULT : displayMode;
|
||||
return self();
|
||||
}
|
||||
|
||||
public final S readonlySummary() {
|
||||
return displayMode(DisplayMode.READONLY_SUMMARY);
|
||||
}
|
||||
|
||||
public final S numericTextField() {
|
||||
return displayMode(DisplayMode.NUMERIC_TEXT_FIELD);
|
||||
}
|
||||
|
||||
public final S playerNameList() {
|
||||
return displayMode(DisplayMode.PLAYER_NAME_LIST);
|
||||
}
|
||||
|
||||
public final S rankTagList() {
|
||||
return displayMode(DisplayMode.RANK_TAG_LIST);
|
||||
}
|
||||
|
||||
public final S macroPicker() {
|
||||
return displayMode(DisplayMode.MACRO_PICKER);
|
||||
}
|
||||
|
||||
public final S conditionalMacroPicker() {
|
||||
return displayMode(DisplayMode.CONDITIONAL_MACRO_PICKER);
|
||||
}
|
||||
|
||||
public final S filePicker(String linkedActionId) {
|
||||
this.linkedActionId = linkedActionId == null ? "" : linkedActionId;
|
||||
return displayMode(DisplayMode.FILE_PICKER);
|
||||
}
|
||||
|
||||
public final S linkedActionId(String linkedActionId) {
|
||||
this.linkedActionId = linkedActionId == null ? "" : linkedActionId;
|
||||
return self();
|
||||
}
|
||||
|
||||
public final S availableOffline() {
|
||||
this.availability = Availability.ALWAYS;
|
||||
return self();
|
||||
}
|
||||
|
||||
public final S requiresWorld() {
|
||||
this.availability = Availability.IN_WORLD;
|
||||
return self();
|
||||
}
|
||||
|
||||
public final S requiresContainer() {
|
||||
this.availability = Availability.IN_CONTAINER;
|
||||
return self();
|
||||
}
|
||||
|
||||
public final S build() {
|
||||
return self();
|
||||
}
|
||||
|
||||
protected final void setRange(double min, double max) {
|
||||
this.min = min;
|
||||
this.max = Math.max(min, max);
|
||||
}
|
||||
|
||||
protected final void setSliderRange(double min, double max) {
|
||||
this.sliderMin = min;
|
||||
this.sliderMax = Math.max(min, max);
|
||||
}
|
||||
|
||||
protected final void setStep(double step) {
|
||||
this.step = step <= 0 ? 1.0 : step;
|
||||
}
|
||||
|
||||
protected final void setChoices(List<String> choices) {
|
||||
this.choices = choices == null ? List.of() : List.copyOf(choices);
|
||||
}
|
||||
|
||||
protected final void setAction(Runnable action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public final String id() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public final String label() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public final String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public final String group() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public final Kind kind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
public final DisplayMode displayMode() {
|
||||
return displayMode;
|
||||
}
|
||||
|
||||
public final Availability availability() {
|
||||
return availability == null
|
||||
? (kind == Kind.ACTION ? Availability.IN_WORLD : Availability.ALWAYS)
|
||||
: availability;
|
||||
}
|
||||
|
||||
public final String unit() {
|
||||
return unit;
|
||||
}
|
||||
|
||||
public final List<String> choices() {
|
||||
return choices;
|
||||
}
|
||||
|
||||
public final double min() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public final double max() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public final double sliderMin() {
|
||||
return sliderMin;
|
||||
}
|
||||
|
||||
public final double sliderMax() {
|
||||
return sliderMax;
|
||||
}
|
||||
|
||||
public final double step() {
|
||||
return step;
|
||||
}
|
||||
|
||||
public final Runnable action() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public final String linkedActionId() {
|
||||
return linkedActionId;
|
||||
}
|
||||
|
||||
public final String defaultValue() {
|
||||
return encode(def);
|
||||
}
|
||||
|
||||
public final String serialize() {
|
||||
return stored();
|
||||
}
|
||||
|
||||
public final String displayString() {
|
||||
return format(serialize());
|
||||
}
|
||||
|
||||
public final String format(String value) {
|
||||
if (formatter == null) return value == null ? "" : value;
|
||||
try {
|
||||
return formatter.apply(value);
|
||||
} catch (Throwable t) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
}
|
||||
|
||||
public final String sanitizeUiString(String raw) {
|
||||
return encode(decode(raw));
|
||||
}
|
||||
|
||||
public final String deserialize(String raw) {
|
||||
return sanitizeUiString(raw);
|
||||
}
|
||||
|
||||
public final boolean isVisible() {
|
||||
if (visible == null) return true;
|
||||
try {
|
||||
return visible.getAsBoolean();
|
||||
} catch (Throwable t) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean isAvailable(boolean inWorld, boolean inContainer) {
|
||||
return switch (availability()) {
|
||||
case ALWAYS -> true;
|
||||
case IN_WORLD -> inWorld;
|
||||
case IN_CONTAINER -> inContainer;
|
||||
};
|
||||
}
|
||||
|
||||
public final boolean isModified() {
|
||||
return !Objects.equals(serialize(), defaultValue());
|
||||
}
|
||||
}
|
||||
18
src/main/java/autismclient/api/module/SettingGroup.java
Normal file
18
src/main/java/autismclient/api/module/SettingGroup.java
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public final class SettingGroup {
|
||||
private final String name;
|
||||
|
||||
public SettingGroup(String name) {
|
||||
this.name = name == null || name.isBlank() ? "General" : name;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public <T, S extends Setting<T, S>> S apply(S setting) {
|
||||
if (setting != null) setting.group(name);
|
||||
return setting;
|
||||
}
|
||||
}
|
||||
8
src/main/java/autismclient/api/module/SettingOwner.java
Normal file
8
src/main/java/autismclient/api/module/SettingOwner.java
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public interface SettingOwner {
|
||||
|
||||
String settingValue(String name);
|
||||
|
||||
void putSettingValue(String name, String value);
|
||||
}
|
||||
101
src/main/java/autismclient/api/module/SimpleModule.java
Normal file
101
src/main/java/autismclient/api/module/SimpleModule.java
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
import autismclient.api.AutismAddons;
|
||||
import autismclient.modules.Module;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class SimpleModule extends Module {
|
||||
private Consumer<SimpleModule> enableHandler;
|
||||
private Consumer<SimpleModule> disableHandler;
|
||||
private Consumer<SimpleModule> tickHandler;
|
||||
|
||||
public SimpleModule(String localId, String name, String description) {
|
||||
super(AutismAddons.id(localId), name, description);
|
||||
}
|
||||
|
||||
public final SimpleModule onEnabled(Consumer<SimpleModule> handler) {
|
||||
this.enableHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public final SimpleModule onDisabled(Consumer<SimpleModule> handler) {
|
||||
this.disableHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public final SimpleModule onTick(Consumer<SimpleModule> handler) {
|
||||
this.tickHandler = handler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public final SimpleModule addBool(String id, String label, boolean defaultValue) {
|
||||
add(new BoolSetting(id, label, defaultValue));
|
||||
return this;
|
||||
}
|
||||
|
||||
public final SimpleModule addInt(String id, String label, int defaultValue, int min, int max, int step) {
|
||||
add(new IntSetting(id, label, defaultValue, min, max, step));
|
||||
return this;
|
||||
}
|
||||
|
||||
public final SimpleModule addDouble(String id, String label, double defaultValue, double min, double max, double step) {
|
||||
add(new DoubleSetting(id, label, defaultValue, min, max, step));
|
||||
return this;
|
||||
}
|
||||
|
||||
public final SimpleModule addChoice(String id, String label, String defaultValue, String... choices) {
|
||||
add(new ChoiceSetting(id, label, defaultValue, choices == null ? new String[0] : choices));
|
||||
return this;
|
||||
}
|
||||
|
||||
public final SimpleModule addText(String id, String label, String defaultValue) {
|
||||
add(new StringSetting(id, label, defaultValue));
|
||||
return this;
|
||||
}
|
||||
|
||||
public final SimpleModule addColor(String id, String label, int defaultArgb) {
|
||||
add(new ColorSetting(id, label, defaultArgb));
|
||||
return this;
|
||||
}
|
||||
|
||||
public final boolean getBool(String id) {
|
||||
return bool(id);
|
||||
}
|
||||
|
||||
public final int getInt(String id) {
|
||||
return integer(id);
|
||||
}
|
||||
|
||||
public final double getDouble(String id) {
|
||||
return decimal(id);
|
||||
}
|
||||
|
||||
public final String getText(String id) {
|
||||
return text(id);
|
||||
}
|
||||
|
||||
public final String getChoice(String id) {
|
||||
return choice(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
if (enableHandler != null) enableHandler.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (disableHandler != null) disableHandler.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (tickHandler != null) tickHandler.accept(this);
|
||||
}
|
||||
|
||||
protected final String upper(String value) {
|
||||
return value == null ? "" : value.toUpperCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
17
src/main/java/autismclient/api/module/StringListSetting.java
Normal file
17
src/main/java/autismclient/api/module/StringListSetting.java
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class StringListSetting extends ListSetting<StringListSetting> {
|
||||
public StringListSetting(String name, String title) {
|
||||
super(Kind.STRING_LIST, name, title, List.of());
|
||||
}
|
||||
|
||||
public StringListSetting(String name, String title, List<String> defaultValue) {
|
||||
super(Kind.STRING_LIST, name, title, defaultValue);
|
||||
}
|
||||
|
||||
public StringListSetting(String name, String title, String defaultValue) {
|
||||
super(Kind.STRING_LIST, name, title, defaultValue);
|
||||
}
|
||||
}
|
||||
17
src/main/java/autismclient/api/module/StringSetting.java
Normal file
17
src/main/java/autismclient/api/module/StringSetting.java
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package autismclient.api.module;
|
||||
|
||||
public final class StringSetting extends Setting<String, StringSetting> {
|
||||
public StringSetting(String name, String title, String defaultValue) {
|
||||
super(Kind.STRING, name, title, defaultValue == null ? "" : defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String decode(String raw) {
|
||||
return raw == null ? "" : raw;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String encode(String value) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue