Network init
This commit is contained in:
parent
b50b768852
commit
d7e9217695
43 changed files with 1064 additions and 794 deletions
19
build.gradle
19
build.gradle
|
@ -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'
|
||||
|
|
34
patches/minecraft/net/minecraft/client/Minecraft.java.patch
Normal file
34
patches/minecraft/net/minecraft/client/Minecraft.java.patch
Normal 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;
|
|
@ -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);
|
|
@ -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));
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
+}
|
|
@ -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 {
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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");
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
|
@ -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);
|
|
@ -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]));
|
||||
}
|
||||
|
|
@ -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_);
|
||||
}
|
|
@ -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() {
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
178
src/main/java/net/minecraftforge/fml/network/FMLNetworking.java
Normal file
178
src/main/java/net/minecraftforge/fml/network/FMLNetworking.java
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ public class ServerLifecycleHooks
|
|||
return false;
|
||||
}
|
||||
|
||||
NetworkHooks.registerServerChannel(manager, packet);
|
||||
NetworkHooks.registerServerLoginChannel(manager, packet);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue