Network init

This commit is contained in:
cpw 2018-09-04 20:23:45 -04:00 committed by LexManos
parent b50b768852
commit d7e9217695
43 changed files with 1064 additions and 794 deletions

View file

@ -36,6 +36,15 @@ project(':clean') {
mappings channel: 'snapshot', version: '20180813-1.12'
mcVersion = '1.13'
}
task runclient(type: JavaExec) {
doFirst {
mkdir 'runclient'
}
classpath sourceSets.main.runtimeClasspath
args = ['--accessToken', '0', '--version', '1.13']
main 'net.minecraft.client.main.Main'
workingDir 'runclient'
}
}
project(':forge') {
@ -94,7 +103,17 @@ project(':forge') {
jvmArgs = ['-classpath', project.configurations.ecj.asPath, 'org.eclipse.jdt.internal.compiler.batch.Main', '-nowarn']
}
}
task runclient(type: JavaExec) {
doFirst {
mkdir 'runclient'
}
doFirst {
copy {
from sourceSets.main.resources
into "$buildDir/classes/java/main"
}
}
classpath sourceSets.main.runtimeClasspath
main 'net.minecraftforge.fml.LaunchTesting'
systemProperties target:'fmldevclient'

View file

@ -0,0 +1,34 @@
--- a/net/minecraft/client/Minecraft.java
+++ b/net/minecraft/client/Minecraft.java
@@ -413,6 +413,7 @@
this.languageManager = new LanguageManager(this.gameSettings.language);
this.resourceManager.func_199006_a(this.languageManager);
this.gameSettings.func_198017_a(this.resourcePackRepository);
+ net.minecraftforge.fml.client.ClientModLoader.begin(this, this.resourcePackRepository, this.resourceManager, this.field_195554_ax);
this.refreshResources();
this.renderEngine = new TextureManager(this.resourceManager);
this.resourceManager.func_199006_a(this.renderEngine);
@@ -469,6 +470,7 @@
this.resourceManager.func_199006_a(this.searchTreeManager);
GlStateManager.viewport(0, 0, this.field_195558_d.func_198109_k(), this.field_195558_d.func_198091_l());
this.effectRenderer = new ParticleManager(this.world, this.renderEngine);
+ net.minecraftforge.fml.client.ClientModLoader.end();
this.ingameGUI = new GuiIngame(this);
if (this.serverName != null) {
this.displayGuiScreen(new GuiConnecting(new GuiMainMenu(), this, this.serverName, this.serverPort));
@@ -478,6 +480,7 @@
this.debugRenderer = new DebugRenderer(this);
GLFW.glfwSetErrorCallback(this::func_195545_a).free();
+ net.minecraftforge.fml.client.ClientModLoader.complete();
if (this.gameSettings.fullScreen && !this.field_195558_d.func_198113_j()) {
this.field_195558_d.func_198077_g();
}
@@ -1404,6 +1407,7 @@
NetworkManager networkmanager = NetworkManager.provideLocalClient(socketaddress);
networkmanager.setNetHandler(new NetHandlerLoginClient(networkmanager, this, (GuiScreen)null, (p_209507_0_) -> {
}));
+ net.minecraftforge.fml.network.NetworkHooks.registerClientLoginChannel(networkmanager);
networkmanager.sendPacket(new CPacketHandshake(socketaddress.toString(), 0, EnumConnectionState.LOGIN));
networkmanager.sendPacket(new CPacketLoginStart(this.getSession().getProfile()));
this.networkManager = networkmanager;

View file

@ -0,0 +1,34 @@
--- a/net/minecraft/client/gui/GuiMainMenu.java
+++ b/net/minecraft/client/gui/GuiMainMenu.java
@@ -192,12 +192,18 @@
GuiMainMenu.this.mc.displayGuiScreen(new GuiMultiplayer(GuiMainMenu.this));
}
});
- this.addButton(new GuiButton(14, this.width / 2 - 100, p_73969_1_ + p_73969_2_ * 2, I18n.format("menu.online")) {
+ this.addButton(new GuiButton(14, this.width / 2 + 2, p_73969_1_ + p_73969_2_ * 2, 98, 20, I18n.format("menu.online")) {
public void func_194829_a(double p_194829_1_, double p_194829_3_) {
GuiMainMenu.this.switchToRealms();
}
});
+ this.addButton(new GuiButton(6, this.width / 2 - 100, p_73969_1_ + p_73969_2_ * 2, 98, 20, I18n.format("fml.menu.mods")) {
+ @Override
+ public void func_194829_a(double x, double y) {
+ GuiMainMenu.this.mc.displayGuiScreen(new net.minecraftforge.fml.client.gui.GuiModList(GuiMainMenu.this));
}
+ });
+ }
private void addDemoButtons(int p_73972_1_, int p_73972_2_) {
this.addButton(new GuiButton(11, this.width / 2 - 100, p_73972_1_, I18n.format("menu.playdemo")) {
@@ -283,7 +289,10 @@
s = s + ("release".equalsIgnoreCase(this.mc.getVersionType()) ? "" : "/" + this.mc.getVersionType());
}
- this.drawString(this.fontRenderer, s, 2, this.height - 10, -1);
+ net.minecraftforge.fml.BrandingControl.forEachLine(true, true, (brdline, brd) ->
+ this.drawString(this.fontRenderer, brd, 2, this.height - ( 10 + brdline * (this.fontRenderer.FONT_HEIGHT + 1)), 16777215)
+ );
+
this.drawString(this.fontRenderer, "Copyright Mojang AB. Do not distribute!", this.widthCopyrightRest, this.height - 10, -1);
if (mouseX > this.widthCopyrightRest && mouseX < this.widthCopyrightRest + this.widthCopyright && mouseY > this.height - 10 && mouseY < this.height) {
drawRect(this.widthCopyrightRest, this.height - 1, this.widthCopyrightRest + this.widthCopyright, this.height, -1);

View file

@ -0,0 +1,10 @@
--- a/net/minecraft/client/network/NetHandlerHandshakeMemory.java
+++ b/net/minecraft/client/network/NetHandlerHandshakeMemory.java
@@ -20,6 +20,7 @@
}
public void processHandshake(CPacketHandshake packetIn) {
+ if (!net.minecraftforge.fml.server.ServerLifecycleHooks.handleServerLogin(packetIn, this.networkManager)) return;
this.networkManager.setConnectionState(packetIn.getRequestedState());
this.networkManager.setNetHandler(new NetHandlerLoginServer(this.server, this.networkManager));
}

View file

@ -0,0 +1,12 @@
--- a/net/minecraft/client/network/NetHandlerLoginClient.java
+++ b/net/minecraft/client/network/NetHandlerLoginClient.java
@@ -123,7 +123,9 @@
}
public void func_209521_a(SPacketCustomPayloadLogin p_209521_1_) {
+ if (!net.minecraftforge.fml.network.NetworkHooks.onCustomPayload(p_209521_1_, this.networkManager)) {
this.field_209525_d.accept(new TextComponentTranslation("connect.negotiating", new Object[0]));
this.networkManager.sendPacket(new CPacketCustomPayloadLogin(p_209521_1_.func_209918_a(), (PacketBuffer)null));
}
}
+}

View file

@ -0,0 +1,10 @@
--- a/net/minecraft/client/network/NetHandlerPlayClient.java
+++ b/net/minecraft/client/network/NetHandlerPlayClient.java
@@ -1615,6 +1615,7 @@
((DebugRendererWorldGenAttempts)this.client.debugRenderer.field_201750_j).func_201734_a(packetbuffer.readBlockPos(), packetbuffer.readFloat(), packetbuffer.readFloat(), packetbuffer.readFloat(), packetbuffer.readFloat(), packetbuffer.readFloat());
LOGGER.warn("Unknown custom packed identifier: {}", (Object)resourcelocation);
} else {
+ if (!net.minecraftforge.fml.network.NetworkHooks.onCustomPayload(packetIn, this.netManager))
LOGGER.warn("Unknown custom packed identifier: {}", (Object)resourcelocation);
}
} finally {

View file

@ -0,0 +1,10 @@
--- a/net/minecraft/network/NetHandlerPlayServer.java
+++ b/net/minecraft/network/NetHandlerPlayServer.java
@@ -1267,5 +1267,7 @@
}
public void processCustomPayload(CPacketCustomPayload packetIn) {
+ PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.player.getServerWorld());
+ net.minecraftforge.fml.network.NetworkHooks.onCustomPayload(packetIn, this.netManager);
}
}

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/network/login/client/CPacketCustomPayloadLogin.java
+++ b/net/minecraft/network/login/client/CPacketCustomPayloadLogin.java
@@ -8,7 +8,7 @@
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
-public class CPacketCustomPayloadLogin implements Packet<INetHandlerLoginServer> {
+public class CPacketCustomPayloadLogin implements Packet<INetHandlerLoginServer>, net.minecraftforge.fml.network.ICustomPacket<CPacketCustomPayloadLogin> {
private int field_209922_a;
private PacketBuffer field_209923_b;

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/network/login/server/SPacketCustomPayloadLogin.java
+++ b/net/minecraft/network/login/server/SPacketCustomPayloadLogin.java
@@ -8,7 +8,7 @@
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
-public class SPacketCustomPayloadLogin implements Packet<INetHandlerLoginClient> {
+public class SPacketCustomPayloadLogin implements Packet<INetHandlerLoginClient>, net.minecraftforge.fml.network.ICustomPacket<SPacketCustomPayloadLogin> {
private int field_209919_a;
private ResourceLocation field_209920_b;
private PacketBuffer field_209921_c;

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/network/play/server/SPacketCustomPayload.java
+++ b/net/minecraft/network/play/server/SPacketCustomPayload.java
@@ -8,7 +8,7 @@
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
-public class SPacketCustomPayload implements Packet<INetHandlerPlayClient> {
+public class SPacketCustomPayload implements Packet<INetHandlerPlayClient>, net.minecraftforge.fml.network.ICustomPacket<SPacketCustomPayload> {
public static final ResourceLocation field_209910_a = new ResourceLocation("minecraft:trader_list");
public static final ResourceLocation field_209911_b = new ResourceLocation("minecraft:brand");
public static final ResourceLocation field_209912_c = new ResourceLocation("minecraft:book_open");

View file

@ -0,0 +1,37 @@
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -528,6 +528,7 @@
public void run() {
try {
if (this.init()) {
+ net.minecraftforge.fml.server.ServerLifecycleHooks.handleServerStarted(this);
this.field_211151_aa = Util.func_211177_b();
this.statusResponse.setServerDescription(new TextComponentString(this.motd));
this.statusResponse.setVersion(new ServerStatusResponse.Version("1.13", 393));
@@ -551,7 +552,10 @@
this.serverIsRunning = true;
}
+ net.minecraftforge.fml.server.ServerLifecycleHooks.handleServerStopping(this);
+ net.minecraftforge.fml.server.ServerLifecycleHooks.expectServerStopped(); // has to come before finalTick to avoid race conditions
} else {
+ net.minecraftforge.fml.server.ServerLifecycleHooks.expectServerStopped(); // has to come before finalTick to avoid race conditions
this.finalTick((CrashReport)null);
}
} catch (Throwable throwable1) {
@@ -570,6 +574,7 @@
LOGGER.error("We were unable to save this crash report to disk.");
}
+ net.minecraftforge.fml.server.ServerLifecycleHooks.expectServerStopped(); // has to come before finalTick to avoid race conditions
this.finalTick(crashreport);
} finally {
try {
@@ -578,6 +583,7 @@
} catch (Throwable throwable) {
LOGGER.error("Exception stopping the server", throwable);
} finally {
+ net.minecraftforge.fml.server.ServerLifecycleHooks.handleServerStopped(this);
this.systemExitNow();
}

View file

@ -16,3 +16,21 @@
this.setPlayerList(new DedicatedPlayerList(this));
long j = Util.func_211178_c();
if (this.getFolderName() == null) {
@@ -219,6 +221,7 @@
TileEntitySkull.setProfileCache(this.getPlayerProfileCache());
TileEntitySkull.setSessionService(this.getMinecraftSessionService());
PlayerProfileCache.setOnlineMode(this.isServerInOnlineMode());
+ if (!net.minecraftforge.fml.server.ServerLifecycleHooks.handleServerAboutToStart(this)) return false;
LOGGER.info("Preparing level \"{}\"", (Object)this.getFolderName());
JsonObject jsonobject = new JsonObject();
if (worldtype == WorldType.FLAT) {
@@ -258,7 +261,8 @@
}
Items.AIR.getSubItems(ItemGroup.SEARCH, NonNullList.create());
- return true;
+ // <3 you Grum for this, saves us ~30 patch files! --^
+ return net.minecraftforge.fml.server.ServerLifecycleHooks.handleServerStarting(this);
}
}
}

View file

@ -0,0 +1,14 @@
--- a/net/minecraft/server/integrated/IntegratedServer.java
+++ b/net/minecraft/server/integrated/IntegratedServer.java
@@ -122,9 +122,10 @@
this.setAllowFlight(true);
LOGGER.info("Generating keypair");
this.setKeyPair(CryptManager.generateKeyPair());
+ if (!net.minecraftforge.fml.server.ServerLifecycleHooks.handleServerAboutToStart(this)) return false;
this.loadAllWorlds(this.getFolderName(), this.getWorldName(), this.worldSettings.getSeed(), this.worldSettings.getTerrainType(), this.worldSettings.func_205391_j());
this.setMOTD(this.getServerOwner() + " - " + this.worlds[0].getWorldInfo().getWorldName());
- return true;
+ return net.minecraftforge.fml.server.ServerLifecycleHooks.handleServerStarting(this);
}
public void tick() {

View file

@ -0,0 +1,10 @@
--- a/net/minecraft/server/network/NetHandlerHandshakeTCP.java
+++ b/net/minecraft/server/network/NetHandlerHandshakeTCP.java
@@ -19,6 +19,7 @@
}
public void processHandshake(CPacketHandshake packetIn) {
+ if (!net.minecraftforge.fml.server.ServerLifecycleHooks.handleServerLogin(packetIn, this.networkManager)) return;
switch(packetIn.getRequestedState()) {
case LOGIN:
this.networkManager.setConnectionState(EnumConnectionState.LOGIN);

View file

@ -0,0 +1,55 @@
--- a/net/minecraft/server/network/NetHandlerLoginServer.java
+++ b/net/minecraft/server/network/NetHandlerLoginServer.java
@@ -56,6 +56,12 @@
}
public void update() {
+ if (this.currentLoginState == LoginState.NEGOTIATING) {
+ // We force the state into "NEGOTIATING" which is otherwise unused. Once we're completed we move the negotiation onto "READY_TO_ACCEPT"
+ // Might want to promote player object creation to here as well..
+ boolean negotiationComplete = net.minecraftforge.fml.network.NetworkHooks.tickNegotiation(this, this.networkManager, this.player);
+ if (negotiationComplete) this.currentLoginState = LoginState.READY_TO_ACCEPT;
+ } else
if (this.currentLoginState == NetHandlerLoginServer.LoginState.READY_TO_ACCEPT) {
this.tryAcceptPlayer();
} else if (this.currentLoginState == NetHandlerLoginServer.LoginState.DELAY_ACCEPT) {
@@ -127,7 +133,7 @@
this.currentLoginState = NetHandlerLoginServer.LoginState.KEY;
this.networkManager.sendPacket(new SPacketEncryptionRequest("", this.server.getKeyPair().getPublic(), this.verifyToken));
} else {
- this.currentLoginState = NetHandlerLoginServer.LoginState.READY_TO_ACCEPT;
+ this.currentLoginState = LoginState.NEGOTIATING;
}
}
@@ -150,11 +156,11 @@
NetHandlerLoginServer.this.loginGameProfile = NetHandlerLoginServer.this.server.getMinecraftSessionService().hasJoinedServer(new GameProfile((UUID)null, gameprofile.getName()), s, this.getAddress());
if (NetHandlerLoginServer.this.loginGameProfile != null) {
NetHandlerLoginServer.LOGGER.info("UUID of player {} is {}", NetHandlerLoginServer.this.loginGameProfile.getName(), NetHandlerLoginServer.this.loginGameProfile.getId());
- NetHandlerLoginServer.this.currentLoginState = NetHandlerLoginServer.LoginState.READY_TO_ACCEPT;
+ NetHandlerLoginServer.this.currentLoginState = LoginState.NEGOTIATING;
} else if (NetHandlerLoginServer.this.server.isSinglePlayer()) {
NetHandlerLoginServer.LOGGER.warn("Failed to verify username but will let them in anyway!");
NetHandlerLoginServer.this.loginGameProfile = NetHandlerLoginServer.this.getOfflineProfile(gameprofile);
- NetHandlerLoginServer.this.currentLoginState = NetHandlerLoginServer.LoginState.READY_TO_ACCEPT;
+ NetHandlerLoginServer.this.currentLoginState = LoginState.NEGOTIATING;
} else {
NetHandlerLoginServer.this.disconnect(new TextComponentTranslation("multiplayer.disconnect.unverified_username", new Object[0]));
NetHandlerLoginServer.LOGGER.error("Username '{}' tried to join with an invalid session", (Object)gameprofile.getName());
@@ -163,7 +169,7 @@
if (NetHandlerLoginServer.this.server.isSinglePlayer()) {
NetHandlerLoginServer.LOGGER.warn("Authentication servers are down but will let them in anyway!");
NetHandlerLoginServer.this.loginGameProfile = NetHandlerLoginServer.this.getOfflineProfile(gameprofile);
- NetHandlerLoginServer.this.currentLoginState = NetHandlerLoginServer.LoginState.READY_TO_ACCEPT;
+ NetHandlerLoginServer.this.currentLoginState = LoginState.NEGOTIATING;
} else {
NetHandlerLoginServer.this.disconnect(new TextComponentTranslation("multiplayer.disconnect.authservers_down", new Object[0]));
NetHandlerLoginServer.LOGGER.error("Couldn't verify username because servers are unavailable");
@@ -184,6 +190,7 @@
}
public void func_209526_a(CPacketCustomPayloadLogin p_209526_1_) {
+ if (!net.minecraftforge.fml.network.NetworkHooks.onCustomPayload(p_209526_1_, this.networkManager))
this.disconnect(new TextComponentTranslation("multiplayer.disconnect.unexpected_query_response", new Object[0]));
}

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/tileentity/IChestLid.java
+++ b/net/minecraft/tileentity/IChestLid.java
@@ -3,7 +3,7 @@
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
-@OnlyIn(Dist.CLIENT)
public interface IChestLid {
+ @OnlyIn(Dist.CLIENT)
float func_195480_a(float p_195480_1_);
}

View file

@ -0,0 +1,42 @@
--- a/net/minecraft/util/text/translation/LanguageMap.java
+++ b/net/minecraft/util/text/translation/LanguageMap.java
@@ -26,21 +26,34 @@
private long lastUpdateTimeInMilliseconds;
public LanguageMap() {
- try {
InputStream inputstream = LanguageMap.class.getResourceAsStream("/assets/minecraft/lang/en_us.json");
+ injectLanguage(this, inputstream);
+ }
+
+ public static void injectLanguage(InputStream inputStream){
+ injectLanguage(field_197636_c, inputStream);
+ }
+
+ private static void injectLanguage(LanguageMap inst, InputStream inputStream){
+ final Map<String, String> map = parseLanguageFile(inputStream);
+ inst.languageList.putAll(map);
+ inst.lastUpdateTimeInMilliseconds = System.currentTimeMillis();
+ }
+
+ private static Map<String, String> parseLanguageFile(InputStream inputstream) {
+ Map<String,String> languageList = Maps.newHashMap();
+ try {
JsonElement jsonelement = (JsonElement)(new Gson()).fromJson(new InputStreamReader(inputstream, StandardCharsets.UTF_8), JsonElement.class);
JsonObject jsonobject = JsonUtils.getJsonObject(jsonelement, "strings");
for(Entry<String, JsonElement> entry : jsonobject.entrySet()) {
String s = NUMERIC_VARIABLE_PATTERN.matcher(JsonUtils.getString(entry.getValue(), entry.getKey())).replaceAll("%$1s");
- this.languageList.put(entry.getKey(), s);
+ languageList.put(entry.getKey(), s);
}
-
- this.lastUpdateTimeInMilliseconds = Util.func_211177_b();
} catch (JsonParseException jsonparseexception) {
field_201045_a.error("Couldn't read strings from /assets/minecraft/lang/en_us.json", (Throwable)jsonparseexception);
}
-
+ return languageList;
}
public static LanguageMap getInstance() {

View file

@ -35,6 +35,7 @@ import net.minecraftforge.fml.VersionChecker;
import net.minecraftforge.fml.WorldPersistenceHooks;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLModLoadingContext;
import net.minecraftforge.server.command.ForgeCommand;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -410,7 +411,7 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
public void serverStarting(FMLServerStartingEvent evt)
{
new ForgeCommand(evt.getCommandDispatcher());
}
public void serverStopping(FMLServerStoppingEvent evt)

View file

@ -38,11 +38,11 @@ public class ForgeVersion
//This number is incremented every time Jenkins builds Forge, and never reset. Should always be 0 in the repo code.
public static final int buildVersion = 0;
// This is the minecraft version we're building for - used in various places in Forge/FML code
public static final String mcVersion = "1.12.2";
public static final String mcVersion = "1.13";
// This is the MCP data version we're using
public static final String mcpVersion = "9.42";
private static final Logger log = LogManager.getLogger("ForgeVersionCheck");
private static final Logger log = LogManager.getLogger();
public static int getMajorVersion()
{

View file

@ -48,8 +48,8 @@ public class LaunchTesting
System.setProperty("fml.explodedDir", "/home/cpw/projects/mods/inventorysorter/classes");
hackNatives();
Launcher.main("--launchTarget", System.getProperty("target"),"--gameDir", ".",
"--accessToken", "blah", "--version", "FMLDev", "--assetIndex", "1.12",
"--assetsDir","/home/cpw/.gradle/caches/minecraft/assets",
"--accessToken", "blah", "--version", "FMLDev", "--assetIndex", "1.13",
"--assetsDir","/home/cpw/MultiMC/assets",
"--userProperties", "{}");
Thread.sleep(10000);
}

View file

@ -1,5 +1,8 @@
package net.minecraftforge.fml;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.ICustomPacket;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
@ -20,13 +23,40 @@ public class UnsafeHacks
}
}
@SuppressWarnings("unchecked")
public static <T> T newInstance(Class<T> packetClass)
{
try
{
return (T) UNSAFE.allocateInstance(packetClass);
}
catch (InstantiationException e)
{
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public static <T> T getField(Field field, Object object) {
final long l = UNSAFE.objectFieldOffset(field);
return (T) UNSAFE.getObject(object, l);
}
public static <T> T getField(Object object) {
UNSAFE.staticFieldBase()
public static void setField(Field data, Object object, Object buffer)
{
long offset = UNSAFE.objectFieldOffset(data);
UNSAFE.putObject(object, offset, buffer);
}
public static int getIntField(Field f, Object obj)
{
long offset = UNSAFE.objectFieldOffset(f);
return UNSAFE.getInt(obj, offset);
}
public static void setIntField(Field data, Object object, int value)
{
long offset = UNSAFE.objectFieldOffset(data);
UNSAFE.putInt(object, offset, value);
}
}

View file

@ -21,8 +21,11 @@ package net.minecraftforge.fml.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.DownloadingPackFinder;
import net.minecraft.client.resources.ResourcePackInfoClient;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResourcePack;
import net.minecraft.resources.ResourcePackList;
import net.minecraft.resources.data.IMetadataSectionSerializer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@ -42,7 +45,7 @@ public class ClientModLoader
private static boolean loading;
private static Minecraft mc;
public static void begin(final Minecraft minecraft, final List<IResourcePack> defaultResourcePacks, final IReloadableResourceManager mcResourceManager, IMetadataSectionSerializer metadataSerializer)
public static void begin(final Minecraft minecraft, final ResourcePackList<ResourcePackInfoClient> defaultResourcePacks, final IReloadableResourceManager mcResourceManager, DownloadingPackFinder metadataSerializer)
{
loading = true;
ClientModLoader.mc = minecraft;
@ -50,7 +53,6 @@ public class ClientModLoader
LogicalSidedProvider.setClient(()->minecraft);
ModLoader.get().loadMods();
ResourcePackLoader.loadResourcePacks(defaultResourcePacks);
minecraft.refreshResources();
}
public static void end()

View file

@ -19,10 +19,15 @@
package net.minecraftforge.fml.client;
import net.minecraft.client.resources.ResourcePackInfoClient;
import net.minecraft.resources.AbstractResourcePack;
import net.minecraft.resources.FilePack;
import net.minecraft.resources.FolderPack;
import net.minecraft.resources.IPackFinder;
import net.minecraft.resources.IReloadableResourceManager;
import net.minecraft.resources.IResourcePack;
import net.minecraft.resources.ResourcePackInfo;
import net.minecraft.resources.ResourcePackList;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
@ -37,20 +42,35 @@ public class ResourcePackLoader
{
private static Map<ModFile, ModFileResourcePack> modResourcePacks;
private static AbstractResourcePack forgePack;
private static ResourcePackList<?> resourcePackList;
public static IResourcePack getResourcePackFor(String modId)
{
return modResourcePacks.get(ModList.get().getModFileById(modId).getFile());
}
public static void loadResourcePacks(List<IResourcePack> resourcePacks) {
@SuppressWarnings("unchecked")
public static <T extends ResourcePackInfo> T getResourcePackInfo(String modId) {
return (T)resourcePackList.func_198981_a(modId);
}
public static <T extends ResourcePackInfo> void loadResourcePacks(ResourcePackList<T> resourcePacks) {
resourcePackList = 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 FolderPack(FMLLoader.getForgePath().toFile()) :
new FilePack(FMLLoader.getForgePath().toFile());
resourcePacks.add(forgePack);
resourcePacks.addAll(modResourcePacks.values());
resourcePacks.func_198982_a(new ModPackFinder());
}
private static class ModPackFinder implements net.minecraft.resources.IPackFinder
{
@Override
public <T extends ResourcePackInfo> void func_195730_a(Map<String, T> packList, ResourcePackInfo.IFactory<T> factory)
{
packList.put("forge", ResourcePackInfo.func_195793_a("forge", true, ()->forgePack, factory, ResourcePackInfo.Priority.BOTTOM));
}
}
}

View file

@ -20,7 +20,6 @@
package net.minecraftforge.fml.client.gui;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@ -29,14 +28,17 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.imageio.ImageIO;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiListExtended;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.gui.GuiUtilRenderComponents;
@ -44,14 +46,14 @@ import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.client.renderer.texture.NativeImage;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.resources.IResourcePack;
import net.minecraft.client.resources.ResourcePackInfoClient;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.VersionChecker;
import net.minecraftforge.fml.client.ConfigGuiHandler;
@ -67,9 +69,6 @@ import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
/**
* @author cpw
@ -78,7 +77,6 @@ import org.lwjgl.opengl.GL11;
public class GuiModList extends GuiScreen
{
private static final Logger LOGGER = LogManager.getLogger();
private enum SortType implements Comparator<ModInfo>
{
NORMAL(24),
@ -86,27 +84,15 @@ public class GuiModList extends GuiScreen
Z_TO_A(26){ @Override protected int compare(String name1, String name2){ return name2.compareTo(name1); }};
GuiButton button;
private int buttonID;
private SortType(int buttonID)
{
this.buttonID = buttonID;
}
@Nullable
public static SortType getTypeForButton(GuiButton button)
{
for (SortType t : values())
{
if (t.buttonID == button.id)
{
return t;
}
}
return null;
}
protected int compare(String name1, String name2){ return 0; }
@Override
public int compare(ModInfo o1, ModInfo o2)
{
@ -115,95 +101,142 @@ public class GuiModList extends GuiScreen
return compare(name1, name2);
}
String getButtonText() {
return I18n.format("fml.menu.mods."+StringUtils.toLowerCase(name()));
}
}
private class SortButton extends GuiButton {
private final SortType type;
public SortButton(int buttonId, int x, int y, int width, int height, SortType type)
{
super(buttonId, x, y, width, height, type.getButtonText());
this.type = type;
}
@Override
public void func_194829_a(double p_194829_1_, double p_194829_3_)
{
GuiModList.this.sortType = this.type;
resortMods();
}
}
private GuiScreen mainMenu;
private GuiSlotModList modList;
private GuiScrollingList modInfo;
private InfoPanel modInfo;
private int selected = -1;
private ModInfo selectedMod;
private int listWidth;
private List<ModInfo> mods;
private GuiButton configModButton;
private final List<ModInfo> unsortedMods;
private GuiButton configButton;
private int buttonMargin = 1;
private int numButtons = SortType.values().length;
private String lastFilterText = "";
private GuiTextField search;
private boolean sorted = false;
private SortType sortType = SortType.NORMAL;
/**
* @param mainMenu
*/
public GuiModList(GuiScreen mainMenu)
{
this.mainMenu = mainMenu;
this.mods = ModList.get().getModFiles().stream().
map(mf -> mf.getMods().stream().findFirst()).
map(Optional::get).
map(ModInfo.class::cast).
collect(Collectors.toList());
this.mods = Collections.unmodifiableList(ModList.get().getMods());
this.unsortedMods = Collections.unmodifiableList(this.mods);
}
class InfoPanel extends GuiListExtended<Info> {
InfoPanel(Minecraft mcIn, int widthIn, int heightIn, int topIn, int bottomIn, int slotHeightIn)
{
super(mcIn, widthIn, heightIn, topIn, bottomIn, slotHeightIn);
}
@Override
protected int getScrollBarX()
{
return this.width - 6;
}
void setInfo(Info info)
{
this.func_195086_c();
this.func_195085_a(info);
}
public void clear()
{
this.func_195086_c();
}
}
@Override
public void initGui()
{
int slotHeight = 35;
for (ModInfo mod : mods)
{
listWidth = Math.max(listWidth,getFontRenderer().getStringWidth(mod.getDisplayName()) + 10);
listWidth = Math.max(listWidth,getFontRenderer().getStringWidth(mod.getVersion().getVersionString()) + 5 + slotHeight);
listWidth = Math.max(listWidth,getFontRenderer().getStringWidth(mod.getVersion().getVersionString()) + 5);
}
listWidth = Math.min(listWidth, 150);
this.modList = new GuiSlotModList(this, mods, listWidth, slotHeight);
this.modList = new GuiSlotModList(this, listWidth);
this.modList.setSlotXBoundsFromLeft(6);
this.modInfo = new InfoPanel(this.mc, this.width - this.listWidth - 30, this.height, 32, this.height - 88 + 4, 1);
this.modInfo.setSlotXBoundsFromLeft(this.listWidth + 24);
this.buttonList.add(new GuiButton(6, ((modList.right + this.width) / 2) - 100, this.height - 38, I18n.format("gui.done")));
configModButton = new GuiButton(20, 10, this.height - 49, this.listWidth, 20, "Config");
this.buttonList.add(configModButton);
this.addButton(new GuiButton(6, ((modList.right + this.width) / 2) - 100, this.height - 38, I18n.format("gui.done")){
@Override
public void func_194829_a(double p_194829_1_, double p_194829_3_)
{
GuiModList.this.mc.displayGuiScreen(GuiModList.this.mainMenu);
}
});
this.addButton(this.configButton = new GuiButton(20, 10, this.height - 49, this.listWidth, 20, I18n.format("fml.menu.mods.config")){
@Override
public void func_194829_a(double p_194829_1_, double p_194829_3_)
{
GuiModList.this.displayModConfig();
}
});
search = new GuiTextField(0, getFontRenderer(), 12, modList.bottom + 17, modList.listWidth - 4, 14);
search = new GuiTextField(0, getFontRenderer(), 12, modList.bottom + 17, modList.width - 4, 14);
field_195124_j.add(search);
field_195124_j.add(modList);
search.setFocused(true);
search.setCanLoseFocus(true);
int width = (modList.listWidth / numButtons);
final int width = (modList.width / numButtons);
int x = 10, y = 10;
GuiButton normalSort = new GuiButton(SortType.NORMAL.buttonID, x, y, width - buttonMargin, 20, I18n.format("fml.menu.mods.normal"));
normalSort.enabled = false;
buttonList.add(normalSort);
addButton(SortType.NORMAL.button = new SortButton(SortType.NORMAL.buttonID, x, y, width - buttonMargin, 20, SortType.NORMAL));
x += width + buttonMargin;
buttonList.add(new GuiButton(SortType.A_TO_Z.buttonID, x, y, width - buttonMargin, 20, "A-Z"));
addButton(SortType.A_TO_Z.button = new SortButton(SortType.NORMAL.buttonID, x, y, width - buttonMargin, 20, SortType.A_TO_Z));
x += width + buttonMargin;
buttonList.add(new GuiButton(SortType.Z_TO_A.buttonID, x, y, width - buttonMargin, 20, "Z-A"));
addButton(SortType.Z_TO_A.button = new SortButton(SortType.NORMAL.buttonID, x, y, width - buttonMargin, 20, SortType.Z_TO_A));
resortMods();
updateCache();
}
@Override
protected void mouseClicked(int x, int y, int button) throws IOException
private void displayModConfig()
{
super.mouseClicked(x, y, button);
search.mouseClicked(x, y, button);
if (button == 1 && x >= search.x && x < search.x + search.width && y >= search.y && y < search.y + search.height) {
search.setText("");
if (selectedMod == null) return;
try
{
ConfigGuiHandler.getGuiFactoryFor(selectedMod).map(f->f.apply(this.mc, this)).ifPresent(newScreen -> this.mc.displayGuiScreen(newScreen));
}
catch (final Exception e)
{
LOGGER.error("There was a critical issue trying to build the config GUI for {}", selectedMod.getModId(), e);
}
}
@Override
protected void keyTyped(char c, int keyCode) throws IOException
{
super.keyTyped(c, keyCode);
search.textboxKeyTyped(c, keyCode);
}
@Override
public void updateScreen()
{
super.updateScreen();
search.updateCursorCounter();
if (!search.getText().equals(lastFilterText))
@ -216,11 +249,17 @@ public class GuiModList extends GuiScreen
{
reloadMods();
mods.sort(sortType);
selected = modList.selectedIndex = mods.indexOf(selectedMod);
selected = mods.indexOf(selectedMod);
modList.refreshList();
sorted = true;
}
}
public <T extends GuiListExtended.IGuiListEntry<T>> void buildModList(Consumer<T> modListViewConsumer, Function<ModInfo, T> newEntry)
{
mods.forEach(mod->modListViewConsumer.accept(newEntry.apply(mod)));
}
private void reloadMods()
{
this.mods = this.unsortedMods.stream().
@ -228,89 +267,30 @@ public class GuiModList extends GuiScreen
lastFilterText = search.getText();
}
@Override
protected void actionPerformed(GuiButton button) throws IOException
private void resortMods()
{
if (button.enabled)
for (GuiButton b : buttonList)
{
SortType type = SortType.getTypeForButton(button);
if (type != null)
{
for (GuiButton b : buttonList)
{
if (SortType.getTypeForButton(b) != null)
{
b.enabled = true;
}
}
button.enabled = false;
sorted = false;
sortType = type;
Collections.copy(this.mods, this.unsortedMods);
}
else
{
switch (button.id)
{
case 6:
{
this.mc.displayGuiScreen(this.mainMenu);
return;
}
case 20:
{
try
{
ConfigGuiHandler.getGuiFactoryFor(selectedMod).
map(f->f.apply(this.mc, this)).
ifPresent(newScreen -> this.mc.displayGuiScreen(newScreen));
}
catch (final Exception e)
{
LOGGER.error("There was a critical issue trying to build the config GUI for {}", selectedMod.getModId(), e);
}
return;
}
}
if (b instanceof SortButton) {
b.enabled = sortType.button != b;
}
}
super.actionPerformed(button);
}
public int drawLine(String line, int offset, int shifty)
{
this.fontRenderer.drawString(line, offset, shifty, 0xd7edea);
return shifty + 10;
sorted = false;
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks)
{
this.modList.drawScreen(mouseX, mouseY, partialTicks);
if (this.modInfo != null)
this.modInfo.drawScreen(mouseX, mouseY, partialTicks);
this.modInfo.drawScreen(mouseX, mouseY, partialTicks);
int left = ((this.width - this.listWidth - 38) / 2) + this.listWidth + 30;
this.drawCenteredString(this.fontRenderer, "Mod List", left, 16, 0xFFFFFF);
super.drawScreen(mouseX, mouseY, partialTicks);
String text = I18n.format("fml.menu.mods.search");
int x = ((10 + modList.right) / 2) - (getFontRenderer().getStringWidth(text) / 2);
getFontRenderer().drawString(text, x, modList.bottom + 5, 0xFFFFFF);
search.drawTextBox();
}
@Override
public void handleMouseInput() throws IOException
{
int mouseX = Mouse.getEventX() * this.width / this.mc.displayWidth;
int mouseY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1;
super.handleMouseInput();
if (this.modInfo != null)
this.modInfo.handleMouseInput(mouseX, mouseY);
this.modList.handleMouseInput(mouseX, mouseY);
getFontRenderer().func_211126_b(text, x, modList.bottom + 5, 0xFFFFFF);
this.search.func_195608_a(mouseX, mouseY, partialTicks);
}
Minecraft getMinecraftInstance()
@ -325,10 +305,13 @@ public class GuiModList extends GuiScreen
public void selectModIndex(int index)
{
if (index == this.selected)
return;
this.selected = index;
this.selectedMod = (index >= 0 && index < mods.size()) ? mods.get(selected) : null;
if (index == this.selected) {
this.selected = -1;
} else
{
this.selected = index;
}
this.selectedMod = (this.selected >= 0 && this.selected< mods.size()) ? mods.get(this.selected) : null;
updateCache();
}
@ -340,43 +323,34 @@ public class GuiModList extends GuiScreen
private void updateCache()
{
configModButton.visible = false;
modInfo = null;
if (selectedMod == null)
if (selectedMod == null) {
modInfo.clear();
return;
}
this.configButton.enabled = selectedMod.hasConfigUI();
List<String> lines = new ArrayList<>();
VersionChecker.CheckResult vercheck = VersionChecker.getResult(selectedMod);
Pair<ResourceLocation, Dimension> logoData = selectedMod.getLogoFile().map(logoFile->
{
TextureManager tm = mc.getTextureManager();
IResourcePack pack = ResourcePackLoader.getResourcePackFor(selectedMod.getModId());
ResourcePackInfoClient pack = ResourcePackLoader.getResourcePackInfo(selectedMod.getModId());
try
{
BufferedImage logo = null;
if (pack != null)
{
logo = pack.getPackImage();
}
else
{
InputStream logoResource = getClass().getResourceAsStream(logoFile);
if (logoResource != null)
logo = ImageIO.read(logoResource);
}
NativeImage logo = null;
InputStream logoResource = getClass().getResourceAsStream(logoFile);
if (logoResource != null)
logo = NativeImage.func_195713_a(logoResource);
if (logo != null)
{
return Pair.of(tm.getDynamicTextureLocation("modlogo", new DynamicTexture(logo)), new Dimension(logo.getWidth(), logo.getHeight()));
return Pair.of(tm.getDynamicTextureLocation("modlogo", new DynamicTexture(logo)), new Dimension(logo.func_195702_a(), logo.func_195714_b()));
}
}
catch (IOException e) { }
return Pair.<ResourceLocation, Dimension>of(null, new Dimension(0, 0));
}).orElse(Pair.of(null, new Dimension(0, 0)));
configModButton.visible = true;
configModButton.enabled = true;
lines.add(selectedMod.getDisplayName());
lines.add(String.format("Version: %s", selectedMod.getVersion().getVersionString()));
lines.add(String.format("Mod ID: '%s' Mod State: %s", selectedMod.getModId(), ModList.get().getModContainerById(selectedMod.getModId()).
@ -388,7 +362,7 @@ public class GuiModList extends GuiScreen
lines.add("Authors: " + authors));
selectedMod.getModConfig().getOptional("displayURL").ifPresent(displayURL ->
lines.add("URL: " + displayURL));
if (selectedMod.getOwningFile().getMods().size()==1)
if (selectedMod.getOwningFile() == null || selectedMod.getOwningFile().getMods().size()==1)
lines.add("No child mods for this mod");
else
lines.add("Child mods: " + selectedMod.getOwningFile().getMods().stream().map(IModInfo::getDisplayName).collect(Collectors.joining(",")));
@ -411,38 +385,23 @@ public class GuiModList extends GuiScreen
}
}
modInfo = new Info(this.width - this.listWidth - 30, lines, logoData.getLeft(), logoData.getRight());
modInfo.setInfo(new Info(modInfo, lines, logoData.getLeft(), logoData.getRight()));
}
private class Info extends GuiScrollingList
class Info extends GuiListExtended.IGuiListEntry<Info>
{
@Nullable
private ResourceLocation logoPath;
private Dimension logoDims;
private List<ITextComponent> lines = null;
public Info(int width, List<String> lines, @Nullable ResourceLocation logoPath, Dimension logoDims)
public Info(GuiListExtended<Info> parent, List<String> lines, @Nullable ResourceLocation logoPath, Dimension logoDims)
{
super(GuiModList.this.getMinecraftInstance(),
width,
GuiModList.this.height,
32, GuiModList.this.height - 88 + 4,
GuiModList.this.listWidth + 20, 60,
GuiModList.this.width,
GuiModList.this.height);
this.field_195004_a = parent;
this.lines = resizeContent(lines);
this.logoPath = logoPath;
this.logoDims = logoDims;
this.setHeaderInfo(true, getHeaderHeight());
}
@Override protected int getSize() { return 0; }
@Override protected void elementClicked(int index, boolean doubleClick) { }
@Override protected boolean isSelected(int index) { return false; }
@Override protected void drawBackground() {}
@Override protected void drawSlot(int slotIdx, int entryRight, int slotTop, int slotBuffer, Tessellator tess) { }
private List<ITextComponent> resizeContent(List<String> lines)
{
List<ITextComponent> ret = new ArrayList<ITextComponent>();
@ -454,8 +413,9 @@ public class GuiModList extends GuiScreen
continue;
}
ITextComponent chat = ForgeHooks.newChatWithLinks(line, false);
int maxTextLength = this.listWidth - 8;
// ITextComponent chat = ForgeHooks.newChatWithLinks(line, false);
ITextComponent chat = new TextComponentString(line);
int maxTextLength = this.func_195002_d() - 8;
if (maxTextLength >= 0)
{
ret.addAll(GuiUtilRenderComponents.splitText(chat, maxTextLength, GuiModList.this.fontRenderer, false, true));
@ -464,39 +424,20 @@ public class GuiModList extends GuiScreen
return ret;
}
private int getHeaderHeight()
{
int height = 0;
if (logoPath != null)
{
double scaleX = logoDims.width / 200.0;
double scaleY = logoDims.height / 65.0;
double scale = 1.0;
if (scaleX > 1 || scaleY > 1)
{
scale = 1.0 / Math.max(scaleX, scaleY);
}
logoDims.width *= scale;
logoDims.height *= scale;
height += logoDims.height;
height += 10;
}
height += (lines.size() * 10);
if (height < this.bottom - this.top - 8) height = this.bottom - this.top - 8;
return height;
}
@Override
protected void drawHeader(int entryRight, int relativeY, Tessellator tess)
public void func_194999_a(int p_194999_1_, int p_194999_2_, int p_194999_3_, int p_194999_4_, boolean p_194999_5_, float p_194999_6_)
{
int top = relativeY;
int top = this.func_195001_c();
int left = this.func_195002_d();
/*
int top = this.
if (logoPath != null)
{
GlStateManager.enableBlend();
GuiModList.this.mc.renderEngine.bindTexture(logoPath);
GlStateManager.draw
BufferBuilder wr = tess.getBuffer();
int offset = (this.left + this.listWidth/2) - (logoDims.width / 2);
wr.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
@ -509,48 +450,19 @@ public class GuiModList extends GuiScreen
top += logoDims.height + 10;
}
*/
for (ITextComponent line : lines)
{
if (line != null)
{
GlStateManager.enableBlend();
GuiModList.this.fontRenderer.drawStringWithShadow(line.getFormattedText(), this.left + 4, top, 0xFFFFFF);
GuiModList.this.fontRenderer.drawStringWithShadow(line.getFormattedText(), left + 4, top, 0xFFFFFF);
GlStateManager.disableAlpha();
GlStateManager.disableBlend();
}
top += 10;
top += fontRenderer.FONT_HEIGHT + 1;
}
}
@Override
protected void clickHeader(int x, int y)
{
int offset = y;
if (logoPath != null) {
offset -= logoDims.height + 10;
}
if (offset <= 0)
return;
int lineIdx = offset / 10;
if (lineIdx >= lines.size())
return;
ITextComponent line = lines.get(lineIdx);
if (line != null)
{
int k = -4;
for (ITextComponent part : line) {
if (!(part instanceof TextComponentString))
continue;
k += GuiModList.this.fontRenderer.getStringWidth(((TextComponentString)part).getText());
if (k >= x)
{
GuiModList.this.handleComponentClick(part);
break;
}
}
}
}
}
}

View file

@ -1,395 +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.client.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraftforge.fml.client.config.GuiUtils;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import java.io.IOException;
import java.util.List;
public abstract class GuiScrollingList
{
private final Minecraft client;
protected final int listWidth;
protected final int listHeight;
protected final int screenWidth;
protected final int screenHeight;
protected final int top;
protected final int bottom;
protected final int right;
protected final int left;
protected final int slotHeight;
private int scrollUpActionId;
private int scrollDownActionId;
protected int mouseX;
protected int mouseY;
private float initialMouseClickY = -2.0F;
private float scrollFactor;
private float scrollDistance;
protected int selectedIndex = -1;
private long lastClickTime = 0L;
private boolean highlightSelected = true;
private boolean hasHeader;
private int headerHeight;
protected boolean captureMouse = true;
@Deprecated // We need to know screen size.
public GuiScrollingList(Minecraft client, int width, int height, int top, int bottom, int left, int entryHeight)
{
this(client, width, height, top, bottom, left, entryHeight, width, height);
}
public GuiScrollingList(Minecraft client, int width, int height, int top, int bottom, int left, int entryHeight, int screenWidth, int screenHeight)
{
this.client = client;
this.listWidth = width;
this.listHeight = height;
this.top = top;
this.bottom = bottom;
this.slotHeight = entryHeight;
this.left = left;
this.right = width + this.left;
this.screenWidth = screenWidth;
this.screenHeight = screenHeight;
}
@Deprecated // Unused, remove in 1.9.3?
public void func_27258_a(boolean p_27258_1_)
{
this.highlightSelected = p_27258_1_;
}
@Deprecated protected void func_27259_a(boolean hasFooter, int footerHeight){ setHeaderInfo(hasFooter, footerHeight); }
protected void setHeaderInfo(boolean hasHeader, int headerHeight)
{
this.hasHeader = hasHeader;
this.headerHeight = headerHeight;
if (!hasHeader) this.headerHeight = 0;
}
protected abstract int getSize();
protected abstract void elementClicked(int index, boolean doubleClick);
protected abstract boolean isSelected(int index);
protected int getContentHeight()
{
return this.getSize() * this.slotHeight + this.headerHeight;
}
protected abstract void drawBackground();
/**
* Draw anything special on the screen. GL_SCISSOR is enabled for anything that
* is rendered outside of the view box. Do not mess with SCISSOR unless you support this.
*/
protected abstract void drawSlot(int slotIdx, int entryRight, int slotTop, int slotBuffer, Tessellator tess);
@Deprecated protected void func_27260_a(int entryRight, int relativeY, Tessellator tess) {}
/**
* Draw anything special on the screen. GL_SCISSOR is enabled for anything that
* is rendered outside of the view box. Do not mess with SCISSOR unless you support this.
*/
protected void drawHeader(int entryRight, int relativeY, Tessellator tess) { func_27260_a(entryRight, relativeY, tess); }
@Deprecated protected void func_27255_a(int x, int y) {}
protected void clickHeader(int x, int y) { func_27255_a(x, y); }
@Deprecated protected void func_27257_b(int mouseX, int mouseY) {}
/**
* Draw anything special on the screen. GL_SCISSOR is enabled for anything that
* is rendered outside of the view box. Do not mess with SCISSOR unless you support this.
*/
protected void drawScreen(int mouseX, int mouseY) { func_27257_b(mouseX, mouseY); }
@Deprecated // Unused, Remove in 1.9.3?
public int func_27256_c(int x, int y)
{
int left = this.left + 1;
int right = this.left + this.listWidth - 7;
int relativeY = y - this.top - this.headerHeight + (int)this.scrollDistance - 4;
int entryIndex = relativeY / this.slotHeight;
return x >= left && x <= right && entryIndex >= 0 && relativeY >= 0 && entryIndex < this.getSize() ? entryIndex : -1;
}
// FIXME: is this correct/still needed?
public void registerScrollButtons(List<GuiButton> buttons, int upActionID, int downActionID)
{
this.scrollUpActionId = upActionID;
this.scrollDownActionId = downActionID;
}
private void applyScrollLimits()
{
int listHeight = this.getContentHeight() - (this.bottom - this.top - 4);
if (listHeight < 0)
{
listHeight /= 2;
}
if (this.scrollDistance < 0.0F)
{
this.scrollDistance = 0.0F;
}
if (this.scrollDistance > (float)listHeight)
{
this.scrollDistance = (float)listHeight;
}
}
public void actionPerformed(GuiButton button)
{
if (button.enabled)
{
if (button.id == this.scrollUpActionId)
{
this.scrollDistance -= (float)(this.slotHeight * 2 / 3);
this.initialMouseClickY = -2.0F;
this.applyScrollLimits();
}
else if (button.id == this.scrollDownActionId)
{
this.scrollDistance += (float)(this.slotHeight * 2 / 3);
this.initialMouseClickY = -2.0F;
this.applyScrollLimits();
}
}
}
public void handleMouseInput(int mouseX, int mouseY) throws IOException
{
boolean isHovering = mouseX >= this.left && mouseX <= this.left + this.listWidth &&
mouseY >= this.top && mouseY <= this.bottom;
if (!isHovering)
return;
int scroll = Mouse.getEventDWheel();
if (scroll != 0)
{
this.scrollDistance += (float)((-1 * scroll / 120.0F) * this.slotHeight / 2);
}
}
public void drawScreen(int mouseX, int mouseY, float partialTicks)
{
this.mouseX = mouseX;
this.mouseY = mouseY;
this.drawBackground();
boolean isHovering = mouseX >= this.left && mouseX <= this.left + this.listWidth &&
mouseY >= this.top && mouseY <= this.bottom;
int listLength = this.getSize();
int scrollBarWidth = 6;
int scrollBarRight = this.left + this.listWidth;
int scrollBarLeft = scrollBarRight - scrollBarWidth;
int entryLeft = this.left;
int entryRight = scrollBarLeft - 1;
int viewHeight = this.bottom - this.top;
int border = 4;
if (Mouse.isButtonDown(0))
{
if (this.initialMouseClickY == -1.0F)
{
if (isHovering)
{
int mouseListY = mouseY - this.top - this.headerHeight + (int)this.scrollDistance - border;
int slotIndex = mouseListY / this.slotHeight;
if (mouseX >= entryLeft && mouseX <= entryRight && slotIndex >= 0 && mouseListY >= 0 && slotIndex < listLength)
{
this.elementClicked(slotIndex, slotIndex == this.selectedIndex && System.currentTimeMillis() - this.lastClickTime < 250L);
this.selectedIndex = slotIndex;
this.lastClickTime = System.currentTimeMillis();
}
else if (mouseX >= entryLeft && mouseX <= entryRight && mouseListY < 0)
{
this.clickHeader(mouseX - entryLeft, mouseY - this.top + (int)this.scrollDistance - border);
}
if (mouseX >= scrollBarLeft && mouseX <= scrollBarRight)
{
this.scrollFactor = -1.0F;
int scrollHeight = this.getContentHeight() - viewHeight - border;
if (scrollHeight < 1) scrollHeight = 1;
int var13 = (int)((float)(viewHeight * viewHeight) / (float)this.getContentHeight());
if (var13 < 32) var13 = 32;
if (var13 > viewHeight - border*2)
var13 = viewHeight - border*2;
this.scrollFactor /= (float)(viewHeight - var13) / (float)scrollHeight;
}
else
{
this.scrollFactor = 1.0F;
}
this.initialMouseClickY = mouseY;
}
else
{
this.initialMouseClickY = -2.0F;
}
}
else if (this.initialMouseClickY >= 0.0F)
{
this.scrollDistance -= ((float)mouseY - this.initialMouseClickY) * this.scrollFactor;
this.initialMouseClickY = (float)mouseY;
}
}
else
{
this.initialMouseClickY = -1.0F;
}
this.applyScrollLimits();
Tessellator tess = Tessellator.getInstance();
BufferBuilder worldr = tess.getBuffer();
ScaledResolution res = new ScaledResolution(client);
double scaleW = client.displayWidth / res.getScaledWidth_double();
double scaleH = client.displayHeight / res.getScaledHeight_double();
GL11.glEnable(GL11.GL_SCISSOR_TEST);
GL11.glScissor((int)(left * scaleW), (int)(client.displayHeight - (bottom * scaleH)),
(int)(listWidth * scaleW), (int)(viewHeight * scaleH));
if (this.client.world != null)
{
this.drawGradientRect(this.left, this.top, this.right, this.bottom, 0xC0101010, 0xD0101010);
}
else // Draw dark dirt background
{
GlStateManager.disableLighting();
GlStateManager.disableFog();
this.client.renderEngine.bindTexture(Gui.OPTIONS_BACKGROUND);
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
final float scale = 32.0F;
worldr.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
worldr.pos(this.left, this.bottom, 0.0D).tex(this.left / scale, (this.bottom + (int)this.scrollDistance) / scale).color(0x20, 0x20, 0x20, 0xFF).endVertex();
worldr.pos(this.right, this.bottom, 0.0D).tex(this.right / scale, (this.bottom + (int)this.scrollDistance) / scale).color(0x20, 0x20, 0x20, 0xFF).endVertex();
worldr.pos(this.right, this.top, 0.0D).tex(this.right / scale, (this.top + (int)this.scrollDistance) / scale).color(0x20, 0x20, 0x20, 0xFF).endVertex();
worldr.pos(this.left, this.top, 0.0D).tex(this.left / scale, (this.top + (int)this.scrollDistance) / scale).color(0x20, 0x20, 0x20, 0xFF).endVertex();
tess.draw();
}
int baseY = this.top + border - (int)this.scrollDistance;
if (this.hasHeader) {
this.drawHeader(entryRight, baseY, tess);
}
for (int slotIdx = 0; slotIdx < listLength; ++slotIdx)
{
int slotTop = baseY + slotIdx * this.slotHeight + this.headerHeight;
int slotBuffer = this.slotHeight - border;
if (slotTop <= this.bottom && slotTop + slotBuffer >= this.top)
{
if (this.highlightSelected && this.isSelected(slotIdx))
{
int min = this.left;
int max = entryRight;
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.disableTexture2D();
worldr.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
worldr.pos(min, slotTop + slotBuffer + 2, 0).tex(0, 1).color(0x80, 0x80, 0x80, 0xFF).endVertex();
worldr.pos(max, slotTop + slotBuffer + 2, 0).tex(1, 1).color(0x80, 0x80, 0x80, 0xFF).endVertex();
worldr.pos(max, slotTop - 2, 0).tex(1, 0).color(0x80, 0x80, 0x80, 0xFF).endVertex();
worldr.pos(min, slotTop - 2, 0).tex(0, 0).color(0x80, 0x80, 0x80, 0xFF).endVertex();
worldr.pos(min + 1, slotTop + slotBuffer + 1, 0).tex(0, 1).color(0x00, 0x00, 0x00, 0xFF).endVertex();
worldr.pos(max - 1, slotTop + slotBuffer + 1, 0).tex(1, 1).color(0x00, 0x00, 0x00, 0xFF).endVertex();
worldr.pos(max - 1, slotTop - 1, 0).tex(1, 0).color(0x00, 0x00, 0x00, 0xFF).endVertex();
worldr.pos(min + 1, slotTop - 1, 0).tex(0, 0).color(0x00, 0x00, 0x00, 0xFF).endVertex();
tess.draw();
GlStateManager.enableTexture2D();
}
this.drawSlot(slotIdx, entryRight, slotTop, slotBuffer, tess);
}
}
GlStateManager.disableDepth();
int extraHeight = (this.getContentHeight() + border) - viewHeight;
if (extraHeight > 0)
{
int height = (viewHeight * viewHeight) / this.getContentHeight();
if (height < 32) height = 32;
if (height > viewHeight - border*2)
height = viewHeight - border*2;
int barTop = (int)this.scrollDistance * (viewHeight - height) / extraHeight + this.top;
if (barTop < this.top)
{
barTop = this.top;
}
GlStateManager.disableTexture2D();
worldr.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
worldr.pos(scrollBarLeft, this.bottom, 0.0D).tex(0.0D, 1.0D).color(0x00, 0x00, 0x00, 0xFF).endVertex();
worldr.pos(scrollBarRight, this.bottom, 0.0D).tex(1.0D, 1.0D).color(0x00, 0x00, 0x00, 0xFF).endVertex();
worldr.pos(scrollBarRight, this.top, 0.0D).tex(1.0D, 0.0D).color(0x00, 0x00, 0x00, 0xFF).endVertex();
worldr.pos(scrollBarLeft, this.top, 0.0D).tex(0.0D, 0.0D).color(0x00, 0x00, 0x00, 0xFF).endVertex();
tess.draw();
worldr.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
worldr.pos(scrollBarLeft, barTop + height, 0.0D).tex(0.0D, 1.0D).color(0x80, 0x80, 0x80, 0xFF).endVertex();
worldr.pos(scrollBarRight, barTop + height, 0.0D).tex(1.0D, 1.0D).color(0x80, 0x80, 0x80, 0xFF).endVertex();
worldr.pos(scrollBarRight, barTop, 0.0D).tex(1.0D, 0.0D).color(0x80, 0x80, 0x80, 0xFF).endVertex();
worldr.pos(scrollBarLeft, barTop, 0.0D).tex(0.0D, 0.0D).color(0x80, 0x80, 0x80, 0xFF).endVertex();
tess.draw();
worldr.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
worldr.pos(scrollBarLeft, barTop + height - 1, 0.0D).tex(0.0D, 1.0D).color(0xC0, 0xC0, 0xC0, 0xFF).endVertex();
worldr.pos(scrollBarRight - 1, barTop + height - 1, 0.0D).tex(1.0D, 1.0D).color(0xC0, 0xC0, 0xC0, 0xFF).endVertex();
worldr.pos(scrollBarRight - 1, barTop, 0.0D).tex(1.0D, 0.0D).color(0xC0, 0xC0, 0xC0, 0xFF).endVertex();
worldr.pos(scrollBarLeft, barTop, 0.0D).tex(0.0D, 0.0D).color(0xC0, 0xC0, 0xC0, 0xFF).endVertex();
tess.draw();
}
this.drawScreen(mouseX, mouseY);
GlStateManager.enableTexture2D();
GlStateManager.shadeModel(GL11.GL_FLAT);
GlStateManager.enableAlpha();
GlStateManager.disableBlend();
GL11.glDisable(GL11.GL_SCISSOR_TEST);
}
protected void drawGradientRect(int left, int top, int right, int bottom, int color1, int color2)
{
GuiUtils.drawGradientRect(0, left, top, right, bottom, color1, color2);
}
}

View file

@ -24,6 +24,7 @@ import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiListExtended;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.ResourceLocation;
@ -37,31 +38,36 @@ import static net.minecraft.util.StringUtils.stripControlCodes;
* @author cpw
*
*/
public class GuiSlotModList extends GuiScrollingList
public class GuiSlotModList extends GuiListExtended<GuiSlotModList.ModEntry>
{
private static final ResourceLocation VERSION_CHECK_ICONS = new ResourceLocation(ForgeVersion.MOD_ID, "textures/gui/version_check_icons.png");
private final int listWidth;
private GuiModList parent;
private List<ModInfo> mods;
public GuiSlotModList(GuiModList parent, List<ModInfo> mods, int listWidth, int slotHeight)
public GuiSlotModList(GuiModList parent, int listWidth)
{
super(parent.getMinecraftInstance(), listWidth, parent.height, 32, parent.height - 88 + 4, 10, slotHeight, parent.width, parent.height);
super(parent.getMinecraftInstance(), listWidth, parent.height, 32, parent.height - 88 + 4, parent.getFontRenderer().FONT_HEIGHT * 2 + 8);
this.parent = parent;
this.mods = mods;
this.listWidth = listWidth;
this.refreshList();
}
@Override
protected int getSize()
protected int getScrollBarX()
{
return mods.size();
return this.listWidth + 6;
}
@Override
protected void elementClicked(int index, boolean doubleClick)
public int getListWidth()
{
this.parent.selectModIndex(index);
return this.listWidth;
}
void refreshList() {
this.func_195086_c();
parent.buildModList(this::func_195085_a, mod->new ModEntry(mod, this.parent));
}
@Override
@ -76,32 +82,42 @@ public class GuiSlotModList extends GuiScrollingList
this.parent.drawDefaultBackground();
}
@Override
protected int getContentHeight()
{
return (this.getSize()) * 35 + 1;
}
class ModEntry extends GuiListExtended.IGuiListEntry<ModEntry> {
private final ModInfo modInfo;
private final GuiModList parent;
@Override
protected void drawSlot(int idx, int right, int top, int height, Tessellator tess)
{
ModInfo mc = mods.get(idx);
String name = stripControlCodes(mc.getDisplayName());
String version = stripControlCodes(mc.getVersion().getVersionString());
FontRenderer font = this.parent.getFontRenderer();
VersionChecker.CheckResult vercheck = VersionChecker.getResult(mc);
ModEntry(ModInfo info, GuiModList parent) {
this.modInfo = info;
this.parent = parent;
}
font.drawString(font.trimStringToWidth(name, listWidth - 10), this.left + 3 , top + 2, 0xFFFFFF);
font.drawString(font.trimStringToWidth(version, listWidth - (5 + height)), this.left + 3 , top + 12, 0xCCCCCC);
if (vercheck.status.shouldDraw())
@Override
public void func_194999_a(int p_194999_1_, int p_194999_2_, int p_194999_3_, int p_194999_4_, boolean p_194999_5_, float p_194999_6_)
{
//TODO: Consider adding more icons for visualization
Minecraft.getMinecraft().getTextureManager().bindTexture(VERSION_CHECK_ICONS);
GlStateManager.color(1, 1, 1, 1);
GlStateManager.pushMatrix();
Gui.drawModalRectWithCustomSizedTexture(right - (height / 2 + 4), top + (height / 2 - 4), vercheck.status.getSheetOffset() * 8, (vercheck.status.isAnimated() && ((System.currentTimeMillis() / 800 & 1)) == 1) ? 8 : 0, 8, 8, 64, 16);
GlStateManager.popMatrix();
int top = this.func_195001_c();
int left = this.func_195002_d();
String name = stripControlCodes(modInfo.getDisplayName());
String version = stripControlCodes(modInfo.getVersion().getVersionString());
VersionChecker.CheckResult vercheck = VersionChecker.getResult(modInfo);
FontRenderer font = this.parent.getFontRenderer();
font.func_211126_b(font.trimStringToWidth(name, listWidth),left + 3, top + 2, 0xFFFFFF);
font.func_211126_b(font.trimStringToWidth(version, listWidth), left + 3 , top + 2 + font.FONT_HEIGHT, 0xCCCCCC);
if (vercheck.status.shouldDraw())
{
//TODO: Consider adding more icons for visualization
Minecraft.getMinecraft().getTextureManager().bindTexture(VERSION_CHECK_ICONS);
GlStateManager.color(1, 1, 1, 1);
GlStateManager.pushMatrix();
Gui.drawModalRectWithCustomSizedTexture(right - (height / 2 + 4), GuiSlotModList.this.top + (height / 2 - 4), vercheck.status.getSheetOffset() * 8, (vercheck.status.isAnimated() && ((System.currentTimeMillis() / 800 & 1)) == 1) ? 8 : 0, 8, 8, 64, 16);
GlStateManager.popMatrix();
}
}
@Override
public boolean mouseClicked(double p_mouseClicked_1_, double p_mouseClicked_3_, int p_mouseClicked_5_)
{
parent.selectModIndex(this.func_195003_b());
return false;
}
}
}

View file

@ -19,6 +19,8 @@
package net.minecraftforge.fml.common.event;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.command.CommandSource;
import net.minecraft.server.MinecraftServer;
/**
@ -34,5 +36,4 @@ public class FMLServerAboutToStartEvent extends ServerLifecycleEvent {
{
super(server);
}
}

View file

@ -19,6 +19,8 @@
package net.minecraftforge.fml.common.event;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.command.CommandSource;
import net.minecraft.server.MinecraftServer;
/**
@ -34,4 +36,8 @@ public class FMLServerStartingEvent extends ServerLifecycleEvent
{
super(server);
}
public CommandDispatcher<CommandSource> getCommandDispatcher() {
return server.func_195571_aL().func_197054_a();
}
}

View file

@ -43,6 +43,7 @@ import javax.annotation.Nullable;
*/
public class VillagerRegistry
{
/*
public static final RegistryObject<VillagerProfession> FARMER = RegistryObject.of("minecraft:farmer", ()->VillagerProfession.class);
private static final VillagerRegistry INSTANCE = new VillagerRegistry();
@ -53,29 +54,36 @@ public class VillagerRegistry
init();
}
/**
*/
/**
* Allow access to the {@link net.minecraft.world.gen.structure.StructureVillagePieces} array controlling new village
* creation so you can insert your own new village pieces
*
* @author cpw
*/
*//*
public interface IVillageCreationHandler
{
/**
*/
/**
* Called when {@link net.minecraft.world.gen.structure.MapGenVillage} is creating a new village
*
* @param random
* @param i
*/
*//*
StructureVillagePieces.PieceWeight getVillagePieceWeight(Random random, int i);
/**
*/
/**
* The class of the root structure component to add to the village
*/
*//*
Class<?> getComponentClass();
/**
*/
/**
* Build an instance of the village component {@link net.minecraft.world.gen.structure.StructureVillagePieces}
*
* @param villagePiece
@ -87,7 +95,8 @@ public class VillagerRegistry
* @param p3
* @param facing
* @param p5
*/
*//*
Village buildComponent(StructureVillagePieces.PieceWeight villagePiece, StructureVillagePieces.Start startPiece, List<StructureComponent> pieces, Random random, int p1,
int p2, int p3, EnumFacing facing, int p5);
}
@ -97,11 +106,13 @@ public class VillagerRegistry
return INSTANCE;
}
/**
*/
/**
* Register a new village creation handler
*
* @param handler
*/
*//*
public void registerVillageCreationHandler(IVillageCreationHandler handler)
{
villageCreationHandlers.put(handler.getComponentClass(), handler);
@ -301,12 +312,14 @@ public class VillagerRegistry
}
}
/**
*/
/**
* Hook called when spawning a Villager, sets it's profession to a random registered profession.
*
* @param entity The new entity
* @param rand The world's RNG
*/
*//*
public static void setRandomProfession(EntityVillager entity, Random rand)
{
entity.setProfession(INSTANCE.REGISTRY.getRandomObject(rand));
@ -356,4 +369,5 @@ public class VillagerRegistry
//It is nasty I know but it's vanilla.
private static final ITradeList[][][][] trades = EntityVillager.GET_TRADES_DONT_USE();
}
*/
}

View file

@ -63,7 +63,6 @@ public class ModInfo implements IModInfo
this.dependencies = Collections.emptyList();
this.properties = Collections.emptyMap();
}
}
@Override
@ -104,6 +103,11 @@ public class ModInfo implements IModInfo
public Optional<String> getLogoFile()
{
return this.owningFile.getConfig().getOptional("logoFile");
return this.owningFile != null ? this.owningFile.getConfig().getOptional("logoFile") : Optional.empty();
}
public boolean hasConfigUI()
{
return false;
}
}

View file

@ -0,0 +1,178 @@
package net.minecraftforge.fml.network;
import io.netty.util.AttributeKey;
import net.minecraft.nbt.INBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.fml.network.simple.SimpleChannel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class FMLNetworking
{
private static final Logger LOGGER = LogManager.getLogger();
private static final Marker FMLHSMARKER = MarkerManager.getMarker("FMLHSMARKER");
static final AttributeKey<String> FML_MARKER = AttributeKey.valueOf("fml:marker");
private static final AttributeKey<FMLHandshake> FML_HANDSHAKE = AttributeKey.newInstance("fml:handshake");
static void registerHandshake(NetworkManager manager, NetworkDirection direction) {
manager.channel().attr(FML_HANDSHAKE).compareAndSet(null, new FMLHandshake(manager, direction));
}
private static FMLHandshake getHandshake(Supplier<NetworkEvent.Context> contextSupplier) {
final NetworkManager networkManager = contextSupplier.get().getNetworkManager();
return getHandshake(networkManager);
}
private static FMLHandshake getHandshake(NetworkManager manager)
{
return manager.channel().attr(FML_HANDSHAKE).get();
}
static boolean dispatch(NetworkManager networkManager)
{
return getHandshake(networkManager).tickServer();
}
public static class FMLHandshake {
private static SimpleChannel channel;
private static List<Supplier<HandshakeMessage>> messages = Arrays.asList(HandshakeMessage.S2CModList::new);
private List<HandshakeMessage> sentMessages = new ArrayList<>();
static {
channel = NetworkRegistry.ChannelBuilder.named(NetworkHooks.FMLHANDSHAKE).
clientAcceptedVersions(a -> true).
serverAcceptedVersions(a -> true).
networkProtocolVersion(() -> NetworkHooks.NETVERSION).
simpleChannel();
channel.messageBuilder(HandshakeMessage.S2CModList.class, 1).
decoder(HandshakeMessage.S2CModList::decode).
encoder(HandshakeMessage.S2CModList::encode).
loginIndex(HandshakeMessage.S2CModList::setPacketIndexSequence).
consumer((m,c)->getHandshake(c).handleServerModListOnClient(m, c)).
add();
channel.messageBuilder(HandshakeMessage.C2SModListReply.class, 2).
loginIndex(HandshakeMessage::setPacketIndexSequence).
decoder(HandshakeMessage.C2SModListReply::decode).
encoder(HandshakeMessage.C2SModListReply::encode).
consumer((m,c) -> getHandshake(c).handleClientModListOnServer(m,c)).
add();
}
private final NetworkDirection direction;
private final NetworkManager manager;
private int packetPosition;
public FMLHandshake(NetworkManager networkManager, NetworkDirection side)
{
this.direction = side;
this.manager = networkManager;
}
public void handleServerModListOnClient(HandshakeMessage.S2CModList serverModList, Supplier<NetworkEvent.Context> c)
{
LOGGER.debug(FMLHSMARKER, "Received S2CModList packet with index {}", serverModList.getPacketIndexSequence());
c.get().setPacketHandled(true);
final HandshakeMessage.C2SModListReply reply = new HandshakeMessage.C2SModListReply();
channel.sendLogin(reply, c.get().getNetworkManager(), c.get().getDirection().reply(), reply.getPacketIndexSequence());
LOGGER.debug(FMLHSMARKER, "Sent C2SModListReply packet with index {}", reply.getPacketIndexSequence());
}
private void handleClientModListOnServer(HandshakeMessage.C2SModListReply m, Supplier<NetworkEvent.Context> c)
{
LOGGER.debug(FMLHSMARKER, "Received C2SModListReply with index {}", m.getPacketIndexSequence());
final HandshakeMessage message = this.sentMessages.stream().filter(ob -> ob.getPacketIndexSequence() == m.getPacketIndexSequence()).findFirst().orElseThrow(() -> new RuntimeException("Unexpected reply from client"));
boolean removed = this.sentMessages.remove(message);
c.get().setPacketHandled(true);
LOGGER.debug(FMLHSMARKER, "Cleared original message {}", removed);
}
public boolean tickServer()
{
if (packetPosition < messages.size()) {
final HandshakeMessage message = messages.get(packetPosition).get();
LOGGER.debug(FMLHSMARKER, "Sending ticking packet {} index {}", message.getClass().getName(), message.getPacketIndexSequence());
channel.sendLogin(message, this.manager, this.direction, packetPosition);
sentMessages.add(message);
packetPosition++;
}
// we're done when sentMessages is empty
if (sentMessages.isEmpty()) {
// clear ourselves - we're done!
this.manager.channel().attr(FML_HANDSHAKE).set(null);
return true;
}
return false;
}
}
static class HandshakeMessage
{
private int index;
public void setPacketIndexSequence(int i)
{
this.index = i;
}
public int getPacketIndexSequence()
{
return index;
}
static class S2CModList extends HandshakeMessage
{
private List<String> modList;
private int index;
S2CModList() {
this.modList = ModList.get().getMods().stream().map(ModInfo::getModId).collect(Collectors.toList());
}
S2CModList(NBTTagCompound nbtTagCompound)
{
this.modList = nbtTagCompound.getTagList("list", 8).stream().map(INBTBase::getString).collect(Collectors.toList());
}
public static S2CModList decode(PacketBuffer packetBuffer)
{
final NBTTagCompound nbtTagCompound = packetBuffer.readCompoundTag();
return new S2CModList(nbtTagCompound);
}
public void encode(PacketBuffer packetBuffer)
{
NBTTagCompound tag = new NBTTagCompound();
tag.setTag("list",modList.stream().map(NBTTagString::new).collect(Collectors.toCollection(NBTTagList::new)));
packetBuffer.writeCompoundTag(tag);
}
}
static class C2SModListReply extends HandshakeMessage
{
public static C2SModListReply decode(PacketBuffer buffer)
{
return new C2SModListReply();
}
public void encode(PacketBuffer buffer)
{
}
}
}
}

View file

@ -1,23 +1,32 @@
package net.minecraftforge.fml.network;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceArrayMap;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.login.client.CPacketCustomPayloadLogin;
import net.minecraft.network.login.server.SPacketCustomPayloadLogin;
import net.minecraft.network.play.client.CPacketCustomPayload;
import net.minecraft.network.play.server.SPacketCustomPayload;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.UnsafeHacks;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public interface ICustomPacket<T extends Packet<?>> {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
enum Fields {
CPACKETCUSTOMPAYLOAD(CPacketCustomPayload.class),
SPACKETCUSTOMPAYLOAD(SPacketCustomPayload.class),
CPACKETCUSTOMLOGIN(CPacketCustomPayloadLogin.class),
SPACKETCUSTOMLOGIN(SPacketCustomPayloadLogin.class),
;
static final Reference2ReferenceArrayMap<Class<?>, Fields> lookup;
@ -28,20 +37,17 @@ public interface ICustomPacket<T extends Packet<?>> {
private final Class<?> clazz;
public final Field data;
public final Field channel;
final Optional<Field> data;
final Optional<Field> channel;
final Optional<Field> index;
Fields(Class<?> customPacketClass)
{
this.clazz = customPacketClass;
try
{
data = customPacketClass.getDeclaredField("data");
channel = customPacketClass.getDeclaredField("channel");
}
catch (NoSuchFieldException e)
{
throw new RuntimeException("BARF?");
}
Field[] fields = customPacketClass.getDeclaredFields();
data = Arrays.stream(fields).filter(f-> !Modifier.isStatic(f.getModifiers()) && f.getType() == PacketBuffer.class).findFirst();
channel = Arrays.stream(fields).filter(f->!Modifier.isStatic(f.getModifiers()) && f.getType() == ResourceLocation.class).findFirst();
index = Arrays.stream(fields).filter(f->!Modifier.isStatic(f.getModifiers()) && f.getType() == int.class).findFirst();
}
private Class<?> getClazz()
@ -51,11 +57,27 @@ public interface ICustomPacket<T extends Packet<?>> {
}
default PacketBuffer getData() {
return UnsafeHacks.getField(Fields.lookup.get(this.getClass()).data, this);
return Fields.lookup.get(this.getClass()).data.map(f->UnsafeHacks.<PacketBuffer>getField(f, this)).orElse(null);
}
default ResourceLocation getName() {
return UnsafeHacks.getField(Fields.lookup.get(this.getClass()).channel, this);
return Fields.lookup.get(this.getClass()).channel.map(f->UnsafeHacks.<ResourceLocation>getField(f, this)).orElse(NetworkHooks.FMLHANDSHAKE);
}
default int getIndex() {
return Fields.lookup.get(this.getClass()).index.map(f->UnsafeHacks.getIntField(f, this)).orElse(Integer.MIN_VALUE);
}
default void setData(PacketBuffer buffer) {
Fields.lookup.get(this.getClass()).data.ifPresent(f->UnsafeHacks.setField(f, this, buffer));
}
default void setName(ResourceLocation channelName) {
Fields.lookup.get(this.getClass()).channel.ifPresent(f->UnsafeHacks.setField(f, this, channelName));
}
default void setIndex(int index) {
Fields.lookup.get(this.getClass()).index.ifPresent(f->UnsafeHacks.setIntField(f, this, index));
}
default NetworkDirection getDirection() {

View file

@ -26,7 +26,9 @@ import net.minecraft.network.login.client.CPacketCustomPayloadLogin;
import net.minecraft.network.login.server.SPacketCustomPayloadLogin;
import net.minecraft.network.play.client.CPacketCustomPayload;
import net.minecraft.network.play.server.SPacketCustomPayload;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.UnsafeHacks;
import java.util.function.BiFunction;
import java.util.function.Function;
@ -36,14 +38,15 @@ import java.util.stream.Stream;
public enum NetworkDirection
{
PLAY_TO_SERVER(NetworkEvent.ClientCustomPayloadEvent::new, LogicalSide.CLIENT, CPacketCustomPayload.class),
PLAY_TO_CLIENT(NetworkEvent.ServerCustomPayloadEvent::new, LogicalSide.SERVER, SPacketCustomPayload.class),
LOGIN_TO_SERVER(NetworkEvent.ClientCustomPayloadEvent::new, LogicalSide.CLIENT, CPacketCustomPayloadLogin.class),
LOGIN_TO_CLIENT(NetworkEvent.ServerCustomPayloadEvent::new, LogicalSide.SERVER, SPacketCustomPayloadLogin.class);
PLAY_TO_SERVER(NetworkEvent.ClientCustomPayloadEvent::new, LogicalSide.CLIENT, CPacketCustomPayload.class, 1),
PLAY_TO_CLIENT(NetworkEvent.ServerCustomPayloadEvent::new, LogicalSide.SERVER, SPacketCustomPayload.class, 0),
LOGIN_TO_SERVER(NetworkEvent.ClientCustomPayloadLoginEvent::new, LogicalSide.CLIENT, CPacketCustomPayloadLogin.class, 3),
LOGIN_TO_CLIENT(NetworkEvent.ServerCustomPayloadLoginEvent::new, LogicalSide.SERVER, SPacketCustomPayloadLogin.class, 2);
private final BiFunction<PacketBuffer, Supplier<NetworkEvent.Context>, NetworkEvent> eventSupplier;
private final BiFunction<ICustomPacket<?>, Supplier<NetworkEvent.Context>, NetworkEvent> eventSupplier;
private final LogicalSide logicalSide;
private final Class<? extends Packet> packetClass;
private final int otherWay;
private static final Reference2ReferenceArrayMap<Class<? extends Packet>, NetworkDirection> packetLookup;
@ -52,11 +55,12 @@ public enum NetworkDirection
collect(Collectors.toMap(NetworkDirection::getPacketClass, Function.identity(), (m1,m2)->m1, Reference2ReferenceArrayMap::new));
}
NetworkDirection(BiFunction<PacketBuffer, Supplier<NetworkEvent.Context>, NetworkEvent> eventSupplier, LogicalSide logicalSide, Class<? extends Packet> clazz)
NetworkDirection(BiFunction<ICustomPacket<?>, Supplier<NetworkEvent.Context>, NetworkEvent> eventSupplier, LogicalSide logicalSide, Class<? extends Packet> clazz, int i)
{
this.eventSupplier = eventSupplier;
this.logicalSide = logicalSide;
this.packetClass = clazz;
this.otherWay = i;
}
private Class<? extends Packet> getPacketClass() {
@ -67,7 +71,10 @@ public enum NetworkDirection
return packetLookup.get(customPacket);
}
public NetworkEvent getEvent(final PacketBuffer buffer, final Supplier<NetworkEvent.Context> manager) {
public NetworkDirection reply() {
return NetworkDirection.values()[this.otherWay];
}
public NetworkEvent getEvent(final ICustomPacket<?> buffer, final Supplier<NetworkEvent.Context> manager) {
return this.eventSupplier.apply(buffer, manager);
}
@ -75,4 +82,14 @@ public enum NetworkDirection
{
return logicalSide;
}
@SuppressWarnings("unchecked")
public <T extends Packet<?>> ICustomPacket<T> buildPacket(PacketBuffer packetBuffer, ResourceLocation channelName, int index)
{
ICustomPacket<T> packet = (ICustomPacket<T>)UnsafeHacks.newInstance(getPacketClass());
packet.setName(channelName);
packet.setData(packetBuffer);
packet.setIndex(index);
return packet;
}
}

View file

@ -20,9 +20,6 @@
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;
@ -35,10 +32,9 @@ public class NetworkEvent extends Event
{
private final PacketBuffer payload;
private final Supplier<Context> source;
private NetworkEvent(PacketBuffer payload, Supplier<Context> source)
private NetworkEvent(ICustomPacket<?> payload, Supplier<Context> source)
{
this.payload = payload;
this.payload = payload.getData();
this.source = source;
}
@ -54,56 +50,92 @@ public class NetworkEvent extends Event
public static class ServerCustomPayloadEvent extends NetworkEvent
{
ServerCustomPayloadEvent(final PacketBuffer payload, final Supplier<Context> source) {
ServerCustomPayloadEvent(final ICustomPacket<?> payload, final Supplier<Context> source) {
super(payload, source);
}
}
public static class ClientCustomPayloadEvent extends NetworkEvent
{
ClientCustomPayloadEvent(final PacketBuffer payload, final Supplier<Context> source) {
ClientCustomPayloadEvent(final ICustomPacket<?> payload, final Supplier<Context> source) {
super(payload, source);
}
}
public static class ServerCustomPayloadLoginEvent extends ServerCustomPayloadEvent implements ILoginIndex {
private final int index;
ServerCustomPayloadLoginEvent(ICustomPacket<?> payload, Supplier<Context> source)
{
super(payload, source);
this.index = payload.getIndex();
}
public int getIndex()
{
return index;
}
}
public static class ClientCustomPayloadLoginEvent extends ClientCustomPayloadEvent implements ILoginIndex {
private final int index;
ClientCustomPayloadLoginEvent(ICustomPacket<?> payload, Supplier<Context> source)
{
super(payload, source);
this.index = payload.getIndex();
}
public int getIndex()
{
return index;
}
}
public interface ILoginIndex {
int getIndex();
}
/**
* Context for {@link NetworkEvent}
*/
public static class Context
{
/**
* The {@link INetHandler} for this message. It could be a client or server handler, depending
* on the {@link #side} received.
* The {@link NetworkManager} for this message.
*/
private final INetHandler netHandler;
private final NetworkManager networkManager;
/**
* The {@link NetworkDirection} this message has been received on
* The {@link NetworkDirection} this message has been received on.
*/
private final NetworkDirection side;
private boolean packetHandled;
Context(NetworkManager netHandler, NetworkDirection side)
{
this.netHandler = netHandler.getNetHandler();
this.networkManager = netHandler;
this.side = side;
}
public NetworkDirection getSide() {
public NetworkDirection getDirection() {
return side;
}
public NetHandlerPlayServer getServerHandler()
{
return (NetHandlerPlayServer) netHandler;
public NetworkManager getNetworkManager() {
return networkManager;
}
public NetHandlerPlayClient getClientHandler()
public void setPacketHandled(boolean packetHandled) {
this.packetHandled = packetHandled;
}
public boolean getPacketHandled()
{
return (NetHandlerPlayClient) netHandler;
return packetHandled;
}
@SuppressWarnings("unchecked")
public <V> ListenableFuture<V> enqueueWork(Runnable runnable) {
return (ListenableFuture<V>)LogicalSidedProvider.WORKQUEUE.<IThreadListener>get(getSide().getLogicalSide()).addScheduledTask(runnable);
return (ListenableFuture<V>)LogicalSidedProvider.WORKQUEUE.<IThreadListener>get(getDirection().getLogicalSide()).addScheduledTask(runnable);
}
}
}

View file

@ -20,10 +20,14 @@
package net.minecraftforge.fml.network;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.handshake.client.CPacketHandshake;
import net.minecraft.network.login.client.CPacketCustomPayloadLogin;
import net.minecraft.server.network.NetHandlerLoginServer;
import net.minecraft.util.ResourceLocation;
import java.util.Objects;
@ -31,6 +35,7 @@ public class NetworkHooks
{
public static final String NETVERSION = "FML1";
public static final String NOVERSION = "NONE";
static final ResourceLocation FMLHANDSHAKE = new ResourceLocation("fml", "handshake");
public static String getFMLVersion(final String ip)
{
return ip.contains("\0") ? Objects.equals(ip.split("\0")[1], NETVERSION) ? NETVERSION : ip.split("\0")[1] : NOVERSION;
@ -43,7 +48,7 @@ public class NetworkHooks
public static ConnectionType getConnectionType(final NetHandlerPlayServer connection)
{
return ConnectionType.forVersionFlag(connection.netManager.channel().attr(NetworkRegistry.FML_MARKER).get());
return ConnectionType.forVersionFlag(connection.netManager.channel().attr(FMLNetworking.FML_MARKER).get());
}
public static Packet<?> getEntitySpawningPacket(Entity entity)
@ -51,15 +56,25 @@ public class NetworkHooks
return null;
}
public static void onCustomPayload(final ICustomPacket<?> packet, final NetworkManager manager) {
NetworkRegistry.findTarget(packet.getName()).
ifPresent(ni->ni.dispatch(packet.getDirection(), packet.getData(), manager));
public static boolean onCustomPayload(final ICustomPacket<?> packet, final NetworkManager manager) {
return NetworkRegistry.findTarget(packet.getName()).
map(ni->ni.dispatch(packet.getDirection(), packet, manager)).orElse(Boolean.FALSE);
}
public static void registerServerChannel(NetworkManager manager, CPacketHandshake packet)
public static void registerServerLoginChannel(NetworkManager manager, CPacketHandshake packet)
{
manager.channel().attr(NetworkRegistry.FML_MARKER).set(packet.getFMLVersion());
manager.channel().attr(FMLNetworking.FML_MARKER).set(packet.getFMLVersion());
FMLNetworking.registerHandshake(manager, NetworkDirection.LOGIN_TO_CLIENT);
}
public static void registerClientLoginChannel(NetworkManager manager)
{
manager.channel().attr(FMLNetworking.FML_MARKER).set(NETVERSION);
FMLNetworking.registerHandshake(manager, NetworkDirection.LOGIN_TO_SERVER);
}
public static boolean tickNegotiation(NetHandlerLoginServer netHandlerLoginServer, NetworkManager networkManager, EntityPlayerMP player)
{
return FMLNetworking.dispatch(networkManager);
}
}

View file

@ -70,9 +70,11 @@ public class NetworkInstance
this.networkEventBus.unregister(object);
}
void dispatch(final NetworkDirection side, final PacketBuffer bufferData, final NetworkManager manager)
boolean dispatch(final NetworkDirection side, final ICustomPacket<?> packet, final NetworkManager manager)
{
this.networkEventBus.post(side.getEvent(bufferData,()->new NetworkEvent.Context(manager, side)));
final NetworkEvent.Context context = new NetworkEvent.Context(manager, side);
this.networkEventBus.post(side.getEvent(packet, () -> context));
return context.getPacketHandled();
}

View file

@ -41,8 +41,6 @@ public class NetworkRegistry
private static final Logger LOGGER = LogManager.getLogger();
private static final Marker NETREGISTRY = MarkerManager.getMarker("NETREGISTRY");
public static final AttributeKey<String> FML_MARKER = AttributeKey.valueOf("fml:versionMarker");
private static Map<ResourceLocation, NetworkInstance> instances = new HashMap<>();
public static List<String> getNonVanillaNetworkMods()
{

View file

@ -21,7 +21,9 @@ package net.minecraftforge.fml.network.simple;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import it.unimi.dsi.fastutil.shorts.Short2ObjectArrayMap;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.ICustomPacket;
import net.minecraftforge.fml.network.NetworkEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -30,6 +32,7 @@ import org.apache.logging.log4j.MarkerManager;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
@ -49,6 +52,8 @@ public class IndexedMessageCodec
private final int index;
private final BiConsumer<MSG,Supplier<NetworkEvent.Context>> messageConsumer;
private final Class<MSG> messageType;
private Optional<BiConsumer<MSG, Integer>> loginIndexFunction;
public CodecIndex(int index, Class<MSG> messageType, BiConsumer<MSG, PacketBuffer> encoder, Function<PacketBuffer, MSG> decoder, BiConsumer<MSG, Supplier<NetworkEvent.Context>> messageConsumer)
{
this.index = index;
@ -56,23 +61,39 @@ public class IndexedMessageCodec
this.encoder = Optional.ofNullable(encoder);
this.decoder = Optional.ofNullable(decoder);
this.messageConsumer = messageConsumer;
this.loginIndexFunction = Optional.empty();
indicies.put((short)(index & 0xff), this);
types.put(messageType, this);
}
public void setLoginIndexFunction(BiConsumer<MSG, Integer> loginIndexFunction)
{
this.loginIndexFunction = Optional.of(loginIndexFunction);
}
public Optional<BiConsumer<MSG, Integer>> getLoginIndexFunction() {
return this.loginIndexFunction;
}
}
private static <M> void tryDecode(PacketBuffer payload, Supplier<NetworkEvent.Context> context, CodecIndex<M> codec)
{
codec.decoder.map(d->d.apply(payload)).ifPresent(m->codec.messageConsumer.accept(m, context));
}
private static <M> void tryDecode(PacketBuffer payload, Supplier<NetworkEvent.Context> context, int payloadIndex, CodecIndex<M> codec)
{
codec.decoder.map(d->d.apply(payload)).
map(p->{ codec.getLoginIndexFunction().ifPresent(f-> f.accept(p, payloadIndex)); return p; }).
ifPresent(m->codec.messageConsumer.accept(m, context));
}
private static <M> void tryEncode(PacketBuffer target, M message, CodecIndex<M> codec) {
codec.encoder.ifPresent(encoder->{
target.writeByte(codec.index & 0xff);
encoder.accept(message, target);
});
}
public <MSG> void build(MSG message, PacketBuffer target)
{
@SuppressWarnings("unchecked")
@ -84,7 +105,26 @@ public class IndexedMessageCodec
tryEncode(target, message, codecIndex);
}
void consume(final PacketBuffer payload, Supplier<NetworkEvent.Context> context) {
void consume(PacketBuffer payload, int payloadIndex, Supplier<NetworkEvent.Context> context) {
if (payload == null) {
LOGGER.error(SIMPLENET, "Received empty payload");
return;
}
short discriminator = payload.readUnsignedByte();
final CodecIndex<?> codecIndex = indicies.get(discriminator);
if (codecIndex == null) {
LOGGER.error(SIMPLENET, "Received invalid discriminator byte {}", discriminator);
return;
}
tryDecode(payload, context, payloadIndex, codecIndex);
}
void consume(PacketBuffer payload, Supplier<NetworkEvent.Context> context) {
// no data in empty payload
if (payload == null) {
LOGGER.error(SIMPLENET, "Received empty payload");
return;
}
short discriminator = payload.readUnsignedByte();
final CodecIndex<?> codecIndex = indicies.get(discriminator);
if (codecIndex == null) {
@ -94,7 +134,7 @@ public class IndexedMessageCodec
tryDecode(payload, context, codecIndex);
}
<MSG> void addCodecIndex(int index, Class<MSG> messageType, BiConsumer<MSG, PacketBuffer> encoder, Function<PacketBuffer, MSG> decoder, BiConsumer<MSG, Supplier<NetworkEvent.Context>> messageConsumer) {
new CodecIndex<>(index, messageType, encoder, decoder, messageConsumer);
<MSG> CodecIndex<MSG> addCodecIndex(int index, Class<MSG> messageType, BiConsumer<MSG, PacketBuffer> encoder, Function<PacketBuffer, MSG> decoder, BiConsumer<MSG, Supplier<NetworkEvent.Context>> messageConsumer) {
return new CodecIndex<>(index, messageType, encoder, decoder, messageConsumer);
}
}

View file

@ -21,13 +21,21 @@ package net.minecraftforge.fml.network.simple;
import io.netty.buffer.Unpooled;
import net.minecraft.client.Minecraft;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.play.client.CPacketCustomPayload;
import net.minecraftforge.fml.network.ICustomPacket;
import net.minecraftforge.fml.network.NetworkDirection;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraftforge.fml.network.NetworkInstance;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.function.Supplier;
public class SimpleChannel
@ -44,24 +52,42 @@ public class SimpleChannel
private void networkEventListener(final NetworkEvent networkEvent)
{
this.indexedCodec.consume(networkEvent.getPayload(),networkEvent.getSource());
if (networkEvent instanceof NetworkEvent.ILoginIndex)
{
this.indexedCodec.consume(networkEvent.getPayload(), ((NetworkEvent.ILoginIndex)networkEvent).getIndex(), networkEvent.getSource());
}
else
{
this.indexedCodec.consume(networkEvent.getPayload(), networkEvent.getSource());
}
}
public <MSG> void encodeMessage(MSG message, final PacketBuffer target) {
this.indexedCodec.build(message, target);
}
public <MSG> void registerMessage(int index, Class<MSG> messageType, BiConsumer<MSG, PacketBuffer> encoder, Function<PacketBuffer, MSG> decoder, BiConsumer<MSG, Supplier<NetworkEvent.Context>> messageConsumer) {
this.indexedCodec.addCodecIndex(index, messageType, encoder, decoder, messageConsumer);
public <MSG> IndexedMessageCodec.CodecIndex<MSG> registerMessage(int index, Class<MSG> messageType, BiConsumer<MSG, PacketBuffer> encoder, Function<PacketBuffer, MSG> decoder, BiConsumer<MSG, Supplier<NetworkEvent.Context>> messageConsumer) {
return this.indexedCodec.addCodecIndex(index, messageType, encoder, decoder, messageConsumer);
}
private <MSG> PacketBuffer toBuffer(MSG msg) {
final PacketBuffer bufIn = new PacketBuffer(Unpooled.buffer());
encodeMessage(msg, bufIn);
return bufIn;
}
public <MSG> void sendToServer(MSG message)
{
final PacketBuffer bufIn = new PacketBuffer(Unpooled.buffer());
encodeMessage(message, bufIn);
final CPacketCustomPayload payload = new CPacketCustomPayload(instance.getChannelName(), bufIn);
Minecraft.getMinecraft().getConnection().sendPacket(payload);
sendTo(message, Minecraft.getMinecraft().getConnection().getNetworkManager(), NetworkDirection.PLAY_TO_SERVER);
}
public <MSG> void sendTo(MSG message, NetworkManager manager, NetworkDirection direction) {
ICustomPacket<Packet<?>> payload = direction.buildPacket(toBuffer(message), instance.getChannelName(), -1);
manager.sendPacket(payload.getThis());
}
public <MSG> void sendLogin(MSG message, NetworkManager manager, NetworkDirection direction, int packetIndex) {
ICustomPacket<Packet<?>> payload = direction.buildPacket(toBuffer(message), instance.getChannelName(), packetIndex);
manager.sendPacket(payload.getThis());
}
public <M> MessageBuilder<M> messageBuilder(final Class<M> type, int id) {
return MessageBuilder.forType(this, type, id);
}
@ -73,6 +99,7 @@ public class SimpleChannel
private BiConsumer<MSG, PacketBuffer> encoder;
private Function<PacketBuffer, MSG> decoder;
private BiConsumer<MSG, Supplier<NetworkEvent.Context>> consumer;
private BiConsumer<MSG, Integer> loginIndexFunction;
private static <MSG> MessageBuilder<MSG> forType(final SimpleChannel channel, final Class<MSG> type, int id) {
MessageBuilder<MSG> builder = new MessageBuilder<>();
@ -92,13 +119,20 @@ public class SimpleChannel
return this;
}
public MessageBuilder<MSG> loginIndex(BiConsumer<MSG, Integer> loginIndexFunction) {
this.loginIndexFunction = loginIndexFunction;
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);
final IndexedMessageCodec.CodecIndex<MSG> message = this.channel.registerMessage(this.id, this.type, this.encoder, this.decoder, this.consumer);
if (this.loginIndexFunction != null) {
message.setLoginIndexFunction(this.loginIndexFunction);
}
}
}
}

View file

@ -119,7 +119,7 @@ public class ServerLifecycleHooks
return false;
}
NetworkHooks.registerServerChannel(manager, packet);
NetworkHooks.registerServerLoginChannel(manager, packet);
return true;
}

View file

@ -50,12 +50,10 @@ import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.RegistryEvent.MissingMappings;
import net.minecraftforge.fml.common.EnhancedRuntimeException;
import net.minecraftforge.fml.StartupQuery;
import net.minecraftforge.fml.common.registry.VillagerRegistry.VillagerProfession;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;

View file

@ -19,15 +19,20 @@
package net.minecraftforge.server.command;
import net.minecraft.command.ICommand;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import net.minecraft.command.CommandSource;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.command.ICommandSender;
import net.minecraft.server.MinecraftServer;
public class ForgeCommand extends CommandTreeBase
public class ForgeCommand
{
public ForgeCommand()
public ForgeCommand(CommandDispatcher<CommandSource> dispatcher)
{
dispatcher.register(LiteralArgumentBuilder.<CommandSource>literal("forge").
requires(cs->cs.func_197034_c(2)).
then(LiteralArgumentBuilder.literal("tps")).
executes(c->{c.getSource().func_197021_a(new TextComponentString("command.forge.tps.summary")); return 1;}));
/*
super.addSubcommand(new CommandTps());
super.addSubcommand(new CommandTrack());
super.addSubcommand(new CommandGenerate());
@ -35,35 +40,6 @@ public class ForgeCommand extends CommandTreeBase
super.addSubcommand(new CommandSetDimension());
super.addSubcommand(new CommandDimensions());
super.addSubcommand(new CommandTreeHelp(this));
}
@Override
public String getName()
{
return "forge";
}
@Override
public void addSubcommand(ICommand command)
{
throw new UnsupportedOperationException("Don't add sub-commands to /forge, create your own command.");
}
@Override
public int getRequiredPermissionLevel()
{
return 0;
}
@Override
public boolean checkPermission(MinecraftServer server, ICommandSender sender)
{
return true;
}
@Override
public String getUsage(ICommandSender icommandsender)
{
return "commands.forge.usage";
*/
}
}

View file

@ -19,15 +19,13 @@
package net.minecraftforge.server.command;
import io.netty.channel.Channel;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.ICommandSource;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.util.text.TextComponentBase;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.translation.I18n;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraft.util.text.translation.LanguageMap;
import net.minecraftforge.fml.network.ConnectionType;
import net.minecraftforge.fml.network.NetworkHooks;
@ -39,11 +37,11 @@ public class TextComponentHelper
* Detects when sending to a vanilla client and falls back to sending english,
* since they don't have the lang data necessary to translate on the client.
*/
public static TextComponentBase createComponentTranslation(ICommandSender sender, final String translation, final Object... args)
public static TextComponentBase createComponentTranslation(ICommandSource source, final String translation, final Object... args)
{
if (isVanillaClient(sender))
if (isVanillaClient(source))
{
return new TextComponentString(I18n.translateToLocalFormatted(translation, args));
return new TextComponentString(LanguageMap.getInstance().translateKey(translation, args));
}
return new TextComponentTranslation(translation, args);
}