Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
53bf5c1
native fluid
kuba6000 Nov 8, 2025
3aadfe7
Show fluids in the terminal
kuba6000 Nov 8, 2025
c6064d5
Update dependencies.gradle
kuba6000 Apr 25, 2026
63b57b8
fix crash on order
kuba6000 Apr 25, 2026
1f8f236
Refactor: Extract Forge and Minecraft dependencies out of core engine
kuba6000 May 7, 2026
ed64dcd
Extract core engine to interface submodule and setup gradle dependencies
kuba6000 May 7, 2026
d099f16
Clean up architecture: single @Mod, remove forge/, move core to submo…
kuba6000 May 7, 2026
f266fbc
Rename submodule web-engine -> core to match branch name
kuba6000 May 7, 2026
4f02ca0
fix: wire mod version through interface
kuba6000 May 7, 2026
ba851f4
fix: keep GTNH build passing
kuba6000 May 7, 2026
ee4ffc8
fix: update core submodule — mark jar deobfuscated, remove GTNH conve…
kuba6000 May 7, 2026
ac466ba
fix: update core submodule — deobfuscation attr on all consumable con…
kuba6000 May 7, 2026
4345ea6
fix: avoid Log4j 2.4+ API in CommonProxy for MC 1.7.10 compat
kuba6000 May 7, 2026
dfc5fb0
spotless
kuba6000 May 7, 2026
2c6fc20
Interface: abstract config loading through IConfigProvider, delegate …
kuba6000 May 10, 2026
ab1b838
Interface: delegate command logic to core CommandProcessor
kuba6000 May 10, 2026
ae16d8b
gtnh-native-fluid: Phase 4 - implement new core interfaces (IAEKey, I…
kuba6000 May 10, 2026
5b2bb7e
gtnh-native-fluid: config inversion - ForgeConfigBuilder/Value, core …
kuba6000 May 10, 2026
ec0d2ca
gtnh-native-fluid: command inversion - ForgeCommandContext/Registry, …
kuba6000 May 10, 2026
0d0a5dd
gtnh-native-fluid: fix registration crash + admin password default
kuba6000 May 10, 2026
64a2fa1
Remove accidentally committed AE2 source file
kuba6000 May 10, 2026
e604975
gtnh-native-fluid: full command inversion - ForgeCommandBuilder tree …
kuba6000 May 14, 2026
04c5b33
gtnh-native-fluid: rename Forge*→unprefixed, organize into config/pla…
kuba6000 May 14, 2026
810b590
spotlessApply
kuba6000 May 14, 2026
266aecf
Set VERSION_IDENTIFIER to -forge-1.7.10 in CommonProxy preInit
kuba6000 May 16, 2026
6e6a840
Update core submodule (UTF-8 encoding fix)
kuba6000 May 16, 2026
9f00eed
update core
kuba6000 May 27, 2026
f2ad0e2
Update core
kuba6000 Jun 9, 2026
373a3e0
Fix fluid crafting in interface mixins and update core submodule.
kuba6000 Jun 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "core"]
path = core
url = https://github.com/kuba6000/AE2-Web-Integration.git
branch = core
1 change: 1 addition & 0 deletions core
Submodule core added at eb7a31
16 changes: 12 additions & 4 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,16 @@
* For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph
*/
dependencies {
api("com.github.GTNewHorizons:GTNHLib:0.6.39:dev")
api("com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-684-GTNH:dev")
api("com.github.GTNewHorizons:AE2FluidCraft-Rework:1.4.114-gtnh:dev")
runtimeOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughItems:2.7.82-GTNH:dev")
implementation project(':core')
// Select the jar explicitly so shadow resolution does not hit variant ambiguity on the submodule.
shadowImplementation project(path: ':core', configuration: 'default')

api("com.github.GTNewHorizons:GTNHLib:0.9.53:dev")
api("com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-909-GTNH:dev")
api("com.github.GTNewHorizons:AE2FluidCraft-Rework:1.5.76-gtnh:dev")
runtimeOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughItems:2.8.91-GTNH:dev")
}

tasks.named("shadowJar").configure {
dependsOn(project(":core").tasks.named("jar"))
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ forceEnableMixins = false

# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated into your jar. It is your
# responsibility to check the license and request permission for distribution if required.
usesShadowedDependencies = false
usesShadowedDependencies = true

# If disabled, won't remove unused classes from shadowed dependencies. Some libraries use reflection to access
# their own classes, making the minimization unreliable.
Expand Down
3 changes: 2 additions & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

pluginManagement {
repositories {
maven {
Expand All @@ -19,3 +18,5 @@ pluginManagement {
plugins {
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.24'
}

include ':core'
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,71 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.mojang.authlib.GameProfile;

import appeng.me.cache.SecurityCache;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerStartedEvent;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
import cpw.mods.fml.common.event.FMLServerStoppingEvent;
import pl.kuba6000.ae2webintegration.Tags;
import pl.kuba6000.ae2webintegration.ae2interface.implementations.AE;
import pl.kuba6000.ae2webintegration.core.api.IAEWebInterface;

@Mod(
modid = AE2WebIntegration.MODID,
version = Tags.VERSION,
name = "AE2WebIntegration-Interface",
name = "AE2 Web Integration",
acceptedMinecraftVersions = "[1.7.10]",
acceptableRemoteVersions = "*")
public class AE2WebIntegration {

public static final String MODID = "ae2webintegration-interface";
public static final String MODID = "ae2webintegration";
public static final Logger LOG = LogManager.getLogger(MODID);

@SidedProxy(
clientSide = "pl.kuba6000.ae2webintegration.ae2interface.proxy.ClientProxy",
serverSide = "pl.kuba6000.ae2webintegration.ae2interface.proxy.CommonProxy")
public static pl.kuba6000.ae2webintegration.ae2interface.proxy.CommonProxy proxy;

@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {}
public void preInit(FMLPreInitializationEvent event) {
proxy.preInit(event);
}

@Mod.EventHandler
public void init(FMLInitializationEvent event) {
proxy.init(event);
IAEWebInterface.getInstance()
.initAEInterface(AE.instance);
}

@Mod.EventHandler
public void postInit(FMLPostInitializationEvent event) {
proxy.postInit(event);
SecurityCache.registerOpPlayer(
IAEWebInterface.getInstance()
.getAEWebGameProfile());
new GameProfile(
IAEWebInterface.getInstance()
.getAEWebUUID(),
"AE2CONTROLLER"));
}

@Mod.EventHandler
public void serverStarting(FMLServerStartingEvent event) {
proxy.serverStarting(event);
}

@Mod.EventHandler
public void serverStarted(FMLServerStartedEvent event) {
proxy.serverStarted(event);
}

@Mod.EventHandler
public void serverStopping(FMLServerStoppingEvent event) {
proxy.serverStopping(event);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package pl.kuba6000.ae2webintegration.core;
package pl.kuba6000.ae2webintegration.ae2interface;

import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;

import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.PlayerEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
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;

public class FMLEventHandler {

private static final PlayerMessenger messenger = new PlayerMessenger();

@SubscribeEvent
public void tick(TickEvent.ServerTickEvent event) {
if (event.phase == TickEvent.Phase.START) return;
Expand All @@ -27,12 +29,9 @@ public void tick(TickEvent.ServerTickEvent event) {
@SubscribeEvent
public void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
if (!(event.player instanceof EntityPlayerMP)) return;
if (Config.CHECK_FOR_UPDATES && VersionChecker.isOutdated()
&& event.player.canCommandSenderUseCommand(4, "seed"))
event.player.addChatMessage(
new ChatComponentText(
EnumChatFormatting.GREEN.toString() + EnumChatFormatting.BOLD
+ "----> AE2WebIntegration -> New version detected! Consider updating at https://github.com/kuba6000/AE2-Web-Integration/releases/latest"));
EntityPlayerMP player = (EntityPlayerMP) event.player;
if (!player.canCommandSenderUseCommand(4, "seed")) return;
UpdateNotifier
.notifyPlayerIfOutdated(messenger, new PlayerIdentity(player.getUniqueID(), player.getCommandSenderName()));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package pl.kuba6000.ae2webintegration.ae2interface;

import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;

import cpw.mods.fml.common.FMLCommonHandler;
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) {
for (EntityPlayerMP entityPlayerMP : (java.util.List<EntityPlayerMP>) FMLCommonHandler.instance()
.getMinecraftServerInstance()
.getConfigurationManager().playerEntityList) {
if (entityPlayerMP.getUniqueID()
.equals(player.uuid)) {
entityPlayerMP.addChatMessage(
new ChatComponentText(
EnumChatFormatting.GREEN.toString() + EnumChatFormatting.BOLD.toString() + message));
return;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package pl.kuba6000.ae2webintegration.ae2interface.commands;

import java.util.List;

import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;

import pl.kuba6000.ae2webintegration.ae2interface.commands.CommandBuilder.CommandNode;

/**
* Forge 1.7.10 command handler. Traverses the command tree built by
* {@link CommandBuilder} to find the matching handler for the
* player's arguments, then delegates to it via {@link CommandContext}.
*/
public class BaseCommandHandler extends CommandBase {

private final List<CommandNode> rootNodes;

public BaseCommandHandler(List<CommandNode> rootNodes) {
this.rootNodes = rootNodes;
}

@Override
public String getCommandName() {
return "ae2webintegration";
}

@Override
public String getCommandUsage(ICommandSender sender) {
return "ae2webintegration <reload/auth>";
}

@Override
public int getRequiredPermissionLevel() {
return 0;
}

@Override
public void processCommand(ICommandSender sender, String[] args) {
if (sender.getEntityWorld().isRemote) return;

if (rootNodes.isEmpty()) return;
CommandNode root = rootNodes.get(0); // "ae2webintegration"

CommandNode matched = walkTree(root, args, 0);
if (matched != null && matched.handler != null) {
// Check permission on the matched node
if (matched.permission > 0 && !sender.canCommandSenderUseCommand(matched.permission, getCommandName())) {
sender.addChatMessage(
new ChatComponentText(EnumChatFormatting.RED + "You do not have permission to use this command!"));
return;
}
matched.handler.accept(new CommandContext(sender, args));
} else {
sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "/ae2webintegration <reload/auth>"));
}
}

/**
* Recursively walks the command tree, matching arguments against literal
* names and argument placeholders. Returns the deepest matching node that
* has a handler, or {@code null} if no path matches.
*/
private static CommandNode walkTree(CommandNode node, String[] args, int index) {
if (index >= args.length) {
return node.handler != null ? node : null;
}

String current = args[index];

// Try to match a literal child by name
for (CommandNode child : node.children) {
if (!child.isArgument && child.name.equals(current)) {
CommandNode result = walkTree(child, args, index + 1);
if (result != null) return result;
}
}

// Try to match an argument child (matches any token)
for (CommandNode child : node.children) {
if (child.isArgument) {
CommandNode result = walkTree(child, args, index + 1);
if (result != null) return result;
}
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package pl.kuba6000.ae2webintegration.ae2interface.commands;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import pl.kuba6000.ae2webintegration.core.api.ICommandBuilder;
import pl.kuba6000.ae2webintegration.core.api.ICommandContext;

/**
* {@link ICommandBuilder} implementation for Forge 1.7.10.
* <p>
* Builds a tree of {@link CommandNode} instances as
* {@code CommandBootstrap.init()} calls the fluent API. The tree is then
* traversed by {@link BaseCommandHandler} at runtime to find the matching
* handler for the given arguments.
* <p>
* {@link #register()} is a no-op because Forge commands are registered via
* {@code FMLServerStartingEvent} + a {@code CommandBase} subclass, not via
* the builder.
*/
public class CommandBuilder implements ICommandBuilder {

/** A node in the command tree. */
public static class CommandNode {

public final String name;
public final int permission;
public final boolean isArgument;
public final List<CommandNode> children = new ArrayList<>();
public Consumer<ICommandContext> handler;

CommandNode(String name, int permission, boolean isArgument) {
this.name = name;
this.permission = permission;
this.isArgument = isArgument;
}

void addChild(CommandNode child) {
children.add(child);
}
}

private final CommandNode currentNode;
private final ICommandBuilder parent;
private final List<CommandNode> rootNodes;

/** Root constructor. */
public CommandBuilder() {
this.currentNode = null;
this.parent = null;
this.rootNodes = new ArrayList<>();
}

private CommandBuilder(CommandNode currentNode, ICommandBuilder parent, List<CommandNode> rootNodes) {
this.currentNode = currentNode;
this.parent = parent;
this.rootNodes = rootNodes;
}

@Override
public ICommandBuilder literal(String name, int permission) {
CommandNode child = new CommandNode(name, permission, false);
if (parent == null) {
rootNodes.add(child);
} else if (currentNode != null) {
currentNode.addChild(child);
}
return new CommandBuilder(child, this, rootNodes);
}

@Override
public ICommandBuilder argument(String name) {
CommandNode child = new CommandNode(name, 0, true);
if (currentNode != null) {
currentNode.addChild(child);
}
return new CommandBuilder(child, this, rootNodes);
}

@Override
public ICommandBuilder executes(Consumer<ICommandContext> handler) {
if (currentNode != null) {
currentNode.handler = handler;
}
return parent;
}

/** Returns the top-level nodes built by the fluent calls. */
public List<CommandNode> getRootNodes() {
return rootNodes;
}
}
Loading
Loading