diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 97373a0..a9149f4 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -19,6 +19,7 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
+ submodules: 'recursive'
- name: Checkout workflows repo
uses: actions/checkout@v4
with:
@@ -42,7 +43,7 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Compile the mod
- run: ./gradlew --build-cache --info --stacktrace assemble
+ run: ./gradlew --build-cache --info --stacktrace :core:test assemble
- name: Attach compilation artifacts
uses: actions/upload-artifact@v4
with:
diff --git a/.github/workflows/release-tags.yml b/.github/workflows/release-tags.yml
index ae885f3..b50baa5 100644
--- a/.github/workflows/release-tags.yml
+++ b/.github/workflows/release-tags.yml
@@ -23,6 +23,7 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 32
+ submodules: 'recursive'
- name: Set up JDK versions
uses: actions/setup-java@v4
@@ -70,7 +71,12 @@ jobs:
-f tag_name="${RELEASE_VERSION}" \
--jq ".body" > "${CHANGELOG_FILE}"
cat "${CHANGELOG_FILE}"
- gh release create "${RELEASE_VERSION}" -F "${CHANGELOG_FILE}" $PRERELEASE ./build/libs/*.jar
+ mapfile -t RELEASE_JARS < <(find build/libs -maxdepth 1 -name '*.jar' ! -name '*-sources*' ! -name '*-slim*')
+ if [[ ${#RELEASE_JARS[@]} -eq 0 ]]; then
+ echo "No production jar found in build/libs"
+ exit 1
+ fi
+ gh release create "${RELEASE_VERSION}" -F "${CHANGELOG_FILE}" $PRERELEASE "${RELEASE_JARS[@]}"
shell: bash
continue-on-error: true
env:
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..d1df2d5
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "core"]
+ path = core
+ url = https://github.com/kuba6000/AE2-Web-Integration.git
+ branch = core
diff --git a/build.gradle b/build.gradle
index 98c75fd..e9ca578 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,7 @@
plugins {
id 'java-library'
id 'net.neoforged.moddev' version '2.0.113'
+ id 'com.gradleup.shadow' version '9.4.2'
id 'idea'
id 'maven-publish'
id 'com.diffplug.spotless' version '7.0.2'
@@ -72,6 +73,9 @@ afterEvaluate {
}
apply from: "$rootDir/gradle/scripts/jars.gradle"
+if (findProperty('usesShadowedDependencies')?.toString()?.toBoolean()) {
+ apply from: "$rootDir/gradle/scripts/shadow.gradle"
+}
apply from: "$rootDir/gradle/scripts/moddevgradle.gradle"
apply from: "$rootDir/gradle/scripts/repositories.gradle"
apply from: "$rootDir/dependencies.gradle"
diff --git a/core b/core
new file mode 160000
index 0000000..eb7a313
--- /dev/null
+++ b/core
@@ -0,0 +1 @@
+Subproject commit eb7a31329a458cb32dc110581e333a029e4e93e0
diff --git a/core_compile_output.txt b/core_compile_output.txt
new file mode 100644
index 0000000..9292ca2
--- /dev/null
+++ b/core_compile_output.txt
@@ -0,0 +1,30 @@
+
+[Incubating] Problems report is available at: file:///C:/github/AE2-Web-Integration/build/reports/problems/problems-report.html
+.\gradlew.bat :
+At C:\Users\TellingSalamander\AppData\Local\Temp\.ctx-mode-ocpAC8\script.ps1:1 char:35
++ ... hub\AE2-Web-Integration; .\gradlew.bat :core:compileJava 2>&1 | Out-F ...
++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ + CategoryInfo : NotSpecified: (:String) [], RemoteException
+ + FullyQualifiedErrorId : NativeCommandError
+
+FAILURE: Build failed with an exception.
+
+* What went wrong:
+Cannot locate tasks that match ':core:compileJava' as project 'core' not found in root project 'ae2webintegration'.
+
+* Try:
+> Run gradlew projects to get a list of available projects.
+> For more on name expansion, please refer to https://docs.gradle.org/9.1.0/userguide/command_line_interface.html#sec:n
+ame_abbreviation in the Gradle documentation.
+> Run with --stacktrace option to get the stack trace.
+> Run with --info or --debug option to get more log output.
+> Run with --scan to generate a Build Scan (Powered by Develocity).
+> Get more help at https://help.gradle.org.
+
+Deprecated Gradle features were used in this build, making it incompatible with Gradle 10.
+
+You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
+
+For more on this, please refer to https://docs.gradle.org/9.1.0/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
+
+BUILD FAILED in 2s
diff --git a/dependencies.gradle b/dependencies.gradle
index 52550af..3b90a82 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -1,6 +1,9 @@
dependencies {
compileOnly(libs.jetbrains.annotations)
+ // Core submodule (pure Java — no NeoForge/MC/AE2 references)
+ implementation project(':core')
+
// AE2
implementation(neoforge.ae2)
compileOnly(neoforge.ae2wtlib)
diff --git a/gradle.properties b/gradle.properties
index 882f36d..d0578c2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -12,3 +12,8 @@ mod_license = LGPL-3.0 license
mod_url = https://github.com/kuba6000/AE2-Web-Integration
mod_issue_tracker = https://github.com/kuba6000/AE2-Web-Integration/issues/
maven_group =
+
+# Shadow core submodule into the production jar (see gradle/scripts/shadow.gradle)
+usesShadowedDependencies = true
+minimizeShadowedDependencies = false
+relocateShadowedDependencies = true
diff --git a/gradle/scripts/jars.gradle b/gradle/scripts/jars.gradle
index 025441b..063cd53 100644
--- a/gradle/scripts/jars.gradle
+++ b/gradle/scripts/jars.gradle
@@ -11,14 +11,14 @@ java {
withSourcesJar()
}
-jar.archiveClassifier = "dev"
-
base {
archivesName = "${project.name}" // -${libs.versions.minecraft.get()}
}
afterEvaluate {
- jar.archiveClassifier = ""
+ if (!findProperty('usesShadowedDependencies')?.toString()?.toBoolean()) {
+ jar.archiveClassifier = ''
+ }
tasks.withType(org.gradle.jvm.tasks.Jar).configureEach {
destinationDirectory = file('build/libs/')
manifest.attributes([
diff --git a/gradle/scripts/shadow.gradle b/gradle/scripts/shadow.gradle
new file mode 100644
index 0000000..11325b8
--- /dev/null
+++ b/gradle/scripts/shadow.gradle
@@ -0,0 +1,49 @@
+def shadowRelocationPrefix = 'pl.kuba6000.ae2webintegration.shadow'
+
+configurations {
+ coreShadow {
+ canBeConsumed = false
+ canBeResolved = true
+ }
+}
+
+dependencies {
+ coreShadow(project(':core')) {
+ transitive = true
+ }
+}
+
+tasks.named('shadowJar').configure {
+ dependsOn(':core:jar')
+ archiveClassifier = ''
+ configurations = [project.configurations.coreShadow]
+
+ dependencies {
+ exclude(dependency('org.apache.logging.log4j:log4j-api:.*'))
+ exclude(dependency('org.apache.logging.log4j:log4j-core:.*'))
+ }
+
+ if (findProperty('relocateShadowedDependencies')?.toString()?.toBoolean() != false) {
+ relocate('com.google', "${shadowRelocationPrefix}.com.google")
+ relocate('org.apache.commons', "${shadowRelocationPrefix}.org.apache.commons")
+ relocate('commons-io', "${shadowRelocationPrefix}.commons-io")
+ relocate('club.minnced', "${shadowRelocationPrefix}.club.minnced")
+ relocate(
+ 'pl.kuba6000.ae2webintegration.core',
+ "${shadowRelocationPrefix}.pl.kuba6000.ae2webintegration.core")
+ }
+}
+
+tasks.named('jar', Jar).configure {
+ enabled = false
+ finalizedBy(tasks.named('shadowJar'))
+}
+
+configurations.runtimeElements.outgoing.artifacts.clear()
+configurations.apiElements.outgoing.artifacts.clear()
+configurations.runtimeElements.outgoing.artifact(tasks.named('shadowJar'))
+configurations.apiElements.outgoing.artifact(tasks.named('shadowJar'))
+
+configurations.named('shadowRuntimeElements') {
+ outgoing.artifacts.clear()
+}
diff --git a/settings.gradle b/settings.gradle
index a0545e6..d1f092c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -20,3 +20,5 @@ dependencyResolutionManagement {
}
rootProject.name = "${mod_id}"
+
+include ':core'
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/AE2WebIntegration.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/AE2WebIntegration.java
index 8c9811c..5f50bed 100644
--- a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/AE2WebIntegration.java
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/AE2WebIntegration.java
@@ -1,41 +1,75 @@
package pl.kuba6000.ae2webintegration.ae2interface;
import net.neoforged.bus.api.SubscribeEvent;
+import net.neoforged.fml.ModContainer;
+import net.neoforged.fml.ModLoadingContext;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.common.Mod;
+import net.neoforged.fml.config.ModConfig;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
+import net.neoforged.neoforge.event.RegisterCommandsEvent;
+import net.neoforged.neoforge.event.server.ServerStartedEvent;
+import net.neoforged.neoforge.event.server.ServerStoppingEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import pl.kuba6000.ae2webintegration.ae2interface.commands.CommandBuilder;
+import pl.kuba6000.ae2webintegration.ae2interface.config.Config;
import pl.kuba6000.ae2webintegration.ae2interface.implementations.AE;
+import pl.kuba6000.ae2webintegration.ae2interface.platform.Platform;
+import pl.kuba6000.ae2webintegration.ae2interface.proxy.CommonProxy;
+import pl.kuba6000.ae2webintegration.core.CommandBootstrap;
import pl.kuba6000.ae2webintegration.core.api.IAEWebInterface;
@Mod(value = AE2WebIntegration.MODID)
+@EventBusSubscriber(modid = AE2WebIntegration.MODID)
public class AE2WebIntegration {
- public static final String MODID = "ae2webintegration_interface";
+ public static final String MODID = "ae2webintegration";
public static final Logger LOG = LogManager.getLogger(MODID);
+ private static final CommonProxy PROXY = new CommonProxy();
+
public AE2WebIntegration() {
- // ModLoadingContext.get()
- // .registerExtensionPoint(
- // IExtensionPoint.DisplayTest.class,
- // () -> new IExtensionPoint.DisplayTest(() -> NetworkConstants.IGNORESERVERONLY, (a, b) -> true));
- // SecurityCache.registerOpPlayer(
- // IAEWebInterface.getInstance()
- // .getAEWebGameProfile());
+ Platform platform = new Platform();
+ String version = ModLoadingContext.get()
+ .getActiveContainer()
+ .getModInfo()
+ .getVersion()
+ .toString();
+
+ // Register config before anything that depends on it
+ ModContainer container = ModLoadingContext.get()
+ .getActiveContainer();
+ container.registerConfig(ModConfig.Type.COMMON, Config.SPEC, "ae2webintegration/ae2webintegration.toml");
+
+ // Delegate remaining init to the proxy
+ PROXY.preInit(platform, version);
}
@EventBusSubscriber(modid = MODID, bus = EventBusSubscriber.Bus.MOD)
- private static class eventHandler {
+ private static class ModEventHandler {
@SubscribeEvent
public static void commonSetup(FMLCommonSetupEvent event) {
- // This is where you can do common setup tasks
IAEWebInterface.getInstance()
.initAEInterface(AE.instance);
}
}
+ @SubscribeEvent
+ public static void commandsRegister(RegisterCommandsEvent event) {
+ CommandBootstrap.init(new CommandBuilder(event.getDispatcher()));
+ }
+
+ @SubscribeEvent
+ public static void serverStarted(ServerStartedEvent event) {
+ PROXY.onServerStarted();
+ }
+
+ @SubscribeEvent
+ public static void serverStopping(ServerStoppingEvent event) {
+ PROXY.onServerStopping();
+ }
}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/FMLEventHandler.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/FMLEventHandler.java
similarity index 54%
rename from src/main/java/pl/kuba6000/ae2webintegration/core/FMLEventHandler.java
rename to src/main/java/pl/kuba6000/ae2webintegration/ae2interface/FMLEventHandler.java
index 7d18c84..9d69b33 100644
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/FMLEventHandler.java
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/FMLEventHandler.java
@@ -1,9 +1,5 @@
-package pl.kuba6000.ae2webintegration.core;
+package pl.kuba6000.ae2webintegration.ae2interface;
-import static pl.kuba6000.ae2webintegration.core.AE2WebIntegration.MODID;
-
-import net.minecraft.ChatFormatting;
-import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.neoforged.bus.api.SubscribeEvent;
@@ -11,10 +7,12 @@
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.event.tick.ServerTickEvent;
+import pl.kuba6000.ae2webintegration.core.AE2Controller;
+import pl.kuba6000.ae2webintegration.core.UpdateNotifier;
import pl.kuba6000.ae2webintegration.core.ae2request.sync.ISyncedRequest;
-import pl.kuba6000.ae2webintegration.core.utils.VersionChecker;
+import pl.kuba6000.ae2webintegration.core.api.PlayerIdentity;
-@EventBusSubscriber(modid = MODID)
+@EventBusSubscriber(modid = AE2WebIntegration.MODID)
public class FMLEventHandler {
@SubscribeEvent
@@ -31,13 +29,11 @@ public static void tick(ServerTickEvent.Pre event) {
@SubscribeEvent
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
Player player = event.getEntity();
- if (!(player instanceof ServerPlayer)) return;
- if (Config.INSTANCE.CHECK_FOR_UPDATES.get() && VersionChecker.isOutdated() && player.hasPermissions(4)) {
- player.sendSystemMessage(
- Component.literal(
- ChatFormatting.GREEN.toString() + ChatFormatting.BOLD
- + "----> AE2WebIntegration -> New version detected! Consider updating at https://github.com/kuba6000/AE2-Web-Integration/releases/latest"));
- }
- }
+ if (!(player instanceof ServerPlayer serverPlayer)) return;
+ if (!serverPlayer.hasPermissions(4)) return;
+ PlayerIdentity identity = new PlayerIdentity(serverPlayer.getUUID(), serverPlayer.getScoreboardName());
+ PlayerMessenger messenger = new PlayerMessenger();
+ UpdateNotifier.notifyPlayerIfOutdated(messenger, identity);
+ }
}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/PlayerMessenger.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/PlayerMessenger.java
new file mode 100644
index 0000000..fa3a466
--- /dev/null
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/PlayerMessenger.java
@@ -0,0 +1,25 @@
+package pl.kuba6000.ae2webintegration.ae2interface;
+
+import net.minecraft.ChatFormatting;
+import net.minecraft.network.chat.Component;
+import net.minecraft.server.level.ServerPlayer;
+import net.neoforged.neoforge.server.ServerLifecycleHooks;
+
+import pl.kuba6000.ae2webintegration.core.api.IPlayerMessenger;
+import pl.kuba6000.ae2webintegration.core.api.PlayerIdentity;
+
+public class PlayerMessenger implements IPlayerMessenger {
+
+ @Override
+ public void sendMessage(PlayerIdentity player, String message) {
+ if (ServerLifecycleHooks.getCurrentServer() == null) return;
+ ServerPlayer serverPlayer = ServerLifecycleHooks.getCurrentServer()
+ .getPlayerList()
+ .getPlayer(player.uuid);
+ if (serverPlayer != null) {
+ serverPlayer.sendSystemMessage(
+ Component.literal(message)
+ .withStyle(ChatFormatting.GREEN, ChatFormatting.BOLD));
+ }
+ }
+}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/commands/CommandBuilder.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/commands/CommandBuilder.java
new file mode 100644
index 0000000..7109128
--- /dev/null
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/commands/CommandBuilder.java
@@ -0,0 +1,149 @@
+package pl.kuba6000.ae2webintegration.ae2interface.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.commands.Commands;
+
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.arguments.StringArgumentType;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+
+import pl.kuba6000.ae2webintegration.core.api.ICommandBuilder;
+import pl.kuba6000.ae2webintegration.core.api.ICommandContext;
+
+/**
+ * {@link ICommandBuilder} implementation that builds a Brigadier command tree
+ * and registers it with the {@link CommandDispatcher}.
+ *
+ * The tree is stored in simple data nodes during the fluent construction phase
+ * (no Brigadier objects involved). At {@link #register()} time the data tree
+ * is walked depth-first and the full Brigadier tree is built from scratch,
+ * ensuring every subtree is complete before it's attached via {@code .then()}.
+ */
+public class CommandBuilder implements ICommandBuilder {
+
+ /** A node in the command tree. */
+ private static class CommandNode {
+
+ final String name;
+ final int permission;
+ final boolean isArgument;
+ final List children = new ArrayList<>();
+ Consumer handler;
+
+ CommandNode(String name, int permission, boolean isArgument) {
+ this.name = name;
+ this.permission = permission;
+ this.isArgument = isArgument;
+ }
+ }
+
+ private final CommandDispatcher dispatcher;
+ private final ICommandBuilder fluentParent;
+ private final boolean isRoot;
+ private final CommandNode currentNode;
+ private final List rootNodes;
+
+ /** Root constructor — called by AE2WebIntegration. */
+ public CommandBuilder(CommandDispatcher dispatcher) {
+ this.dispatcher = dispatcher;
+ this.fluentParent = null;
+ this.isRoot = true;
+ this.currentNode = null;
+ this.rootNodes = new ArrayList<>();
+ }
+
+ /** Child constructor — created by {@link #literal} and {@link #argument}. */
+ private CommandBuilder(ICommandBuilder fluentParent, CommandNode currentNode, List rootNodes) {
+ this.dispatcher = null;
+ this.fluentParent = fluentParent;
+ this.isRoot = false;
+ this.currentNode = currentNode;
+ this.rootNodes = rootNodes;
+ }
+
+ @Override
+ public ICommandBuilder literal(String name, int permission) {
+ CommandNode child = new CommandNode(name, permission, false);
+
+ if (isRoot) {
+ rootNodes.add(child);
+ } else if (currentNode != null) {
+ currentNode.children.add(child);
+ }
+
+ return new CommandBuilder(this, child, rootNodes);
+ }
+
+ @Override
+ public ICommandBuilder argument(String name) {
+ CommandNode child = new CommandNode(name, 0, true);
+
+ if (currentNode != null) {
+ currentNode.children.add(child);
+ }
+
+ return new CommandBuilder(this, child, rootNodes);
+ }
+
+ @Override
+ public ICommandBuilder executes(Consumer handler) {
+ if (currentNode != null) {
+ currentNode.handler = handler;
+ }
+ return fluentParent;
+ }
+
+ @Override
+ public void register() {
+ for (CommandNode root : rootNodes) {
+ dispatcher.register(buildLiteral(root));
+ }
+ }
+
+ /** Builds a Brigadier {@link LiteralArgumentBuilder} from a data node. */
+ private static LiteralArgumentBuilder buildLiteral(CommandNode node) {
+ LiteralArgumentBuilder lit = Commands.literal(node.name)
+ .requires(s -> s.hasPermission(node.permission));
+
+ if (node.handler != null) {
+ lit.executes(ctx -> {
+ node.handler.accept(new CommandContext(ctx));
+ return 1;
+ });
+ }
+
+ for (CommandNode child : node.children) {
+ lit.then(buildChild(child));
+ }
+
+ return lit;
+ }
+
+ /** Builds a child node (literal or argument) from a data node. */
+ private static com.mojang.brigadier.builder.ArgumentBuilder buildChild(CommandNode node) {
+ if (node.isArgument) {
+ RequiredArgumentBuilder arg = Commands
+ .argument(node.name, StringArgumentType.word());
+
+ if (node.handler != null) {
+ arg.executes(ctx -> {
+ node.handler.accept(new CommandContext(ctx));
+ return 1;
+ });
+ }
+
+ for (CommandNode child : node.children) {
+ arg.then(buildChild(child));
+ }
+
+ return arg;
+ } else {
+ return buildLiteral(node);
+ }
+ }
+}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/commands/CommandContext.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/commands/CommandContext.java
new file mode 100644
index 0000000..ac604da
--- /dev/null
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/commands/CommandContext.java
@@ -0,0 +1,94 @@
+package pl.kuba6000.ae2webintegration.ae2interface.commands;
+
+import java.util.UUID;
+
+import net.minecraft.ChatFormatting;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.network.chat.Component;
+import net.minecraft.server.level.ServerPlayer;
+import net.neoforged.fml.config.ConfigTracker;
+import net.neoforged.fml.config.ModConfig;
+
+import pl.kuba6000.ae2webintegration.core.Config;
+import pl.kuba6000.ae2webintegration.core.api.ICommandContext;
+
+/**
+ * {@link ICommandContext} implementation wrapping a NeoForge Brigadier
+ * {@link CommandContext}.
+ *
+ * Args are extracted from the raw command input string by splitting on
+ * whitespace and dropping the first element (the command name).
+ */
+public class CommandContext implements ICommandContext {
+
+ private final com.mojang.brigadier.context.CommandContext context;
+ private final String[] args;
+
+ public CommandContext(com.mojang.brigadier.context.CommandContext context) {
+ this.context = context;
+ this.args = parseArgs(context.getInput());
+ }
+
+ private static String[] parseArgs(String input) {
+ String[] parts = input.split(" ");
+ if (parts.length <= 1) {
+ return new String[0];
+ }
+ String[] result = new String[parts.length - 1];
+ System.arraycopy(parts, 1, result, 0, parts.length - 1);
+ return result;
+ }
+
+ @Override
+ public String[] getArgs() {
+ return args;
+ }
+
+ @Override
+ public UUID getPlayerUUID() {
+ ServerPlayer player = context.getSource()
+ .getPlayer();
+ return player != null ? player.getUUID() : null;
+ }
+
+ @Override
+ public boolean hasPermission(int level) {
+ return context.getSource()
+ .hasPermission(level);
+ }
+
+ @Override
+ public void sendMessage(String text) {
+ context.getSource()
+ .sendSuccess(
+ () -> Component.literal(text)
+ .withStyle(ChatFormatting.GREEN),
+ false);
+ }
+
+ @Override
+ public void sendError(String text) {
+ context.getSource()
+ .sendFailure(
+ Component.literal(text)
+ .withStyle(ChatFormatting.RED));
+ }
+
+ /**
+ * Returns a Runnable that restarts the HTTP server.
+ *
+ * Reloads the common config file from disk before the HTTP server restarts.
+ */
+ @Override
+ public Runnable getReloader() {
+ return () -> {
+ if (Config.getConfigDirectory() == null) {
+ return;
+ }
+ ConfigTracker.INSTANCE.loadConfigs(
+ ModConfig.Type.COMMON,
+ Config.getConfigDirectory()
+ .toPath());
+ };
+ }
+}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/config/Config.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/config/Config.java
new file mode 100644
index 0000000..94f9d5a
--- /dev/null
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/config/Config.java
@@ -0,0 +1,52 @@
+package pl.kuba6000.ae2webintegration.ae2interface.config;
+
+import net.neoforged.bus.api.SubscribeEvent;
+import net.neoforged.fml.common.EventBusSubscriber;
+import net.neoforged.fml.event.config.ModConfigEvent;
+import net.neoforged.neoforge.common.ModConfigSpec;
+
+import pl.kuba6000.ae2webintegration.ae2interface.AE2WebIntegration;
+import pl.kuba6000.ae2webintegration.core.AE2Controller;
+import pl.kuba6000.ae2webintegration.core.ConfigBootstrap;
+
+/**
+ * NeoForge config wiring. This class does NOT define what config keys exist —
+ * that is owned by {@link ConfigBootstrap}. Instead it:
+ *
+ * Creates a {@link ModConfigSpec.Builder}
+ * Wraps it in a {@link ConfigBuilder}
+ * Passes the wrapper to {@link ConfigBootstrap#init} so core defines all keys
+ * Builds the {@link ModConfigSpec} and exposes it as {@link #SPEC}
+ *
+ *
+ * Because {@link ConfigValue} reads live from the NeoForge config
+ * system on every {@code get()}, no explicit value-copying step is needed —
+ * values are always current after NeoForge fires its config events.
+ */
+@EventBusSubscriber(modid = AE2WebIntegration.MODID, bus = EventBusSubscriber.Bus.MOD)
+public class Config {
+
+ public static final ModConfigSpec SPEC;
+
+ static {
+ ModConfigSpec.Builder builder = new ModConfigSpec.Builder();
+ ConfigBootstrap.init(new ConfigBuilder(builder));
+ SPEC = builder.build();
+ }
+
+ private Config() {}
+
+ // --- Event handlers ---
+
+ @SubscribeEvent
+ public static void onConfigLoading(ModConfigEvent.Loading event) {
+ AE2WebIntegration.LOG.info("Config loaded");
+ }
+
+ @SubscribeEvent
+ public static void onConfigReloading(ModConfigEvent.Reloading event) {
+ AE2Controller.stopHTTPServer();
+ AE2Controller.startHTTPServer();
+ AE2WebIntegration.LOG.info("Config reloaded, web server restarted");
+ }
+}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/config/ConfigBuilder.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/config/ConfigBuilder.java
new file mode 100644
index 0000000..d9c4337
--- /dev/null
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/config/ConfigBuilder.java
@@ -0,0 +1,56 @@
+package pl.kuba6000.ae2webintegration.ae2interface.config;
+
+import net.neoforged.neoforge.common.ModConfigSpec;
+
+import pl.kuba6000.ae2webintegration.core.api.IConfigBuilder;
+import pl.kuba6000.ae2webintegration.core.api.IConfigValue;
+
+/**
+ * {@link IConfigBuilder} implementation that wraps NeoForge's
+ * {@link ModConfigSpec.Builder}.
+ *
+ * Each {@code defineXxx} call:
+ *
+ * Sets the human-readable comment on the NeoForge builder
+ * Delegates to the appropriate {@code define} / {@code defineInRange} method
+ * Returns a {@link ConfigValue} wrapping the resulting
+ * {@link ModConfigSpec.ConfigValue} together with the hardcoded default
+ * (used as fallback before {@code ModConfigEvent.Loading} fires)
+ *
+ *
+ * All config keys are defined at the root level (no {@code push}/{@code pop}
+ * categories). Categories can be added later if needed by extending the
+ * {@link IConfigBuilder} contract.
+ */
+public class ConfigBuilder implements IConfigBuilder {
+
+ private final ModConfigSpec.Builder builder;
+
+ public ConfigBuilder(ModConfigSpec.Builder builder) {
+ this.builder = builder;
+ }
+
+ @Override
+ public IConfigValue defineInt(String key, int defaultValue, int min, int max, String comment) {
+ return new ConfigValue<>(
+ builder.comment(comment)
+ .defineInRange(key, defaultValue, min, max),
+ defaultValue);
+ }
+
+ @Override
+ public IConfigValue defineString(String key, String defaultValue, String comment) {
+ return new ConfigValue<>(
+ builder.comment(comment)
+ .define(key, defaultValue),
+ defaultValue);
+ }
+
+ @Override
+ public IConfigValue defineBoolean(String key, boolean defaultValue, String comment) {
+ return new ConfigValue<>(
+ builder.comment(comment)
+ .define(key, defaultValue),
+ defaultValue);
+ }
+}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/config/ConfigValue.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/config/ConfigValue.java
new file mode 100644
index 0000000..6bc9789
--- /dev/null
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/config/ConfigValue.java
@@ -0,0 +1,41 @@
+package pl.kuba6000.ae2webintegration.ae2interface.config;
+
+import net.neoforged.neoforge.common.ModConfigSpec;
+
+import pl.kuba6000.ae2webintegration.core.api.IConfigValue;
+
+/**
+ * Wraps a NeoForge {@link ModConfigSpec.ConfigValue} inside the
+ * platform-agnostic {@link IConfigValue} interface.
+ *
+ * Until {@code ModConfigEvent.Loading} fires, {@code ConfigValue.get()}
+ * throws {@link IllegalStateException}. This wrapper catches that and returns
+ * the hardcoded default, allowing code that runs before the config
+ * event (e.g. static initializers triggered by {@code WebEngine.init()}) to
+ * read configuration values without crashing.
+ *
+ * After the loading event, every call to {@link #get()} reads from the live
+ * NeoForge config system — no explicit reload/apply step is required.
+ *
+ * @param the value type (Integer, String, Boolean)
+ */
+public class ConfigValue implements IConfigValue {
+
+ private final ModConfigSpec.ConfigValue configValue;
+ private final T defaultValue;
+
+ public ConfigValue(ModConfigSpec.ConfigValue configValue, T defaultValue) {
+ this.configValue = configValue;
+ this.defaultValue = defaultValue;
+ }
+
+ @Override
+ public T get() {
+ try {
+ return configValue.get();
+ } catch (IllegalStateException e) {
+ // Config not yet loaded — return the hardcoded default.
+ return defaultValue;
+ }
+ }
+}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/CraftingCPULogicMixin.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/CraftingCPULogicMixin.java
index 55539f4..1c1f880 100644
--- a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/CraftingCPULogicMixin.java
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/CraftingCPULogicMixin.java
@@ -85,11 +85,11 @@ public class CraftingCPULogicMixin implements ICraftingCPULogicAccessor {
private boolean ae2webintegration$pushPattern(ICraftingProvider medium, IPatternDetails details, KeyCounter[] ic) {
if (medium.pushPattern(details, ic)) {
IGridNode viewable = null;
- Map mediumToViewable = ((IAECraftingGrid) cluster.getGrid()
+ Map mediumToViewable = ((IAECraftingGrid) cluster.getGrid()
.getService(ICraftingService.class)).web$getCraftingProviders()
.web$getCraftingMediums();
if (mediumToViewable != null) {
- viewable = mediumToViewable.get(medium);
+ viewable = (IGridNode) mediumToViewable.get(medium);
}
IAEMixinCallbacks.getInstance()
.pushedPattern(
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/NetworkCraftingProvidersMixin.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/NetworkCraftingProvidersMixin.java
index 46b8eda..68d480c 100644
--- a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/NetworkCraftingProvidersMixin.java
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/NetworkCraftingProvidersMixin.java
@@ -43,7 +43,8 @@ private Object onRemoveProvider(Map map, Object node)
}
@Override
- public Map web$getCraftingMediums() {
- return web$providerToNode;
+ @SuppressWarnings("unchecked")
+ public Map web$getCraftingMediums() {
+ return (Map) (Map, ?>) web$providerToNode;
}
}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/AEGridMixin.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/AEGridMixin.java
index 84da40a..3ab40c3 100644
--- a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/AEGridMixin.java
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/AEGridMixin.java
@@ -28,6 +28,7 @@
import appeng.me.helpers.PlayerSource;
import appeng.parts.reporting.AbstractTerminalPart;
import pl.kuba6000.ae2webintegration.core.AE2Controller;
+import pl.kuba6000.ae2webintegration.core.api.PlayerIdentity;
import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
import pl.kuba6000.ae2webintegration.core.interfaces.service.IAECraftingGrid;
import pl.kuba6000.ae2webintegration.core.interfaces.service.IAEPathingGrid;
@@ -110,13 +111,20 @@ public abstract class AEGridMixin implements IAEGrid, IAESecurityGrid {
else return web$cachedPlayerSource;
}
- web$cachedPlayerSource = new PlayerSource(new FakePlayer(world, AE2Controller.AEControllerProfile) {
+ PlayerIdentity controllerProfile = AE2Controller.AEControllerProfile;
+ if (controllerProfile == null) {
+ controllerProfile = new PlayerIdentity(AE2Controller.AEControllerUUID, "AE2CONTROLLER");
+ }
- @Override
- public void sendSystemMessage(Component p_component, boolean bypassHiddenChat) {
- web$lastFakePlayerChatMessage = p_component;
- }
- }, actionHost);
+ web$cachedPlayerSource = new PlayerSource(
+ new FakePlayer(world, new GameProfile(controllerProfile.uuid, controllerProfile.name)) {
+
+ @Override
+ public void sendSystemMessage(Component p_component, boolean bypassHiddenChat) {
+ web$lastFakePlayerChatMessage = p_component;
+ }
+ },
+ actionHost);
return web$cachedPlayerSource;
}
@@ -224,16 +232,20 @@ public void sendSystemMessage(Component p_component, boolean bypassHiddenChat) {
}
@Override
- public GameProfile web$getOwnerProfile() {
+ public PlayerIdentity web$getOwnerProfile() {
UUID profileID = IPlayerRegistry.getMapping(ServerLifecycleHooks.getCurrentServer())
.getProfileId(web$getOwner());
if (profileID == null) {
return null;
}
- return ServerLifecycleHooks.getCurrentServer()
+ GameProfile profile = ServerLifecycleHooks.getCurrentServer()
.getProfileCache()
.get(profileID)
.orElse(null);
+ if (profile == null) {
+ return new PlayerIdentity(profileID, profileID.toString());
+ }
+ return new PlayerIdentity(profile.getId(), profile.getName());
}
@Override
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/AEPlayerDataMixin.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/AEPlayerDataMixin.java
index 3fb1f12..2a07e50 100644
--- a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/AEPlayerDataMixin.java
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/AEPlayerDataMixin.java
@@ -9,6 +9,7 @@
import com.mojang.authlib.GameProfile;
+import pl.kuba6000.ae2webintegration.core.api.PlayerIdentity;
import pl.kuba6000.ae2webintegration.core.interfaces.IAEPlayerData;
@Mixin(targets = "appeng.api.features.PlayerRegistryInternal", remap = false)
@@ -25,26 +26,32 @@ public UUID getProfileId(int playerId) {
}
@Override
- public GameProfile web$getPlayerProfile(int playerId) {
+ public PlayerIdentity web$getPlayerProfile(int playerId) {
UUID uuid = getProfileId(playerId);
if (uuid == null) return null;
- // for (final EntityPlayer player : CommonHelper.proxy.getPlayers()) {
- // if (player.getUniqueID().equals(uuid)) {
- // return player.getGameProfile();
- // }
- // }
- GameProfile p = ServerLifecycleHooks.getCurrentServer()
+ GameProfile profile = ServerLifecycleHooks.getCurrentServer()
.getProfileCache()
.get(uuid)
.orElse(null);
- if (p == null) {
- p = new GameProfile(uuid, uuid.toString());
+ if (profile == null) {
+ profile = new GameProfile(uuid, uuid.toString());
}
- return p;
+ return new PlayerIdentity(profile.getId(), profile.getName());
}
@Override
- public int web$getPlayerId(GameProfile id) {
- return getPlayerId(id.getId());
+ public int web$getPlayerId(UUID id) {
+ return getPlayerId(id);
+ }
+
+ @Override
+ public int web$getPlayerId(Object profile) {
+ if (profile instanceof PlayerIdentity identity) {
+ return getPlayerId(identity.uuid);
+ }
+ if (profile instanceof GameProfile gameProfile) {
+ return getPlayerId(gameProfile.getId());
+ }
+ return -1;
}
}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/service/AEStorageGridMixin.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/service/AEStorageGridMixin.java
index 8822b6e..200f04e 100644
--- a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/service/AEStorageGridMixin.java
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/AE2/implementations/service/AEStorageGridMixin.java
@@ -20,4 +20,17 @@ public class AEStorageGridMixin implements IAEStorageGrid {
public IAEMeInventoryItem web$getItemInventory() {
return (IAEMeInventoryItem) ((StorageService) (Object) this).getInventory();
}
+
+ @Override
+ public IItemList web$getFluidStorageList() {
+ // 1.21.1 AE2 unifies items and fluids; return the same available stacks
+ return (IItemList) (Object) ((StorageService) (Object) this).getInventory()
+ .getAvailableStacks();
+ }
+
+ @Override
+ public IAEMeInventoryItem web$getFluidInventory() {
+ // 1.21.1 AE2 unifies items and fluids; return the same inventory
+ return (IAEMeInventoryItem) ((StorageService) (Object) this).getInventory();
+ }
}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/advanced_ae/CraftingCPULogicMixin.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/advanced_ae/CraftingCPULogicMixin.java
index ae6ebcf..07a4593 100644
--- a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/advanced_ae/CraftingCPULogicMixin.java
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/mixins/advanced_ae/CraftingCPULogicMixin.java
@@ -86,11 +86,11 @@ public class CraftingCPULogicMixin implements ICraftingCPULogicAccessor {
private boolean ae2webintegration$pushPattern(ICraftingProvider medium, IPatternDetails details, KeyCounter[] ic) {
if (medium.pushPattern(details, ic)) {
IGridNode viewable = null;
- Map mediumToViewable = ((IAECraftingGrid) cpu.getGrid()
+ Map mediumToViewable = ((IAECraftingGrid) cpu.getGrid()
.getService(ICraftingService.class)).web$getCraftingProviders()
.web$getCraftingMediums();
if (mediumToViewable != null) {
- viewable = mediumToViewable.get(medium);
+ viewable = (IGridNode) mediumToViewable.get(medium);
}
IAEMixinCallbacks.getInstance()
.pushedPattern(
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/platform/Platform.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/platform/Platform.java
new file mode 100644
index 0000000..8c7ea98
--- /dev/null
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/platform/Platform.java
@@ -0,0 +1,34 @@
+package pl.kuba6000.ae2webintegration.ae2interface.platform;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.util.UUID;
+
+import net.minecraft.server.level.ServerPlayer;
+import net.neoforged.fml.loading.FMLPaths;
+import net.neoforged.neoforge.server.ServerLifecycleHooks;
+
+import pl.kuba6000.ae2webintegration.core.api.IServerPlatform;
+
+public class Platform implements IServerPlatform {
+
+ @Override
+ public UUID getOnlinePlayerUUID(String username) {
+ if (ServerLifecycleHooks.getCurrentServer() == null) return null;
+ ServerPlayer player = ServerLifecycleHooks.getCurrentServer()
+ .getPlayerList()
+ .getPlayerByName(username);
+ return player != null ? player.getUUID() : null;
+ }
+
+ @Override
+ public UUID getOfflinePlayerUUID(String username) {
+ return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
+ }
+
+ @Override
+ public File getConfigDirectory() {
+ return FMLPaths.CONFIGDIR.get()
+ .toFile();
+ }
+}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/proxy/CommonProxy.java b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/proxy/CommonProxy.java
new file mode 100644
index 0000000..4661d83
--- /dev/null
+++ b/src/main/java/pl/kuba6000/ae2webintegration/ae2interface/proxy/CommonProxy.java
@@ -0,0 +1,47 @@
+package pl.kuba6000.ae2webintegration.ae2interface.proxy;
+
+import pl.kuba6000.ae2webintegration.ae2interface.AE2WebIntegration;
+import pl.kuba6000.ae2webintegration.ae2interface.platform.Platform;
+import pl.kuba6000.ae2webintegration.core.AE2Controller;
+import pl.kuba6000.ae2webintegration.core.Config;
+import pl.kuba6000.ae2webintegration.core.GridData;
+import pl.kuba6000.ae2webintegration.core.StartupHandler;
+import pl.kuba6000.ae2webintegration.core.WebData;
+import pl.kuba6000.ae2webintegration.core.WebEngine;
+import pl.kuba6000.ae2webintegration.core.utils.VersionChecker;
+
+/**
+ * Lifecycle coordinator for AE2 Web Integration.
+ *
+ * Called by the @Mod class (AE2WebIntegration) at appropriate lifecycle
+ * points. In NeoForge 1.21.1 there is no ISidedProxy system; this class
+ * simply groups initialization logic that the @Mod constructor and event
+ * handlers delegate to.
+ */
+public class CommonProxy {
+
+ /**
+ * Called during mod construction (FMLCommonSetupEvent would also work, but
+ * loading data earlier avoids race conditions with the web server).
+ */
+ public void preInit(Platform platform, String version) {
+ VersionChecker.setVersionIdentifier("-neoforge-1.21.1");
+ WebEngine.init(platform, version);
+ Config.init(platform.getConfigDirectory());
+ WebData.loadData();
+ GridData.loadData();
+ AE2WebIntegration.LOG.info("AE2WebIntegration loading at version {}", version);
+ }
+
+ /** Called when the integrated/dedicated server has fully started. */
+ public void onServerStarted() {
+ AE2Controller.init();
+ StartupHandler.logOutdatedWarning();
+ StartupHandler.handleDiscordIntegration();
+ }
+
+ /** Called when the server is about to stop. */
+ public void onServerStopping() {
+ AE2Controller.stopHTTPServer();
+ }
+}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/AE2Controller.java b/src/main/java/pl/kuba6000/ae2webintegration/core/AE2Controller.java
deleted file mode 100644
index 05f10f9..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/AE2Controller.java
+++ /dev/null
@@ -1,718 +0,0 @@
-package pl.kuba6000.ae2webintegration.core;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.security.SecureRandom;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-import net.minecraft.server.level.ServerPlayer;
-import net.neoforged.neoforge.server.ServerLifecycleHooks;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.tuple.Pair;
-
-import com.google.gson.JsonObject;
-import com.mojang.authlib.GameProfile;
-import com.sun.net.httpserver.HttpExchange;
-import com.sun.net.httpserver.HttpHandler;
-import com.sun.net.httpserver.HttpServer;
-
-import pl.kuba6000.ae2webintegration.core.ae2request.async.GetTracking;
-import pl.kuba6000.ae2webintegration.core.ae2request.async.GetTrackingHistory;
-import pl.kuba6000.ae2webintegration.core.ae2request.async.GridSettings;
-import pl.kuba6000.ae2webintegration.core.ae2request.async.IAsyncRequest;
-import pl.kuba6000.ae2webintegration.core.ae2request.sync.CancelCPU;
-import pl.kuba6000.ae2webintegration.core.ae2request.sync.GetCPU;
-import pl.kuba6000.ae2webintegration.core.ae2request.sync.GetCPUList;
-import pl.kuba6000.ae2webintegration.core.ae2request.sync.GetGridList;
-import pl.kuba6000.ae2webintegration.core.ae2request.sync.GetItems;
-import pl.kuba6000.ae2webintegration.core.ae2request.sync.ISyncedRequest;
-import pl.kuba6000.ae2webintegration.core.ae2request.sync.Job;
-import pl.kuba6000.ae2webintegration.core.ae2request.sync.Order;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAE;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-import pl.kuba6000.ae2webintegration.core.utils.HTTPUtils;
-import pl.kuba6000.ae2webintegration.core.utils.RateLimiter;
-import pl.kuba6000.ae2webintegration.core.utils.VersionChecker;
-
-public class AE2Controller {
-
- public static IAE AE2Interface;
-
- public static long timer;
- private static HttpServer server;
-
- public static GameProfile AEControllerProfile;
-
- static {
- try {
- AEControllerProfile = new GameProfile(
- UUID.nameUUIDFromBytes("AE2-WEB-INTEGRATION-AE2CONTROLLER".getBytes("UTF-8")),
- "AE2CONTROLLER");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- }
-
- public static class RequestContext {
-
- private final HttpExchange exchange;
- private final Map getParams;
- // -1 id is admin permissions -2 is localhost access
- private final int userID;
- private final String username;
-
- public RequestContext(HttpExchange exchange, int userID) {
- this.exchange = exchange;
- this.getParams = HTTPUtils.parseQueryString(
- exchange.getRequestURI()
- .getQuery());
- this.userID = userID;
- if (userID == -1) {
- this.username = "admin";
- } else if (userID == -2) {
- this.username = "localhost";
- } else {
- GameProfile profile = AE2Controller.AE2Interface.web$getPlayerData()
- .web$getPlayerProfile(userID);
- this.username = profile != null ? profile.getName() : "unknown";
- }
- }
-
- public HttpExchange getExchange() {
- return exchange;
- }
-
- public Map getGetParams() {
- return getParams;
- }
-
- public int getUserID() {
- return userID;
- }
-
- public boolean isAdmin() {
- return userID == -1 || userID == -2;
- }
- }
-
- static ThreadLocal requestContext = new ThreadLocal<>();
-
- public static HashMap> awaitingRegistration = new HashMap<>();
-
- public static ConcurrentLinkedQueue requests = new ConcurrentLinkedQueue<>();
-
- private static RateLimiter rateLimiter;
-
- public static void startHTTPServer() {
- rateLimiter = new RateLimiter(
- Config.INSTANCE.AE_MAX_REQUESTS_BEFORE_LOGGED_IN_PER_MINUTE.get(),
- 60 * 1000,
- 60 * 60 * 1000); // 60 requests per minute, whitelisted for 1 hour
- try {
- server = HttpServer.create(new InetSocketAddress(Config.INSTANCE.AE_PORT.get()), 0);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- server.createContext("/grids", new SyncedRequestHandler(GetGridList.class));
- server.createContext("/list", new SyncedRequestHandler(GetCPUList.class));
- server.createContext("/get", new SyncedRequestHandler(GetCPU.class));
- server.createContext("/cancelcpu", new SyncedRequestHandler(CancelCPU.class));
- server.createContext("/items", new SyncedRequestHandler(GetItems.class));
- server.createContext("/order", new SyncedRequestHandler(Order.class));
- server.createContext("/job", new SyncedRequestHandler(Job.class));
- server.createContext("/trackinghistory", new ASyncRequestHandler(GetTrackingHistory.class));
- server.createContext("/gettracking", new ASyncRequestHandler(GetTracking.class));
- server.createContext("/gridsettings", new ASyncRequestHandler(GridSettings.class));
- server.createContext("/auth", new AuthHandler());
- server.createContext("/", new WebHandler());
- server.setExecutor(serverThread);
- server.start();
- }
-
- public static void stopHTTPServer() {
- server.stop(0);
- }
-
- private static final ExecutorService serverThread = new ThreadPoolExecutor(
- 0,
- Integer.MAX_VALUE,
- 60L,
- TimeUnit.SECONDS,
- new SynchronousQueue()) {
-
- @Override
- protected void afterExecute(Runnable r, Throwable t) {
- super.afterExecute(r, t);
- requestContext.remove();
- }
- };
-
- public static ConcurrentHashMap hashcodeToAEKey = new ConcurrentHashMap<>();
-
- private static final HashMap> validTokens = new HashMap<>();
-
- private static String generateToken() {
- return generateToken(200);
- }
-
- private static String generateToken(int limit) {
- return new SecureRandom().ints(48, 122 + 1)
- .filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
- .limit(limit)
- .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
- .toString();
- }
-
- private static boolean checkAuth(HttpExchange t) throws IOException {
- InetAddress remoteAddress = t.getRemoteAddress()
- .getAddress();
-
- if (Config.INSTANCE.ALLOW_NO_PASSWORD_ON_LOCALHOST.get() && remoteAddress.isLoopbackAddress()) {
- requestContext.set(new RequestContext(t, -2)); // Localhost access
- rateLimiter.ensureWhitelisted(remoteAddress);
- return true;
- }
-
- // Alternative authentication method
- List auth = t.getRequestHeaders()
- .get("Authorization");
- if (auth != null && !auth.isEmpty()) {
- String token = auth.get(0);
- token = token.replace("Bearer ", "");
- Pair tokenData = validTokens.get(token);
- if (tokenData != null) {
- long validity = tokenData.getLeft();
- if (System.currentTimeMillis() < validity) {
- requestContext.set(new RequestContext(t, tokenData.getRight()));
- rateLimiter.ensureWhitelisted(remoteAddress);
- return true; // Token is valid
- } else {
- validTokens.remove(token); // Remove expired token
- return false; // Token expired
- }
- } else {
- return false; // Invalid token
- }
- }
-
- List cookies = t.getRequestHeaders()
- .get("Cookie");
- if (cookies != null && !cookies.isEmpty()) {
- String cookiesString = cookies.get(0);
- for (String cookie : cookiesString.split("; ")) {
- if (cookie.startsWith("authenticationToken=")) {
- String token = cookie.substring("authenticationToken=".length());
- Pair tokenData = validTokens.get(token);
- if (tokenData != null) {
- long validity = tokenData.getLeft();
- if (System.currentTimeMillis() < validity) {
- Map GET_PARAMS = HTTPUtils.parseQueryString(
- t.getRequestURI()
- .getQuery());
- if (GET_PARAMS.containsKey("logout")) {
- validTokens.remove(token); // Invalidate token on logout
- t.getResponseHeaders()
- .add("Set-Cookie", "authenticationToken=" + token + "; Max-Age=-1; HttpOnly");
- t.getResponseHeaders()
- .add("Location", ".");
- t.sendResponseHeaders(302, -1);
- return false; // Logout successful
- }
- requestContext.set(new RequestContext(t, tokenData.getRight()));
- rateLimiter.ensureWhitelisted(remoteAddress);
- return true; // Token is valid
- } else {
- validTokens.remove(token); // Remove expired token
- t.getResponseHeaders()
- .add("Set-Cookie", "authenticationToken=" + token + "; Max-Age=-1; HttpOnly");
- return false; // Token expired
- }
- } else {
- t.getResponseHeaders()
- .add("Set-Cookie", "authenticationToken=" + token + "; Max-Age=-1; HttpOnly");
- return false; // Invalid token
- }
- }
- }
- }
- if (t.getRequestMethod()
- .equals("POST")) {
- String postRaw = new Scanner(t.getRequestBody()).nextLine();
- Map postData = HTTPUtils.parseQueryString(postRaw);
-
- if (postData.containsKey("register") && postData.containsKey("password")) {
- String username = postData.get("register");
- UUID uuid = null;
- for (ServerPlayer entityPlayerMP : ServerLifecycleHooks.getCurrentServer()
- .getPlayerList()
- .getPlayers()) {
- if (entityPlayerMP.getName()
- .getString()
- .equalsIgnoreCase(username)) {
- username = entityPlayerMP.getName()
- .getString();
- uuid = entityPlayerMP.getUUID();
- break;
- }
- }
- if (uuid == null) {
- t.getResponseHeaders()
- .add("Location", "?notonline");
- t.sendResponseHeaders(302, -1);
- return false;
- }
- String password = postData.get("password");
- try {
- password = PasswordHelper.generateStrongPasswordHash(password);
- } catch (Exception e) {
- t.getResponseHeaders()
- .add("Location", "?invalidpassword");
- t.sendResponseHeaders(302, -1);
- return false;
- }
-
- String confirmationToken = generateToken(50);
- awaitingRegistration.put(uuid, Pair.of(confirmationToken, password));
- t.getResponseHeaders()
- .add("Location", "?confirmregistration&token=" + confirmationToken);
- t.sendResponseHeaders(302, -1);
- return false; // Registration initiated
- }
-
- if (postData.containsKey("password") && postData.containsKey("username")) {
- String username = postData.get("username");
- int playerID;
- if (username.equalsIgnoreCase("admin") || !Config.INSTANCE.AE_PUBLIC_MODE.get()) {
- username = "Admin";
- playerID = -1;
- String password = postData.get("password");
- if (!password.equals(Config.INSTANCE.AE_PASSWORD.get()) && !Config.INSTANCE.AE_PASSWORD.get()
- .isEmpty()) {
- t.getResponseHeaders()
- .add("Location", "?invalidpassword");
- t.sendResponseHeaders(302, -1);
- return false;
- }
- } else {
- playerID = WebData.getPlayerId(username);
- if (playerID == -1) {
- t.getResponseHeaders()
- .add("Location", "?invaliduser");
- t.sendResponseHeaders(302, -1);
- return false;
- }
- String password = postData.get("password");
- if (!WebData.verifyPassword(playerID, password)) {
- t.getResponseHeaders()
- .add("Location", "?invalidpassword");
- t.sendResponseHeaders(302, -1);
- return false;
- }
- }
- boolean rememberMe = postData.containsKey("remember");
- String token = generateToken();
- long validFor = rememberMe ? 604_800L : 3600L; // 1 week or 1 hour
- validTokens.put(token, Pair.of(System.currentTimeMillis() + validFor * 1000L, playerID)); // 1 hour
- // validity
- t.getResponseHeaders()
- .add("Set-Cookie", "authenticationToken=" + token + "; Max-Age=" + validFor + "; HttpOnly");
- t.getResponseHeaders()
- .add("Location", ".");
- t.sendResponseHeaders(302, -1);
- rateLimiter.ensureWhitelisted(remoteAddress);
- return true;
- }
- }
- return false;
- }
-
- private static boolean preHTTPHandler(HttpExchange t) throws IOException {
- if (!rateLimiter.isAllowed(
- t.getRemoteAddress()
- .getAddress())) {
- byte[] raw_response = "Too Many Requests".getBytes();
- t.getResponseHeaders()
- .add("Content-Type", "text/plain");
- t.sendResponseHeaders(429, raw_response.length); // Too Many Requests
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- return true;
- }
- t.getResponseHeaders()
- .add("Access-Control-Allow-Origin", "*");
- if (t.getRequestMethod()
- .equalsIgnoreCase("OPTIONS")) {
- t.getResponseHeaders()
- .add("Access-Control-Allow-Methods", "GET, OPTIONS");
- t.getResponseHeaders()
- .add("Access-Control-Allow-Headers", "Content-Type,Authorization");
- t.sendResponseHeaders(204, -1);
- return true;
- }
- if (!checkAuth(t)) {
- t.sendResponseHeaders(401, -1);
- return true;
- }
- return false;
- }
-
- private static boolean sendRequest(ISyncedRequest request) {
- requests.offer(request);
- int timeout = 0;
- while (!request.isDone.get() && timeout < 50) {
- try {
- Thread.sleep(200);
- timeout++;
- } catch (InterruptedException e) {
- return requests.remove(request);
- }
- }
- if (timeout == 50) {
- return requests.remove(request);
- }
- return true;
- }
-
- static class SyncedRequestHandler implements HttpHandler {
-
- private final Constructor extends ISyncedRequest> factory;
-
- public SyncedRequestHandler(Class extends ISyncedRequest> syncedRequestClass) {
- try {
- factory = syncedRequestClass.getConstructor();
- } catch (NoSuchMethodException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void handle(HttpExchange t) throws IOException {
- if (preHTTPHandler(t)) return;
-
- ISyncedRequest syncedRequest;
-
- try {
- syncedRequest = factory.newInstance();
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
- throw new RuntimeException(e);
- }
-
- if (syncedRequest.init(requestContext.get())) {
- sendRequest(syncedRequest);
- }
-
- byte[] raw_response = syncedRequest.getJSON()
- .getBytes();
- t.sendResponseHeaders(200, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
-
- }
-
- }
-
- static class ASyncRequestHandler implements HttpHandler {
-
- private final Constructor extends IAsyncRequest> factory;
-
- public ASyncRequestHandler(Class extends IAsyncRequest> syncedRequestClass) {
- try {
- factory = syncedRequestClass.getConstructor();
- } catch (NoSuchMethodException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void handle(HttpExchange t) throws IOException {
- if (preHTTPHandler(t)) return;
-
- IAsyncRequest asyncRequest;
-
- try {
- asyncRequest = factory.newInstance();
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
- throw new RuntimeException(e);
- }
-
- asyncRequest.handle(requestContext.get());
-
- byte[] raw_response = asyncRequest.getJSON()
- .getBytes();
- t.sendResponseHeaders(200, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- }
-
- }
-
- static class AuthHandler implements HttpHandler {
-
- @Override
- public void handle(HttpExchange t) throws IOException {
- if (!rateLimiter.isAllowed(
- t.getRemoteAddress()
- .getAddress())) {
- byte[] raw_response = "Too Many Requests".getBytes();
- t.getResponseHeaders()
- .add("Content-Type", "text/plain");
- t.sendResponseHeaders(429, raw_response.length); // Too Many Requests
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- return;
- }
- if (t.getRequestMethod()
- .equals("POST")) {
- String postRaw = new Scanner(t.getRequestBody()).nextLine();
- Map postData = HTTPUtils.parseQueryString(postRaw);
-
- if (postData.containsKey("register") && postData.containsKey("password")) {
- String username = postData.get("register");
- UUID uuid = null;
- for (ServerPlayer entityPlayerMP : ServerLifecycleHooks.getCurrentServer()
- .getPlayerList()
- .getPlayers()) {
- if (entityPlayerMP.getName()
- .getString()
- .equalsIgnoreCase(username)) {
- username = entityPlayerMP.getName()
- .getString();
- uuid = entityPlayerMP.getUUID();
- break;
- }
- }
- if (uuid == null) {
- byte[] raw_response = "notonline".getBytes();
- t.sendResponseHeaders(400, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- return;
- }
- String password = postData.get("password");
- try {
- password = PasswordHelper.generateStrongPasswordHash(password);
- } catch (Exception e) {
- byte[] raw_response = "invalidpassword".getBytes();
- t.sendResponseHeaders(400, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- return;
- }
-
- String confirmationToken = generateToken(50);
- awaitingRegistration.put(uuid, Pair.of(confirmationToken, password));
- byte[] raw_response = confirmationToken.getBytes();
- t.sendResponseHeaders(200, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- return;
- }
-
- if (postData.containsKey("password") && postData.containsKey("username")) {
- String username = postData.get("username");
- int playerID;
- if (username.equalsIgnoreCase("admin") || !Config.INSTANCE.AE_PUBLIC_MODE.get()) {
- username = "Admin";
- playerID = -1;
- String password = postData.get("password");
- if (!password.equals(Config.INSTANCE.AE_PASSWORD.get()) && !Config.INSTANCE.AE_PASSWORD.get()
- .isEmpty()) {
- byte[] raw_response = "invalidpassword".getBytes();
- t.sendResponseHeaders(400, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- return;
- }
- } else {
- playerID = WebData.getPlayerId(username);
- if (playerID == -1) {
- byte[] raw_response = "invaliduser".getBytes();
- t.sendResponseHeaders(400, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- return;
- }
- String password = postData.get("password");
- if (!WebData.verifyPassword(playerID, password)) {
- byte[] raw_response = "invalidpassword".getBytes();
- t.sendResponseHeaders(400, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- return;
- }
- }
- boolean rememberMe = postData.containsKey("remember");
- String token = generateToken();
- long validFor = rememberMe ? 604_800L : 3600L; // 1 week or 1 hour
- validTokens.put(token, Pair.of(System.currentTimeMillis() + validFor * 1000L, playerID)); // 1 hour
- // validity
- JsonObject json = new JsonObject();
- json.addProperty("token", token);
- json.addProperty("username", username);
- json.addProperty("isAdmin", playerID == -1);
- json.addProperty(
- "isOutdated",
- Config.INSTANCE.CHECK_FOR_UPDATES.get() && VersionChecker.isOutdated());
- byte[] raw_response = json.toString()
- .getBytes();
- t.sendResponseHeaders(200, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- rateLimiter.ensureWhitelisted(
- t.getRemoteAddress()
- .getAddress());
- return;
- }
- }
-
- Map GET_PARAMS = HTTPUtils.parseQueryString(
- t.getRequestURI()
- .getQuery());
-
- if (GET_PARAMS.containsKey("revoke")) {
- List auth = t.getRequestHeaders()
- .get("Authorization");
- if (auth != null && !auth.isEmpty()) {
- String token = auth.get(0);
- token = token.replace("Bearer ", "");
- validTokens.remove(token);
- t.sendResponseHeaders(200, -1);
- return;
- }
- }
-
- t.sendResponseHeaders(400, -1);
- }
-
- }
-
- static class WebHandler implements HttpHandler {
-
- @Override
- public void handle(HttpExchange t) throws IOException {
-
- if (!rateLimiter.isAllowed(
- t.getRemoteAddress()
- .getAddress())) {
- byte[] raw_response = "Too Many Requests".getBytes();
- t.getResponseHeaders()
- .add("Content-Type", "text/plain");
- t.sendResponseHeaders(429, raw_response.length); // Too Many Requests
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- return;
- }
-
- String path = t.getRequestURI()
- .getPath();
-
- if (path.equals("/favicon.ico")) {
- t.getResponseHeaders()
- .set("Content-Type", "image/x-icon");
- try (InputStream is = AE2Controller.class.getResourceAsStream("/assets/favicon.ico")) {
- if (is == null) return;
-
- byte[] raw_response = IOUtils.toByteArray(is);
- is.read(raw_response);
- t.sendResponseHeaders(200, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- }
- return;
- }
-
- // only accept index file
- if (!path.equals("/") && !path.isEmpty()
- && !path.equals("/index.php")
- && !path.equals("/index.html")
- && !path.equals("/index.htm")
- && !path.equals("/index.asp")
- && !path.equals("/index.aspx")
- && !path.equals("/index.jsp")) {
-
- String response = "Invalid url! (ERROR 404) ";
- byte[] raw_response = response.getBytes();
- t.sendResponseHeaders(404, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- return;
- }
-
- String site = "/assets/webpage.html";
-
- if (!checkAuth(t)) {
- site = "/assets/login.html";
- }
-
- String response;
- try (InputStream is = AE2Controller.class.getResourceAsStream(site)) {
- if (is == null) return;
- try (InputStreamReader isr = new InputStreamReader(is);
- BufferedReader reader = new BufferedReader(isr)) {
- response = reader.lines()
- .collect(Collectors.joining(System.lineSeparator()));
- }
- }
- response = response
- .replace("_REPLACE_ME_IS_PUBLIC_MODE", Config.INSTANCE.AE_PUBLIC_MODE.get() ? "true" : "false");
- response = response.replace(
- "_REPLACE_ME_VERSION_OUTDATED",
- Config.INSTANCE.CHECK_FOR_UPDATES.get() && VersionChecker.isOutdated() ? "true" : "false");
- RequestContext context = requestContext.get();
- if (context != null) {
- response = response.replace("_REPLACE_ME_USERNAME", context.username);
- response = response.replace("_REPLACE_ME_IS_ADMIN", context.isAdmin() ? "true" : "false");
- }
- byte[] raw_response = response.getBytes();
- t.sendResponseHeaders(200, raw_response.length);
- OutputStream os = t.getResponseBody();
- os.write(raw_response);
- os.close();
- }
-
- }
-
- public static void init() {
- try {
- startHTTPServer();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
-
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/AE2JobTracker.java b/src/main/java/pl/kuba6000/ae2webintegration/core/AE2JobTracker.java
deleted file mode 100644
index 4773242..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/AE2JobTracker.java
+++ /dev/null
@@ -1,241 +0,0 @@
-package pl.kuba6000.ae2webintegration.core;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.lang3.tuple.Pair;
-
-import pl.kuba6000.ae2webintegration.core.api.DimensionalCoords;
-import pl.kuba6000.ae2webintegration.core.discord.DiscordManager;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAECraftingPatternDetails;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGenericStack;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingCPUCluster;
-import pl.kuba6000.ae2webintegration.core.interfaces.IItemList;
-import pl.kuba6000.ae2webintegration.core.interfaces.IPatternProviderViewable;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAECraftingGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAESecurityGrid;
-
-public class AE2JobTracker {
-
- public static class AEInterface {
-
- public String name;
- public HashSet location = new HashSet<>();
-
- AEInterface(String name) {
- this.name = name;
- }
-
- @Override
- public int hashCode() {
- return name.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof AEInterface)) return false;
- return ((AEInterface) obj).name.equals(this.name);
- }
- }
-
- public static class JobTrackingInfo {
-
- public IAEGenericStack finalOutput;
- public long timeStarted;
- public long timeDone;
- public HashMap timeSpentOn = new HashMap<>();
- public HashMap startedWaitingFor = new HashMap<>();
- public HashMap craftedTotal = new HashMap<>();
- public HashMap waitingFor = new HashMap<>();
- public HashMap>> itemShare = new HashMap<>();
- public HashMap>> interfaceShare = new HashMap<>();
- public HashMap interfaceStarted = new HashMap<>();
- public HashMap interfaceLookup = new HashMap<>();
- public HashMap> interfaceWaitingFor = new HashMap<>();
- public HashMap>> interfaceWaitingForLookup = new HashMap<>();
- public boolean isDone = false;
- public boolean wasCancelled = false;
-
- public long getTimeSpentOn(IAEKey stack) {
- Long time = timeSpentOn.get(stack);
- if (time == null) return 0L;
- Long additionalTime = startedWaitingFor.get(stack);
- if (additionalTime != null) {
- time += System.currentTimeMillis() - additionalTime;
- }
- return time;
- }
-
- public double getShareInCraftingTime(IAEKey stack) {
- long total = 0L;
- long stackTime = 0L;
- for (IAEKey itemStack : timeSpentOn.keySet()) {
- long timeSpent = getTimeSpentOn(itemStack);
- total += timeSpent;
- if (stack.web$isSameType(itemStack)) {
- stackTime = timeSpent;
- }
- }
- if (total == 0L) return 1d;
- return (double) stackTime / (double) total;
- }
- }
-
- public static IdentityHashMap trackingInfoMap = new IdentityHashMap<>();
- public ConcurrentHashMap trackingInfos = new ConcurrentHashMap<>();
-
- private int nextFreeTrackingInfoID = 1;
-
- public static void addJob(ICraftingCPUCluster cpuCluster, IAECraftingGrid cache, IAEGrid grid, boolean isMerging) {
- GridData gridData = GridData.get(grid);
- if (gridData == null || !gridData.isTracked) return; // We don't track this grid, so we don't track jobs on it
- JobTrackingInfo info;
- if (isMerging) {
- info = trackingInfoMap.get(cpuCluster);
- if (info == null) return; // We can't start tracking mid crafting :P
- } else {
- trackingInfoMap.put(cpuCluster, info = new JobTrackingInfo());
- info.timeStarted = System.currentTimeMillis();
- }
- info.finalOutput = cpuCluster.web$getFinalOutput()
- .web$copy();
- }
-
- public static void updateCraftingStatus(ICraftingCPUCluster cpu, IAEKey diff) {
- JobTrackingInfo info = trackingInfoMap.get(cpu);
- if (info == null) return;
- IItemList waitingFor = cpu.web$getWaitingFor();
- long found = waitingFor.web$findPrecise(diff);
- if (found > 0L) {
- if (!info.startedWaitingFor.containsKey(diff)) {
- info.startedWaitingFor.put(diff, System.currentTimeMillis());
- info.timeSpentOn.putIfAbsent(diff, 0L);
- info.waitingFor.put(diff, found);
- } else {
- long i = info.waitingFor.get(diff);
- if (i > found) {
- info.craftedTotal.merge(diff, i - found, Long::sum);
- }
- info.waitingFor.put(diff, found);
- }
- } else {
- if (info.startedWaitingFor.containsKey(diff)) {
- long started = info.startedWaitingFor.remove(diff);
- long ended = System.currentTimeMillis();
- long elapsed = ended - started;
- long endedReal = System.currentTimeMillis();
- info.timeSpentOn.merge(diff, elapsed, Long::sum);
- info.craftedTotal.merge(diff, info.waitingFor.remove(diff), Long::sum);
- info.itemShare.computeIfAbsent(diff, k -> new ArrayList<>())
- .add(Pair.of(started, endedReal));
- if (info.interfaceWaitingForLookup.containsKey(diff)) {
- for (Map.Entry> entry : info.interfaceWaitingForLookup.get(diff)
- .entrySet()) {
- AEInterface aeInterface = entry.getKey();
- HashSet itemList = entry.getValue();
- itemList.remove(diff);
- if (itemList.isEmpty()) {
- info.interfaceWaitingFor.remove(aeInterface);
- long interfaceStarted = info.interfaceStarted.remove(aeInterface);
- info.interfaceShare.computeIfAbsent(aeInterface, k -> new ArrayList<>())
- .add(Pair.of(interfaceStarted, endedReal));
- }
- }
- info.interfaceWaitingForLookup.remove(diff);
- }
- }
- }
- }
-
- public static void pushedPattern(ICraftingCPUCluster cpu, IPatternProviderViewable provider,
- IAECraftingPatternDetails details) {
- JobTrackingInfo info = trackingInfoMap.get(cpu);
- if (info == null) return;
- if (provider != null) {
- String name = provider.web$getName();
- if (name == null) name = "[NULL]";
- final AEInterface aeInterfaceToLookup = new AEInterface(name);
- final AEInterface aeInterface = info.interfaceLookup
- .computeIfAbsent(aeInterfaceToLookup, k -> aeInterfaceToLookup);
- aeInterface.location.add(provider.web$getLocation());
- info.interfaceStarted.computeIfAbsent(aeInterface, k -> System.currentTimeMillis());
- final HashSet itemList = info.interfaceWaitingFor
- .computeIfAbsent(aeInterface, k -> new HashSet<>());
-
- for (IAEGenericStack out : details.web$getCondensedOutputs()) {
- info.interfaceWaitingForLookup.computeIfAbsent(out.web$what(), k -> new HashMap<>())
- .putIfAbsent(aeInterface, itemList);
- itemList.add(out.web$what());
- }
- }
- }
-
- public static void completeCrafting(IAEGrid grid, ICraftingCPUCluster cpu) {
- JobTrackingInfo info = trackingInfoMap.remove(cpu);
- if (info == null) return;
- GridData gridData = GridData.get(grid);
- if (gridData == null || !gridData.isTracked) return; // We don't track this grid, so we don't track jobs on it
- for (Map.Entry entry : info.waitingFor.entrySet()) {
- info.craftedTotal.merge(entry.getKey(), entry.getValue(), Long::sum);
- }
- info.waitingFor.clear();
- final long now = System.currentTimeMillis();
- for (Map.Entry entry : info.startedWaitingFor.entrySet()) {
- info.timeSpentOn.merge(entry.getKey(), now - entry.getValue(), Long::sum);
- info.itemShare.computeIfAbsent(entry.getKey(), k -> new ArrayList<>())
- .add(Pair.of(entry.getValue(), now));
- }
- for (Map.Entry entry : info.interfaceStarted.entrySet()) {
- info.interfaceShare.computeIfAbsent(entry.getKey(), k -> new ArrayList<>())
- .add(Pair.of(entry.getValue(), now));
- }
- info.interfaceStarted.clear();
- info.interfaceWaitingFor.clear();
- info.interfaceWaitingForLookup.clear();
- info.interfaceLookup.clear();
- info.startedWaitingFor.clear();
- info.isDone = true;
- info.timeDone = System.currentTimeMillis();
- gridData.trackingInfo.trackingInfos.put(gridData.trackingInfo.nextFreeTrackingInfoID++, info);
- double took = info.timeDone - info.timeStarted;
- took /= 1000d;
- if (!Config.INSTANCE.AE_PUBLIC_MODE.get() && !Config.INSTANCE.DISCORD_WEBHOOK.get()
- .isEmpty()) {
- IAESecurityGrid securityGrid = grid.web$getSecurityGrid();
- if (securityGrid != null && securityGrid.web$isAvailable()) {
- IAECraftingGrid craftingGrid = grid.web$getCraftingGrid();
- craftingGrid.web$getCPUs(); // make sure the cpu has id
- DiscordManager.postMessageNonBlocking(
- new DiscordManager.DiscordEmbed(
- "AE2 Job Tracker [ Grid " + securityGrid.web$getSecurityKey()
- + " ][ "
- + cpu.web$getName()
- + " ]",
- "Crafting for `" + info.finalOutput.web$what()
- .web$getDisplayName()
- + " x"
- + info.finalOutput.web$amount()
- + "` "
- + (info.wasCancelled ? "cancelled" : "completed")
- + "!\nIt took "
- + took
- + "s",
- info.wasCancelled ? 15548997 : 5763719));
- }
- }
- }
-
- public static void cancelCrafting(IAEGrid grid, ICraftingCPUCluster cpu) {
- JobTrackingInfo info = trackingInfoMap.get(cpu);
- if (info == null) return;
- info.wasCancelled = true;
- completeCrafting(grid, cpu);
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/AE2WebIntegration.java b/src/main/java/pl/kuba6000/ae2webintegration/core/AE2WebIntegration.java
deleted file mode 100644
index 27b6f78..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/AE2WebIntegration.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package pl.kuba6000.ae2webintegration.core;
-
-import static pl.kuba6000.ae2webintegration.core.AE2WebIntegration.MODID;
-
-import net.neoforged.bus.api.SubscribeEvent;
-import net.neoforged.fml.ModContainer;
-import net.neoforged.fml.ModLoadingContext;
-import net.neoforged.fml.common.EventBusSubscriber;
-import net.neoforged.fml.common.Mod;
-import net.neoforged.fml.config.ConfigTracker;
-import net.neoforged.fml.config.ModConfig;
-import net.neoforged.neoforge.event.RegisterCommandsEvent;
-import net.neoforged.neoforge.event.server.ServerStartedEvent;
-import net.neoforged.neoforge.event.server.ServerStoppingEvent;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import pl.kuba6000.ae2webintegration.Tags;
-import pl.kuba6000.ae2webintegration.core.commands.BaseCommandHandler;
-import pl.kuba6000.ae2webintegration.core.discord.DiscordManager;
-import pl.kuba6000.ae2webintegration.core.utils.VersionChecker;
-
-@Mod(value = MODID)
-@EventBusSubscriber(modid = MODID)
-public class AE2WebIntegration {
-
- public static final String MODID = "ae2webintegration_core";
- public static final Logger LOG = LogManager.getLogger(MODID);
-
- public static ModContainer myContainer;
-
- public AE2WebIntegration() {
- // ModLoadingContext.get()
- // .registerExtensionPoint(
- // IExtensionPoint.DisplayTest.class,
- // () -> new IExtensionPoint.DisplayTest(() -> NetworkConstants.IGNORESERVERONLY, (a, b) -> true));
- Tags.VERSION = ModLoadingContext.get()
- .getActiveContainer()
- .getModInfo()
- .getVersion()
- .toString();
- // ModLoadingContext.get()
- // .registerConfig(ModConfig.Type.COMMON, Config.SPEC, "ae2webintegration/ae2webintegration.toml");
- myContainer = ModLoadingContext.get()
- .getActiveContainer();
- // ModLoadingContext.get()
- // .getActiveContainer()
- // .registerConfig(
- // Config.CONFIG = new ModConfig(
- // ModConfig.Type.COMMON,
- // Config.SPEC,
- // myContainer,
- // "ae2webintegration/ae2webintegration.toml"));
- Config.CONFIG = ConfigTracker.INSTANCE.registerConfig(
- ModConfig.Type.COMMON,
- Config.SPEC,
- myContainer,
- "ae2webintegration/ae2webintegration.toml");
- WebData.loadData();
- GridData.loadData();
-
- AE2WebIntegration.LOG.info("AE2WebIntegration loading at version {}", Tags.VERSION);
- }
-
- @SubscribeEvent
- public static void commandsRegister(RegisterCommandsEvent event) {
- BaseCommandHandler.register(event.getDispatcher());
- }
-
- @SubscribeEvent
- public static void serverStarted(ServerStartedEvent event) {
- AE2Controller.init();
- DiscordManager.init();
- if (Config.INSTANCE.CHECK_FOR_UPDATES.get() && VersionChecker.isOutdated()) AE2WebIntegration.LOG.warn(
- "You are not on latest version ! Consider updating to {} at https://github.com/kuba6000/AE2-Web-Integration/releases/latest",
- VersionChecker.getLatestTag());
- if (!Config.INSTANCE.AE_PUBLIC_MODE.get() && !Config.INSTANCE.DISCORD_WEBHOOK.get()
- .isEmpty()) {
- DiscordManager.postMessageNonBlocking(
- new DiscordManager.DiscordEmbed("AE2 Web Integration", "Discord integration started!"));
- } else if (Config.INSTANCE.AE_PUBLIC_MODE.get() && !Config.INSTANCE.DISCORD_WEBHOOK.get()
- .isEmpty()) {
- DiscordManager.postMessageNonBlocking(
- new DiscordManager.DiscordEmbed(
- "AE2 Web Integration",
- "Warning!\nDiscord integration webhook is set in the config, but the public mode is enabled!\nDiscord integration will be disabled!",
- 15548997));
- }
- }
-
- @SubscribeEvent
- public static void serverStopping(ServerStoppingEvent event) {
- AE2Controller.stopHTTPServer();
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/AEMixinCallbacks.java b/src/main/java/pl/kuba6000/ae2webintegration/core/AEMixinCallbacks.java
deleted file mode 100644
index 7580b00..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/AEMixinCallbacks.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package pl.kuba6000.ae2webintegration.core;
-
-import pl.kuba6000.ae2webintegration.core.api.IAEMixinCallbacks;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAECraftingPatternDetails;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingCPUCluster;
-import pl.kuba6000.ae2webintegration.core.interfaces.IPatternProviderViewable;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAECraftingGrid;
-
-public class AEMixinCallbacks implements IAEMixinCallbacks {
-
- public static AEMixinCallbacks INSTANCE = new AEMixinCallbacks();
-
- @Override
- public void jobStarted(ICraftingCPUCluster cpuCluster, IAECraftingGrid cache, IAEGrid grid, boolean isMerging,
- boolean isAuthorPlayer) {
- if (!Config.INSTANCE.TRACKING_TRACK_MACHINE_CRAFTING.get() && !isAuthorPlayer) {
- return;
- }
- AE2JobTracker.addJob(cpuCluster, cache, grid, isMerging);
- }
-
- @Override
- public void craftingStatusPostedUpdate(ICraftingCPUCluster cpu, IAEKey diff) {
- AE2JobTracker.updateCraftingStatus(cpu, diff);
- }
-
- @Override
- public void pushedPattern(ICraftingCPUCluster cpu, IPatternProviderViewable provider,
- IAECraftingPatternDetails details) {
- AE2JobTracker.pushedPattern(cpu, provider, details);
- }
-
- @Override
- public void jobCompleted(IAEGrid grid, ICraftingCPUCluster cpu) {
- AE2JobTracker.completeCrafting(grid, cpu);
- }
-
- @Override
- public void jobCancelled(IAEGrid grid, ICraftingCPUCluster cpu) {
- AE2JobTracker.cancelCrafting(grid, cpu);
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/AEWebAPI.java b/src/main/java/pl/kuba6000/ae2webintegration/core/AEWebAPI.java
deleted file mode 100644
index 0e6f1c5..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/AEWebAPI.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package pl.kuba6000.ae2webintegration.core;
-
-import com.mojang.authlib.GameProfile;
-
-import pl.kuba6000.ae2webintegration.core.api.IAEWebInterface;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAE;
-
-public class AEWebAPI implements IAEWebInterface {
-
- public static final AEWebAPI INSTANCE = new AEWebAPI();
-
- @Override
- public GameProfile getAEWebGameProfile() {
- return AE2Controller.AEControllerProfile;
- }
-
- @Override
- public void initAEInterface(IAE ae) {
- AE2Controller.AE2Interface = ae;
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/Config.java b/src/main/java/pl/kuba6000/ae2webintegration/core/Config.java
deleted file mode 100644
index 538ddf4..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/Config.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package pl.kuba6000.ae2webintegration.core;
-
-import static pl.kuba6000.ae2webintegration.core.AE2WebIntegration.MODID;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Random;
-
-import net.neoforged.bus.api.SubscribeEvent;
-import net.neoforged.fml.common.EventBusSubscriber;
-import net.neoforged.fml.config.ModConfig;
-import net.neoforged.fml.event.config.ModConfigEvent;
-import net.neoforged.fml.loading.FMLPaths;
-import net.neoforged.neoforge.common.ModConfigSpec;
-
-@EventBusSubscriber(modid = MODID, bus = EventBusSubscriber.Bus.MOD)
-public class Config {
-
- static {
- ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder();
- INSTANCE = new Config(BUILDER);
- SPEC = BUILDER.build();
- }
- public static final Config INSTANCE;
- public static final ModConfigSpec SPEC;
- public static ModConfig CONFIG;
-
- private static Path configDirectory;
-
- public final ModConfigSpec.ConfigValue AE_PASSWORD;
- public final ModConfigSpec.ConfigValue AE_PORT;
- public final ModConfigSpec.ConfigValue ALLOW_NO_PASSWORD_ON_LOCALHOST;
- public final ModConfigSpec.ConfigValue AE_PUBLIC_MODE;
- public final ModConfigSpec.ConfigValue AE_MAX_REQUESTS_BEFORE_LOGGED_IN_PER_MINUTE;
-
- // discord
- public final ModConfigSpec.ConfigValue DISCORD_WEBHOOK;
- public final ModConfigSpec.ConfigValue DISCORD_ROLE_ID;
-
- // tracking
- // TODO: Add more customization options (order time, size, item type ? etc.)
- public final ModConfigSpec.ConfigValue TRACKING_TRACK_MACHINE_CRAFTING;
-
- // updates
- public final ModConfigSpec.ConfigValue CHECK_FOR_UPDATES;
-
- private Config(ModConfigSpec.Builder builder) {
- builder.push("General");
- AE_PORT = builder.comment("Port for the hosted website")
- .defineInRange("port", 2324, 1, 65535);
- AE_PASSWORD = builder.comment("Password for the admin account")
- .define(
- "password",
- new Random().ints(48, 122 + 1)
- .filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
- .limit(16)
- .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
- .toString());
- ALLOW_NO_PASSWORD_ON_LOCALHOST = builder
- .comment("Don't require to login using loopback address (127.0.0.1/localhost)")
- .define("allow_no_password_on_localhost", true);
- AE_PUBLIC_MODE = builder.comment(
- "Public server mode = enable registration system on the website, players will be able to register and login to monitor their own ae networks, "
- + "if disabled, there is only one admin account with password set in the config file with access to all networks on the server")
- .define("public_mode", true);
- AE_MAX_REQUESTS_BEFORE_LOGGED_IN_PER_MINUTE = builder
- .comment("How many requests can be made before user is logged in per minute")
- .defineInRange("max_requests_before_logged_in_per_minute", 20, 1, 1000);
- CHECK_FOR_UPDATES = builder
- .comment("Check for new versions and display notifications in chat and on the website")
- .define("check_for_updates", true);
- builder.pop();
- builder.push("Discord");
- DISCORD_WEBHOOK = builder
- .comment("Discord webhook url (OPTIONAL, leave empty to ignore) (WORKS ONLY IF PUBLIC_MODE IS DISABLED)")
- .define("webhook", "");
- DISCORD_ROLE_ID = builder.comment("Role to ping on message (OPTIONAL, leave empty to ignore)")
- .define("role_id", "");
- builder.pop();
- builder.push("Tracking");
- TRACKING_TRACK_MACHINE_CRAFTING = builder.comment("Track automated crafting jobs (not ordered by player)")
- .define("track_machine_crafting", false);
- builder.pop();
-
- }
-
- public static File getConfigFile(String fileName) {
- if (configDirectory == null) {
- configDirectory = FMLPaths.CONFIGDIR.get()
- .resolve("ae2webintegration/");
- if (Files.notExists(configDirectory)) {
- try {
- Files.createDirectories(configDirectory);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- return configDirectory.resolve(fileName)
- .toFile();
- }
-
- @SubscribeEvent
- private static void onReload(ModConfigEvent.Reloading event) {
- AE2Controller.stopHTTPServer();
- AE2Controller.startHTTPServer();
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/GridData.java b/src/main/java/pl/kuba6000/ae2webintegration/core/GridData.java
deleted file mode 100644
index 11044b2..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/GridData.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package pl.kuba6000.ae2webintegration.core;
-
-import static pl.kuba6000.ae2webintegration.core.AE2WebIntegration.LOG;
-
-import java.io.File;
-import java.io.Reader;
-import java.io.Writer;
-import java.lang.reflect.Type;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Future;
-
-import com.google.common.io.Files;
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-
-import pl.kuba6000.ae2webintegration.core.api.AEApi.AEControllerState;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAECraftingJob;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAEPathingGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAESecurityGrid;
-import pl.kuba6000.ae2webintegration.core.utils.GSONUtils;
-
-public class GridData {
-
- @GSONUtils.SkipGSON
- private static final File dataFile = Config.getConfigFile("griddata.json");
-
- @GSONUtils.SkipGSON
- private static ConcurrentHashMap gridDataMap = new ConcurrentHashMap<>();
-
- public boolean isTracked = false;
-
- @GSONUtils.SkipGSON
- public AE2JobTracker trackingInfo = new AE2JobTracker();
-
- @GSONUtils.SkipGSON
- private int nextJobID = 1;
-
- private int getNextJobID() {
- return nextJobID++;
- }
-
- @GSONUtils.SkipGSON
- public HashMap> jobs = new HashMap<>();
-
- public int addJob(Future job) {
- int jobID = getNextJobID();
- jobs.put(jobID, job);
- return jobID;
- }
-
- public static GridData get(long gridKey) {
- return gridDataMap.computeIfAbsent(gridKey, k -> new GridData());
- }
-
- public static GridData get(IAEGrid grid) {
- IAEPathingGrid pathing = grid.web$getPathingGrid();
- if (pathing == null || pathing.web$isNetworkBooting()
- || pathing.web$getControllerState() != AEControllerState.CONTROLLER_ONLINE) {
- return null;
- }
- IAESecurityGrid security = grid.web$getSecurityGrid();
- if (security == null || !security.web$isAvailable()) {
- return null;
- }
- long gridKey = security.web$getSecurityKey();
- if (gridKey == -1) {
- return null;
- }
- return gridDataMap.computeIfAbsent(gridKey, k -> new GridData());
- }
-
- public static void saveChanges() {
- Gson gson = GSONUtils.GSON_BUILDER.create();
- Writer writer = null;
- try {
- writer = Files.newWriter(dataFile, StandardCharsets.UTF_8);
- gson.toJson(gridDataMap, writer);
- writer.flush();
- writer.close();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (writer != null) try {
- writer.close();
- } catch (Exception ignored) {}
- }
- }
-
- public static void loadData() {
- Gson gson = GSONUtils.GSON_BUILDER.create();
- if (!dataFile.exists()) {
- LOG.info("Grid data file not found, creating a new one.");
- saveChanges();
- return;
- }
- Reader reader = null;
- try {
- reader = Files.newReader(dataFile, StandardCharsets.UTF_8);
- Type type = new TypeToken>() {}.getType();
- gridDataMap = gson.fromJson(reader, type);
- } catch (Exception e) {
- LOG.error("Failed to load web data from file: {}", dataFile.getAbsolutePath(), e);
- gridDataMap.clear();
- saveChanges();
- } finally {
- if (reader != null) try {
- reader.close();
- } catch (Exception ignored) {}
- }
-
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/PasswordHelper.java b/src/main/java/pl/kuba6000/ae2webintegration/core/PasswordHelper.java
deleted file mode 100644
index b3224b3..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/PasswordHelper.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package pl.kuba6000.ae2webintegration.core;
-
-import java.math.BigInteger;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.spec.InvalidKeySpecException;
-
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.PBEKeySpec;
-
-public class PasswordHelper {
-
- private static final int ITERATIONS = 65536;
- private static final int HASH_LENGTH = 512; // Length of the hash in bytes
-
- public static String generateStrongPasswordHash(String password)
- throws NoSuchAlgorithmException, InvalidKeySpecException {
- char[] chars = password.toCharArray();
- byte[] salt = getSalt();
-
- PBEKeySpec spec = new PBEKeySpec(chars, salt, ITERATIONS, HASH_LENGTH);
- SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
-
- byte[] hash = skf.generateSecret(spec)
- .getEncoded();
- return ITERATIONS + ":" + toHex(salt) + ":" + toHex(hash);
- }
-
- private static byte[] getSalt() throws NoSuchAlgorithmException {
- SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
- byte[] salt = new byte[16];
- sr.nextBytes(salt);
- return salt;
- }
-
- private static String toHex(byte[] array) throws NoSuchAlgorithmException {
- BigInteger bi = new BigInteger(1, array);
- String hex = bi.toString(16);
-
- int paddingLength = (array.length * 2) - hex.length();
- if (paddingLength > 0) {
- return String.format("%0" + paddingLength + "d", 0) + hex;
- } else {
- return hex;
- }
- }
-
- public static boolean validatePassword(String originalPassword, String storedPassword)
- throws NoSuchAlgorithmException, InvalidKeySpecException {
- String[] parts = storedPassword.split(":");
- int iterations = Integer.parseInt(parts[0]);
-
- byte[] salt = fromHex(parts[1]);
- byte[] hash = fromHex(parts[2]);
-
- PBEKeySpec spec = new PBEKeySpec(originalPassword.toCharArray(), salt, iterations, hash.length * 8);
- SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
- byte[] testHash = skf.generateSecret(spec)
- .getEncoded();
-
- int diff = hash.length ^ testHash.length;
- for (int i = 0; i < hash.length && i < testHash.length; i++) {
- diff |= hash[i] ^ testHash[i];
- }
- return diff == 0;
- }
-
- private static byte[] fromHex(String hex) throws NoSuchAlgorithmException {
- byte[] bytes = new byte[hex.length() / 2];
- for (int i = 0; i < bytes.length; i++) {
- bytes[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
- }
- return bytes;
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/WebData.java b/src/main/java/pl/kuba6000/ae2webintegration/core/WebData.java
deleted file mode 100644
index 7ce2003..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/WebData.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package pl.kuba6000.ae2webintegration.core;
-
-import static pl.kuba6000.ae2webintegration.core.AE2WebIntegration.LOG;
-
-import java.io.File;
-import java.io.Reader;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Optional;
-import java.util.UUID;
-
-import net.neoforged.neoforge.server.ServerLifecycleHooks;
-
-import com.google.common.io.Files;
-import com.google.gson.Gson;
-import com.mojang.authlib.GameProfile;
-
-import pl.kuba6000.ae2webintegration.core.utils.GSONUtils;
-
-public class WebData {
-
- static WebData instance = new WebData();
-
- private static final File dataFile = Config.getConfigFile("webdata.json");
-
- private HashMap UUIDToId = new HashMap<>();
- private HashMap IdToUUID = new HashMap<>();
- private HashMap passwords = new HashMap<>();
-
- public static int getPlayerId(String name) {
- if (name == null || name.isEmpty()) {
- return -1;
- }
- Optional profile = ServerLifecycleHooks.getCurrentServer()
- .getProfileCache()
- .get(name);
- if (!profile.isPresent()) {
- return -1;
- }
- Integer id = instance.UUIDToId.get(
- profile.get()
- .getId());
- if (id != null) {
- return id;
- }
-
- return -1;
- }
-
- public static boolean verifyPassword(int playerId, String password) {
- UUID id = instance.IdToUUID.get(playerId);
- if (id == null) {
- LOG.warn("Player ID {} not found in IdToUUID map.", playerId);
- return false;
- }
- if (instance.passwords.containsKey(id)) {
- try {
- return PasswordHelper.validatePassword(password, instance.passwords.get(id));
- } catch (Exception e) {
- LOG.error("Password verification failed for player ID: {}", playerId, e);
- return false;
- }
- }
-
- return false;
- }
-
- public static void setPassword(GameProfile playerId, String passwordHash) {
- if (passwordHash == null || passwordHash.isEmpty()) {
- instance.passwords.remove(playerId.getId());
- } else {
- try {
- instance.passwords.put(playerId.getId(), passwordHash);
- int pID = AE2Controller.AE2Interface.web$getPlayerData()
- .web$getPlayerId(playerId);
- instance.UUIDToId.put(playerId.getId(), pID);
- instance.IdToUUID.put(pID, playerId.getId());
- } catch (Exception e) {
- LOG.error("Failed to set password for player ID: {}", playerId, e);
- }
- }
- saveChanges();
- }
-
- private static void saveChanges() {
- Gson gson = GSONUtils.GSON_BUILDER.create();
- Writer writer = null;
- try {
- writer = Files.newWriter(dataFile, StandardCharsets.UTF_8);
- gson.toJson(instance, writer);
- writer.flush();
- writer.close();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (writer != null) try {
- writer.close();
- } catch (Exception ignored) {}
- }
- }
-
- public static void loadData() {
- Gson gson = GSONUtils.GSON_BUILDER.create();
- if (!dataFile.exists()) {
- LOG.info("Web data file not found, creating a new one.");
- saveChanges();
- return;
- }
- Reader reader = null;
- try {
- reader = Files.newReader(dataFile, StandardCharsets.UTF_8);
- instance = gson.fromJson(reader, WebData.class);
- } catch (Exception e) {
- LOG.error("Failed to load web data from file: {}", dataFile.getAbsolutePath(), e);
- instance.UUIDToId.clear();
- instance.IdToUUID.clear();
- instance.passwords.clear();
- saveChanges();
- } finally {
- if (reader != null) try {
- reader.close();
- } catch (Exception ignored) {}
- }
-
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/IRequest.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/IRequest.java
deleted file mode 100644
index 07f7a9e..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/IRequest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import com.google.gson.GsonBuilder;
-
-import pl.kuba6000.ae2webintegration.core.AE2Controller;
-import pl.kuba6000.ae2webintegration.core.utils.GSONUtils;
-
-public abstract class IRequest {
-
- protected static GsonBuilder JSONBuilder = GSONUtils.GSON_BUILDER;
-
- private static class JSON_Structure {
-
- String status;
- Object data;
- }
-
- public AtomicBoolean isDone = new AtomicBoolean(false);
- protected String status = "TIMEOUT";
- protected Object data = null;
-
- abstract public void handle(AE2Controller.RequestContext context);
-
- Object getData() {
- return data;
- }
-
- protected void setData(Object data) {
- this.data = data;
- }
-
- public String getJSON() {
- JSON_Structure structure = new JSON_Structure();
- structure.status = status;
- structure.data = getData();
- return JSONBuilder.create()
- .toJson(structure);
- }
-
- public void done() {
- this.status = "OK";
- this.isDone.set(true);
- }
-
- public void deny(String status) {
- this.status = status;
- this.isDone.set(true);
- }
-
- public void noParam(String... params) {
- deny("NO_PARAM");
- setData(params);
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/GetTracking.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/GetTracking.java
deleted file mode 100644
index 0e9f3d6..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/GetTracking.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.async;
-
-import java.util.Map;
-
-import pl.kuba6000.ae2webintegration.core.AE2JobTracker;
-import pl.kuba6000.ae2webintegration.core.api.JSON_CompactedJobTrackingInfo;
-
-public class GetTracking extends IAsyncRequest {
-
- @Override
- public void handle(Map getParams) {
- if (grid == null) {
- deny("GRID_NOT_FOUND");
- return;
- }
- if (!getParams.containsKey("id")) {
- noParam("id");
- return;
- }
- int id = Integer.parseInt(getParams.get("id"));
-
- AE2JobTracker.JobTrackingInfo info = grid.trackingInfo.trackingInfos.get(id);
- if (info == null) {
- deny("TRACKING_NOT_FOUND");
- return;
- }
-
- setData(new JSON_CompactedJobTrackingInfo(info));
- done();
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/GetTrackingHistory.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/GetTrackingHistory.java
deleted file mode 100644
index 94146c3..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/GetTrackingHistory.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.async;
-
-import java.util.ArrayList;
-import java.util.Map;
-
-import pl.kuba6000.ae2webintegration.core.AE2JobTracker;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGenericStack;
-
-public class GetTrackingHistory extends IAsyncRequest {
-
- private static class JSON_TrackingHistoryElement {
-
- public long timeStarted;
- public long timeDone;
- public boolean wasCancelled;
- public IAEGenericStack finalOutput;
- public int id;
- }
-
- @Override
- public void handle(Map getParams) {
- if (grid == null) {
- deny("GRID_NOT_FOUND");
- return;
- }
- ArrayList jobs = new ArrayList<>(grid.trackingInfo.trackingInfos.size());
-
- for (Map.Entry integerJobTrackingInfoEntry : grid.trackingInfo.trackingInfos
- .entrySet()) {
- JSON_TrackingHistoryElement element = new JSON_TrackingHistoryElement();
- element.id = integerJobTrackingInfoEntry.getKey();
- element.timeStarted = integerJobTrackingInfoEntry.getValue().timeStarted;
- element.timeDone = integerJobTrackingInfoEntry.getValue().timeDone;
- element.wasCancelled = integerJobTrackingInfoEntry.getValue().wasCancelled;
- element.finalOutput = integerJobTrackingInfoEntry.getValue().finalOutput;
- jobs.add(element);
- }
-
- jobs.sort((i1, i2) -> Long.compare(i2.timeDone, i1.timeDone));
-
- setData(jobs);
- done();
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/GridSettings.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/GridSettings.java
deleted file mode 100644
index 944bf97..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/GridSettings.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.async;
-
-import java.util.Map;
-
-import pl.kuba6000.ae2webintegration.core.GridData;
-
-public class GridSettings extends IAsyncRequest {
-
- @Override
- public void handle(Map getParams) {
- if (grid == null) {
- deny("GRID_NOT_FOUND");
- return;
- }
-
- if (getParams.containsKey("track")) {
- grid.isTracked = getParams.get("track")
- .equals("1");
- GridData.saveChanges();
- }
-
- setData(grid);
- done();
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/IAsyncRequest.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/IAsyncRequest.java
deleted file mode 100644
index 26f8e21..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/async/IAsyncRequest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.async;
-
-import java.util.Map;
-
-import pl.kuba6000.ae2webintegration.core.AE2Controller;
-import pl.kuba6000.ae2webintegration.core.GridData;
-import pl.kuba6000.ae2webintegration.core.ae2request.IRequest;
-
-public abstract class IAsyncRequest extends IRequest {
-
- protected AE2Controller.RequestContext context = null;
- protected long gridKey = -1;
- protected GridData grid = null;
-
- public void handle(Map getParams) {};
-
- @Override
- public void handle(AE2Controller.RequestContext context) {
- this.context = context;
- String gridstr = context.getGetParams()
- .get("grid");
- if (gridstr == null || gridstr.isEmpty()) gridKey = -1;
- else gridKey = Long.parseLong(gridstr);
- if (gridKey != -1) {
- grid = GridData.get(gridKey);
- }
- handle(context.getGetParams());
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/CancelCPU.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/CancelCPU.java
deleted file mode 100644
index 4428572..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/CancelCPU.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.sync;
-
-import java.util.Map;
-
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingCPUCluster;
-
-public class CancelCPU extends ISyncedRequest {
-
- private String cpuName;
-
- @Override
- boolean init(Map getParams) {
- if (!getParams.containsKey("cpu")) {
- noParam("cpu");
- return false;
- }
- cpuName = getParams.get("cpu");
- return true;
- }
-
- @Override
- void handle(IAEGrid grid) {
- if (grid == null) {
- deny("GRID_NOT_FOUND");
- return;
- }
- ICraftingCPUCluster cluster = GetCPUList.getCPUList(grid.web$getCraftingGrid())
- .get(cpuName);
- if (cluster == null) {
- deny("CPU_NOT_FOUND");
- return;
- }
- if (cluster.web$isBusy()) {
- cluster.web$cancel();
- done();
- return;
- }
- deny("CPU_NOT_BUSY");
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetCPU.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetCPU.java
deleted file mode 100644
index 99dccf7..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetCPU.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.sync;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-
-import it.unimi.dsi.fastutil.objects.Object2LongMap;
-import pl.kuba6000.ae2webintegration.core.AE2Controller;
-import pl.kuba6000.ae2webintegration.core.AE2JobTracker;
-import pl.kuba6000.ae2webintegration.core.api.JSON_CompactedItem;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGenericStack;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingCPUCluster;
-import pl.kuba6000.ae2webintegration.core.interfaces.IItemList;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAECraftingGrid;
-
-public class GetCPU extends ISyncedRequest {
-
- private static class JSON_ClusterData {
-
- public long size;
- public boolean isBusy;
- public IAEGenericStack finalOutput;
- public ArrayList items;
- public boolean hasTrackingInfo = false;
- public long timeStarted = 0L;
- public long timeElapsed = 0L;
- }
-
- String cpuName = null;
-
- @Override
- boolean init(Map getParams) {
- if (!getParams.containsKey("cpu")) {
- noParam("cpu");
- return false;
- }
- cpuName = getParams.get("cpu");
- return true;
- }
-
- @Override
- void handle(IAEGrid grid) {
- if (grid == null) {
- deny("GRID_NOT_FOUND");
- return;
- }
- IAECraftingGrid craftingGrid = grid.web$getCraftingGrid();
-
- ICraftingCPUCluster cpu = GetCPUList.getCPUList(craftingGrid)
- .get(cpuName);
- if (cpu == null) {
- deny("CPU_NOT_FOUND");
- return;
- }
-
- JSON_ClusterData clusterData = new JSON_ClusterData();
- clusterData.size = cpu.web$getAvailableStorage();
- clusterData.isBusy = cpu.web$isBusy();
- if (clusterData.isBusy) {
- clusterData.finalOutput = cpu.web$getFinalOutput();
- AE2JobTracker.JobTrackingInfo trackingInfo = AE2JobTracker.trackingInfoMap.get(cpu);
- clusterData.hasTrackingInfo = trackingInfo != null;
-
- HashMap prep = new HashMap<>();
- IItemList items = AE2Controller.AE2Interface.web$createItemList();
- cpu.web$getAllItems(items);
- for (Object2LongMap.Entry entry : items) {
- IAEKey key = entry.getKey();
- JSON_CompactedItem compactedItem = JSON_CompactedItem.create(key);
- compactedItem.active = cpu.web$getActiveItems(key);
- compactedItem.pending = cpu.web$getPendingItems(key);
- compactedItem.stored = cpu.web$getStorageItems(key);
- prep.put(key, compactedItem);
- }
-
- if (clusterData.hasTrackingInfo) {
- clusterData.timeStarted = trackingInfo.timeStarted;
- clusterData.timeElapsed = (System.currentTimeMillis()) - clusterData.timeStarted;
- for (IAEKey stack : trackingInfo.timeSpentOn.keySet()) {
- JSON_CompactedItem compactedItem = prep
- .computeIfAbsent(stack, k -> JSON_CompactedItem.create(stack));
- compactedItem.timeSpentCrafting += trackingInfo.getTimeSpentOn(stack);
- compactedItem.craftedTotal += trackingInfo.craftedTotal.getOrDefault(stack, 0L);
- compactedItem.shareInCraftingTime += trackingInfo.getShareInCraftingTime(stack);
- compactedItem.shareInCraftingTimeCombined = Math
- .min(((double) compactedItem.timeSpentCrafting) / (double) clusterData.timeElapsed, 1d);
- compactedItem.craftsPerSec = (double) compactedItem.craftedTotal
- / (compactedItem.timeSpentCrafting / 1000d);
- }
- }
-
- clusterData.items = new ArrayList<>(prep.values());
- // TODO Move sorting to javascript!
- clusterData.items.sort((i1, i2) -> {
- if (i1.active > 0 && i2.active > 0) return Long.compare(i2.active, i1.active);
- else if (i1.active > 0 && i2.active == 0) return -1;
- else if (i1.active == 0 && i2.active > 0) return 1;
- if (i1.pending > 0 && i2.pending > 0) return Long.compare(i2.pending, i1.pending);
- else if (i1.pending > 0 && i2.pending == 0) return -1;
- else if (i1.pending == 0 && i2.pending > 0) return 1;
- return Long.compare(i2.stored, i1.stored);
- });
-
- }
-
- setData(clusterData);
- done();
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetCPUList.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetCPUList.java
deleted file mode 100644
index 5784c34..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetCPUList.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.sync;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import pl.kuba6000.ae2webintegration.core.AE2JobTracker;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGenericStack;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingCPUCluster;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAECraftingGrid;
-
-public class GetCPUList extends ISyncedRequest {
-
- private static class JSON_CpuInfo {
-
- public boolean isBusy;
- public IAEGenericStack finalOutput;
- public long availableStorage;
- public long usedStorage;
- public long coProcessors;
- public boolean hasTrackingInfo = false;
- public long timeStarted = 0L;
- }
-
- public static Map getCPUList(IAECraftingGrid craftingGrid) {
- LinkedHashMap orderedMap = new LinkedHashMap<>();
- for (ICraftingCPUCluster cpu : craftingGrid.web$getCPUs()) {
- String name = cpu.web$getName();
- orderedMap.put(name, cpu);
- }
- return orderedMap;
- }
-
- @Override
- boolean init(Map getParams) {
- return true;
- }
-
- @Override
- void handle(IAEGrid grid) {
- if (grid == null) {
- deny("GRID_NOT_FOUND");
- return;
- }
- Map clusters = getCPUList(grid.web$getCraftingGrid());
- LinkedHashMap cpuList = new LinkedHashMap<>(clusters.size());
- for (Map.Entry entry : clusters.entrySet()) {
- JSON_CpuInfo cpuInfo = new JSON_CpuInfo();
- ICraftingCPUCluster cluster = entry.getValue();
- cpuInfo.availableStorage = cluster.web$getAvailableStorage();
- cpuInfo.usedStorage = cluster.web$getUsedStorage();
- cpuInfo.coProcessors = cluster.web$getCoProcessors();
- if (cpuInfo.isBusy = cluster.web$isBusy()) {
- cpuInfo.finalOutput = cluster.web$getFinalOutput();
- AE2JobTracker.JobTrackingInfo trackingInfo = AE2JobTracker.trackingInfoMap.get(cluster);
- if (cpuInfo.hasTrackingInfo = trackingInfo != null) {
- cpuInfo.timeStarted = trackingInfo.timeStarted;
- }
- }
- cpuList.put(entry.getKey(), cpuInfo);
- }
- setData(cpuList);
- done();
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetGridList.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetGridList.java
deleted file mode 100644
index 06c3a82..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetGridList.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.sync;
-
-import java.util.ArrayList;
-
-import com.mojang.authlib.GameProfile;
-
-import pl.kuba6000.ae2webintegration.core.GridData;
-import pl.kuba6000.ae2webintegration.core.api.AEApi.AEControllerState;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAE;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAEPathingGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAESecurityGrid;
-
-public class GetGridList extends ISyncedRequest {
-
- private static class JSON_GridData {
-
- JSON_GridData(long key, int cpuCount, String owner, boolean isOwned, boolean isTrackingEnabled) {
- this.key = key;
- this.cpuCount = cpuCount;
- this.owner = owner;
- this.isOwned = isOwned;
- this.isTrackingEnabled = isTrackingEnabled;
- }
-
- public long key; // key == -1 -> not attachable
- public int cpuCount;
- public String owner;
- public boolean isOwned;
- public boolean isTrackingEnabled = false;
- }
-
- @Override
- public void handle(IAE ae) {
- ArrayList grids = new ArrayList<>();
- for (IAEGrid grid : ae.web$getGrids()) {
- IAEPathingGrid pathing = grid.web$getPathingGrid();
- if (pathing == null || pathing.web$isNetworkBooting()
- || pathing.web$getControllerState() != AEControllerState.CONTROLLER_ONLINE) {
- continue;
- }
- IAESecurityGrid security = grid.web$getSecurityGrid();
- if (security == null || !security.web$isAvailable() || security.web$getSecurityKey() == -1) {
- if (context.isAdmin()) {
- grids.add(
- new JSON_GridData(
- -1,
- grid.web$getCraftingGrid()
- .web$getCPUCount(),
- "N/A",
- false,
- false));
- }
- continue;
- }
- if (!context.isAdmin() && !security.web$hasPermissions(context.getUserID())) {
- continue;
- }
- GameProfile gameProfile = security.web$getOwnerProfile();
- GridData gridData = GridData.get(security.web$getSecurityKey());
- grids.add(
- new JSON_GridData(
- security.web$getSecurityKey(),
- grid.web$getCraftingGrid()
- .web$getCPUCount(),
- gameProfile == null ? "N/A" : gameProfile.getName(),
- security.web$hasPermissions(context.getUserID()),
- gridData.isTracked));
- }
- grids.sort((d1, d2) -> {
- if (d1.isOwned && !d2.isOwned) {
- return -1;
- } else if (!d1.isOwned && d2.isOwned) {
- return 1;
- } else if (d1.isTrackingEnabled && !d2.isTrackingEnabled) {
- return -1;
- } else if (!d1.isTrackingEnabled && d2.isTrackingEnabled) {
- return 1;
- } else if (d1.key == -1 && d2.key != -1) {
- return 1; // unattached grids go to the end
- } else if (d1.key != -1 && d2.key == -1) {
- return -1; // attached grids come first
- } else {
- return Integer.compare(d2.cpuCount, d1.cpuCount); // sort by cpu count if all else is equal
- }
- });
- setData(grids);
- done();
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetItems.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetItems.java
deleted file mode 100644
index ec94ba2..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/GetItems.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.sync;
-
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.Set;
-
-import it.unimi.dsi.fastutil.objects.Object2LongMap;
-import pl.kuba6000.ae2webintegration.core.AE2Controller;
-import pl.kuba6000.ae2webintegration.core.api.JSON_DetailedItem;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-import pl.kuba6000.ae2webintegration.core.interfaces.IItemList;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAECraftingGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAEStorageGrid;
-
-public class GetItems extends ISyncedRequest {
-
- @Override
- boolean init(Map getParams) {
- return true;
- }
-
- @Override
- void handle(IAEGrid grid) {
- if (grid == null) {
- deny("GRID_NOT_FOUND");
- return;
- }
- IAEStorageGrid storageGrid = grid.web$getStorageGrid();
- IAECraftingGrid craftingGrid = grid.web$getCraftingGrid();
- IItemList storageList = storageGrid.web$getItemStorageList();
- Set craftables = craftingGrid.web$getCraftables(null);
- AE2Controller.hashcodeToAEKey.clear();
- ArrayList items = new ArrayList<>();
- for (Object2LongMap.Entry entry : storageList) {
- IAEKey stack = entry.getKey();
- int hash;
- AE2Controller.hashcodeToAEKey.put(hash = stack.hashCode(), stack);
- JSON_DetailedItem detailedItem = new JSON_DetailedItem();
- detailedItem.itemid = stack.web$getItemID();
- detailedItem.itemname = stack.web$getDisplayName();
- detailedItem.quantity = entry.getLongValue();
- detailedItem.craftable = craftables.remove(stack);
- detailedItem.hashcode = hash;
- items.add(detailedItem);
- }
- for (IAEKey craftable : craftables) {
- int hash;
- // if (storageList.web$findPrecise(craftable) == 0
- // && !AE2Controller.hashcodeToAEKey.containsKey(hash = craftable.hashCode())) {
- AE2Controller.hashcodeToAEKey.put(hash = craftable.hashCode(), craftable);
- JSON_DetailedItem detailedItem = new JSON_DetailedItem();
- detailedItem.itemid = craftable.web$getItemID();
- detailedItem.itemname = craftable.web$getDisplayName();
- detailedItem.quantity = 0;
- detailedItem.craftable = true;
- detailedItem.hashcode = hash;
- items.add(detailedItem);
- // }
- }
- setData(items);
- done();
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/ISyncedRequest.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/ISyncedRequest.java
deleted file mode 100644
index b165dec..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/ISyncedRequest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.sync;
-
-import java.util.Map;
-
-import pl.kuba6000.ae2webintegration.core.AE2Controller;
-import pl.kuba6000.ae2webintegration.core.GridData;
-import pl.kuba6000.ae2webintegration.core.ae2request.IRequest;
-import pl.kuba6000.ae2webintegration.core.api.AEApi.AEControllerState;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAE;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAEPathingGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAESecurityGrid;
-
-public abstract class ISyncedRequest extends IRequest {
-
- protected AE2Controller.RequestContext context = null;
- protected long gridKey = -1;
- protected IAEGrid grid = null;
- protected GridData gridData = null;
-
- boolean init(Map getParams) {
- return true;
- }
-
- public boolean init(AE2Controller.RequestContext context) {
- this.context = context;
- String gridstr = context.getGetParams()
- .get("grid");
- if (gridstr == null || gridstr.isEmpty()) gridKey = -1;
- else gridKey = Long.parseLong(gridstr);
- return init(context.getGetParams());
- }
-
- void handle(IAEGrid grid) {}
-
- public void handle(IAE ae) {
- if (gridKey != -1) {
- for (IAEGrid grid : ae.web$getGrids()) {
- IAEPathingGrid pathing = grid.web$getPathingGrid();
- if (pathing == null || pathing.web$isNetworkBooting()
- || pathing.web$getControllerState() != AEControllerState.CONTROLLER_ONLINE) {
- continue;
- }
- IAESecurityGrid security = grid.web$getSecurityGrid();
- if (security == null || !security.web$isAvailable()) {
- continue;
- }
- if (gridKey == security.web$getSecurityKey()) {
- if (!context.isAdmin() && !security.web$hasPermissions(context.getUserID())) {
- deny("NO_PERMISSIONS");
- return;
- }
- this.grid = grid;
- }
- }
- }
- if (grid != null) gridData = GridData.get(gridKey);
- handle(grid);
- }
-
- @Override
- public void handle(AE2Controller.RequestContext context) {
- throw new IllegalArgumentException("ONLY SYNCED");
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/Job.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/Job.java
deleted file mode 100644
index aea8f46..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/Job.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.sync;
-
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
-import pl.kuba6000.ae2webintegration.core.interfaces.IAECraftingJob;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEMeInventoryItem;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingCPUCluster;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingPlanSummary;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingPlanSummaryEntry;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAECraftingGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAEStorageGrid;
-
-public class Job extends ISyncedRequest {
-
- private static class JSON_JobData {
-
- boolean isDone;
- public boolean isSimulating;
- public long bytesTotal;
- public ArrayList plan;
-
- public static class JobItem {
-
- public String itemid;
- public String itemname;
- public long stored;
- public long requested;
- public long missing;
- public long steps;
- public double usedPercent;
- }
- }
-
- private enum ERequestType {
- CHECK,
- CANCEL,
- SUBMIT
- }
-
- private ERequestType type = null;
- private int jobID;
- private String cpuName;
-
- @Override
- boolean init(Map getParams) {
- if (!getParams.containsKey("id")) {
- noParam("id");
- return false;
- }
- this.jobID = Integer.parseInt(getParams.get("id"));
- if (getParams.containsKey("cancel")) this.type = ERequestType.CANCEL;
- else if (getParams.containsKey("submit")) {
- this.type = ERequestType.SUBMIT;
- if (getParams.containsKey("cpu")) this.cpuName = getParams.get("cpu");
- } else this.type = ERequestType.CHECK;
- return true;
- }
-
- @Override
- void handle(IAEGrid grid) {
- if (grid == null) {
- deny("GRID_NOT_FOUND");
- return;
- }
- Future job = gridData.jobs.get(jobID);
- if (job == null) {
- deny("INVALID_ID");
- return;
- }
- if (type == ERequestType.CHECK) {
- JSON_JobData jobData = new JSON_JobData();
- if (jobData.isDone = job.isDone()) {
- try {
- IAECraftingJob craftingJob = job.get();
- IAEStorageGrid storageGrid = grid.web$getStorageGrid();
- IAEMeInventoryItem items = storageGrid.web$getItemInventory();
- jobData.isSimulating = craftingJob.web$isSimulation();
- jobData.bytesTotal = craftingJob.web$getByteTotal();
- ICraftingPlanSummary summary = craftingJob.web$generateSummary(grid);
- jobData.plan = new ArrayList<>();
- for (ICraftingPlanSummaryEntry entry : summary.web$getEntries()) {
- JSON_JobData.JobItem jobItem = new JSON_JobData.JobItem();
- IAEKey stack = entry.web$getWhat();
- jobItem.itemid = stack.web$getItemID();
- jobItem.itemname = stack.web$getDisplayName();
- jobItem.requested = entry.web$getCraftAmount();
- jobItem.steps = -1L; // steps not supported
- jobItem.stored = entry.web$getStoredAmount();
- jobItem.missing = entry.web$getMissingAmount();
- if (jobItem.missing == 0 && jobItem.requested == 0 && jobItem.stored > 0) {
- long available = items.web$getAvailableItem(stack, grid);
- if (available > 0L) jobItem.usedPercent = (double) jobItem.stored / (double) available;
- }
- jobData.plan.add(jobItem);
- }
- // TODO Move sorting to javascript!
- jobData.plan.sort((i1, i2) -> {
- if (i1.missing > 0 && i2.missing > 0) return Long.compare(i2.missing, i1.missing);
- else if (i1.missing > 0 && i2.missing == 0) return -1;
- else if (i1.missing == 0 && i2.missing > 0) return 1;
- if (i1.requested > 0 && i2.requested > 0) return Long.compare(i2.steps, i1.steps);
- else if (i1.requested > 0 && i2.requested == 0) return -1;
- else if (i1.requested == 0 && i2.requested > 0) return 1;
- return Long.compare(i2.stored, i1.stored);
- });
- } catch (InterruptedException | ExecutionException e) {
- e.printStackTrace();
- deny("INTERNAL_ERROR");
- return;
- }
- }
- setData(jobData);
- done();
- } else if (type == ERequestType.CANCEL) {
- job.cancel(true);
- gridData.jobs.remove(this.jobID);
- done();
- } else if (type == ERequestType.SUBMIT) {
- IAECraftingGrid craftingGrid = grid.web$getCraftingGrid();
- if (job.isDone()) {
- try {
- IAECraftingJob craftingJob = job.get();
- ICraftingCPUCluster target = null;
- if (cpuName != null) {
- target = GetCPUList.getCPUList(craftingGrid)
- .get(cpuName);
- if (target == null) {
- deny("CPU_NOT_FOUND");
- return;
- }
- }
- String error = craftingGrid.web$submitJob(craftingJob, target, true, grid);
- if (error != null) {
- deny("FAIL");
- setData(error);
- } else {
- done();
- }
- } catch (InterruptedException | ExecutionException e) {
- e.printStackTrace();
- deny("INTERNAL_ERROR");
- }
- } else {
- deny("JOB_NOT_DONE");
- }
- }
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/Order.java b/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/Order.java
deleted file mode 100644
index eb9e48f..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/ae2request/sync/Order.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.ae2request.sync;
-
-import static pl.kuba6000.ae2webintegration.core.AE2Controller.hashcodeToAEKey;
-
-import java.util.Map;
-import java.util.concurrent.Future;
-
-import com.google.gson.JsonObject;
-
-import pl.kuba6000.ae2webintegration.core.interfaces.IAECraftingJob;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingCPUCluster;
-import pl.kuba6000.ae2webintegration.core.interfaces.IItemList;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAECraftingGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAEStorageGrid;
-
-public class Order extends ISyncedRequest {
-
- private IAEKey item;
- private long quantity;
-
- @Override
- boolean init(Map getParams) {
- if (!getParams.containsKey("item") || !getParams.containsKey("quantity")) {
- noParam("item", "quantity");
- return false;
- }
- int hash = Integer.parseInt(getParams.get("item"));
- this.quantity = Integer.parseInt(getParams.get("quantity"));
- this.item = hashcodeToAEKey.get(hash);
- if (this.item == null) {
- deny("ITEM_NOT_FOUND");
- return false;
- }
- return true;
- }
-
- @Override
- void handle(IAEGrid grid) {
- if (grid == null) {
- deny("GRID_NOT_FOUND");
- return;
- }
- IAECraftingGrid craftingGrid = grid.web$getCraftingGrid();
- boolean allBusy = true;
- for (ICraftingCPUCluster cpu : craftingGrid.web$getCPUs()) {
- if (!cpu.web$isBusy()) {
- allBusy = false;
- break;
- }
- }
- if (!allBusy) {
- IAEStorageGrid storageGrid = grid.web$getStorageGrid();
- final IItemList itemList = storageGrid.web$getItemStorageList();
- // long realItem = itemList.web$findPrecise(this.item);
- if (/* realItem > 0L && */this.item.web$isCraftable(grid)) {
- Future job = craftingGrid.web$beginCraftingJob(grid, this.item, this.quantity);
-
- int jobID = gridData.addJob(job);
- JsonObject jobData = new JsonObject();
- jobData.addProperty("jobID", jobID);
- if (gridData.jobs.size() > 3) {
- int toDeleteBelowAndEqual = jobID - 3;
- gridData.jobs.entrySet()
- .removeIf(integerFutureEntry -> integerFutureEntry.getKey() <= toDeleteBelowAndEqual);
- }
- setData(jobData);
- done();
- } else {
- deny("ITEM_NOT_FOUND");
- }
- } else {
- deny("ALL_CPU_BUSY");
- }
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/api/AEApi/AEActionable.java b/src/main/java/pl/kuba6000/ae2webintegration/core/api/AEApi/AEActionable.java
deleted file mode 100644
index f6ce667..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/api/AEApi/AEActionable.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.api.AEApi;
-
-public enum AEActionable {
- MODULATE,
- SIMULATE
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/api/AEApi/AEControllerState.java b/src/main/java/pl/kuba6000/ae2webintegration/core/api/AEApi/AEControllerState.java
deleted file mode 100644
index b3f4bf1..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/api/AEApi/AEControllerState.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.api.AEApi;
-
-public enum AEControllerState {
- NO_CONTROLLER,
- CONTROLLER_ONLINE,
- CONTROLLER_CONFLICT,
- // not implemented
- UNSUPPORTED
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/api/DimensionalCoords.java b/src/main/java/pl/kuba6000/ae2webintegration/core/api/DimensionalCoords.java
deleted file mode 100644
index 12b6bb7..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/api/DimensionalCoords.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.api;
-
-import java.util.Objects;
-
-import net.minecraft.resources.ResourceKey;
-import net.minecraft.world.level.Level;
-
-import pl.kuba6000.ae2webintegration.core.utils.GSONUtils;
-
-public class DimensionalCoords {
-
- @GSONUtils.SkipGSON
- ResourceKey dimid_internal;
- String dimid;
- int x;
- int y;
- int z;
-
- public DimensionalCoords(ResourceKey dimid, int x, int y, int z) {
- this.dimid_internal = dimid;
- this.dimid = dimid_internal.location()
- .toString();
- this.x = x;
- this.y = y;
- this.z = z;
- }
-
- public DimensionalCoords(Level world, int x, int y, int z) {
- this.dimid_internal = world.dimension();
- this.dimid = dimid_internal.location()
- .toString();
- this.x = x;
- this.y = y;
- this.z = z;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(dimid_internal.registry(), dimid_internal.location(), x, y, z);
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof DimensionalCoords coords && coords.dimid_internal.equals(dimid_internal)
- && coords.x == x
- && coords.y == y
- && coords.z == z;
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/api/IAEMixinCallbacks.java b/src/main/java/pl/kuba6000/ae2webintegration/core/api/IAEMixinCallbacks.java
deleted file mode 100644
index 7fdba8c..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/api/IAEMixinCallbacks.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.api;
-
-import pl.kuba6000.ae2webintegration.core.AEMixinCallbacks;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAECraftingPatternDetails;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingCPUCluster;
-import pl.kuba6000.ae2webintegration.core.interfaces.IPatternProviderViewable;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAECraftingGrid;
-
-public interface IAEMixinCallbacks {
-
- static IAEMixinCallbacks getInstance() {
- return AEMixinCallbacks.INSTANCE;
- }
-
- void jobStarted(ICraftingCPUCluster cpuCluster, IAECraftingGrid cache, IAEGrid grid, boolean isMerging,
- boolean isAuthorPlayer);
-
- void craftingStatusPostedUpdate(ICraftingCPUCluster cpu, IAEKey diff);
-
- void pushedPattern(ICraftingCPUCluster cpu, IPatternProviderViewable provider, IAECraftingPatternDetails details);
-
- void jobCompleted(IAEGrid grid, ICraftingCPUCluster cpu);
-
- void jobCancelled(IAEGrid grid, ICraftingCPUCluster cpu);
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/api/IAEWebInterface.java b/src/main/java/pl/kuba6000/ae2webintegration/core/api/IAEWebInterface.java
deleted file mode 100644
index 9e70f30..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/api/IAEWebInterface.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.api;
-
-import com.mojang.authlib.GameProfile;
-
-import pl.kuba6000.ae2webintegration.core.AEWebAPI;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAE;
-
-public interface IAEWebInterface {
-
- static IAEWebInterface getInstance() {
- return AEWebAPI.INSTANCE;
- }
-
- GameProfile getAEWebGameProfile();
-
- void initAEInterface(IAE ae);
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/api/JSON_CompactedItem.java b/src/main/java/pl/kuba6000/ae2webintegration/core/api/JSON_CompactedItem.java
deleted file mode 100644
index e932d6e..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/api/JSON_CompactedItem.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.api;
-
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-import pl.kuba6000.ae2webintegration.core.utils.GSONUtils;
-
-public class JSON_CompactedItem {
-
- @GSONUtils.SkipGSON
- private final IAEKey internalItem;
- @GSONUtils.SkipGSON
- private final int hashcode;
-
- public final String itemid;
- public final String itemname;
- public long active = 0;
- public long pending = 0;
- public long stored = 0;
- public long timeSpentCrafting = 0;
- public long craftedTotal = 0;
- public double shareInCraftingTime = 0d;
- public double shareInCraftingTimeCombined = 0d;
- public double craftsPerSec = 0d;
-
- public JSON_CompactedItem(IAEKey itemStack) {
- this.internalItem = itemStack;
- this.hashcode = this.internalItem.hashCode();
- this.itemid = itemStack.web$getItemID();
- this.itemname = itemStack.web$getDisplayName();
- }
-
- public static JSON_CompactedItem create(IAEKey stack) {
- return new JSON_CompactedItem(stack);
- }
-
- @Override
- public int hashCode() {
- return hashcode;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof JSON_CompactedItem) {
- return ((JSON_CompactedItem) obj).internalItem.equals(this.internalItem);
- }
- return false;
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/api/JSON_CompactedJobTrackingInfo.java b/src/main/java/pl/kuba6000/ae2webintegration/core/api/JSON_CompactedJobTrackingInfo.java
deleted file mode 100644
index f1c10c2..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/api/JSON_CompactedJobTrackingInfo.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.api;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Map;
-
-import org.apache.commons.lang3.tuple.Pair;
-
-import pl.kuba6000.ae2webintegration.core.AE2JobTracker;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGenericStack;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-
-public class JSON_CompactedJobTrackingInfo {
-
- public static class timingClass {
-
- long started;
- long ended;
-
- public timingClass(long started, long ended) {
- this.started = started;
- this.ended = ended;
- }
- }
-
- public static class CompactedTrackingGSONItem {
-
- public String itemid;
- public String itemname;
- public long timeSpentOn;
- public long craftedTotal;
- public double shareInCraftingTime = 0d;
- public double shareInCraftingTimeCombined = 0d;
- public double craftsPerSec = 0d;
-
- public ArrayList timings = new ArrayList<>();
- }
-
- public IAEGenericStack finalOutput;
- public long timeStarted;
- public long timeDone;
- public boolean wasCancelled;
- public ArrayList items = new ArrayList<>();
-
- public static class AEInterfaceGSON {
-
- String name;
-
- public ArrayList timings = new ArrayList<>();
- public long timingsCombined;
-
- public HashSet location = new HashSet<>();
- }
-
- public ArrayList interfaceShare = new ArrayList<>();
-
- public JSON_CompactedJobTrackingInfo(AE2JobTracker.JobTrackingInfo info) {
- this.finalOutput = info.finalOutput;
- this.timeStarted = info.timeStarted;
- this.timeDone = info.timeDone;
- long elapsed = this.timeDone - this.timeStarted;
- this.wasCancelled = info.wasCancelled;
- for (Map.Entry entry : info.timeSpentOn.entrySet()) {
- IAEKey stack = entry.getKey();
- long spent = entry.getValue();
- CompactedTrackingGSONItem item = new CompactedTrackingGSONItem();
- item.itemid = stack.web$getItemID();
- item.itemname = stack.web$getDisplayName();
- item.timeSpentOn = spent;
- item.craftedTotal = info.craftedTotal.get(stack);
- item.shareInCraftingTime = info.getShareInCraftingTime(stack);
- item.shareInCraftingTimeCombined = Math.min(((double) item.timeSpentOn) / (double) elapsed, 1d);
- item.craftsPerSec = (double) item.craftedTotal / (item.timeSpentOn / 1000d);
- for (Pair longLongPair : info.itemShare.get(stack)) {
- item.timings.add(new timingClass(longLongPair.getKey(), longLongPair.getValue()));
- }
- items.add(item);
- }
- items.sort((i1, i2) -> Double.compare(i2.shareInCraftingTime, i1.shareInCraftingTime));
- for (Map.Entry>> entry : info.interfaceShare.entrySet()) {
- AEInterfaceGSON interfaceGSON = new AEInterfaceGSON();
- interfaceGSON.name = entry.getKey().name;
- interfaceGSON.location = entry.getKey().location;
- for (Pair longLongPair : entry.getValue()) {
- interfaceGSON.timings.add(new timingClass(longLongPair.getKey(), longLongPair.getValue()));
- }
- long interfaceElapsed = 0L;
- for (Pair pair : entry.getValue()) {
- interfaceElapsed += pair.getValue() - pair.getKey();
- }
- interfaceGSON.timingsCombined = interfaceElapsed;
- interfaceShare.add(interfaceGSON);
- }
- interfaceShare.sort((i1, i2) -> Long.compare(i2.timingsCombined, i1.timingsCombined));
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/api/JSON_DetailedItem.java b/src/main/java/pl/kuba6000/ae2webintegration/core/api/JSON_DetailedItem.java
deleted file mode 100644
index 9a3cc57..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/api/JSON_DetailedItem.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.api;
-
-public class JSON_DetailedItem {
-
- public int hashcode;
- public String itemid;
- public String itemname;
- public long quantity;
- public boolean craftable;
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/commands/BaseCommandHandler.java b/src/main/java/pl/kuba6000/ae2webintegration/core/commands/BaseCommandHandler.java
deleted file mode 100644
index 114f143..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/commands/BaseCommandHandler.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.commands;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.file.Path;
-import java.util.UUID;
-import java.util.function.Function;
-
-import net.minecraft.ChatFormatting;
-import net.minecraft.commands.CommandSourceStack;
-import net.minecraft.commands.Commands;
-import net.minecraft.network.chat.Component;
-import net.minecraft.server.level.ServerPlayer;
-import net.neoforged.fml.config.ConfigTracker;
-import net.neoforged.fml.config.ModConfig;
-import net.neoforged.fml.event.config.ModConfigEvent;
-
-import org.apache.commons.lang3.tuple.Pair;
-
-import com.mojang.brigadier.CommandDispatcher;
-import com.mojang.brigadier.arguments.StringArgumentType;
-import com.mojang.brigadier.builder.RequiredArgumentBuilder;
-import com.mojang.brigadier.context.CommandContext;
-
-import pl.kuba6000.ae2webintegration.core.AE2Controller;
-import pl.kuba6000.ae2webintegration.core.Config;
-import pl.kuba6000.ae2webintegration.core.WebData;
-
-public class BaseCommandHandler {
-
- public static void register(CommandDispatcher dispatcher) {
- dispatcher.register(
- Commands.literal("ae2webintegration")
- .then(
- Commands.literal("reload")
- .requires(p -> p.hasPermission(4))
- .executes(BaseCommandHandler::reload))
- .then(
- Commands.literal("auth")
- .then(
- RequiredArgumentBuilder
- .argument("token", StringArgumentType.string())
- .executes(BaseCommandHandler::auth))));
- }
-
- // force config reload, if the config watcher didn't work for some reason
- public static int reload(CommandContext context) {
- try {
- Method m = ConfigTracker.class.getDeclaredMethod("loadConfig", ModConfig.class, Path.class, Function.class);
- m.setAccessible(true);
- m.invoke(
- null,
- Config.CONFIG,
- Config.CONFIG.getFullPath(),
- (Function) (ModConfigEvent.Reloading::new));
- } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
- context.getSource()
- .sendSuccess(
- () -> Component
- .literal(ChatFormatting.RED + "Error while reloading the config, restart the server instead!"),
- false);
- }
- context.getSource()
- .sendSuccess(
- () -> Component
- .literal(ChatFormatting.GREEN + "Successfully reloaded the config and restarted the web server!"),
- false);
- return 1;
- }
-
- public static int auth(CommandContext context) {
- final String token = StringArgumentType.getString(context, "token");
-
- ServerPlayer sender = context.getSource()
- .getPlayer();
-
- if (sender == null) {
- context.getSource()
- .sendFailure(Component.literal(ChatFormatting.RED + "This command can only be used by players!"));
- return -1;
- }
-
- UUID id = sender.getUUID();
-
- Pair p = AE2Controller.awaitingRegistration.get(id);
- if (p == null) {
- context.getSource()
- .sendFailure(
- Component.literal(
- ChatFormatting.RED + "You have to initialize the registration on the web interface first!"));
- return -1;
- }
-
- if (!p.getLeft()
- .equals(token)) {
- context.getSource()
- .sendFailure(Component.literal(ChatFormatting.RED + "Invalid token!"));
- return -1;
- }
-
- WebData.setPassword(sender.getGameProfile(), p.getRight());
-
- AE2Controller.awaitingRegistration.remove(id);
-
- context.getSource()
- .sendSuccess(() -> Component.literal(ChatFormatting.GREEN + "Registered successfully!"), false);
-
- return 1;
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/discord/DiscordManager.java b/src/main/java/pl/kuba6000/ae2webintegration/core/discord/DiscordManager.java
deleted file mode 100644
index f54046d..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/discord/DiscordManager.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.discord;
-
-import static pl.kuba6000.ae2webintegration.core.AE2WebIntegration.MODID;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.net.URL;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import javax.net.ssl.HttpsURLConnection;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-
-import pl.kuba6000.ae2webintegration.core.Config;
-
-public class DiscordManager extends Thread {
-
- private static final Logger LOG = LogManager.getLogger(MODID + " - DISCORD INTEGRATION");
-
- private static DiscordManager thread;
-
- private static ConcurrentLinkedQueue toPush = new ConcurrentLinkedQueue<>();
-
- public static void init() {
- if (thread != null) return;
- thread = new DiscordManager();
- thread.start();
- }
-
- public static void postMessageNonBlocking(DiscordEmbed message) {
- toPush.offer(message);
- }
-
- public static class DiscordEmbed {
-
- String title;
- String description;
- int color;
-
- public DiscordEmbed(String title, String description, int color) {
- this.title = title;
- this.description = description;
- this.color = color;
- }
-
- public DiscordEmbed(String title, String description) {
- this(title, description, 1752220);
- }
- }
-
- private static void postMessage(DiscordEmbed message) {
- if (Config.INSTANCE.DISCORD_WEBHOOK.get()
- .isEmpty()) return;
-
- String roleID = Config.INSTANCE.DISCORD_ROLE_ID.get();
-
- JsonObject json = new JsonObject();
- json.addProperty("username", "AE2 Web Integration");
- json.addProperty("content", !roleID.isEmpty() ? "<@&" + roleID + ">" : "");
- JsonArray embeds = new JsonArray();
- JsonObject embed = new JsonObject();
- embed.addProperty("title", message.title);
- embed.addProperty("description", message.description);
- embed.addProperty("color", message.color);
- embeds.add(embed);
- json.add("embeds", embeds);
- json.add("attachments", new JsonArray());
-
- URL url = null;
- try {
- url = new URL(Config.INSTANCE.DISCORD_WEBHOOK.get());
-
- HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
- connection.addRequestProperty("Content-Type", "application/json");
- connection.addRequestProperty("User-Agent", "AE2-Web-Integration");
- connection.setDoOutput(true);
- connection.setRequestMethod("POST");
-
- OutputStream stream = connection.getOutputStream();
- stream.write(
- json.toString()
- .getBytes());
- stream.flush();
- stream.close();
-
- int code;
- if ((code = connection.getResponseCode()) != 200 && code != 204) {
- LOG.error("Error, response code: {}", code);
- }
- } catch (IOException e) {
- // throw new RuntimeException(e);
- }
- }
-
- @Override
- public void run() {
- while (true) {
- if (toPush.peek() != null) {
- DiscordEmbed message;
- while ((message = toPush.poll()) != null) {
- postMessage(message);
- }
- }
-
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // throw new RuntimeException(e);
- }
- }
- }
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAE.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAE.java
deleted file mode 100644
index 088f25b..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAE.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-public interface IAE {
-
- Iterable web$getGrids();
-
- IItemList web$createItemList();
-
- IAEPlayerData web$getPlayerData();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAECraftingJob.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAECraftingJob.java
deleted file mode 100644
index d328d2a..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAECraftingJob.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-public interface IAECraftingJob {
-
- boolean web$isSimulation();
-
- long web$getByteTotal();
-
- ICraftingPlanSummary web$generateSummary(IAEGrid grid);
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAECraftingPatternDetails.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAECraftingPatternDetails.java
deleted file mode 100644
index f681125..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAECraftingPatternDetails.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-public interface IAECraftingPatternDetails {
-
- IAEGenericStack[] web$getCondensedOutputs();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEGenericStack.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEGenericStack.java
deleted file mode 100644
index 9b9b636..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEGenericStack.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-public interface IAEGenericStack {
-
- IAEKey web$what();
-
- long web$amount();
-
- IAEGenericStack web$copy();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEGrid.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEGrid.java
deleted file mode 100644
index 38b0ca4..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEGrid.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-import net.minecraft.network.chat.Component;
-
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAECraftingGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAEPathingGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAESecurityGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.service.IAEStorageGrid;
-
-public interface IAEGrid {
-
- IAECraftingGrid web$getCraftingGrid();
-
- IAEPathingGrid web$getPathingGrid();
-
- IAEStorageGrid web$getStorageGrid();
-
- IAESecurityGrid web$getSecurityGrid();
-
- boolean web$isEmpty();
-
- Object web$getPlayerSource();
-
- @Deprecated
- Component web$getLastFakePlayerChatMessage();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEKey.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEKey.java
deleted file mode 100644
index 4fe59ab..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEKey.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-public interface IAEKey {
-
- String web$getItemID();
-
- String web$getDisplayName();
-
- // long web$getStackSize();
-
- boolean web$isCraftable(IAEGrid grid);
-
- // long web$getCountRequestable();
-
- // long web$getCountRequestableCrafts();
-
- // void web$reset();
-
- boolean web$isSameType(IAEKey other);
-
- // IAEKey web$copy();
-
- // void web$setStackSize(long size);
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEMeInventoryItem.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEMeInventoryItem.java
deleted file mode 100644
index 6e18903..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEMeInventoryItem.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-import pl.kuba6000.ae2webintegration.core.api.AEApi.AEActionable;
-
-public interface IAEMeInventoryItem {
-
- long web$extractItems(IAEKey stack, long amount, AEActionable mode, IAEGrid grid);
-
- long web$getAvailableItem(IAEKey stack, IAEGrid grid);
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEPlayerData.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEPlayerData.java
deleted file mode 100644
index 9d882fc..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IAEPlayerData.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-import com.mojang.authlib.GameProfile;
-
-public interface IAEPlayerData {
-
- GameProfile web$getPlayerProfile(int playerId);
-
- int web$getPlayerId(GameProfile id);
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingCPUCluster.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingCPUCluster.java
deleted file mode 100644
index 4f78b1b..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingCPUCluster.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-public interface ICraftingCPUCluster {
-
- void web$setInternalID(int id);
-
- boolean web$hasCustomName();
-
- String web$getName();
-
- long web$getAvailableStorage();
-
- long web$getUsedStorage();
-
- long web$getCoProcessors();
-
- boolean web$isBusy();
-
- void web$cancel();
-
- IAEGenericStack web$getFinalOutput();
-
- void web$getAllItems(IItemList list);
-
- long web$getActiveItems(IAEKey key);
-
- long web$getPendingItems(IAEKey key);
-
- long web$getStorageItems(IAEKey key);
-
- IItemList web$getWaitingFor();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingMediumTracker.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingMediumTracker.java
deleted file mode 100644
index 2b9e73a..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingMediumTracker.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-import java.util.Map;
-
-import appeng.api.networking.IGridNode;
-import appeng.api.networking.crafting.ICraftingProvider;
-
-public interface ICraftingMediumTracker {
-
- Map web$getCraftingMediums();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingPlanSummary.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingPlanSummary.java
deleted file mode 100644
index f6db8b0..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingPlanSummary.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-import java.util.List;
-
-public interface ICraftingPlanSummary {
-
- long web$getUsedBytes();
-
- boolean web$isSimulation();
-
- List web$getEntries();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingPlanSummaryEntry.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingPlanSummaryEntry.java
deleted file mode 100644
index 01efac2..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/ICraftingPlanSummaryEntry.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-public interface ICraftingPlanSummaryEntry {
-
- IAEKey web$getWhat();
-
- long web$getMissingAmount();
-
- long web$getStoredAmount();
-
- long web$getCraftAmount();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IItemList.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IItemList.java
deleted file mode 100644
index 00bf625..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IItemList.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-import it.unimi.dsi.fastutil.objects.Object2LongMap;
-
-public interface IItemList extends Iterable> {
-
- long web$findPrecise(IAEKey stack);
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IPatternProviderViewable.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IPatternProviderViewable.java
deleted file mode 100644
index 23a1722..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/IPatternProviderViewable.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces;
-
-import pl.kuba6000.ae2webintegration.core.api.DimensionalCoords;
-
-public interface IPatternProviderViewable {
-
- String web$getName();
-
- DimensionalCoords web$getLocation();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAECraftingGrid.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAECraftingGrid.java
deleted file mode 100644
index 7e45870..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAECraftingGrid.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces.service;
-
-import java.util.Set;
-import java.util.concurrent.Future;
-import java.util.function.Function;
-
-import pl.kuba6000.ae2webintegration.core.interfaces.IAECraftingJob;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGrid;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingCPUCluster;
-import pl.kuba6000.ae2webintegration.core.interfaces.ICraftingMediumTracker;
-
-public interface IAECraftingGrid {
-
- ICraftingMediumTracker web$getCraftingProviders();
-
- int web$getCPUCount();
-
- Set web$getCPUs();
-
- Future web$beginCraftingJob(IAEGrid grid, IAEKey stack, long quantity);
-
- String web$submitJob(IAECraftingJob job, ICraftingCPUCluster target, boolean prioritizePower, IAEGrid grid);
-
- Set web$getCraftables(Function filter);
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAEPathingGrid.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAEPathingGrid.java
deleted file mode 100644
index 73d0fd1..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAEPathingGrid.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces.service;
-
-import pl.kuba6000.ae2webintegration.core.api.AEApi.AEControllerState;
-
-public interface IAEPathingGrid {
-
- boolean web$isNetworkBooting();
-
- AEControllerState web$getControllerState();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAESecurityGrid.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAESecurityGrid.java
deleted file mode 100644
index abea4bb..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAESecurityGrid.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces.service;
-
-import com.mojang.authlib.GameProfile;
-
-public interface IAESecurityGrid {
-
- boolean web$isAvailable();
-
- long web$getSecurityKey();
-
- int web$getOwner();
-
- GameProfile web$getOwnerProfile();
-
- boolean web$hasPermissions(int playerId);
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAEStorageGrid.java b/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAEStorageGrid.java
deleted file mode 100644
index 6a7402f..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/interfaces/service/IAEStorageGrid.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.interfaces.service;
-
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEMeInventoryItem;
-import pl.kuba6000.ae2webintegration.core.interfaces.IItemList;
-
-public interface IAEStorageGrid {
-
- IItemList web$getItemStorageList();
-
- IAEMeInventoryItem web$getItemInventory();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/utils/GSONUtils.java b/src/main/java/pl/kuba6000/ae2webintegration/core/utils/GSONUtils.java
deleted file mode 100644
index e06386d..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/utils/GSONUtils.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.utils;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import com.google.gson.ExclusionStrategy;
-import com.google.gson.FieldAttributes;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonSerializer;
-
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEGenericStack;
-import pl.kuba6000.ae2webintegration.core.interfaces.IAEKey;
-
-public class GSONUtils {
-
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.FIELD)
- public @interface SkipGSON {}
-
- private static final ExclusionStrategy GSONStrategy = new ExclusionStrategy() {
-
- @Override
- public boolean shouldSkipField(FieldAttributes f) {
- return f.getAnnotation(SkipGSON.class) != null;
- }
-
- @Override
- public boolean shouldSkipClass(Class> clazz) {
- return false;
- }
- };
-
- private static final JsonSerializer IItemStackSerializer = (src, typeOfSrc, context) -> {
- JsonObject json = new JsonObject();
- IAEKey key = src.web$what();
- json.addProperty("itemid", key.web$getItemID());
- json.addProperty("itemname", key.web$getDisplayName());
- json.addProperty("hashcode", key.hashCode());
- json.addProperty("quantity", src.web$amount());
- return json;
- };
-
- public static final GsonBuilder GSON_BUILDER = new GsonBuilder().addSerializationExclusionStrategy(GSONStrategy)
- .addDeserializationExclusionStrategy(GSONStrategy)
- .registerTypeHierarchyAdapter(IAEGenericStack.class, IItemStackSerializer)
- .serializeNulls();
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/utils/HTTPUtils.java b/src/main/java/pl/kuba6000/ae2webintegration/core/utils/HTTPUtils.java
deleted file mode 100644
index 1346eea..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/utils/HTTPUtils.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.utils;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.util.HashMap;
-import java.util.Map;
-
-public class HTTPUtils {
-
- public static Map parseQueryString(String qs) {
- Map result = new HashMap<>();
- if (qs == null) return result;
-
- int last = 0, next, l = qs.length();
- while (last < l) {
- next = qs.indexOf('&', last);
- if (next == -1) next = l;
-
- if (next > last) {
- int eqPos = qs.indexOf('=', last);
- try {
- if (eqPos < 0 || eqPos > next) result.put(URLDecoder.decode(qs.substring(last, next), "utf-8"), "");
- else result.put(
- URLDecoder.decode(qs.substring(last, eqPos), "utf-8"),
- URLDecoder.decode(qs.substring(eqPos + 1, next), "utf-8"));
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e); // will never happen, utf-8 support is mandatory for java
- }
- }
- last = next + 1;
- }
- return result;
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/utils/RateLimiter.java b/src/main/java/pl/kuba6000/ae2webintegration/core/utils/RateLimiter.java
deleted file mode 100644
index f63a2e6..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/utils/RateLimiter.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.utils;
-
-import java.net.InetAddress;
-import java.util.HashMap;
-
-public class RateLimiter {
-
- private final int MAX_REQUESTS_PER_INTERVAL;
- private final int RESET_INTERVAL_MS;
- private final int RESET_WHITELIST_INTERVAL_MS; // 1 hour
-
- public RateLimiter(int maxRequestsPerInterval, int resetIntervalMs, int resetWhitelistIntervalMs) {
- MAX_REQUESTS_PER_INTERVAL = maxRequestsPerInterval;
- RESET_INTERVAL_MS = resetIntervalMs;
- RESET_WHITELIST_INTERVAL_MS = resetWhitelistIntervalMs;
- }
-
- private long lastUpdate = 0;
- private final HashMap requestCounter = new HashMap<>();
- private final HashMap whitelist = new HashMap<>();
-
- public boolean isAllowed(InetAddress userId) {
- updateRequests();
-
- if (whitelist.containsKey(userId)) {
- return true; // User is whitelisted
- }
-
- return requestCounter.merge(userId, 1, Integer::sum) < MAX_REQUESTS_PER_INTERVAL;
- }
-
- public void ensureWhitelisted(InetAddress userId) {
- whitelist.put(userId, System.currentTimeMillis());
- }
-
- private void updateRequests() {
- long currentTime = System.currentTimeMillis();
-
- if (currentTime - lastUpdate > RESET_INTERVAL_MS) { // Reset every 60 seconds
- requestCounter.clear();
- lastUpdate = currentTime;
- }
-
- whitelist.entrySet()
- .removeIf(entry -> currentTime - entry.getValue() > RESET_WHITELIST_INTERVAL_MS); // Remove entries older
- // than 1 hour
- }
-
-}
diff --git a/src/main/java/pl/kuba6000/ae2webintegration/core/utils/VersionChecker.java b/src/main/java/pl/kuba6000/ae2webintegration/core/utils/VersionChecker.java
deleted file mode 100644
index e4846d6..0000000
--- a/src/main/java/pl/kuba6000/ae2webintegration/core/utils/VersionChecker.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package pl.kuba6000.ae2webintegration.core.utils;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
-import java.net.URL;
-
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParser;
-
-import pl.kuba6000.ae2webintegration.Tags;
-
-public class VersionChecker {
-
- // example version: 0.0.9-alpha-forge-1.12.2
- private static final String VERSION_IDENTIFIER = "-neoforge-1.21.1";
-
- private static final String versionCheckURL = "https://api.github.com/repos/kuba6000/AE2-Web-Integration/tags";
- private static String latestTag = null;
-
- private static long lastChecked = 0L;
-
- private static void updateLatestVersion() {
- if (lastChecked != 0L) {
- if (!Tags.VERSION.equals(latestTag)) return;
- long elapsed = System.currentTimeMillis() - lastChecked;
- if (latestTag == null) {
- if (elapsed < 5 * 60 * 1000) // 5 minutes
- return;
- } else if (elapsed < 5 * 60 * 60 * 1000) { // 5 hours
- return;
- }
- }
- lastChecked = System.currentTimeMillis();
- try {
- HttpURLConnection conn = (HttpURLConnection) new URL(versionCheckURL).openConnection();
- if (conn.getResponseCode() == 200) {
- try (BufferedReader buf = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
- JsonElement element = new JsonParser().parse(buf);
- // this should be sorted right?
- for (JsonElement tag : element.getAsJsonArray()) {
- String name = tag.getAsJsonObject()
- .get("name")
- .getAsString();
- if (name.contains(VERSION_IDENTIFIER)) {
- latestTag = name;
- return;
- }
- }
- // not found???
- latestTag = Tags.VERSION;
- }
- }
-
- } catch (Exception ignored) {
-
- }
- }
-
- public static boolean isOutdated() {
- updateLatestVersion();
- if (latestTag == null) return false;
- return !latestTag.equals(Tags.VERSION);
- }
-
- public static String getLatestTag() {
- return latestTag;
- }
-
-}
diff --git a/src/main/resources/assets/favicon.ico b/src/main/resources/assets/favicon.ico
deleted file mode 100644
index 65f94a9..0000000
Binary files a/src/main/resources/assets/favicon.ico and /dev/null differ
diff --git a/src/main/resources/assets/login.html b/src/main/resources/assets/login.html
deleted file mode 100644
index 462a9a3..0000000
--- a/src/main/resources/assets/login.html
+++ /dev/null
@@ -1,257 +0,0 @@
-
-
-
-
-
-
-
-
-
- AE2
-
-
-UNIVERSAL WEB TERMINAL
-
-
- Cookie Notice 🍪
- Before you continue, please note that this website uses cookies to:
-
- Save your terminal preferences
- Enable login functionality
- Improve your overall experience
-
- By clicking "Accept", you consent to our use of cookies.
- Accept Cookies
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/assets/webpage.html b/src/main/resources/assets/webpage.html
deleted file mode 100644
index e927504..0000000
--- a/src/main/resources/assets/webpage.html
+++ /dev/null
@@ -1,1819 +0,0 @@
-
-
-
-
-
-
-
-
-
- AE2
-
-
-
-UNIVERSAL WEB TERMINAL
-
-
-
- No grid selected
-
-
-
-
-
-
- To be able to select a grid, there must be a wireless access point available, and you have to be owner of it (you have to be the one who placed it).
-
-
-
-
-
-
- Terminal options
-
- initializing
- initializing
- initializing
- initializing
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/templates/META-INF/neoforge.mods.toml b/src/main/templates/META-INF/neoforge.mods.toml
index 544a247..39ec5e1 100644
--- a/src/main/templates/META-INF/neoforge.mods.toml
+++ b/src/main/templates/META-INF/neoforge.mods.toml
@@ -4,19 +4,9 @@ issueTrackerURL = "${mod_issue_tracker}"
license = "${mod_license}"
[[mods]]
-modId = "ae2webintegration_core"
+modId = "ae2webintegration"
version = "${version}"
-displayName = "AE2WebIntegration-Core"
-authors = "kuba6000"
-description = "${mod_description}"
-logoFile = ""
-displayURL = "${mod_url}"
-credits = ""
-
-[[mods]]
-modId = "ae2webintegration_interface"
-version = "${version}"
-displayName = "AE2WebIntegration-Interface"
+displayName = "AE2 Web Integration"
authors = "kuba6000"
description = "${mod_description}"
logoFile = ""
@@ -26,7 +16,7 @@ credits = ""
[[mixins]]
config = "mixins.ae2webintegration.json"
-[[dependencies.ae2webintegration_interface]]
+[[dependencies.ae2webintegration]]
modId = "ae2"
mandatory = true
versionRange = "[19.2.4,)"