Dediserver runs and talks to clients.

This commit is contained in:
cpw 2018-06-22 22:45:01 -04:00 committed by LexManos
parent 506b51f189
commit 689ebd8036
31 changed files with 605 additions and 324 deletions

View File

@ -22,44 +22,9 @@ package net.minecraftforge.classloading;
import java.io.File;
import java.util.Map;
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
import javax.annotation.Nullable;
public class FMLForgePlugin implements IFMLLoadingPlugin
public class FMLForgePlugin
{
public static boolean RUNTIME_DEOBF = false;
public static File forgeLocation;
@Override
public String[] getASMTransformerClass()
{
return new String[0];
}
@Override
public String getModContainerClass()
{
return "net.minecraftforge.common.ForgeMod";
}
@Override
@Nullable
public String getSetupClass()
{
return null;
}
@Override
public void injectData(Map<String, Object> data)
{
RUNTIME_DEOBF = (Boolean)data.get("runtimeDeobfuscationEnabled");
forgeLocation = (File)data.get("coremodLocation");
}
@Override
public String getAccessTransformerClass()
{
return null;
}
}

View File

@ -22,6 +22,7 @@ package net.minecraftforge.fml;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.IResourcePack;
import net.minecraftforge.fml.client.ModFileResourcePack;
import java.util.function.BiFunction;
import java.util.function.Function;
@ -29,5 +30,10 @@ import java.util.function.Function;
public class ExtensionPoint<T>
{
public static final ExtensionPoint<BiFunction<Minecraft, GuiScreen, GuiScreen>> GUIFACTORY = new ExtensionPoint<>();
public static final ExtensionPoint<Function<Minecraft, IResourcePack>> RESOURCEPACK = new ExtensionPoint<>();
public static final ExtensionPoint<BiFunction<Minecraft, ModFileResourcePack, IResourcePack>> RESOURCEPACK = new ExtensionPoint<>();
private Class<T> type;
private ExtensionPoint() {
}
}

View File

@ -61,7 +61,7 @@ public class LaunchTesting
logcontext.updateLoggers();
System.setProperty("fml.explodedDir", "/home/cpw/projects/mods/inventorysorter/classes");
hackNatives();
Launcher.main("--launchTarget", "devfmlclient","--gameDir", "projects/run",
Launcher.main("--launchTarget", System.getProperty("target"),"--gameDir", ".",
"--accessToken", "blah", "--version", "FMLDev", "--assetIndex", "1.12",
"--assetsDir","/home/cpw/.gradle/caches/minecraft/assets",
"--userProperties", "{}");

View File

@ -0,0 +1,57 @@
/*
* Minecraft Forge
* Copyright (c) 2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml;
import net.minecraft.client.Minecraft;
import net.minecraft.server.MinecraftServer;
import java.util.function.Function;
import java.util.function.Supplier;
public enum LogicalSidedProvider
{
WORKQUEUE((c)->c.get(), (s)->s.get());
private static Supplier<Minecraft> client;
private static Supplier<MinecraftServer> server;
LogicalSidedProvider(Function<Supplier<Minecraft>, ?> clientSide, Function<Supplier<MinecraftServer>, ?> serverSide)
{
this.clientSide = clientSide;
this.serverSide = serverSide;
}
public static void setClient(Supplier<Minecraft> client)
{
LogicalSidedProvider.client = client;
}
public static void setServer(Supplier<MinecraftServer> server)
{
LogicalSidedProvider.server = server;
}
private final Function<Supplier<Minecraft>, ?> clientSide;
private final Function<Supplier<MinecraftServer>, ?> serverSide;
@SuppressWarnings("unchecked")
public <T> T get(final LogicalSide side) {
return (T)(side==LogicalSide.CLIENT ? clientSide.apply(client) : serverSide.apply(server));
}
}

View File

@ -51,6 +51,7 @@ public class ServerLifecycleHooks
public static boolean handleServerAboutToStart(final MinecraftServer server)
{
currentServer = server;
LogicalSidedProvider.setServer(()->server);
return !MinecraftForge.EVENT_BUS.post(new FMLServerAboutToStartEvent(server));
}
@ -80,6 +81,7 @@ public class ServerLifecycleHooks
{
MinecraftForge.EVENT_BUS.post(new FMLServerStoppedEvent());
currentServer = null;
LogicalSidedProvider.setServer(null);
CountDownLatch latch = exitLatch;
if (latch != null)

View File

@ -33,12 +33,14 @@ import java.util.function.Supplier;
public enum SidedProvider
{
// All of these need to be careful not to directly dereference the client and server elements in their signatures
DATAFIXER(c->c.get().getDataFixer(), s->s.get().getDataFixer()),
SIDEDINIT((Function<Supplier<Minecraft>, Function<ModContainer, Event>>)c-> mc->new FMLClientInitEvent(c.get(), mc),
(Function<Supplier<DedicatedServer>, Function<ModContainer, Event>>)s-> mc->new FMLServerInitEvent(s.get(), mc)),
SIDEDINIT((Function<Supplier<Minecraft>, Function<ModContainer, Event>>)c-> mc->new FMLClientInitEvent(c, mc),
(Function<Supplier<DedicatedServer>, Function<ModContainer, Event>>)s-> mc->new FMLServerInitEvent(s, mc)),
STRIPCHARS((Function<Supplier<Minecraft>, Function<String, String>>)c-> SplashProgress::stripSpecialChars,
(Function<Supplier<DedicatedServer>, Function<String, String>>)s-> str->str),
STARTUPQUERY(StartupQuery::clientQuery, StartupQuery::dedicatedServerQuery);
@SuppressWarnings("Convert2MethodRef") // need to not be methodrefs to avoid classloading all of StartupQuery's data
STARTUPQUERY(c->StartupQuery.QueryWrapper.clientQuery(c), s->StartupQuery.QueryWrapper.dedicatedServerQuery(s));
private static Supplier<Minecraft> client;
private static Supplier<DedicatedServer> server;

View File

@ -211,112 +211,118 @@ public class StartupQuery {
}
public static Consumer<StartupQuery> clientQuery(Supplier<Minecraft> clientSupplier)
public static class QueryWrapper
{
return (query) -> {
Minecraft client = clientSupplier.get();
if (query.getResult() == null)
{
client.displayGuiScreen(new GuiNotification(query));
}
else
{
client.displayGuiScreen(new GuiConfirmation(query));
}
if (query.isSynchronous())
{
while (client.currentScreen instanceof GuiNotification)
public static Consumer<StartupQuery> clientQuery(Supplier<Minecraft> clientSupplier)
{
return (query) -> {
Minecraft client = clientSupplier.get();
if (query.getResult() == null)
{
if (Thread.interrupted()) {
query.exception = new InterruptedException();
throw new RuntimeException();
}
client.loadingScreen.displayLoadingString("");
try
{
Thread.sleep(50);
} catch (InterruptedException ie) {
query.exception = ie;
}
client.displayGuiScreen(new GuiNotification(query));
}
else
{
client.displayGuiScreen(new GuiConfirmation(query));
}
client.loadingScreen.displayLoadingString(""); // make sure the blank screen is being drawn at the end
}
};
}
public static Consumer<StartupQuery> dedicatedServerQuery(Supplier<DedicatedServer> serverSupplier)
{
return (query) -> {
DedicatedServer server = serverSupplier.get();
if (query.getResult() == null)
{
LOGGER.warn(SQ, query.getText());
query.finish();
}
else
{
String text = query.getText() +
"\n\nRun the command /fml confirm or or /fml cancel to proceed." +
"\nAlternatively start the server with -Dfml.queryResult=confirm or -Dfml.queryResult=cancel to preselect the answer.";
LOGGER.warn(SQ, text);
if (!query.isSynchronous()) return; // no-op until mc does commands in another thread (if ever)
boolean done = false;
while (!done && server.isServerRunning())
if (query.isSynchronous())
{
if (Thread.interrupted())
while (client.currentScreen instanceof GuiNotification)
{
query.exception = new InterruptedException();
throw new RuntimeException();
}
DedicatedServer dedServer = (DedicatedServer)server;
// rudimentary command processing, check for fml confirm/cancel and stop commands
synchronized (dedServer.pendingCommandList)
{
for (Iterator<PendingCommand> it = dedServer.pendingCommandList.iterator(); it.hasNext(); )
if (Thread.interrupted())
{
String cmd = it.next().command.trim().toLowerCase();
query.exception = new InterruptedException();
throw new RuntimeException();
}
if (cmd.equals("/fml confirm"))
{
LOGGER.info(SQ, "confirmed");
query.setResult(true);
done = true;
it.remove();
}
else if (cmd.equals("/fml cancel"))
{
LOGGER.info(SQ, "cancelled");
query.setResult(false);
done = true;
it.remove();
}
else if (cmd.equals("/stop"))
{
StartupQuery.abort();
}
client.loadingScreen.displayLoadingString("");
try
{
Thread.sleep(50);
}
catch (InterruptedException ie)
{
query.exception = ie;
}
}
try
{
Thread.sleep(10L);
} catch (InterruptedException ie) {
query.exception = ie;
}
client.loadingScreen.displayLoadingString(""); // make sure the blank screen is being drawn at the end
}
};
}
query.finish();
}
};
public static Consumer<StartupQuery> dedicatedServerQuery(Supplier<DedicatedServer> serverSupplier)
{
return (query) -> {
DedicatedServer server = serverSupplier.get();
if (query.getResult() == null)
{
LOGGER.warn(SQ, query.getText());
query.finish();
}
else
{
String text = query.getText() +
"\n\nRun the command /fml confirm or or /fml cancel to proceed." +
"\nAlternatively start the server with -Dfml.queryResult=confirm or -Dfml.queryResult=cancel to preselect the answer.";
LOGGER.warn(SQ, text);
if (!query.isSynchronous()) return; // no-op until mc does commands in another thread (if ever)
boolean done = false;
while (!done && server.isServerRunning())
{
if (Thread.interrupted())
{
query.exception = new InterruptedException();
throw new RuntimeException();
}
DedicatedServer dedServer = (DedicatedServer)server;
// rudimentary command processing, check for fml confirm/cancel and stop commands
synchronized (dedServer.pendingCommandList)
{
for (Iterator<PendingCommand> it = dedServer.pendingCommandList.iterator(); it.hasNext(); )
{
String cmd = it.next().command.trim().toLowerCase();
if (cmd.equals("/fml confirm"))
{
LOGGER.info(SQ, "confirmed");
query.setResult(true);
done = true;
it.remove();
}
else if (cmd.equals("/fml cancel"))
{
LOGGER.info(SQ, "cancelled");
query.setResult(false);
done = true;
it.remove();
}
else if (cmd.equals("/stop"))
{
StartupQuery.abort();
}
}
}
try
{
Thread.sleep(10L);
}
catch (InterruptedException ie)
{
query.exception = ie;
}
}
query.finish();
}
};
}
}
}

View File

@ -26,8 +26,10 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiWorldSelection;
import net.minecraft.client.gui.ServerListEntryNormal;
import net.minecraft.client.multiplayer.GuiConnecting;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.network.NetworkManager;
@ -36,6 +38,7 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.world.storage.WorldSummary;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.StartupQuery;
import net.minecraftforge.fml.client.gui.GuiAccessDenied;
import net.minecraftforge.fml.common.network.internal.FMLNetworkHandler;
import net.minecraftforge.registries.GameData;
import org.apache.logging.log4j.LogManager;
@ -194,4 +197,17 @@ public class ClientHooks
}
}
public static void connectToServer(GuiScreen guiMultiplayer, ServerData serverEntry)
{
ExtendedServerListData extendedData = serverDataTag.get(serverEntry);
if (extendedData != null && extendedData.isBlocked)
{
Minecraft.getMinecraft().displayGuiScreen(new GuiAccessDenied(guiMultiplayer, serverEntry));
}
else
{
Minecraft.getMinecraft().displayGuiScreen(new GuiConnecting(guiMultiplayer, Minecraft.getMinecraft(), serverEntry));
}
}
}

View File

@ -27,6 +27,7 @@ import net.minecraft.client.resources.IResourcePack;
import net.minecraft.client.resources.data.MetadataSerializer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.LogicalSidedProvider;
import net.minecraftforge.fml.SidedProvider;
import net.minecraftforge.fml.VersionChecker;
import net.minecraftforge.fml.ModLoader;
@ -43,20 +44,15 @@ public class ClientModLoader
private static boolean loading;
private static Minecraft mc;
/**
* Mod loading entrypoint for the client
* @param minecraft
* @param defaultResourcePacks
* @param mcResourceManager
* @param metadataSerializer_
*/
public static void begin(final Minecraft minecraft, final List<IResourcePack> defaultResourcePacks, final IReloadableResourceManager mcResourceManager, MetadataSerializer metadataSerializer_)
{
loading = true;
ClientModLoader.mc = minecraft;
SidedProvider.setClient(()->minecraft);
LogicalSidedProvider.setClient(()->minecraft);
SplashProgress.start();
ModLoader.get().loadMods();
ResourcePackLoader.loadResourcePacks(defaultResourcePacks);
minecraft.refreshResources();
}

View File

@ -0,0 +1,76 @@
/*
* Minecraft Forge
* Copyright (c) 2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.client;
import net.minecraft.client.resources.AbstractResourcePack;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
public class ModFileResourcePack extends AbstractResourcePack
{
private final ModFile modFile;
public ModFileResourcePack(final ModFile modFile)
{
super(new File("dummy"));
this.modFile = modFile;
}
public ModFile getModFile() {
return this.modFile;
}
@Override
public String getPackName()
{
return modFile.getFileName();
}
@Override
protected InputStream getInputStreamByName(String name) throws IOException
{
return Files.newInputStream(modFile.getLocator().findPath(modFile, name));
}
@Override
protected boolean hasResourceName(String name)
{
return Files.exists(modFile.getLocator().findPath(modFile, name));
}
@Override
public Set<String> getResourceDomains()
{
try {
return Files.walk(modFile.getLocator().findPath(modFile, "assets"),1).map(p->p.getFileName().toString()).collect(Collectors.toSet());
}
catch (IOException e)
{
return Collections.emptySet();
}
}
}

View File

@ -19,12 +19,38 @@
package net.minecraftforge.fml.client;
import net.minecraft.client.resources.AbstractResourcePack;
import net.minecraft.client.resources.FileResourcePack;
import net.minecraft.client.resources.FolderResourcePack;
import net.minecraft.client.resources.IResourcePack;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ResourcePackLoader
{
private static Map<ModFile, ModFileResourcePack> modResourcePacks;
private static AbstractResourcePack forgePack;
public static IResourcePack getResourcePackFor(String modId)
{
return null;
return modResourcePacks.get(ModList.get().getModFileById(modId).getFile());
}
public static void loadResourcePacks(List<IResourcePack> resourcePacks) {
modResourcePacks = ModList.get().getModFiles().stream().
map(mf -> new ModFileResourcePack(mf.getFile())).
collect(Collectors.toMap(ModFileResourcePack::getModFile, Function.identity()));
forgePack = Files.isDirectory(FMLLoader.getForgePath()) ?
new FolderResourcePack(FMLLoader.getForgePath().toFile()) :
new FileResourcePack(FMLLoader.getForgePath().toFile());
resourcePacks.add(forgePack);
resourcePacks.addAll(modResourcePacks.values());
}
}

View File

@ -558,7 +558,7 @@ public class FMLCommonHandler
* Also verifies the client has the FML marker.
*
* @param packet Handshake Packet
* @param manager Network connection
* @param manager NetworkDirection connection
* @return True to allow connection, otherwise False.
*/
public boolean handleServerHandshake(C00Handshake packet, NetworkManager manager)

View File

@ -22,10 +22,20 @@ package net.minecraftforge.fml.common.event;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.ModContainer;
import java.util.function.Supplier;
public class FMLClientInitEvent extends ModLifecycleEvent
{
public FMLClientInitEvent(Minecraft mc, ModContainer container)
private final Supplier<Minecraft> minecraftSupplier;
public FMLClientInitEvent(Supplier<Minecraft> mc, ModContainer container)
{
super(container);
this.minecraftSupplier = mc;
}
public Supplier<Minecraft> getMinecraftSupplier()
{
return minecraftSupplier;
}
}

View File

@ -19,13 +19,23 @@
package net.minecraftforge.fml.common.event;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraftforge.fml.ModContainer;
import java.util.function.Supplier;
public class FMLServerInitEvent extends ModLifecycleEvent
{
public FMLServerInitEvent(MinecraftServer server, ModContainer container)
private final Supplier<DedicatedServer> serverSupplier;
public FMLServerInitEvent(Supplier<DedicatedServer> server, ModContainer container)
{
super(container);
this.serverSupplier = server;
}
public Supplier<DedicatedServer> getServerSupplier()
{
return serverSupplier;
}
}

View File

@ -318,7 +318,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet<?>> im
private void kickWithMessage(String message)
{
FMLLog.log.error("Network Disconnect: {}", message);
FMLLog.log.error("NetworkDirection Disconnect: {}", message);
final TextComponentString TextComponentString = new TextComponentString(message);
if (side == Side.CLIENT)
{

View File

@ -23,6 +23,8 @@ import cpw.mods.modlauncher.api.IEnvironment;
import cpw.mods.modlauncher.api.ITransformingClassLoader;
import net.minecraftforge.api.distmarker.Dist;
import java.nio.file.Path;
public abstract class FMLCommonLaunchHandler
{
public void setup(final IEnvironment environment)
@ -32,8 +34,8 @@ public abstract class FMLCommonLaunchHandler
public abstract Dist getDist();
protected void beforeStart(ITransformingClassLoader launchClassLoader)
protected void beforeStart(ITransformingClassLoader launchClassLoader, Path forgePath)
{
FMLLoader.beforeStart(launchClassLoader);
FMLLoader.beforeStart(launchClassLoader, forgePath);
}
}

View File

@ -51,27 +51,32 @@ public class FMLDevClientLaunchProvider extends FMLCommonLaunchHandler implement
"net.minecraftforge.fml.common.versioning."
);
@Override
public Path[] identifyTransformationTargets()
private static final Path myPath;
static
{
try
{
return new Path[] {
Paths.get(getClass().getProtectionDomain().getCodeSource().getLocation().toURI())
};
myPath = Paths.get(FMLDevClientLaunchProvider.class.getProtectionDomain().getCodeSource().getLocation().toURI());
}
catch (URISyntaxException e)
{
throw new RuntimeException("I can't find myself!");
throw new RuntimeException("HUH?");
}
}
@Override
public Path[] identifyTransformationTargets()
{
return new Path[] { myPath };
}
@Override
public Callable<Void> launchService(String[] arguments, ITransformingClassLoader launchClassLoader)
{
return () -> {
fmlLog.debug(CORE, "Launching minecraft in {} with arguments {}", launchClassLoader, arguments);
super.beforeStart(launchClassLoader);
super.beforeStart(launchClassLoader, myPath);
launchClassLoader.addTargetPackageFilter(cn -> SKIPPACKAGES.stream().noneMatch(cn::startsWith));
Field scl = ClassLoader.class.getDeclaredField("scl"); // Get system class loader
scl.setAccessible(true); // Set accessible

View File

@ -0,0 +1,101 @@
/*
* Minecraft Forge
* Copyright (c) 2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.loading;
import cpw.mods.modlauncher.api.IEnvironment;
import cpw.mods.modlauncher.api.ILaunchHandlerService;
import cpw.mods.modlauncher.api.ITransformingClassLoader;
import net.minecraftforge.api.distmarker.Dist;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import static net.minecraftforge.fml.Logging.CORE;
import static net.minecraftforge.fml.Logging.fmlLog;
public class FMLDevServerLaunchProvider extends FMLCommonLaunchHandler implements ILaunchHandlerService
{
@Override
public String name()
{
return "devfmlserver";
}
private static final List<String> SKIPPACKAGES = Arrays.asList(
"joptsimple.", "org.lwjgl.", "com.mojang.", "com.google.",
"org.apache.commons.", "io.netty.", "net.minecraftforge.fml.loading.", "net.minecraftforge.fml.language.",
"net.minecraftforge.eventbus.", "it.unimi.dsi.fastutil.", "net.minecraftforge.api.",
"paulscode.sound.", "com.ibm.icu.", "sun.", "gnu.trove.", "com.electronwill.nightconfig.",
"net.minecraftforge.fml.common.versioning."
);
private static final Path myPath;
static
{
try
{
myPath = Paths.get(FMLDevServerLaunchProvider.class.getProtectionDomain().getCodeSource().getLocation().toURI());
}
catch (URISyntaxException e)
{
throw new RuntimeException("HUH?");
}
}
@Override
public Path[] identifyTransformationTargets()
{
return new Path[] { myPath };
}
@Override
public Callable<Void> launchService(String[] arguments, ITransformingClassLoader launchClassLoader)
{
return () -> {
fmlLog.debug(CORE, "Launching minecraft in {} with arguments {}", launchClassLoader, arguments);
super.beforeStart(launchClassLoader, myPath);
launchClassLoader.addTargetPackageFilter(cn -> SKIPPACKAGES.stream().noneMatch(cn::startsWith));
Field scl = ClassLoader.class.getDeclaredField("scl"); // Get system class loader
scl.setAccessible(true); // Set accessible
scl.set(null, launchClassLoader.getInstance()); // Update it to your class loader
Thread.currentThread().setContextClassLoader(launchClassLoader.getInstance());
Class.forName("net.minecraft.server.MinecraftServer", true, launchClassLoader.getInstance()).getMethod("main", String[].class).invoke(null, (Object)arguments);
return null;
};
}
@Override
public void setup(IEnvironment environment)
{
fmlLog.debug(CORE, "No jar creation necessary. Launch is dev environment");
}
@Override
public Dist getDist()
{
return Dist.DEDICATED_SERVER;
}
}

View File

@ -58,6 +58,7 @@ public class FMLLoader
private static ClassLoader launchClassLoader;
private static RuntimeDistCleaner runtimeDistCleaner;
private static Path gamePath;
private static Path forgePath;
static void onInitialLoad(IEnvironment environment, Set<String> otherServices) throws IncompatibleEnvironmentException
{
@ -178,9 +179,10 @@ public class FMLLoader
return dist;
}
public static void beforeStart(ITransformingClassLoader launchClassLoader)
public static void beforeStart(ITransformingClassLoader launchClassLoader, Path forgePath)
{
FMLLoader.launchClassLoader = launchClassLoader.getInstance();
FMLLoader.forgePath = forgePath;
}
@ -199,4 +201,8 @@ public class FMLLoader
{
return gamePath;
}
public static Path getForgePath() {
return forgePath;
}
}

View File

@ -20,26 +20,33 @@
package net.minecraftforge.fml.network;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.LogicalSide;
import java.util.function.BiFunction;
import java.util.function.Supplier;
public enum Network
public enum NetworkDirection
{
PLAYSERVER(NetworkEvent.ClientCustomPayloadEvent::new),
PLAYCLIENT(NetworkEvent.ServerCustomPayloadEvent::new),
LOGINSERVER(NetworkEvent.ClientCustomPayloadEvent::new),
LOGINCLIENT(NetworkEvent.ServerCustomPayloadEvent::new);
PLAYSERVER(NetworkEvent.ClientCustomPayloadEvent::new, LogicalSide.CLIENT),
PLAYCLIENT(NetworkEvent.ServerCustomPayloadEvent::new, LogicalSide.SERVER),
LOGINSERVER(NetworkEvent.ClientCustomPayloadEvent::new, LogicalSide.CLIENT),
LOGINCLIENT(NetworkEvent.ServerCustomPayloadEvent::new, LogicalSide.SERVER);
private final BiFunction<PacketBuffer, Supplier<NetworkEvent.Context>, NetworkEvent> eventSupplier;
private final LogicalSide logicalSide;
Network(BiFunction<PacketBuffer, Supplier<NetworkEvent.Context>, NetworkEvent> eventSupplier)
NetworkDirection(BiFunction<PacketBuffer, Supplier<NetworkEvent.Context>, NetworkEvent> eventSupplier, LogicalSide logicalSide)
{
this.eventSupplier = eventSupplier;
this.logicalSide = logicalSide;
}
public NetworkEvent getEvent(final PacketBuffer buffer, final Supplier<NetworkEvent.Context> manager) {
return this.eventSupplier.apply(buffer, manager);
}
public LogicalSide getLogicalSide()
{
return logicalSide;
}
}

View File

@ -19,12 +19,15 @@
package net.minecraftforge.fml.network;
import com.google.common.util.concurrent.ListenableFuture;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.network.INetHandler;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.IThreadListener;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.LogicalSidedProvider;
import java.util.function.Supplier;
@ -74,17 +77,17 @@ public class NetworkEvent extends Event
private final INetHandler netHandler;
/**
* The {@link Network} this message has been received on
* The {@link NetworkDirection} this message has been received on
*/
private final Network side;
private final NetworkDirection side;
Context(NetworkManager netHandler, Network side)
Context(NetworkManager netHandler, NetworkDirection side)
{
this.netHandler = netHandler.getNetHandler();
this.side = side;
}
public Network getSide() {
public NetworkDirection getSide() {
return side;
}
@ -97,5 +100,10 @@ public class NetworkEvent extends Event
{
return (NetHandlerPlayClient) netHandler;
}
@SuppressWarnings("unchecked")
public <V> ListenableFuture<V> enqueueWork(Runnable runnable) {
return (ListenableFuture<V>)LogicalSidedProvider.WORKQUEUE.<IThreadListener>get(getSide().getLogicalSide()).addScheduledTask(runnable);
}
}
}

View File

@ -62,22 +62,22 @@ public class NetworkHooks
public static void onServerCustomPayload(final SPacketCustomPayload packet, final NetworkManager manager) {
NetworkRegistry.findTarget(new ResourceLocation(packet.getChannelName())).
ifPresent(ni->ni.dispatch(Network.PLAYSERVER, packet.getBufferData(), manager));
ifPresent(ni->ni.dispatch(NetworkDirection.PLAYSERVER, packet.getBufferData(), manager));
}
public static void onClientCustomPayload(final CPacketCustomPayload packet, final NetworkManager manager) {
NetworkRegistry.findTarget(new ResourceLocation(packet.getChannelName())).
ifPresent(ni->ni.dispatch(Network.PLAYCLIENT, packet.getBufferData(), manager));
ifPresent(ni->ni.dispatch(NetworkDirection.PLAYCLIENT, packet.getBufferData(), manager));
}
public static void onServerLoginCustomPayload(final SPacketCustomPayload packet, final NetworkManager manager) {
NetworkRegistry.findTarget(new ResourceLocation(packet.getChannelName())).
ifPresent(ni->ni.dispatch(Network.LOGINSERVER, packet.getBufferData(), manager));
ifPresent(ni->ni.dispatch(NetworkDirection.LOGINSERVER, packet.getBufferData(), manager));
}
public static void onClientLoginCustomPayload(final CPacketCustomPayload packet, final NetworkManager manager) {
NetworkRegistry.findTarget(new ResourceLocation(packet.getChannelName())).
ifPresent(ni->ni.dispatch(Network.LOGINCLIENT, packet.getBufferData(), manager));
ifPresent(ni->ni.dispatch(NetworkDirection.LOGINCLIENT, packet.getBufferData(), manager));
}
public static void registerServerChannel(NetworkManager manager, C00Handshake packet)

View File

@ -70,7 +70,7 @@ public class NetworkInstance
this.networkEventBus.unregister(object);
}
void dispatch(final Network side, final PacketBuffer bufferData, final NetworkManager manager)
void dispatch(final NetworkDirection side, final PacketBuffer bufferData, final NetworkManager manager)
{
this.networkEventBus.post(side.getEvent(bufferData,()->new NetworkEvent.Context(manager, side)));
}

View File

@ -61,8 +61,8 @@ public class NetworkRegistry
{
final NetworkInstance networkInstance = new NetworkInstance(name, networkProtocolVersion, clientAcceptedVersions, serverAcceptedVersions);
if (instances.containsKey(name)) {
LOGGER.error(NETREGISTRY, "Network channel {} already registered.", name);
throw new IllegalArgumentException("Network Channel {"+ name +"} already registered");
LOGGER.error(NETREGISTRY, "NetworkDirection channel {} already registered.", name);
throw new IllegalArgumentException("NetworkDirection Channel {"+ name +"} already registered");
}
instances.put(name, networkInstance);
return networkInstance;
@ -72,4 +72,48 @@ public class NetworkRegistry
{
return Optional.ofNullable(instances.get(resourceLocation));
}
public static class ChannelBuilder {
private ResourceLocation channelName;
private Supplier<String> networkProtocolVersion;
private Predicate<String> clientAcceptedVersions;
private Predicate<String> serverAcceptedVersions;
public static ChannelBuilder named(ResourceLocation channelName)
{
ChannelBuilder builder = new ChannelBuilder();
builder.channelName = channelName;
return builder;
}
public ChannelBuilder networkProtocolVersion(Supplier<String> networkProtocolVersion)
{
this.networkProtocolVersion = networkProtocolVersion;
return this;
}
public ChannelBuilder clientAcceptedVersions(Predicate<String> clientAcceptedVersions)
{
this.clientAcceptedVersions = clientAcceptedVersions;
return this;
}
public ChannelBuilder serverAcceptedVersions(Predicate<String> serverAcceptedVersions)
{
this.serverAcceptedVersions = serverAcceptedVersions;
return this;
}
private NetworkInstance createNetworkInstance() {
return createInstance(channelName, networkProtocolVersion, clientAcceptedVersions, serverAcceptedVersions);
}
public SimpleChannel simpleChannel() {
return new SimpleChannel(createNetworkInstance());
}
public EventNetworkChannel eventNetworkChannel() {
return new EventNetworkChannel(createNetworkInstance());
}
}
}

View File

@ -61,4 +61,40 @@ public class SimpleChannel
final CPacketCustomPayload payload = new CPacketCustomPayload(instance.getChannelName(), bufIn);
Minecraft.getMinecraft().getConnection().sendPacket(payload);
}
public static class MessageBuilder<MSG> {
private SimpleChannel channel;
private Class<MSG> type;
private int id;
private BiConsumer<MSG, PacketBuffer> encoder;
private Function<PacketBuffer, MSG> decoder;
private BiConsumer<MSG, Supplier<NetworkEvent.Context>> consumer;
public static <MSG> MessageBuilder<MSG> forType(final SimpleChannel channel, final Class<MSG> type, int id) {
MessageBuilder<MSG> builder = new MessageBuilder<>();
builder.channel = channel;
builder.id = id;
builder.type = type;
return builder;
}
public MessageBuilder<MSG> encoder(BiConsumer<MSG, PacketBuffer> encoder) {
this.encoder = encoder;
return this;
}
public MessageBuilder<MSG> decoder(Function<PacketBuffer, MSG> decoder) {
this.decoder = decoder;
return this;
}
public MessageBuilder<MSG> consumer(BiConsumer<MSG, Supplier<NetworkEvent.Context>> consumer) {
this.consumer = consumer;
return this;
}
public void add() {
this.channel.registerMessage(this.id, this.type, this.encoder, this.decoder, this.consumer);
}
}
}

View File

@ -1,146 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.relauncher;
import javax.annotation.Nullable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
/**
* The base plugin that provides class name meta information to FML to
* enhance the classloading lifecycle for mods in FML
*
* @author cpw
*
*/
public interface IFMLLoadingPlugin
{
/**
* Return a list of classes that implements the IClassTransformer interface
* @return a list of classes that implements the IClassTransformer interface
*/
String[] getASMTransformerClass();
/**
* Return a class name that implements "ModContainer" for injection into the mod list
* The "getName" function should return a name that other mods can, if need be,
* depend on.
* Trivially, this modcontainer will be loaded before all regular mod containers,
* which means it will be forced to be "immutable" - not susceptible to normal
* sorting behaviour.
* All other mod behaviours are available however- this container can receive and handle
* normal loading events
*/
String getModContainerClass();
/**
* Return the class name of an implementor of "IFMLCallHook", that will be run, in the
* main thread, to perform any additional setup this coremod may require. It will be
* run <strong>prior</strong> to Minecraft starting, so it CANNOT operate on minecraft
* itself. The game will deliberately crash if this code is detected to trigger a
* minecraft class loading
* TODO: implement crash ;)
*/
@Nullable
String getSetupClass();
/**
* Inject coremod data into this coremod
* This data includes:
* "mcLocation" : the location of the minecraft directory,
* "coremodList" : the list of coremods
* "coremodLocation" : the file this coremod loaded from,
*/
void injectData(Map<String, Object> data);
/**
* Return an optional access transformer class for this coremod. It will be injected post-deobf
* so ensure your ATs conform to the new srgnames scheme.
* @return the name of an access transformer class or null if none is provided
*/
String getAccessTransformerClass();
/**
* Annotate your load plugin with a list of package prefixes that will *not* be
* processed by the ASM transformation stack.
*
* Your plugin, and any transformers should *definitely* be in this list, because
* otherwise you can face problems with the classloader trying to transform classes
* with your transformer, whilst it is *loading* your transformer. Not pretty.
*
* @author cpw
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface TransformerExclusions
{
String[] value() default "";
}
/**
* Use this to target a specific minecraft version for your coremod. It will refuse to load with an error if
* minecraft is not this exact version.
*
* @author cpw
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MCVersion
{
String value() default "";
}
/**
* Name this coremod something other than the "short class name"
* @author cpw
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Name
{
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface DependsOn
{
String[] value() default {};
}
/**
* A simple sorting index, interleaved with other tweakers from other sources, as well as FML
* @author cpw
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface SortingIndex
{
int value() default 0;
}
}

View File

@ -0,0 +1,40 @@
/*
* Minecraft Forge
* Copyright (c) 2018.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.server;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraftforge.fml.LogicalSidedProvider;
import net.minecraftforge.fml.ModLoader;
import net.minecraftforge.fml.SidedProvider;
public class ServerModLoader
{
private static DedicatedServer server;
public static void begin(DedicatedServer dedicatedServer) {
ServerModLoader.server = dedicatedServer;
SidedProvider.setServer(()->dedicatedServer);
LogicalSidedProvider.setServer(()->dedicatedServer);
ModLoader.get().loadMods();
}
public static void end() {
ModLoader.get().finishMods();
}
}

View File

@ -1,2 +1,3 @@
net.minecraftforge.fml.loading.FMLLaunchProvider
net.minecraftforge.fml.loading.FMLDevClientLaunchProvider
net.minecraftforge.fml.loading.FMLDevClientLaunchProvider
net.minecraftforge.fml.loading.FMLDevServerLaunchProvider

View File

@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 4,
"description": "Forge resource pack"
}
}

View File

@ -20,7 +20,6 @@
package net.minecraftforge.fml.debug;
import net.minecraft.launchwrapper.IClassTransformer;
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
import java.util.Map;