base mod created
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import net.minecraft.util.LoggingPrintStream;
|
||||
|
||||
public class DebugLoggingPrintStream extends LoggingPrintStream
|
||||
{
|
||||
public DebugLoggingPrintStream(String domainIn, OutputStream outStream)
|
||||
{
|
||||
super(domainIn, outStream);
|
||||
}
|
||||
|
||||
protected void logString(String string)
|
||||
{
|
||||
StackTraceElement[] astacktraceelement = Thread.currentThread().getStackTrace();
|
||||
StackTraceElement stacktraceelement = astacktraceelement[Math.min(3, astacktraceelement.length)];
|
||||
LOGGER.info("[{}]@.({}:{}): {}", this.domain, stacktraceelement.getFileName(), Integer.valueOf(stacktraceelement.getLineNumber()), string);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Properties;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public class ServerEula
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger();
|
||||
private final File eulaFile;
|
||||
private final boolean acceptedEULA;
|
||||
|
||||
public ServerEula(File eulaFile)
|
||||
{
|
||||
this.eulaFile = eulaFile;
|
||||
this.acceptedEULA = this.loadEULAFile(eulaFile);
|
||||
}
|
||||
|
||||
private boolean loadEULAFile(File inFile)
|
||||
{
|
||||
FileInputStream fileinputstream = null;
|
||||
boolean flag = false;
|
||||
|
||||
try
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
fileinputstream = new FileInputStream(inFile);
|
||||
properties.load(fileinputstream);
|
||||
flag = Boolean.parseBoolean(properties.getProperty("eula", "false"));
|
||||
}
|
||||
catch (Exception var8)
|
||||
{
|
||||
LOG.warn("Failed to load {}", (Object)inFile);
|
||||
this.createEULAFile();
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly((InputStream)fileinputstream);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
public boolean hasAcceptedEULA()
|
||||
{
|
||||
return this.acceptedEULA;
|
||||
}
|
||||
|
||||
public void createEULAFile()
|
||||
{
|
||||
FileOutputStream fileoutputstream = null;
|
||||
|
||||
try
|
||||
{
|
||||
Properties properties = new Properties();
|
||||
fileoutputstream = new FileOutputStream(this.eulaFile);
|
||||
properties.setProperty("eula", "false");
|
||||
properties.store(fileoutputstream, "By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LOG.warn("Failed to save {}", this.eulaFile, exception);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly((OutputStream)fileoutputstream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package net.minecraft.server.dedicated;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import java.io.IOException;
|
||||
import net.minecraft.server.management.PlayerList;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public class DedicatedPlayerList extends PlayerList
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
public DedicatedPlayerList(DedicatedServer server)
|
||||
{
|
||||
super(server);
|
||||
this.setViewDistance(server.getIntProperty("view-distance", 10));
|
||||
this.maxPlayers = server.getIntProperty("max-players", 20);
|
||||
this.setWhiteListEnabled(server.getBooleanProperty("white-list", false));
|
||||
|
||||
if (!server.isSinglePlayer())
|
||||
{
|
||||
this.getBannedPlayers().setLanServer(true);
|
||||
this.getBannedIPs().setLanServer(true);
|
||||
}
|
||||
|
||||
this.loadPlayerBanList();
|
||||
this.savePlayerBanList();
|
||||
this.loadIPBanList();
|
||||
this.saveIPBanList();
|
||||
this.loadOpsList();
|
||||
this.readWhiteList();
|
||||
this.saveOpsList();
|
||||
|
||||
if (!this.getWhitelistedPlayers().getSaveFile().exists())
|
||||
{
|
||||
this.saveWhiteList();
|
||||
}
|
||||
}
|
||||
|
||||
public void setWhiteListEnabled(boolean whitelistEnabled)
|
||||
{
|
||||
super.setWhiteListEnabled(whitelistEnabled);
|
||||
this.getServerInstance().setProperty("white-list", Boolean.valueOf(whitelistEnabled));
|
||||
this.getServerInstance().saveProperties();
|
||||
}
|
||||
|
||||
public void addOp(GameProfile profile)
|
||||
{
|
||||
super.addOp(profile);
|
||||
this.saveOpsList();
|
||||
}
|
||||
|
||||
public void removeOp(GameProfile profile)
|
||||
{
|
||||
super.removeOp(profile);
|
||||
this.saveOpsList();
|
||||
}
|
||||
|
||||
public void removePlayerFromWhitelist(GameProfile profile)
|
||||
{
|
||||
super.removePlayerFromWhitelist(profile);
|
||||
this.saveWhiteList();
|
||||
}
|
||||
|
||||
public void addWhitelistedPlayer(GameProfile profile)
|
||||
{
|
||||
super.addWhitelistedPlayer(profile);
|
||||
this.saveWhiteList();
|
||||
}
|
||||
|
||||
public void reloadWhitelist()
|
||||
{
|
||||
this.readWhiteList();
|
||||
}
|
||||
|
||||
private void saveIPBanList()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.getBannedIPs().writeChanges();
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("Failed to save ip banlist: ", (Throwable)ioexception);
|
||||
}
|
||||
}
|
||||
|
||||
private void savePlayerBanList()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.getBannedPlayers().writeChanges();
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("Failed to save user banlist: ", (Throwable)ioexception);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadIPBanList()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.getBannedIPs().readSavedFile();
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("Failed to load ip banlist: ", (Throwable)ioexception);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadPlayerBanList()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.getBannedPlayers().readSavedFile();
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("Failed to load user banlist: ", (Throwable)ioexception);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadOpsList()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.getOppedPlayers().readSavedFile();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LOGGER.warn("Failed to load operators list: ", (Throwable)exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveOpsList()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.getOppedPlayers().writeChanges();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LOGGER.warn("Failed to save operators list: ", (Throwable)exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void readWhiteList()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.getWhitelistedPlayers().readSavedFile();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LOGGER.warn("Failed to load white-list: ", (Throwable)exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveWhiteList()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.getWhitelistedPlayers().writeChanges();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LOGGER.warn("Failed to save white-list: ", (Throwable)exception);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canJoin(GameProfile profile)
|
||||
{
|
||||
return !this.isWhiteListEnabled() || this.canSendCommands(profile) || this.getWhitelistedPlayers().isWhitelisted(profile);
|
||||
}
|
||||
|
||||
public DedicatedServer getServerInstance()
|
||||
{
|
||||
return (DedicatedServer)super.getServerInstance();
|
||||
}
|
||||
|
||||
public boolean bypassesPlayerLimit(GameProfile profile)
|
||||
{
|
||||
return this.getOppedPlayers().bypassesPlayerLimit(profile);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,771 @@
|
||||
package net.minecraft.server.dedicated;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.authlib.GameProfileRepository;
|
||||
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
||||
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Proxy;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Pattern;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.crash.ICrashReportDetail;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.network.rcon.IServer;
|
||||
import net.minecraft.network.rcon.RConConsoleSource;
|
||||
import net.minecraft.network.rcon.RConThreadMain;
|
||||
import net.minecraft.network.rcon.RConThreadQuery;
|
||||
import net.minecraft.profiler.Snooper;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.ServerEula;
|
||||
import net.minecraft.server.gui.MinecraftServerGui;
|
||||
import net.minecraft.server.management.PlayerProfileCache;
|
||||
import net.minecraft.server.management.PreYggdrasilConverter;
|
||||
import net.minecraft.tileentity.TileEntitySkull;
|
||||
import net.minecraft.util.CryptManager;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.datafix.DataFixer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.EnumDifficulty;
|
||||
import net.minecraft.world.GameType;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldSettings;
|
||||
import net.minecraft.world.WorldType;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public class DedicatedServer extends MinecraftServer implements IServer
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Pattern RESOURCE_PACK_SHA1_PATTERN = Pattern.compile("^[a-fA-F0-9]{40}$");
|
||||
public final List<PendingCommand> pendingCommandList = Collections.<PendingCommand>synchronizedList(Lists.newArrayList());
|
||||
private RConThreadQuery rconQueryThread;
|
||||
private final RConConsoleSource rconConsoleSource = new RConConsoleSource(this);
|
||||
private RConThreadMain rconThread;
|
||||
private PropertyManager settings;
|
||||
private ServerEula eula;
|
||||
private boolean canSpawnStructures;
|
||||
private GameType gameType;
|
||||
private boolean guiIsEnabled;
|
||||
public static boolean allowPlayerLogins = false;
|
||||
|
||||
public DedicatedServer(File anvilFileIn, DataFixer dataFixerIn, YggdrasilAuthenticationService authServiceIn, MinecraftSessionService sessionServiceIn, GameProfileRepository profileRepoIn, PlayerProfileCache profileCacheIn)
|
||||
{
|
||||
super(anvilFileIn, Proxy.NO_PROXY, dataFixerIn, authServiceIn, sessionServiceIn, profileRepoIn, profileCacheIn);
|
||||
Thread thread = new Thread("Server Infinisleeper")
|
||||
{
|
||||
{
|
||||
this.setDaemon(true);
|
||||
this.start();
|
||||
}
|
||||
public void run()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(2147483647L);
|
||||
}
|
||||
catch (InterruptedException var2)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the server and starts it.
|
||||
*/
|
||||
public boolean init() throws IOException
|
||||
{
|
||||
Thread thread = new Thread("Server console handler")
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
if (net.minecraftforge.server.console.TerminalHandler.handleCommands(DedicatedServer.this)) return;
|
||||
BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
|
||||
String s4;
|
||||
|
||||
try
|
||||
{
|
||||
while (!DedicatedServer.this.isServerStopped() && DedicatedServer.this.isServerRunning() && (s4 = bufferedreader.readLine()) != null)
|
||||
{
|
||||
DedicatedServer.this.addPendingCommand(s4, DedicatedServer.this);
|
||||
}
|
||||
}
|
||||
catch (IOException ioexception1)
|
||||
{
|
||||
DedicatedServer.LOGGER.error("Exception handling console input", (Throwable)ioexception1);
|
||||
}
|
||||
}
|
||||
};
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
LOGGER.info("Starting minecraft server version 1.12.2");
|
||||
|
||||
if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L)
|
||||
{
|
||||
LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\"");
|
||||
}
|
||||
|
||||
net.minecraftforge.fml.common.FMLCommonHandler.instance().onServerStart(this);
|
||||
|
||||
LOGGER.info("Loading properties");
|
||||
this.settings = new PropertyManager(new File("server.properties"));
|
||||
this.eula = new ServerEula(new File("eula.txt"));
|
||||
|
||||
if (!this.eula.hasAcceptedEULA())
|
||||
{
|
||||
LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info.");
|
||||
this.eula.createEULAFile();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.isSinglePlayer())
|
||||
{
|
||||
this.setHostname("127.0.0.1");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setOnlineMode(this.settings.getBooleanProperty("online-mode", true));
|
||||
this.setPreventProxyConnections(this.settings.getBooleanProperty("prevent-proxy-connections", false));
|
||||
this.setHostname(this.settings.getStringProperty("server-ip", ""));
|
||||
}
|
||||
|
||||
this.setCanSpawnAnimals(this.settings.getBooleanProperty("spawn-animals", true));
|
||||
this.setCanSpawnNPCs(this.settings.getBooleanProperty("spawn-npcs", true));
|
||||
this.setAllowPvp(this.settings.getBooleanProperty("pvp", true));
|
||||
this.setAllowFlight(this.settings.getBooleanProperty("allow-flight", false));
|
||||
this.setResourcePack(this.settings.getStringProperty("resource-pack", ""), this.loadResourcePackSHA());
|
||||
this.setMOTD(this.settings.getStringProperty("motd", "A Minecraft Server"));
|
||||
this.setForceGamemode(this.settings.getBooleanProperty("force-gamemode", false));
|
||||
this.setPlayerIdleTimeout(this.settings.getIntProperty("player-idle-timeout", 0));
|
||||
|
||||
if (this.settings.getIntProperty("difficulty", 1) < 0)
|
||||
{
|
||||
this.settings.setProperty("difficulty", Integer.valueOf(0));
|
||||
}
|
||||
else if (this.settings.getIntProperty("difficulty", 1) > 3)
|
||||
{
|
||||
this.settings.setProperty("difficulty", Integer.valueOf(3));
|
||||
}
|
||||
|
||||
this.canSpawnStructures = this.settings.getBooleanProperty("generate-structures", true);
|
||||
int i = this.settings.getIntProperty("gamemode", GameType.SURVIVAL.getID());
|
||||
this.gameType = WorldSettings.getGameTypeById(i);
|
||||
LOGGER.info("Default game type: {}", (Object)this.gameType);
|
||||
InetAddress inetaddress = null;
|
||||
|
||||
if (!this.getServerHostname().isEmpty())
|
||||
{
|
||||
inetaddress = InetAddress.getByName(this.getServerHostname());
|
||||
}
|
||||
|
||||
if (this.getServerPort() < 0)
|
||||
{
|
||||
this.setServerPort(this.settings.getIntProperty("server-port", 25565));
|
||||
}
|
||||
|
||||
LOGGER.info("Generating keypair");
|
||||
this.setKeyPair(CryptManager.generateKeyPair());
|
||||
LOGGER.info("Starting Minecraft server on {}:{}", this.getServerHostname().isEmpty() ? "*" : this.getServerHostname(), Integer.valueOf(this.getServerPort()));
|
||||
|
||||
try
|
||||
{
|
||||
this.getNetworkSystem().addLanEndpoint(inetaddress, this.getServerPort());
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("**** FAILED TO BIND TO PORT!");
|
||||
LOGGER.warn("The exception was: {}", (Object)ioexception.toString());
|
||||
LOGGER.warn("Perhaps a server is already running on that port?");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.isServerInOnlineMode())
|
||||
{
|
||||
LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!");
|
||||
LOGGER.warn("The server will make no attempt to authenticate usernames. Beware.");
|
||||
LOGGER.warn("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose.");
|
||||
LOGGER.warn("To change this, set \"online-mode\" to \"true\" in the server.properties file.");
|
||||
}
|
||||
|
||||
if (this.convertFiles())
|
||||
{
|
||||
this.getPlayerProfileCache().save();
|
||||
}
|
||||
|
||||
if (!PreYggdrasilConverter.tryConvert(this.settings))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
net.minecraftforge.fml.common.FMLCommonHandler.instance().onServerStarted();
|
||||
this.setPlayerList(new DedicatedPlayerList(this));
|
||||
long j = System.nanoTime();
|
||||
|
||||
if (this.getFolderName() == null)
|
||||
{
|
||||
this.setFolderName(this.settings.getStringProperty("level-name", "world"));
|
||||
}
|
||||
|
||||
String s = this.settings.getStringProperty("level-seed", "");
|
||||
String s1 = this.settings.getStringProperty("level-type", "DEFAULT");
|
||||
String s2 = this.settings.getStringProperty("generator-settings", "");
|
||||
long k = (new Random()).nextLong();
|
||||
|
||||
if (!s.isEmpty())
|
||||
{
|
||||
try
|
||||
{
|
||||
long l = Long.parseLong(s);
|
||||
|
||||
if (l != 0L)
|
||||
{
|
||||
k = l;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException var16)
|
||||
{
|
||||
k = (long)s.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
WorldType worldtype = WorldType.parseWorldType(s1);
|
||||
|
||||
if (worldtype == null)
|
||||
{
|
||||
worldtype = WorldType.DEFAULT;
|
||||
}
|
||||
|
||||
this.isCommandBlockEnabled();
|
||||
this.getOpPermissionLevel();
|
||||
this.isSnooperEnabled();
|
||||
this.getNetworkCompressionThreshold();
|
||||
this.setBuildLimit(this.settings.getIntProperty("max-build-height", 256));
|
||||
this.setBuildLimit((this.getBuildLimit() + 8) / 16 * 16);
|
||||
this.setBuildLimit(MathHelper.clamp(this.getBuildLimit(), 64, 256));
|
||||
this.settings.setProperty("max-build-height", Integer.valueOf(this.getBuildLimit()));
|
||||
TileEntitySkull.setProfileCache(this.getPlayerProfileCache());
|
||||
TileEntitySkull.setSessionService(this.getMinecraftSessionService());
|
||||
PlayerProfileCache.setOnlineMode(this.isServerInOnlineMode());
|
||||
if (!net.minecraftforge.fml.common.FMLCommonHandler.instance().handleServerAboutToStart(this)) return false;
|
||||
LOGGER.info("Preparing level \"{}\"", (Object)this.getFolderName());
|
||||
this.loadAllWorlds(this.getFolderName(), this.getFolderName(), k, worldtype, s2);
|
||||
long i1 = System.nanoTime() - j;
|
||||
String s3 = String.format("%.3fs", (double)i1 / 1.0E9D);
|
||||
LOGGER.info("Done ({})! For help, type \"help\" or \"?\"", (Object)s3);
|
||||
|
||||
if (this.settings.hasProperty("announce-player-achievements"))
|
||||
{
|
||||
this.worlds[0].getGameRules().setOrCreateGameRule("announceAdvancements", this.settings.getBooleanProperty("announce-player-achievements", true) ? "true" : "false");
|
||||
this.settings.removeProperty("announce-player-achievements");
|
||||
this.settings.saveProperties();
|
||||
}
|
||||
|
||||
if (this.settings.getBooleanProperty("enable-query", false))
|
||||
{
|
||||
LOGGER.info("Starting GS4 status listener");
|
||||
this.rconQueryThread = new RConThreadQuery(this);
|
||||
this.rconQueryThread.startThread();
|
||||
}
|
||||
|
||||
if (this.settings.getBooleanProperty("enable-rcon", false))
|
||||
{
|
||||
LOGGER.info("Starting remote control listener");
|
||||
this.rconThread = new RConThreadMain(this);
|
||||
this.rconThread.startThread();
|
||||
}
|
||||
|
||||
if (this.getMaxTickTime() > 0L)
|
||||
{
|
||||
Thread thread1 = new Thread(new ServerHangWatchdog(this));
|
||||
thread1.setName("Server Watchdog");
|
||||
thread1.setDaemon(true);
|
||||
thread1.start();
|
||||
}
|
||||
|
||||
Items.AIR.getSubItems(CreativeTabs.SEARCH, NonNullList.create());
|
||||
// <3 you Grum for this, saves us ~30 patch files! --^
|
||||
return net.minecraftforge.fml.common.FMLCommonHandler.instance().handleServerStarting(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String loadResourcePackSHA()
|
||||
{
|
||||
if (this.settings.hasProperty("resource-pack-hash"))
|
||||
{
|
||||
if (this.settings.hasProperty("resource-pack-sha1"))
|
||||
{
|
||||
LOGGER.warn("resource-pack-hash is deprecated and found along side resource-pack-sha1. resource-pack-hash will be ignored.");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("resource-pack-hash is deprecated. Please use resource-pack-sha1 instead.");
|
||||
this.settings.getStringProperty("resource-pack-sha1", this.settings.getStringProperty("resource-pack-hash", ""));
|
||||
this.settings.removeProperty("resource-pack-hash");
|
||||
}
|
||||
}
|
||||
|
||||
String s = this.settings.getStringProperty("resource-pack-sha1", "");
|
||||
|
||||
if (!s.isEmpty() && !RESOURCE_PACK_SHA1_PATTERN.matcher(s).matches())
|
||||
{
|
||||
LOGGER.warn("Invalid sha1 for ressource-pack-sha1");
|
||||
}
|
||||
|
||||
if (!this.settings.getStringProperty("resource-pack", "").isEmpty() && s.isEmpty())
|
||||
{
|
||||
LOGGER.warn("You specified a resource pack without providing a sha1 hash. Pack will be updated on the client only if you change the name of the pack.");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the game type for all worlds.
|
||||
*/
|
||||
public void setGameType(GameType gameMode)
|
||||
{
|
||||
super.setGameType(gameMode);
|
||||
this.gameType = gameMode;
|
||||
}
|
||||
|
||||
public boolean canStructuresSpawn()
|
||||
{
|
||||
return this.canSpawnStructures;
|
||||
}
|
||||
|
||||
public GameType getGameType()
|
||||
{
|
||||
return this.gameType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the server's difficulty
|
||||
*/
|
||||
public EnumDifficulty getDifficulty()
|
||||
{
|
||||
return EnumDifficulty.getDifficultyEnum(this.settings.getIntProperty("difficulty", EnumDifficulty.NORMAL.getDifficultyId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defaults to false.
|
||||
*/
|
||||
public boolean isHardcore()
|
||||
{
|
||||
return this.settings.getBooleanProperty("hardcore", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the server info, including from theWorldServer, to the crash report.
|
||||
*/
|
||||
public CrashReport addServerInfoToCrashReport(CrashReport report)
|
||||
{
|
||||
report = super.addServerInfoToCrashReport(report);
|
||||
report.getCategory().addDetail("Is Modded", new ICrashReportDetail<String>()
|
||||
{
|
||||
public String call() throws Exception
|
||||
{
|
||||
String s = DedicatedServer.this.getServerModName();
|
||||
return !"vanilla".equals(s) ? "Definitely; Server brand changed to '" + s + "'" : "Unknown (can't tell)";
|
||||
}
|
||||
});
|
||||
report.getCategory().addDetail("Type", new ICrashReportDetail<String>()
|
||||
{
|
||||
public String call() throws Exception
|
||||
{
|
||||
return "Dedicated Server (map_server.txt)";
|
||||
}
|
||||
});
|
||||
return report;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly calls System.exit(0), instantly killing the program.
|
||||
*/
|
||||
public void systemExitNow()
|
||||
{
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public void updateTimeLightAndEntities()
|
||||
{
|
||||
super.updateTimeLightAndEntities();
|
||||
this.executePendingCommands();
|
||||
}
|
||||
|
||||
public boolean getAllowNether()
|
||||
{
|
||||
return this.settings.getBooleanProperty("allow-nether", true);
|
||||
}
|
||||
|
||||
public boolean allowSpawnMonsters()
|
||||
{
|
||||
return this.settings.getBooleanProperty("spawn-monsters", true);
|
||||
}
|
||||
|
||||
public void addServerStatsToSnooper(Snooper playerSnooper)
|
||||
{
|
||||
playerSnooper.addClientStat("whitelist_enabled", Boolean.valueOf(this.getPlayerList().isWhiteListEnabled()));
|
||||
playerSnooper.addClientStat("whitelist_count", Integer.valueOf(this.getPlayerList().getWhitelistedPlayerNames().length));
|
||||
super.addServerStatsToSnooper(playerSnooper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether snooping is enabled or not.
|
||||
*/
|
||||
public boolean isSnooperEnabled()
|
||||
{
|
||||
return this.settings.getBooleanProperty("snooper-enabled", true);
|
||||
}
|
||||
|
||||
public void addPendingCommand(String input, ICommandSender sender)
|
||||
{
|
||||
this.pendingCommandList.add(new PendingCommand(input, sender));
|
||||
}
|
||||
|
||||
public void executePendingCommands()
|
||||
{
|
||||
while (!this.pendingCommandList.isEmpty())
|
||||
{
|
||||
PendingCommand pendingcommand = this.pendingCommandList.remove(0);
|
||||
this.getCommandManager().executeCommand(pendingcommand.sender, pendingcommand.command);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDedicatedServer()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if native transport should be used. Native transport means linux server performance improvements and
|
||||
* optimized packet sending/receiving on linux
|
||||
*/
|
||||
public boolean shouldUseNativeTransport()
|
||||
{
|
||||
return this.settings.getBooleanProperty("use-native-transport", true);
|
||||
}
|
||||
|
||||
public DedicatedPlayerList getPlayerList()
|
||||
{
|
||||
return (DedicatedPlayerList)super.getPlayerList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an integer property. If it does not exist, set it to the specified value.
|
||||
*/
|
||||
public int getIntProperty(String key, int defaultValue)
|
||||
{
|
||||
return this.settings.getIntProperty(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string property. If it does not exist, set it to the specified value.
|
||||
*/
|
||||
public String getStringProperty(String key, String defaultValue)
|
||||
{
|
||||
return this.settings.getStringProperty(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a boolean property. If it does not exist, set it to the specified value.
|
||||
*/
|
||||
public boolean getBooleanProperty(String key, boolean defaultValue)
|
||||
{
|
||||
return this.settings.getBooleanProperty(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an Object with the given property name.
|
||||
*/
|
||||
public void setProperty(String key, Object value)
|
||||
{
|
||||
this.settings.setProperty(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves all of the server properties to the properties file.
|
||||
*/
|
||||
public void saveProperties()
|
||||
{
|
||||
this.settings.saveProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename where server properties are stored
|
||||
*/
|
||||
public String getSettingsFilename()
|
||||
{
|
||||
File file1 = this.settings.getPropertiesFile();
|
||||
return file1 != null ? file1.getAbsolutePath() : "No settings file";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server's hostname.
|
||||
*/
|
||||
public String getHostname()
|
||||
{
|
||||
return this.getServerHostname();
|
||||
}
|
||||
|
||||
/**
|
||||
* Never used, but "getServerPort" is already taken.
|
||||
*/
|
||||
public int getPort()
|
||||
{
|
||||
return this.getServerPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server message of the day
|
||||
*/
|
||||
public String getMotd()
|
||||
{
|
||||
return this.getMOTD();
|
||||
}
|
||||
|
||||
public void setGuiEnabled()
|
||||
{
|
||||
MinecraftServerGui.createServerGui(this);
|
||||
this.guiIsEnabled = true;
|
||||
}
|
||||
|
||||
public boolean getGuiEnabled()
|
||||
{
|
||||
return this.guiIsEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* On dedicated does nothing. On integrated, sets commandsAllowedForAll, gameType and allows external connections.
|
||||
*/
|
||||
public String shareToLAN(GameType type, boolean allowCheats)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether command blocks are enabled.
|
||||
*/
|
||||
public boolean isCommandBlockEnabled()
|
||||
{
|
||||
return this.settings.getBooleanProperty("enable-command-block", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the spawn protection area's size.
|
||||
*/
|
||||
public int getSpawnProtectionSize()
|
||||
{
|
||||
return this.settings.getIntProperty("spawn-protection", super.getSpawnProtectionSize());
|
||||
}
|
||||
|
||||
public boolean isBlockProtected(World worldIn, BlockPos pos, EntityPlayer playerIn)
|
||||
{
|
||||
if (worldIn.provider.getDimension() != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.getPlayerList().getOppedPlayers().isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.getPlayerList().canSendCommands(playerIn.getGameProfile()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (this.getSpawnProtectionSize() <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockPos blockpos = worldIn.getSpawnPoint();
|
||||
int i = MathHelper.abs(pos.getX() - blockpos.getX());
|
||||
int j = MathHelper.abs(pos.getZ() - blockpos.getZ());
|
||||
int k = Math.max(i, j);
|
||||
return k <= this.getSpawnProtectionSize();
|
||||
}
|
||||
}
|
||||
|
||||
public int getOpPermissionLevel()
|
||||
{
|
||||
return this.settings.getIntProperty("op-permission-level", 4);
|
||||
}
|
||||
|
||||
public void setPlayerIdleTimeout(int idleTimeout)
|
||||
{
|
||||
super.setPlayerIdleTimeout(idleTimeout);
|
||||
this.settings.setProperty("player-idle-timeout", Integer.valueOf(idleTimeout));
|
||||
this.saveProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if RCON command events should be broadcast to ops
|
||||
*/
|
||||
public boolean shouldBroadcastRconToOps()
|
||||
{
|
||||
return this.settings.getBooleanProperty("broadcast-rcon-to-ops", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if console command events should be broadcast to ops
|
||||
*/
|
||||
public boolean shouldBroadcastConsoleToOps()
|
||||
{
|
||||
return this.settings.getBooleanProperty("broadcast-console-to-ops", true);
|
||||
}
|
||||
|
||||
public int getMaxWorldSize()
|
||||
{
|
||||
int i = this.settings.getIntProperty("max-world-size", super.getMaxWorldSize());
|
||||
|
||||
if (i < 1)
|
||||
{
|
||||
i = 1;
|
||||
}
|
||||
else if (i > super.getMaxWorldSize())
|
||||
{
|
||||
i = super.getMaxWorldSize();
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* The compression treshold. If the packet is larger than the specified amount of bytes, it will be compressed
|
||||
*/
|
||||
public int getNetworkCompressionThreshold()
|
||||
{
|
||||
return this.settings.getIntProperty("network-compression-threshold", super.getNetworkCompressionThreshold());
|
||||
}
|
||||
|
||||
//Forge: Enable formated text for colors in console.
|
||||
@Override public void sendMessage(net.minecraft.util.text.ITextComponent message) { LOGGER.info(message.getFormattedText()); }
|
||||
|
||||
protected boolean convertFiles() throws IOException
|
||||
{
|
||||
boolean flag = false;
|
||||
|
||||
for (int i = 0; !flag && i <= 2; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
LOGGER.warn("Encountered a problem while converting the user banlist, retrying in a few seconds");
|
||||
this.sleepFiveSeconds();
|
||||
}
|
||||
|
||||
flag = PreYggdrasilConverter.convertUserBanlist(this);
|
||||
}
|
||||
|
||||
boolean flag1 = false;
|
||||
|
||||
for (int j = 0; !flag1 && j <= 2; ++j)
|
||||
{
|
||||
if (j > 0)
|
||||
{
|
||||
LOGGER.warn("Encountered a problem while converting the ip banlist, retrying in a few seconds");
|
||||
this.sleepFiveSeconds();
|
||||
}
|
||||
|
||||
flag1 = PreYggdrasilConverter.convertIpBanlist(this);
|
||||
}
|
||||
|
||||
boolean flag2 = false;
|
||||
|
||||
for (int k = 0; !flag2 && k <= 2; ++k)
|
||||
{
|
||||
if (k > 0)
|
||||
{
|
||||
LOGGER.warn("Encountered a problem while converting the op list, retrying in a few seconds");
|
||||
this.sleepFiveSeconds();
|
||||
}
|
||||
|
||||
flag2 = PreYggdrasilConverter.convertOplist(this);
|
||||
}
|
||||
|
||||
boolean flag3 = false;
|
||||
|
||||
for (int l = 0; !flag3 && l <= 2; ++l)
|
||||
{
|
||||
if (l > 0)
|
||||
{
|
||||
LOGGER.warn("Encountered a problem while converting the whitelist, retrying in a few seconds");
|
||||
this.sleepFiveSeconds();
|
||||
}
|
||||
|
||||
flag3 = PreYggdrasilConverter.convertWhitelist(this);
|
||||
}
|
||||
|
||||
boolean flag4 = false;
|
||||
|
||||
for (int i1 = 0; !flag4 && i1 <= 2; ++i1)
|
||||
{
|
||||
if (i1 > 0)
|
||||
{
|
||||
LOGGER.warn("Encountered a problem while converting the player save files, retrying in a few seconds");
|
||||
this.sleepFiveSeconds();
|
||||
}
|
||||
|
||||
flag4 = PreYggdrasilConverter.convertSaveFiles(this, this.settings);
|
||||
}
|
||||
|
||||
return flag || flag1 || flag2 || flag3 || flag4;
|
||||
}
|
||||
|
||||
private void sleepFiveSeconds()
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(5000L);
|
||||
}
|
||||
catch (InterruptedException var2)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public long getMaxTickTime()
|
||||
{
|
||||
return this.settings.getLongProperty("max-tick-time", TimeUnit.MINUTES.toMillis(1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by RCon's Query in the form of "MajorServerMod 1.2.3: MyPlugin 1.3; AnotherPlugin 2.1; AndSoForth 1.0".
|
||||
*/
|
||||
public String getPlugins()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a command received by an RCon instance
|
||||
*/
|
||||
public String handleRConCommand(String command)
|
||||
{
|
||||
this.rconConsoleSource.resetLog();
|
||||
this.commandManager.executeCommand(this.rconConsoleSource, command);
|
||||
return this.rconConsoleSource.getLogContents();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.minecraft.server.dedicated;
|
||||
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public class PendingCommand
|
||||
{
|
||||
/** The command string. */
|
||||
public final String command;
|
||||
public final ICommandSender sender;
|
||||
|
||||
public PendingCommand(String input, ICommandSender sender)
|
||||
{
|
||||
this.command = input;
|
||||
this.sender = sender;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package net.minecraft.server.dedicated;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public class PropertyManager
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
/** The server properties object. */
|
||||
private final Properties serverProperties = new Properties();
|
||||
/** The server properties file. */
|
||||
private final File serverPropertiesFile;
|
||||
|
||||
public PropertyManager(File propertiesFile)
|
||||
{
|
||||
this.serverPropertiesFile = propertiesFile;
|
||||
|
||||
if (propertiesFile.exists())
|
||||
{
|
||||
FileInputStream fileinputstream = null;
|
||||
|
||||
try
|
||||
{
|
||||
fileinputstream = new FileInputStream(propertiesFile);
|
||||
this.serverProperties.load(fileinputstream);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LOGGER.warn("Failed to load {}", propertiesFile, exception);
|
||||
this.generateNewProperties();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (fileinputstream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
fileinputstream.close();
|
||||
}
|
||||
catch (IOException var11)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("{} does not exist", (Object)propertiesFile);
|
||||
this.generateNewProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new properties file.
|
||||
*/
|
||||
public void generateNewProperties()
|
||||
{
|
||||
LOGGER.info("Generating new properties file");
|
||||
this.saveProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the properties to the properties file.
|
||||
*/
|
||||
public void saveProperties()
|
||||
{
|
||||
FileOutputStream fileoutputstream = null;
|
||||
|
||||
try
|
||||
{
|
||||
fileoutputstream = new FileOutputStream(this.serverPropertiesFile);
|
||||
this.serverProperties.store(fileoutputstream, "Minecraft server properties");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LOGGER.warn("Failed to save {}", this.serverPropertiesFile, exception);
|
||||
this.generateNewProperties();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (fileoutputstream != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
fileoutputstream.close();
|
||||
}
|
||||
catch (IOException var10)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this PropertyManager's file object used for property saving.
|
||||
*/
|
||||
public File getPropertiesFile()
|
||||
{
|
||||
return this.serverPropertiesFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string property. If the property doesn't exist the default is returned.
|
||||
*/
|
||||
public String getStringProperty(String key, String defaultValue)
|
||||
{
|
||||
if (!this.serverProperties.containsKey(key))
|
||||
{
|
||||
this.serverProperties.setProperty(key, defaultValue);
|
||||
this.saveProperties();
|
||||
this.saveProperties();
|
||||
}
|
||||
|
||||
return this.serverProperties.getProperty(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an integer property. If it does not exist, set it to the specified value.
|
||||
*/
|
||||
public int getIntProperty(String key, int defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Integer.parseInt(this.getStringProperty(key, "" + defaultValue));
|
||||
}
|
||||
catch (Exception var4)
|
||||
{
|
||||
this.serverProperties.setProperty(key, "" + defaultValue);
|
||||
this.saveProperties();
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public long getLongProperty(String key, long defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Long.parseLong(this.getStringProperty(key, "" + defaultValue));
|
||||
}
|
||||
catch (Exception var5)
|
||||
{
|
||||
this.serverProperties.setProperty(key, "" + defaultValue);
|
||||
this.saveProperties();
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a boolean property. If it does not exist, set it to the specified value.
|
||||
*/
|
||||
public boolean getBooleanProperty(String key, boolean defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Boolean.parseBoolean(this.getStringProperty(key, "" + defaultValue));
|
||||
}
|
||||
catch (Exception var4)
|
||||
{
|
||||
this.serverProperties.setProperty(key, "" + defaultValue);
|
||||
this.saveProperties();
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an Object with the given property name.
|
||||
*/
|
||||
public void setProperty(String key, Object value)
|
||||
{
|
||||
this.serverProperties.setProperty(key, "" + value);
|
||||
}
|
||||
|
||||
public boolean hasProperty(String key)
|
||||
{
|
||||
return this.serverProperties.containsKey(key);
|
||||
}
|
||||
|
||||
public void removeProperty(String key)
|
||||
{
|
||||
this.serverProperties.remove(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package net.minecraft.server.dedicated;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.ThreadInfo;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.crash.CrashReportCategory;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public class ServerHangWatchdog implements Runnable
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final DedicatedServer server;
|
||||
private final long maxTickTime;
|
||||
private boolean firstRun = true;
|
||||
|
||||
public ServerHangWatchdog(DedicatedServer server)
|
||||
{
|
||||
this.server = server;
|
||||
this.maxTickTime = server.getMaxTickTime();
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
while (this.server.isServerRunning())
|
||||
{
|
||||
long i = this.server.getCurrentTime();
|
||||
long j = MinecraftServer.getCurrentTimeMillis();
|
||||
long k = j - i;
|
||||
|
||||
if (k > this.maxTickTime && !this.firstRun)
|
||||
{
|
||||
LOGGER.fatal("A single server tick took {} seconds (should be max {})", String.format("%.2f", (float)k / 1000.0F), String.format("%.2f", 0.05F));
|
||||
LOGGER.fatal("Considering it to be crashed, server will forcibly shutdown.");
|
||||
ThreadMXBean threadmxbean = ManagementFactory.getThreadMXBean();
|
||||
ThreadInfo[] athreadinfo = threadmxbean.dumpAllThreads(true, true);
|
||||
StringBuilder stringbuilder = new StringBuilder();
|
||||
Error error = new Error(String.format("ServerHangWatchdog detected that a single server tick took %.2f seconds (should be max 0.05)", k / 1000F)); // Forge: don't just make a crash report with a seemingly-inexplicable Error
|
||||
|
||||
for (ThreadInfo threadinfo : athreadinfo)
|
||||
{
|
||||
if (threadinfo.getThreadId() == this.server.getServerThread().getId())
|
||||
{
|
||||
error.setStackTrace(threadinfo.getStackTrace());
|
||||
}
|
||||
|
||||
stringbuilder.append((Object)threadinfo);
|
||||
stringbuilder.append("\n");
|
||||
}
|
||||
|
||||
CrashReport crashreport = new CrashReport("Watching Server", error);
|
||||
this.server.addServerInfoToCrashReport(crashreport);
|
||||
CrashReportCategory crashreportcategory = crashreport.makeCategory("Thread Dump");
|
||||
crashreportcategory.addCrashSection("Threads", stringbuilder);
|
||||
File file1 = new File(new File(this.server.getDataDirectory(), "crash-reports"), "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-server.txt");
|
||||
|
||||
if (crashreport.saveToFile(file1))
|
||||
{
|
||||
LOGGER.error("This crash report has been saved to: {}", (Object)file1.getAbsolutePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.error("We were unable to save this crash report to disk.");
|
||||
}
|
||||
|
||||
this.scheduleHalt();
|
||||
}
|
||||
|
||||
this.firstRun = false;
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(i + this.maxTickTime - j);
|
||||
}
|
||||
catch (InterruptedException var15)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleHalt()
|
||||
{
|
||||
try
|
||||
{
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(new TimerTask()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
Runtime.getRuntime().halt(1);
|
||||
}
|
||||
}, 10000L);
|
||||
System.exit(1);
|
||||
}
|
||||
catch (Throwable var2)
|
||||
{
|
||||
Runtime.getRuntime().halt(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Auto generated package-info by MCP
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraft.server.dedicated;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -0,0 +1,217 @@
|
||||
package net.minecraft.server.gui;
|
||||
|
||||
import com.mojang.util.QueueLogAppender;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EtchedBorder;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import javax.swing.text.AttributeSet;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Document;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public class MinecraftServerGui extends JComponent
|
||||
{
|
||||
private static final Font SERVER_GUI_FONT = new Font("Monospaced", 0, 12);
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final DedicatedServer server;
|
||||
|
||||
/**
|
||||
* Creates the server GUI and sets it visible for the user.
|
||||
*/
|
||||
public static void createServerGui(final DedicatedServer serverIn)
|
||||
{
|
||||
try
|
||||
{
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
}
|
||||
catch (Exception var3)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
MinecraftServerGui minecraftservergui = new MinecraftServerGui(serverIn);
|
||||
JFrame jframe = new JFrame("Minecraft server");
|
||||
jframe.add(minecraftservergui);
|
||||
jframe.pack();
|
||||
jframe.setLocationRelativeTo((Component)null);
|
||||
jframe.setVisible(true);
|
||||
jframe.addWindowListener(new WindowAdapter()
|
||||
{
|
||||
public void windowClosing(WindowEvent p_windowClosing_1_)
|
||||
{
|
||||
serverIn.initiateShutdown();
|
||||
|
||||
while (!serverIn.isServerStopped())
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(100L);
|
||||
}
|
||||
catch (InterruptedException interruptedexception)
|
||||
{
|
||||
interruptedexception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
minecraftservergui.latch.countDown();
|
||||
}
|
||||
|
||||
public MinecraftServerGui(DedicatedServer serverIn)
|
||||
{
|
||||
this.server = serverIn;
|
||||
this.setPreferredSize(new Dimension(854, 480));
|
||||
this.setLayout(new BorderLayout());
|
||||
|
||||
try
|
||||
{
|
||||
this.add(this.getLogComponent(), "Center");
|
||||
this.add(this.getStatsComponent(), "West");
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LOGGER.error("Couldn't build server GUI", (Throwable)exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates new StatsComponent and returns it.
|
||||
*/
|
||||
private JComponent getStatsComponent() throws Exception
|
||||
{
|
||||
JPanel jpanel = new JPanel(new BorderLayout());
|
||||
jpanel.add(new StatsComponent(this.server), "North");
|
||||
jpanel.add(this.getPlayerListComponent(), "Center");
|
||||
jpanel.setBorder(new TitledBorder(new EtchedBorder(), "Stats"));
|
||||
return jpanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates new PlayerListComponent and returns it.
|
||||
*/
|
||||
private JComponent getPlayerListComponent() throws Exception
|
||||
{
|
||||
JList jlist = new PlayerListComponent(this.server);
|
||||
JScrollPane jscrollpane = new JScrollPane(jlist, 22, 30);
|
||||
jscrollpane.setBorder(new TitledBorder(new EtchedBorder(), "Players"));
|
||||
return jscrollpane;
|
||||
}
|
||||
|
||||
private JComponent getLogComponent() throws Exception
|
||||
{
|
||||
JPanel jpanel = new JPanel(new BorderLayout());
|
||||
final JTextArea jtextarea = new JTextArea();
|
||||
final JScrollPane jscrollpane = new JScrollPane(jtextarea, 22, 30);
|
||||
jtextarea.setEditable(false);
|
||||
jtextarea.setFont(SERVER_GUI_FONT);
|
||||
final JTextField jtextfield = new JTextField();
|
||||
jtextfield.addActionListener(new ActionListener()
|
||||
{
|
||||
public void actionPerformed(ActionEvent p_actionPerformed_1_)
|
||||
{
|
||||
String s = jtextfield.getText().trim();
|
||||
|
||||
if (!s.isEmpty())
|
||||
{
|
||||
MinecraftServerGui.this.server.addPendingCommand(s, MinecraftServerGui.this.server);
|
||||
}
|
||||
|
||||
jtextfield.setText("");
|
||||
}
|
||||
});
|
||||
jtextarea.addFocusListener(new FocusAdapter()
|
||||
{
|
||||
public void focusGained(FocusEvent p_focusGained_1_)
|
||||
{
|
||||
}
|
||||
});
|
||||
jpanel.add(jscrollpane, "Center");
|
||||
jpanel.add(jtextfield, "South");
|
||||
jpanel.setBorder(new TitledBorder(new EtchedBorder(), "Log and chat"));
|
||||
Thread thread = new Thread(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
String s;
|
||||
|
||||
while ((s = QueueLogAppender.getNextLogEvent("ServerGuiConsole")) != null)
|
||||
{
|
||||
MinecraftServerGui.this.appendLine(jtextarea, jscrollpane, s);
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
return jpanel;
|
||||
}
|
||||
|
||||
private java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(1);
|
||||
public void appendLine(final JTextArea textArea, final JScrollPane scrollPane, final String line)
|
||||
{
|
||||
try
|
||||
{
|
||||
latch.await();
|
||||
} catch (InterruptedException e){} //Prevent logging until after constructor has ended.
|
||||
if (!SwingUtilities.isEventDispatchThread())
|
||||
{
|
||||
SwingUtilities.invokeLater(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
MinecraftServerGui.this.appendLine(textArea, scrollPane, line);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Document document = textArea.getDocument();
|
||||
JScrollBar jscrollbar = scrollPane.getVerticalScrollBar();
|
||||
boolean flag = false;
|
||||
|
||||
if (scrollPane.getViewport().getView() == textArea)
|
||||
{
|
||||
flag = (double)jscrollbar.getValue() + jscrollbar.getSize().getHeight() + (double)(SERVER_GUI_FONT.getSize() * 4) > (double)jscrollbar.getMaximum();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
document.insertString(document.getLength(), line, (AttributeSet)null);
|
||||
}
|
||||
catch (BadLocationException var8)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
jscrollbar.setValue(Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package net.minecraft.server.gui;
|
||||
|
||||
import java.util.Vector;
|
||||
import javax.swing.JList;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public class PlayerListComponent extends JList implements ITickable
|
||||
{
|
||||
private final MinecraftServer server;
|
||||
private int ticks;
|
||||
|
||||
public PlayerListComponent(MinecraftServer server)
|
||||
{
|
||||
this.server = server;
|
||||
server.registerTickable(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
if (this.ticks++ % 20 == 0)
|
||||
{
|
||||
Vector<String> vector = new Vector<String>();
|
||||
|
||||
for (int i = 0; i < this.server.getPlayerList().getPlayers().size(); ++i)
|
||||
{
|
||||
vector.add(((EntityPlayerMP)this.server.getPlayerList().getPlayers().get(i)).getName());
|
||||
}
|
||||
|
||||
this.setListData(vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package net.minecraft.server.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.text.DecimalFormat;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.Timer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public class StatsComponent extends JComponent
|
||||
{
|
||||
private static final DecimalFormat FORMATTER = new DecimalFormat("########0.000");
|
||||
private final int[] values = new int[256];
|
||||
private int vp;
|
||||
private final String[] msgs = new String[11];
|
||||
private final MinecraftServer server;
|
||||
|
||||
public StatsComponent(MinecraftServer serverIn)
|
||||
{
|
||||
this.server = serverIn;
|
||||
this.setPreferredSize(new Dimension(456, 246));
|
||||
this.setMinimumSize(new Dimension(456, 246));
|
||||
this.setMaximumSize(new Dimension(456, 246));
|
||||
(new Timer(500, new ActionListener()
|
||||
{
|
||||
public void actionPerformed(ActionEvent p_actionPerformed_1_)
|
||||
{
|
||||
StatsComponent.this.tick();
|
||||
}
|
||||
})).start();
|
||||
this.setBackground(Color.BLACK);
|
||||
}
|
||||
|
||||
private void tick()
|
||||
{
|
||||
long i = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
|
||||
System.gc();
|
||||
this.msgs[0] = "Memory use: " + i / 1024L / 1024L + " mb (" + Runtime.getRuntime().freeMemory() * 100L / Runtime.getRuntime().maxMemory() + "% free)";
|
||||
this.msgs[1] = "Avg tick: " + FORMATTER.format(this.mean(this.server.tickTimeArray) * 1.0E-6D) + " ms";
|
||||
this.values[this.vp++ & 255] = (int)(i * 100L / Runtime.getRuntime().maxMemory());
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
private double mean(long[] values)
|
||||
{
|
||||
long i = 0L;
|
||||
|
||||
for (long j : values)
|
||||
{
|
||||
i += j;
|
||||
}
|
||||
|
||||
return (double)i / (double)values.length;
|
||||
}
|
||||
|
||||
public void paint(Graphics p_paint_1_)
|
||||
{
|
||||
p_paint_1_.setColor(new Color(16777215));
|
||||
p_paint_1_.fillRect(0, 0, 456, 246);
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
int j = this.values[i + this.vp & 255];
|
||||
p_paint_1_.setColor(new Color(j + 28 << 16));
|
||||
p_paint_1_.fillRect(i, 100 - j, 1, j);
|
||||
}
|
||||
|
||||
p_paint_1_.setColor(Color.BLACK);
|
||||
|
||||
for (int k = 0; k < this.msgs.length; ++k)
|
||||
{
|
||||
String s = this.msgs[k];
|
||||
|
||||
if (s != null)
|
||||
{
|
||||
p_paint_1_.drawString(s, 32, 116 + k * 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Auto generated package-info by MCP
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraft.server.gui;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -0,0 +1,56 @@
|
||||
package net.minecraft.server.integrated;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import java.net.SocketAddress;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.server.management.PlayerList;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class IntegratedPlayerList extends PlayerList
|
||||
{
|
||||
/** Holds the NBT data for the host player's save file, so this can be written to level.dat. */
|
||||
private NBTTagCompound hostPlayerData;
|
||||
|
||||
public IntegratedPlayerList(IntegratedServer server)
|
||||
{
|
||||
super(server);
|
||||
this.setViewDistance(10);
|
||||
}
|
||||
|
||||
/**
|
||||
* also stores the NBTTags if this is an intergratedPlayerList
|
||||
*/
|
||||
protected void writePlayerData(EntityPlayerMP playerIn)
|
||||
{
|
||||
if (playerIn.getName().equals(this.getServerInstance().getServerOwner()))
|
||||
{
|
||||
this.hostPlayerData = playerIn.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
super.writePlayerData(playerIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks ban-lists, then white-lists, then space for the server. Returns null on success, or an error message
|
||||
*/
|
||||
public String allowUserToConnect(SocketAddress address, GameProfile profile)
|
||||
{
|
||||
return profile.getName().equalsIgnoreCase(this.getServerInstance().getServerOwner()) && this.getPlayerByUsername(profile.getName()) != null ? "That name is already taken." : super.allowUserToConnect(address, profile);
|
||||
}
|
||||
|
||||
public IntegratedServer getServerInstance()
|
||||
{
|
||||
return (IntegratedServer)super.getServerInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* On integrated servers, returns the host's player data to be written to level.dat.
|
||||
*/
|
||||
public NBTTagCompound getHostPlayerData()
|
||||
{
|
||||
return this.hostPlayerData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
package net.minecraft.server.integrated;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.mojang.authlib.GameProfileRepository;
|
||||
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
||||
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import net.minecraft.client.ClientBrandRetriever;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ThreadLanServerPing;
|
||||
import net.minecraft.command.ServerCommandManager;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.crash.ICrashReportDetail;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.profiler.Snooper;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.management.PlayerProfileCache;
|
||||
import net.minecraft.util.CryptManager;
|
||||
import net.minecraft.util.HttpUtil;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.world.EnumDifficulty;
|
||||
import net.minecraft.world.GameType;
|
||||
import net.minecraft.world.ServerWorldEventHandler;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.WorldServerDemo;
|
||||
import net.minecraft.world.WorldServerMulti;
|
||||
import net.minecraft.world.WorldSettings;
|
||||
import net.minecraft.world.WorldType;
|
||||
import net.minecraft.world.storage.ISaveHandler;
|
||||
import net.minecraft.world.storage.WorldInfo;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class IntegratedServer extends MinecraftServer
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
/** The Minecraft instance. */
|
||||
private final Minecraft mc;
|
||||
private final WorldSettings worldSettings;
|
||||
private boolean isGamePaused;
|
||||
private boolean isPublic;
|
||||
private ThreadLanServerPing lanServerPing;
|
||||
|
||||
public IntegratedServer(Minecraft clientIn, String folderNameIn, String worldNameIn, WorldSettings worldSettingsIn, YggdrasilAuthenticationService authServiceIn, MinecraftSessionService sessionServiceIn, GameProfileRepository profileRepoIn, PlayerProfileCache profileCacheIn)
|
||||
{
|
||||
super(new File(clientIn.mcDataDir, "saves"), clientIn.getProxy(), clientIn.getDataFixer(), authServiceIn, sessionServiceIn, profileRepoIn, profileCacheIn);
|
||||
this.setServerOwner(clientIn.getSession().getUsername());
|
||||
this.setFolderName(folderNameIn);
|
||||
this.setWorldName(worldNameIn);
|
||||
this.setDemo(clientIn.isDemo());
|
||||
this.canCreateBonusChest(worldSettingsIn.isBonusChestEnabled());
|
||||
this.setBuildLimit(256);
|
||||
this.setPlayerList(new IntegratedPlayerList(this));
|
||||
this.mc = clientIn;
|
||||
this.worldSettings = this.isDemo() ? WorldServerDemo.DEMO_WORLD_SETTINGS : worldSettingsIn;
|
||||
}
|
||||
|
||||
public ServerCommandManager createCommandManager()
|
||||
{
|
||||
return new IntegratedServerCommandManager(this);
|
||||
}
|
||||
|
||||
public void loadAllWorlds(String saveName, String worldNameIn, long seed, WorldType type, String generatorOptions)
|
||||
{
|
||||
this.convertMapIfNeeded(saveName);
|
||||
ISaveHandler isavehandler = this.getActiveAnvilConverter().getSaveLoader(saveName, true);
|
||||
this.setResourcePackFromWorld(this.getFolderName(), isavehandler);
|
||||
WorldInfo worldinfo = isavehandler.loadWorldInfo();
|
||||
|
||||
if (worldinfo == null)
|
||||
{
|
||||
worldinfo = new WorldInfo(this.worldSettings, worldNameIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
worldinfo.setWorldName(worldNameIn);
|
||||
}
|
||||
|
||||
if (false) { //Forge: Dead Code, implement below.
|
||||
for (int i = 0; i < this.worlds.length; ++i)
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
if (i == 1)
|
||||
{
|
||||
j = -1;
|
||||
}
|
||||
|
||||
if (i == 2)
|
||||
{
|
||||
j = 1;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
if (this.isDemo())
|
||||
{
|
||||
this.worlds[i] = (WorldServer)(new WorldServerDemo(this, isavehandler, worldinfo, j, this.profiler)).init();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.worlds[i] = (WorldServer)(new WorldServer(this, isavehandler, worldinfo, j, this.profiler)).init();
|
||||
}
|
||||
|
||||
this.worlds[i].initialize(this.worldSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.worlds[i] = (WorldServer)(new WorldServerMulti(this, isavehandler, j, this.worlds[0], this.profiler)).init();
|
||||
}
|
||||
|
||||
this.worlds[i].addEventListener(new ServerWorldEventHandler(this, this.worlds[i]));
|
||||
}
|
||||
}// Forge: End Dead Code
|
||||
|
||||
WorldServer overWorld = (isDemo() ? (WorldServer)(new WorldServerDemo(this, isavehandler, worldinfo, 0, this.profiler)).init() :
|
||||
(WorldServer)(new WorldServer(this, isavehandler, worldinfo, 0, this.profiler)).init());
|
||||
overWorld.initialize(this.worldSettings);
|
||||
for (int dim : net.minecraftforge.common.DimensionManager.getStaticDimensionIDs())
|
||||
{
|
||||
WorldServer world = (dim == 0 ? overWorld : (WorldServer)(new WorldServerMulti(this, isavehandler, dim, overWorld, this.profiler)).init());
|
||||
world.addEventListener(new ServerWorldEventHandler(this, world));
|
||||
if (!this.isSinglePlayer())
|
||||
{
|
||||
world.getWorldInfo().setGameType(getGameType());
|
||||
}
|
||||
net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.WorldEvent.Load(world));
|
||||
}
|
||||
|
||||
this.getPlayerList().setPlayerManager(new WorldServer[]{ overWorld });
|
||||
|
||||
if (overWorld.getWorldInfo().getDifficulty() == null)
|
||||
{
|
||||
this.setDifficultyForAllWorlds(this.mc.gameSettings.difficulty);
|
||||
}
|
||||
|
||||
this.initialWorldChunkLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the server and starts it.
|
||||
*/
|
||||
public boolean init() throws IOException
|
||||
{
|
||||
LOGGER.info("Starting integrated minecraft server version 1.12.2");
|
||||
this.setOnlineMode(true);
|
||||
this.setCanSpawnAnimals(true);
|
||||
this.setCanSpawnNPCs(true);
|
||||
this.setAllowPvp(true);
|
||||
this.setAllowFlight(true);
|
||||
LOGGER.info("Generating keypair");
|
||||
this.setKeyPair(CryptManager.generateKeyPair());
|
||||
if (!net.minecraftforge.fml.common.FMLCommonHandler.instance().handleServerAboutToStart(this)) return false;
|
||||
this.loadAllWorlds(this.getFolderName(), this.getWorldName(), this.worldSettings.getSeed(), this.worldSettings.getTerrainType(), this.worldSettings.getGeneratorOptions());
|
||||
this.setMOTD(this.getServerOwner() + " - " + this.worlds[0].getWorldInfo().getWorldName());
|
||||
return net.minecraftforge.fml.common.FMLCommonHandler.instance().handleServerStarting(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function called by run() every loop.
|
||||
*/
|
||||
public void tick()
|
||||
{
|
||||
boolean flag = this.isGamePaused;
|
||||
this.isGamePaused = Minecraft.getMinecraft().getConnection() != null && Minecraft.getMinecraft().isGamePaused();
|
||||
|
||||
if (!flag && this.isGamePaused)
|
||||
{
|
||||
LOGGER.info("Saving and pausing game...");
|
||||
this.getPlayerList().saveAllPlayerData();
|
||||
this.saveAllWorlds(false);
|
||||
}
|
||||
|
||||
if (this.isGamePaused)
|
||||
{
|
||||
synchronized (this.futureTaskQueue)
|
||||
{
|
||||
while (!this.futureTaskQueue.isEmpty())
|
||||
{
|
||||
Util.runTask(this.futureTaskQueue.poll(), LOGGER);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
super.tick();
|
||||
|
||||
if (this.mc.gameSettings.renderDistanceChunks != this.getPlayerList().getViewDistance())
|
||||
{
|
||||
LOGGER.info("Changing view distance to {}, from {}", Integer.valueOf(this.mc.gameSettings.renderDistanceChunks), Integer.valueOf(this.getPlayerList().getViewDistance()));
|
||||
this.getPlayerList().setViewDistance(this.mc.gameSettings.renderDistanceChunks);
|
||||
}
|
||||
|
||||
if (this.mc.world != null)
|
||||
{
|
||||
WorldInfo worldinfo1 = this.worlds[0].getWorldInfo();
|
||||
WorldInfo worldinfo = this.mc.world.getWorldInfo();
|
||||
|
||||
if (!worldinfo1.isDifficultyLocked() && worldinfo.getDifficulty() != worldinfo1.getDifficulty())
|
||||
{
|
||||
LOGGER.info("Changing difficulty to {}, from {}", worldinfo.getDifficulty(), worldinfo1.getDifficulty());
|
||||
this.setDifficultyForAllWorlds(worldinfo.getDifficulty());
|
||||
}
|
||||
else if (worldinfo.isDifficultyLocked() && !worldinfo1.isDifficultyLocked())
|
||||
{
|
||||
LOGGER.info("Locking difficulty to {}", (Object)worldinfo.getDifficulty());
|
||||
|
||||
for (WorldServer worldserver : this.worlds)
|
||||
{
|
||||
if (worldserver != null)
|
||||
{
|
||||
worldserver.getWorldInfo().setDifficultyLocked(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canStructuresSpawn()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public GameType getGameType()
|
||||
{
|
||||
return this.worldSettings.getGameType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the server's difficulty
|
||||
*/
|
||||
public EnumDifficulty getDifficulty()
|
||||
{
|
||||
if (this.mc.world == null) return this.mc.gameSettings.difficulty; // Fix NPE just in case.
|
||||
return this.mc.world.getWorldInfo().getDifficulty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defaults to false.
|
||||
*/
|
||||
public boolean isHardcore()
|
||||
{
|
||||
return this.worldSettings.getHardcoreEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if RCON command events should be broadcast to ops
|
||||
*/
|
||||
public boolean shouldBroadcastRconToOps()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if console command events should be broadcast to ops
|
||||
*/
|
||||
public boolean shouldBroadcastConsoleToOps()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* par1 indicates if a log message should be output.
|
||||
*/
|
||||
public void saveAllWorlds(boolean isSilent)
|
||||
{
|
||||
super.saveAllWorlds(isSilent);
|
||||
}
|
||||
|
||||
public File getDataDirectory()
|
||||
{
|
||||
return this.mc.mcDataDir;
|
||||
}
|
||||
|
||||
public boolean isDedicatedServer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if native transport should be used. Native transport means linux server performance improvements and
|
||||
* optimized packet sending/receiving on linux
|
||||
*/
|
||||
public boolean shouldUseNativeTransport()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on exit from the main run() loop.
|
||||
*/
|
||||
public void finalTick(CrashReport report)
|
||||
{
|
||||
this.mc.crashed(report);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the server info, including from theWorldServer, to the crash report.
|
||||
*/
|
||||
public CrashReport addServerInfoToCrashReport(CrashReport report)
|
||||
{
|
||||
report = super.addServerInfoToCrashReport(report);
|
||||
report.getCategory().addDetail("Type", new ICrashReportDetail<String>()
|
||||
{
|
||||
public String call() throws Exception
|
||||
{
|
||||
return "Integrated Server (map_client.txt)";
|
||||
}
|
||||
});
|
||||
report.getCategory().addDetail("Is Modded", new ICrashReportDetail<String>()
|
||||
{
|
||||
public String call() throws Exception
|
||||
{
|
||||
String s = ClientBrandRetriever.getClientModName();
|
||||
|
||||
if (!s.equals("vanilla"))
|
||||
{
|
||||
return "Definitely; Client brand changed to '" + s + "'";
|
||||
}
|
||||
else
|
||||
{
|
||||
s = IntegratedServer.this.getServerModName();
|
||||
|
||||
if (!"vanilla".equals(s))
|
||||
{
|
||||
return "Definitely; Server brand changed to '" + s + "'";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Minecraft.class.getSigners() == null ? "Very likely; Jar signature invalidated" : "Probably not. Jar signature remains and both client + server brands are untouched.";
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return report;
|
||||
}
|
||||
|
||||
public void setDifficultyForAllWorlds(EnumDifficulty difficulty)
|
||||
{
|
||||
super.setDifficultyForAllWorlds(difficulty);
|
||||
|
||||
if (this.mc.world != null)
|
||||
{
|
||||
this.mc.world.getWorldInfo().setDifficulty(difficulty);
|
||||
}
|
||||
}
|
||||
|
||||
public void addServerStatsToSnooper(Snooper playerSnooper)
|
||||
{
|
||||
super.addServerStatsToSnooper(playerSnooper);
|
||||
playerSnooper.addClientStat("snooper_partner", this.mc.getPlayerUsageSnooper().getUniqueID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether snooping is enabled or not.
|
||||
*/
|
||||
public boolean isSnooperEnabled()
|
||||
{
|
||||
return Minecraft.getMinecraft().isSnooperEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* On dedicated does nothing. On integrated, sets commandsAllowedForAll, gameType and allows external connections.
|
||||
*/
|
||||
public String shareToLAN(GameType type, boolean allowCheats)
|
||||
{
|
||||
try
|
||||
{
|
||||
int i = -1;
|
||||
|
||||
try
|
||||
{
|
||||
i = HttpUtil.getSuitableLanPort();
|
||||
}
|
||||
catch (IOException var5)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
if (i <= 0)
|
||||
{
|
||||
i = 25564;
|
||||
}
|
||||
|
||||
this.getNetworkSystem().addLanEndpoint((InetAddress)null, i);
|
||||
LOGGER.info("Started on {}", (int)i);
|
||||
this.isPublic = true;
|
||||
this.lanServerPing = new ThreadLanServerPing(this.getMOTD(), i + "");
|
||||
this.lanServerPing.start();
|
||||
this.getPlayerList().setGameType(type);
|
||||
this.getPlayerList().setCommandsAllowedForAll(allowCheats);
|
||||
this.mc.player.setPermissionLevel(allowCheats ? 4 : 0);
|
||||
return i + "";
|
||||
}
|
||||
catch (IOException var6)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves all necessary data as preparation for stopping the server.
|
||||
*/
|
||||
public void stopServer()
|
||||
{
|
||||
super.stopServer();
|
||||
|
||||
if (this.lanServerPing != null)
|
||||
{
|
||||
this.lanServerPing.interrupt();
|
||||
this.lanServerPing = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serverRunning variable to false, in order to get the server to shut down.
|
||||
*/
|
||||
public void initiateShutdown()
|
||||
{
|
||||
if (isServerRunning())
|
||||
Futures.getUnchecked(this.addScheduledTask(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
for (EntityPlayerMP entityplayermp : Lists.newArrayList(IntegratedServer.this.getPlayerList().getPlayers()))
|
||||
{
|
||||
if (!entityplayermp.getUniqueID().equals(IntegratedServer.this.mc.player.getUniqueID()))
|
||||
{
|
||||
IntegratedServer.this.getPlayerList().playerLoggedOut(entityplayermp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
super.initiateShutdown();
|
||||
|
||||
if (this.lanServerPing != null)
|
||||
{
|
||||
this.lanServerPing.interrupt();
|
||||
this.lanServerPing = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this integrated server is open to LAN
|
||||
*/
|
||||
public boolean getPublic()
|
||||
{
|
||||
return this.isPublic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the game type for all worlds.
|
||||
*/
|
||||
public void setGameType(GameType gameMode)
|
||||
{
|
||||
super.setGameType(gameMode);
|
||||
this.getPlayerList().setGameType(gameMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether command blocks are enabled.
|
||||
*/
|
||||
public boolean isCommandBlockEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getOpPermissionLevel()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.minecraft.server.integrated;
|
||||
|
||||
import net.minecraft.command.ServerCommandManager;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class IntegratedServerCommandManager extends ServerCommandManager
|
||||
{
|
||||
public IntegratedServerCommandManager(IntegratedServer server)
|
||||
{
|
||||
super(server);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Auto generated package-info by MCP
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraft.server.integrated;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -0,0 +1,142 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.play.server.SPacketChangeGameState;
|
||||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class DemoPlayerInteractionManager extends PlayerInteractionManager
|
||||
{
|
||||
private boolean displayedIntro;
|
||||
private boolean demoTimeExpired;
|
||||
private int demoEndedReminder;
|
||||
private int gameModeTicks;
|
||||
|
||||
public DemoPlayerInteractionManager(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
public void updateBlockRemoving()
|
||||
{
|
||||
super.updateBlockRemoving();
|
||||
++this.gameModeTicks;
|
||||
long i = this.world.getTotalWorldTime();
|
||||
long j = i / 24000L + 1L;
|
||||
|
||||
if (!this.displayedIntro && this.gameModeTicks > 20)
|
||||
{
|
||||
this.displayedIntro = true;
|
||||
this.player.connection.sendPacket(new SPacketChangeGameState(5, 0.0F));
|
||||
}
|
||||
|
||||
this.demoTimeExpired = i > 120500L;
|
||||
|
||||
if (this.demoTimeExpired)
|
||||
{
|
||||
++this.demoEndedReminder;
|
||||
}
|
||||
|
||||
if (i % 24000L == 500L)
|
||||
{
|
||||
if (j <= 6L)
|
||||
{
|
||||
this.player.sendMessage(new TextComponentTranslation("demo.day." + j, new Object[0]));
|
||||
}
|
||||
}
|
||||
else if (j == 1L)
|
||||
{
|
||||
if (i == 100L)
|
||||
{
|
||||
this.player.connection.sendPacket(new SPacketChangeGameState(5, 101.0F));
|
||||
}
|
||||
else if (i == 175L)
|
||||
{
|
||||
this.player.connection.sendPacket(new SPacketChangeGameState(5, 102.0F));
|
||||
}
|
||||
else if (i == 250L)
|
||||
{
|
||||
this.player.connection.sendPacket(new SPacketChangeGameState(5, 103.0F));
|
||||
}
|
||||
}
|
||||
else if (j == 5L && i % 24000L == 22000L)
|
||||
{
|
||||
this.player.sendMessage(new TextComponentTranslation("demo.day.warning", new Object[0]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the player reminding them that this is the demo version
|
||||
*/
|
||||
private void sendDemoReminder()
|
||||
{
|
||||
if (this.demoEndedReminder > 100)
|
||||
{
|
||||
this.player.sendMessage(new TextComponentTranslation("demo.reminder", new Object[0]));
|
||||
this.demoEndedReminder = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If not creative, it calls sendBlockBreakProgress until the block is broken first. tryHarvestBlock can also be the
|
||||
* result of this call.
|
||||
*/
|
||||
public void onBlockClicked(BlockPos pos, EnumFacing side)
|
||||
{
|
||||
if (this.demoTimeExpired)
|
||||
{
|
||||
this.sendDemoReminder();
|
||||
}
|
||||
else
|
||||
{
|
||||
super.onBlockClicked(pos, side);
|
||||
}
|
||||
}
|
||||
|
||||
public void blockRemoving(BlockPos pos)
|
||||
{
|
||||
if (!this.demoTimeExpired)
|
||||
{
|
||||
super.blockRemoving(pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to harvest a block
|
||||
*/
|
||||
public boolean tryHarvestBlock(BlockPos pos)
|
||||
{
|
||||
return this.demoTimeExpired ? false : super.tryHarvestBlock(pos);
|
||||
}
|
||||
|
||||
public EnumActionResult processRightClick(EntityPlayer player, World worldIn, ItemStack stack, EnumHand hand)
|
||||
{
|
||||
if (this.demoTimeExpired)
|
||||
{
|
||||
this.sendDemoReminder();
|
||||
return EnumActionResult.PASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.processRightClick(player, worldIn, stack, hand);
|
||||
}
|
||||
}
|
||||
|
||||
public EnumActionResult processRightClickBlock(EntityPlayer player, World worldIn, ItemStack stack, EnumHand hand, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ)
|
||||
{
|
||||
if (this.demoTimeExpired)
|
||||
{
|
||||
this.sendDemoReminder();
|
||||
return EnumActionResult.PASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return super.processRightClickBlock(player, worldIn, stack, hand, pos, facing, hitX, hitY, hitZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,498 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.WorldProvider;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
public class PlayerChunkMap
|
||||
{
|
||||
private static final Predicate<EntityPlayerMP> NOT_SPECTATOR = new Predicate<EntityPlayerMP>()
|
||||
{
|
||||
public boolean apply(@Nullable EntityPlayerMP p_apply_1_)
|
||||
{
|
||||
return p_apply_1_ != null && !p_apply_1_.isSpectator();
|
||||
}
|
||||
};
|
||||
private static final Predicate<EntityPlayerMP> CAN_GENERATE_CHUNKS = new Predicate<EntityPlayerMP>()
|
||||
{
|
||||
public boolean apply(@Nullable EntityPlayerMP p_apply_1_)
|
||||
{
|
||||
return p_apply_1_ != null && (!p_apply_1_.isSpectator() || p_apply_1_.getServerWorld().getGameRules().getBoolean("spectatorsGenerateChunks"));
|
||||
}
|
||||
};
|
||||
private final WorldServer world;
|
||||
/** players in the current instance */
|
||||
private final List<EntityPlayerMP> players = Lists.<EntityPlayerMP>newArrayList();
|
||||
/** the hash of all playerInstances created */
|
||||
private final Long2ObjectMap<PlayerChunkMapEntry> entryMap = new Long2ObjectOpenHashMap<PlayerChunkMapEntry>(4096);
|
||||
/** the playerInstances(chunks) that need to be updated */
|
||||
private final Set<PlayerChunkMapEntry> dirtyEntries = Sets.<PlayerChunkMapEntry>newHashSet();
|
||||
private final List<PlayerChunkMapEntry> pendingSendToPlayers = Lists.<PlayerChunkMapEntry>newLinkedList();
|
||||
/** List of player instances whose chunk field is unassigned, and need the chunk at their pos to be loaded. */
|
||||
private final List<PlayerChunkMapEntry> entriesWithoutChunks = Lists.<PlayerChunkMapEntry>newLinkedList();
|
||||
/** This field is using when chunk should be processed (every 8000 ticks) */
|
||||
private final List<PlayerChunkMapEntry> entries = Lists.<PlayerChunkMapEntry>newArrayList();
|
||||
/** Number of chunks the server sends to the client. Valid 3<=x<=15. In server.properties. */
|
||||
private int playerViewRadius;
|
||||
/** time what is using to check if InhabitedTime should be calculated */
|
||||
private long previousTotalWorldTime;
|
||||
private boolean sortMissingChunks = true;
|
||||
private boolean sortSendToPlayers = true;
|
||||
|
||||
public PlayerChunkMap(WorldServer serverWorld)
|
||||
{
|
||||
this.world = serverWorld;
|
||||
this.setPlayerViewRadius(serverWorld.getMinecraftServer().getPlayerList().getViewDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the WorldServer associated with this PlayerManager
|
||||
*/
|
||||
public WorldServer getWorldServer()
|
||||
{
|
||||
return this.world;
|
||||
}
|
||||
|
||||
public Iterator<Chunk> getChunkIterator()
|
||||
{
|
||||
final Iterator<PlayerChunkMapEntry> iterator = this.entries.iterator();
|
||||
return new AbstractIterator<Chunk>()
|
||||
{
|
||||
protected Chunk computeNext()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (iterator.hasNext())
|
||||
{
|
||||
PlayerChunkMapEntry playerchunkmapentry = iterator.next();
|
||||
Chunk chunk = playerchunkmapentry.getChunk();
|
||||
|
||||
if (chunk == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!chunk.isLightPopulated() && chunk.isTerrainPopulated())
|
||||
{
|
||||
return chunk;
|
||||
}
|
||||
|
||||
if (!chunk.wasTicked())
|
||||
{
|
||||
return chunk;
|
||||
}
|
||||
|
||||
if (!playerchunkmapentry.hasPlayerMatchingInRange(128.0D, PlayerChunkMap.NOT_SPECTATOR))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
return (Chunk)this.endOfData();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* updates all the player instances that need to be updated
|
||||
*/
|
||||
public void tick()
|
||||
{
|
||||
long i = this.world.getTotalWorldTime();
|
||||
|
||||
if (i - this.previousTotalWorldTime > 8000L)
|
||||
{
|
||||
this.previousTotalWorldTime = i;
|
||||
|
||||
for (int j = 0; j < this.entries.size(); ++j)
|
||||
{
|
||||
PlayerChunkMapEntry playerchunkmapentry = this.entries.get(j);
|
||||
playerchunkmapentry.update();
|
||||
playerchunkmapentry.updateChunkInhabitedTime();
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.dirtyEntries.isEmpty())
|
||||
{
|
||||
for (PlayerChunkMapEntry playerchunkmapentry2 : this.dirtyEntries)
|
||||
{
|
||||
playerchunkmapentry2.update();
|
||||
}
|
||||
|
||||
this.dirtyEntries.clear();
|
||||
}
|
||||
|
||||
if (this.sortMissingChunks && i % 4L == 0L)
|
||||
{
|
||||
this.sortMissingChunks = false;
|
||||
Collections.sort(this.entriesWithoutChunks, new Comparator<PlayerChunkMapEntry>()
|
||||
{
|
||||
public int compare(PlayerChunkMapEntry p_compare_1_, PlayerChunkMapEntry p_compare_2_)
|
||||
{
|
||||
return ComparisonChain.start().compare(p_compare_1_.getClosestPlayerDistance(), p_compare_2_.getClosestPlayerDistance()).result();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this.sortSendToPlayers && i % 4L == 2L)
|
||||
{
|
||||
this.sortSendToPlayers = false;
|
||||
Collections.sort(this.pendingSendToPlayers, new Comparator<PlayerChunkMapEntry>()
|
||||
{
|
||||
public int compare(PlayerChunkMapEntry p_compare_1_, PlayerChunkMapEntry p_compare_2_)
|
||||
{
|
||||
return ComparisonChain.start().compare(p_compare_1_.getClosestPlayerDistance(), p_compare_2_.getClosestPlayerDistance()).result();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.entriesWithoutChunks.isEmpty())
|
||||
{
|
||||
long l = System.nanoTime() + 50000000L;
|
||||
int k = 49;
|
||||
Iterator<PlayerChunkMapEntry> iterator = this.entriesWithoutChunks.iterator();
|
||||
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
PlayerChunkMapEntry playerchunkmapentry1 = iterator.next();
|
||||
|
||||
if (playerchunkmapentry1.getChunk() == null)
|
||||
{
|
||||
boolean flag = playerchunkmapentry1.hasPlayerMatching(CAN_GENERATE_CHUNKS);
|
||||
|
||||
if (playerchunkmapentry1.providePlayerChunk(flag))
|
||||
{
|
||||
iterator.remove();
|
||||
|
||||
if (playerchunkmapentry1.sendToPlayers())
|
||||
{
|
||||
this.pendingSendToPlayers.remove(playerchunkmapentry1);
|
||||
}
|
||||
|
||||
--k;
|
||||
|
||||
if (k < 0 || System.nanoTime() > l)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.pendingSendToPlayers.isEmpty())
|
||||
{
|
||||
int i1 = 81;
|
||||
Iterator<PlayerChunkMapEntry> iterator1 = this.pendingSendToPlayers.iterator();
|
||||
|
||||
while (iterator1.hasNext())
|
||||
{
|
||||
PlayerChunkMapEntry playerchunkmapentry3 = iterator1.next();
|
||||
|
||||
if (playerchunkmapentry3.sendToPlayers())
|
||||
{
|
||||
iterator1.remove();
|
||||
--i1;
|
||||
|
||||
if (i1 < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.players.isEmpty())
|
||||
{
|
||||
WorldProvider worldprovider = this.world.provider;
|
||||
|
||||
if (!worldprovider.canRespawnHere())
|
||||
{
|
||||
this.world.getChunkProvider().queueUnloadAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(int chunkX, int chunkZ)
|
||||
{
|
||||
long i = getIndex(chunkX, chunkZ);
|
||||
return this.entryMap.get(i) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PlayerChunkMapEntry getEntry(int x, int z)
|
||||
{
|
||||
return (PlayerChunkMapEntry)this.entryMap.get(getIndex(x, z));
|
||||
}
|
||||
|
||||
private PlayerChunkMapEntry getOrCreateEntry(int chunkX, int chunkZ)
|
||||
{
|
||||
long i = getIndex(chunkX, chunkZ);
|
||||
PlayerChunkMapEntry playerchunkmapentry = (PlayerChunkMapEntry)this.entryMap.get(i);
|
||||
|
||||
if (playerchunkmapentry == null)
|
||||
{
|
||||
playerchunkmapentry = new PlayerChunkMapEntry(this, chunkX, chunkZ);
|
||||
this.entryMap.put(i, playerchunkmapentry);
|
||||
this.entries.add(playerchunkmapentry);
|
||||
|
||||
if (playerchunkmapentry.getChunk() == null)
|
||||
{
|
||||
this.entriesWithoutChunks.add(playerchunkmapentry);
|
||||
}
|
||||
|
||||
if (!playerchunkmapentry.sendToPlayers())
|
||||
{
|
||||
this.pendingSendToPlayers.add(playerchunkmapentry);
|
||||
}
|
||||
}
|
||||
|
||||
return playerchunkmapentry;
|
||||
}
|
||||
|
||||
public void markBlockForUpdate(BlockPos pos)
|
||||
{
|
||||
int i = pos.getX() >> 4;
|
||||
int j = pos.getZ() >> 4;
|
||||
PlayerChunkMapEntry playerchunkmapentry = this.getEntry(i, j);
|
||||
|
||||
if (playerchunkmapentry != null)
|
||||
{
|
||||
playerchunkmapentry.blockChanged(pos.getX() & 15, pos.getY(), pos.getZ() & 15);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an EntityPlayerMP to the PlayerManager and to all player instances within player visibility
|
||||
*/
|
||||
public void addPlayer(EntityPlayerMP player)
|
||||
{
|
||||
int i = (int)player.posX >> 4;
|
||||
int j = (int)player.posZ >> 4;
|
||||
player.managedPosX = player.posX;
|
||||
player.managedPosZ = player.posZ;
|
||||
|
||||
for (int k = i - this.playerViewRadius; k <= i + this.playerViewRadius; ++k)
|
||||
{
|
||||
for (int l = j - this.playerViewRadius; l <= j + this.playerViewRadius; ++l)
|
||||
{
|
||||
this.getOrCreateEntry(k, l).addPlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
this.players.add(player);
|
||||
this.markSortPending();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an EntityPlayerMP from the PlayerManager.
|
||||
*/
|
||||
public void removePlayer(EntityPlayerMP player)
|
||||
{
|
||||
int i = (int)player.managedPosX >> 4;
|
||||
int j = (int)player.managedPosZ >> 4;
|
||||
|
||||
for (int k = i - this.playerViewRadius; k <= i + this.playerViewRadius; ++k)
|
||||
{
|
||||
for (int l = j - this.playerViewRadius; l <= j + this.playerViewRadius; ++l)
|
||||
{
|
||||
PlayerChunkMapEntry playerchunkmapentry = this.getEntry(k, l);
|
||||
|
||||
if (playerchunkmapentry != null)
|
||||
{
|
||||
playerchunkmapentry.removePlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.players.remove(player);
|
||||
this.markSortPending();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if two rectangles centered at the given points overlap for the provided radius. Arguments: x1, z1, x2,
|
||||
* z2, radius.
|
||||
*/
|
||||
private boolean overlaps(int x1, int z1, int x2, int z2, int radius)
|
||||
{
|
||||
int i = x1 - x2;
|
||||
int j = z1 - z2;
|
||||
|
||||
if (i >= -radius && i <= radius)
|
||||
{
|
||||
return j >= -radius && j <= radius;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update chunks around a player that moved
|
||||
*/
|
||||
public void updateMovingPlayer(EntityPlayerMP player)
|
||||
{
|
||||
int i = (int)player.posX >> 4;
|
||||
int j = (int)player.posZ >> 4;
|
||||
double d0 = player.managedPosX - player.posX;
|
||||
double d1 = player.managedPosZ - player.posZ;
|
||||
double d2 = d0 * d0 + d1 * d1;
|
||||
|
||||
if (d2 >= 64.0D)
|
||||
{
|
||||
int k = (int)player.managedPosX >> 4;
|
||||
int l = (int)player.managedPosZ >> 4;
|
||||
int i1 = this.playerViewRadius;
|
||||
int j1 = i - k;
|
||||
int k1 = j - l;
|
||||
|
||||
if (j1 != 0 || k1 != 0)
|
||||
{
|
||||
for (int l1 = i - i1; l1 <= i + i1; ++l1)
|
||||
{
|
||||
for (int i2 = j - i1; i2 <= j + i1; ++i2)
|
||||
{
|
||||
if (!this.overlaps(l1, i2, k, l, i1))
|
||||
{
|
||||
this.getOrCreateEntry(l1, i2).addPlayer(player);
|
||||
}
|
||||
|
||||
if (!this.overlaps(l1 - j1, i2 - k1, i, j, i1))
|
||||
{
|
||||
PlayerChunkMapEntry playerchunkmapentry = this.getEntry(l1 - j1, i2 - k1);
|
||||
|
||||
if (playerchunkmapentry != null)
|
||||
{
|
||||
playerchunkmapentry.removePlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player.managedPosX = player.posX;
|
||||
player.managedPosZ = player.posZ;
|
||||
this.markSortPending();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPlayerWatchingChunk(EntityPlayerMP player, int chunkX, int chunkZ)
|
||||
{
|
||||
PlayerChunkMapEntry playerchunkmapentry = this.getEntry(chunkX, chunkZ);
|
||||
return playerchunkmapentry != null && playerchunkmapentry.containsPlayer(player) && playerchunkmapentry.isSentToPlayers();
|
||||
}
|
||||
|
||||
public void setPlayerViewRadius(int radius)
|
||||
{
|
||||
radius = MathHelper.clamp(radius, 3, 32);
|
||||
|
||||
if (radius != this.playerViewRadius)
|
||||
{
|
||||
int i = radius - this.playerViewRadius;
|
||||
|
||||
for (EntityPlayerMP entityplayermp : Lists.newArrayList(this.players))
|
||||
{
|
||||
int j = (int)entityplayermp.posX >> 4;
|
||||
int k = (int)entityplayermp.posZ >> 4;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
for (int j1 = j - radius; j1 <= j + radius; ++j1)
|
||||
{
|
||||
for (int k1 = k - radius; k1 <= k + radius; ++k1)
|
||||
{
|
||||
PlayerChunkMapEntry playerchunkmapentry = this.getOrCreateEntry(j1, k1);
|
||||
|
||||
if (!playerchunkmapentry.containsPlayer(entityplayermp))
|
||||
{
|
||||
playerchunkmapentry.addPlayer(entityplayermp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int l = j - this.playerViewRadius; l <= j + this.playerViewRadius; ++l)
|
||||
{
|
||||
for (int i1 = k - this.playerViewRadius; i1 <= k + this.playerViewRadius; ++i1)
|
||||
{
|
||||
if (!this.overlaps(l, i1, j, k, radius))
|
||||
{
|
||||
this.getOrCreateEntry(l, i1).removePlayer(entityplayermp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.playerViewRadius = radius;
|
||||
this.markSortPending();
|
||||
}
|
||||
}
|
||||
|
||||
private void markSortPending()
|
||||
{
|
||||
this.sortMissingChunks = true;
|
||||
this.sortSendToPlayers = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the furthest viewable block given player's view distance
|
||||
*/
|
||||
public static int getFurthestViewableBlock(int distance)
|
||||
{
|
||||
return distance * 16 - 16;
|
||||
}
|
||||
|
||||
private static long getIndex(int p_187307_0_, int p_187307_1_)
|
||||
{
|
||||
return (long)p_187307_0_ + 2147483647L | (long)p_187307_1_ + 2147483647L << 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks an entry as dirty
|
||||
*/
|
||||
public void entryChanged(PlayerChunkMapEntry entry)
|
||||
{
|
||||
this.dirtyEntries.add(entry);
|
||||
}
|
||||
|
||||
public void removeEntry(PlayerChunkMapEntry entry)
|
||||
{
|
||||
ChunkPos chunkpos = entry.getPos();
|
||||
long i = getIndex(chunkpos.x, chunkpos.z);
|
||||
entry.updateChunkInhabitedTime();
|
||||
this.entryMap.remove(i);
|
||||
this.entries.remove(entry);
|
||||
this.dirtyEntries.remove(entry);
|
||||
this.pendingSendToPlayers.remove(entry);
|
||||
this.entriesWithoutChunks.remove(entry);
|
||||
Chunk chunk = entry.getChunk();
|
||||
|
||||
if (chunk != null)
|
||||
{
|
||||
this.getWorldServer().getChunkProvider().queueUnload(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.play.server.SPacketBlockChange;
|
||||
import net.minecraft.network.play.server.SPacketChunkData;
|
||||
import net.minecraft.network.play.server.SPacketMultiBlockChange;
|
||||
import net.minecraft.network.play.server.SPacketUnloadChunk;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class PlayerChunkMapEntry
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final PlayerChunkMap playerChunkMap;
|
||||
private final List<EntityPlayerMP> players = Lists.<EntityPlayerMP>newArrayList();
|
||||
private final ChunkPos pos;
|
||||
private short[] changedBlocks = new short[64];
|
||||
@Nullable
|
||||
private Chunk chunk;
|
||||
private int changes;
|
||||
private int changedSectionFilter;
|
||||
private long lastUpdateInhabitedTime;
|
||||
private boolean sentToPlayers;
|
||||
private Runnable loadedRunnable = new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
PlayerChunkMapEntry.this.chunk = PlayerChunkMapEntry.this.playerChunkMap.getWorldServer().getChunkProvider().loadChunk(PlayerChunkMapEntry.this.pos.x, PlayerChunkMapEntry.this.pos.z);
|
||||
PlayerChunkMapEntry.this.loading = false;
|
||||
}
|
||||
};
|
||||
private boolean loading = true;
|
||||
|
||||
public PlayerChunkMapEntry(PlayerChunkMap mapIn, int chunkX, int chunkZ)
|
||||
{
|
||||
this.playerChunkMap = mapIn;
|
||||
this.pos = new ChunkPos(chunkX, chunkZ);
|
||||
mapIn.getWorldServer().getChunkProvider().loadChunk(chunkX, chunkZ, this.loadedRunnable);
|
||||
}
|
||||
|
||||
public ChunkPos getPos()
|
||||
{
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
public void addPlayer(EntityPlayerMP player)
|
||||
{
|
||||
if (this.players.contains(player))
|
||||
{
|
||||
LOGGER.debug("Failed to add player. {} already is in chunk {}, {}", player, Integer.valueOf(this.pos.x), Integer.valueOf(this.pos.z));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.players.isEmpty())
|
||||
{
|
||||
this.lastUpdateInhabitedTime = this.playerChunkMap.getWorldServer().getTotalWorldTime();
|
||||
}
|
||||
|
||||
this.players.add(player);
|
||||
|
||||
if (this.sentToPlayers)
|
||||
{
|
||||
this.sendToPlayer(player);
|
||||
// chunk watch event - the chunk is ready
|
||||
net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.ChunkWatchEvent.Watch(this.chunk, player));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removePlayer(EntityPlayerMP player)
|
||||
{
|
||||
if (this.players.contains(player))
|
||||
{
|
||||
// If we haven't loaded yet don't load the chunk just so we can clean it up
|
||||
if (this.chunk == null)
|
||||
{
|
||||
this.players.remove(player);
|
||||
|
||||
if (this.players.isEmpty())
|
||||
{
|
||||
if (this.loading) net.minecraftforge.common.chunkio.ChunkIOExecutor.dropQueuedChunkLoad(this.playerChunkMap.getWorldServer(), this.pos.x, this.pos.z, this.loadedRunnable);
|
||||
this.playerChunkMap.removeEntry(this);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.sentToPlayers)
|
||||
{
|
||||
player.connection.sendPacket(new SPacketUnloadChunk(this.pos.x, this.pos.z));
|
||||
}
|
||||
|
||||
this.players.remove(player);
|
||||
|
||||
net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.ChunkWatchEvent.UnWatch(this.chunk, player));
|
||||
|
||||
if (this.players.isEmpty())
|
||||
{
|
||||
this.playerChunkMap.removeEntry(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the chunk at the player's location. Can fail, returning false, if the player is a spectator floating
|
||||
* outside of any pre-existing chunks, and the server is not configured to allow chunk generation for spectators.
|
||||
*/
|
||||
public boolean providePlayerChunk(boolean canGenerate)
|
||||
{
|
||||
if (this.loading) return false;
|
||||
if (this.chunk != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (canGenerate)
|
||||
{
|
||||
this.chunk = this.playerChunkMap.getWorldServer().getChunkProvider().provideChunk(this.pos.x, this.pos.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.chunk = this.playerChunkMap.getWorldServer().getChunkProvider().loadChunk(this.pos.x, this.pos.z);
|
||||
}
|
||||
|
||||
return this.chunk != null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean sendToPlayers()
|
||||
{
|
||||
if (this.sentToPlayers)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (this.chunk == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (!this.chunk.isPopulated())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.changes = 0;
|
||||
this.changedSectionFilter = 0;
|
||||
this.sentToPlayers = true;
|
||||
if (this.players.isEmpty()) return true; // Forge: fix MC-120780
|
||||
Packet<?> packet = new SPacketChunkData(this.chunk, 65535);
|
||||
|
||||
for (EntityPlayerMP entityplayermp : this.players)
|
||||
{
|
||||
entityplayermp.connection.sendPacket(packet);
|
||||
this.playerChunkMap.getWorldServer().getEntityTracker().sendLeashedEntitiesInChunk(entityplayermp, this.chunk);
|
||||
// chunk watch event - delayed to here as the chunk wasn't ready in addPlayer
|
||||
net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.ChunkWatchEvent.Watch(this.chunk, entityplayermp));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully resyncs this chunk's blocks, tile entities, and entity attachments (passengers and leashes) to all tracking
|
||||
* players
|
||||
*/
|
||||
public void sendToPlayer(EntityPlayerMP player)
|
||||
{
|
||||
if (this.sentToPlayers)
|
||||
{
|
||||
player.connection.sendPacket(new SPacketChunkData(this.chunk, 65535));
|
||||
this.playerChunkMap.getWorldServer().getEntityTracker().sendLeashedEntitiesInChunk(player, this.chunk);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateChunkInhabitedTime()
|
||||
{
|
||||
long i = this.playerChunkMap.getWorldServer().getTotalWorldTime();
|
||||
|
||||
if (this.chunk != null)
|
||||
{
|
||||
this.chunk.setInhabitedTime(this.chunk.getInhabitedTime() + i - this.lastUpdateInhabitedTime);
|
||||
}
|
||||
|
||||
this.lastUpdateInhabitedTime = i;
|
||||
}
|
||||
|
||||
public void blockChanged(int x, int y, int z)
|
||||
{
|
||||
if (this.sentToPlayers)
|
||||
{
|
||||
if (this.changes == 0)
|
||||
{
|
||||
this.playerChunkMap.entryChanged(this);
|
||||
}
|
||||
|
||||
this.changedSectionFilter |= 1 << (y >> 4);
|
||||
|
||||
//Forge; Cache everything, so always run
|
||||
{
|
||||
short short1 = (short)(x << 12 | z << 8 | y);
|
||||
|
||||
for (int i = 0; i < this.changes; ++i)
|
||||
{
|
||||
if (this.changedBlocks[i] == short1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this.changes == this.changedBlocks.length)
|
||||
this.changedBlocks = java.util.Arrays.copyOf(this.changedBlocks, this.changedBlocks.length << 1);
|
||||
this.changedBlocks[this.changes++] = short1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendPacket(Packet<?> packetIn)
|
||||
{
|
||||
if (this.sentToPlayers)
|
||||
{
|
||||
for (int i = 0; i < this.players.size(); ++i)
|
||||
{
|
||||
(this.players.get(i)).connection.sendPacket(packetIn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void update()
|
||||
{
|
||||
if (this.sentToPlayers && this.chunk != null)
|
||||
{
|
||||
if (this.changes != 0)
|
||||
{
|
||||
if (this.changes == 1)
|
||||
{
|
||||
int i = (this.changedBlocks[0] >> 12 & 15) + this.pos.x * 16;
|
||||
int j = this.changedBlocks[0] & 255;
|
||||
int k = (this.changedBlocks[0] >> 8 & 15) + this.pos.z * 16;
|
||||
BlockPos blockpos = new BlockPos(i, j, k);
|
||||
this.sendPacket(new SPacketBlockChange(this.playerChunkMap.getWorldServer(), blockpos));
|
||||
net.minecraft.block.state.IBlockState state = this.playerChunkMap.getWorldServer().getBlockState(blockpos);
|
||||
|
||||
if (state.getBlock().hasTileEntity(state))
|
||||
{
|
||||
this.sendBlockEntity(this.playerChunkMap.getWorldServer().getTileEntity(blockpos));
|
||||
}
|
||||
}
|
||||
else if (this.changes >= net.minecraftforge.common.ForgeModContainer.clumpingThreshold)
|
||||
{
|
||||
this.sendPacket(new SPacketChunkData(this.chunk, this.changedSectionFilter));
|
||||
//TODO: FDix Mojang's fuckup to modded by combining all TE data into the chunk data packet... seriously... packet size explosion!
|
||||
}
|
||||
else
|
||||
{
|
||||
this.sendPacket(new SPacketMultiBlockChange(this.changes, this.changedBlocks, this.chunk));
|
||||
//} Keep this in the else until we figure out a fix for mojang's derpitude on the data packet so we don't double send crap.
|
||||
//{// Forge: Send only the tile entities that are updated, Adding this brace lets us keep the indent and the patch small
|
||||
for (int l = 0; l < this.changes; ++l)
|
||||
{
|
||||
int i1 = (this.changedBlocks[l] >> 12 & 15) + this.pos.x * 16;
|
||||
int j1 = this.changedBlocks[l] & 255;
|
||||
int k1 = (this.changedBlocks[l] >> 8 & 15) + this.pos.z * 16;
|
||||
BlockPos blockpos1 = new BlockPos(i1, j1, k1);
|
||||
net.minecraft.block.state.IBlockState state = this.playerChunkMap.getWorldServer().getBlockState(blockpos1);
|
||||
|
||||
if (state.getBlock().hasTileEntity(state))
|
||||
{
|
||||
this.sendBlockEntity(this.playerChunkMap.getWorldServer().getTileEntity(blockpos1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.changes = 0;
|
||||
this.changedSectionFilter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendBlockEntity(@Nullable TileEntity be)
|
||||
{
|
||||
if (be != null)
|
||||
{
|
||||
SPacketUpdateTileEntity spacketupdatetileentity = be.getUpdatePacket();
|
||||
|
||||
if (spacketupdatetileentity != null)
|
||||
{
|
||||
this.sendPacket(spacketupdatetileentity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsPlayer(EntityPlayerMP player)
|
||||
{
|
||||
return this.players.contains(player);
|
||||
}
|
||||
|
||||
public boolean hasPlayerMatching(Predicate<EntityPlayerMP> predicate)
|
||||
{
|
||||
return Iterables.tryFind(this.players, predicate).isPresent();
|
||||
}
|
||||
|
||||
public boolean hasPlayerMatchingInRange(double range, Predicate<EntityPlayerMP> predicate)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (int j = this.players.size(); i < j; ++i)
|
||||
{
|
||||
EntityPlayerMP entityplayermp = this.players.get(i);
|
||||
|
||||
if (predicate.apply(entityplayermp) && this.pos.getDistanceSq(entityplayermp) < range * range)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isSentToPlayers()
|
||||
{
|
||||
return this.sentToPlayers;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Chunk getChunk()
|
||||
{
|
||||
return this.chunk;
|
||||
}
|
||||
|
||||
public double getClosestPlayerDistance()
|
||||
{
|
||||
double d0 = Double.MAX_VALUE;
|
||||
|
||||
for (EntityPlayerMP entityplayermp : this.players)
|
||||
{
|
||||
double d1 = this.pos.getDistanceSq(entityplayermp);
|
||||
|
||||
if (d1 < d0)
|
||||
{
|
||||
d0 = d1;
|
||||
}
|
||||
}
|
||||
|
||||
return d0;
|
||||
}
|
||||
|
||||
public List<EntityPlayerMP> getWatchingPlayers()
|
||||
{
|
||||
return isSentToPlayers() ? java.util.Collections.unmodifiableList(players) : java.util.Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,545 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockChest;
|
||||
import net.minecraft.block.BlockCommandBlock;
|
||||
import net.minecraft.block.BlockStructure;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemSword;
|
||||
import net.minecraft.network.play.server.SPacketBlockChange;
|
||||
import net.minecraft.network.play.server.SPacketPlayerListItem;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityChest;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.GameType;
|
||||
import net.minecraft.world.ILockableContainer;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
|
||||
public class PlayerInteractionManager
|
||||
{
|
||||
/** The world object that this object is connected to. */
|
||||
public World world;
|
||||
/** The EntityPlayerMP object that this object is connected to. */
|
||||
public EntityPlayerMP player;
|
||||
private GameType gameType = GameType.NOT_SET;
|
||||
/** True if the player is destroying a block */
|
||||
private boolean isDestroyingBlock;
|
||||
private int initialDamage;
|
||||
private BlockPos destroyPos = BlockPos.ORIGIN;
|
||||
private int curblockDamage;
|
||||
/**
|
||||
* Set to true when the "finished destroying block" packet is received but the block wasn't fully damaged yet. The
|
||||
* block will not be destroyed while this is false.
|
||||
*/
|
||||
private boolean receivedFinishDiggingPacket;
|
||||
private BlockPos delayedDestroyPos = BlockPos.ORIGIN;
|
||||
private int initialBlockDamage;
|
||||
private int durabilityRemainingOnBlock = -1;
|
||||
|
||||
public PlayerInteractionManager(World worldIn)
|
||||
{
|
||||
this.world = worldIn;
|
||||
}
|
||||
|
||||
public void setGameType(GameType type)
|
||||
{
|
||||
this.gameType = type;
|
||||
type.configurePlayerCapabilities(this.player.capabilities);
|
||||
this.player.sendPlayerAbilities();
|
||||
this.player.mcServer.getPlayerList().sendPacketToAllPlayers(new SPacketPlayerListItem(SPacketPlayerListItem.Action.UPDATE_GAME_MODE, new EntityPlayerMP[] {this.player}));
|
||||
this.world.updateAllPlayersSleepingFlag();
|
||||
}
|
||||
|
||||
public GameType getGameType()
|
||||
{
|
||||
return this.gameType;
|
||||
}
|
||||
|
||||
public boolean survivalOrAdventure()
|
||||
{
|
||||
return this.gameType.isSurvivalOrAdventure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if we are in creative game mode.
|
||||
*/
|
||||
public boolean isCreative()
|
||||
{
|
||||
return this.gameType.isCreative();
|
||||
}
|
||||
|
||||
/**
|
||||
* if the gameType is currently NOT_SET then change it to par1
|
||||
*/
|
||||
public void initializeGameType(GameType type)
|
||||
{
|
||||
if (this.gameType == GameType.NOT_SET)
|
||||
{
|
||||
this.gameType = type;
|
||||
}
|
||||
|
||||
this.setGameType(this.gameType);
|
||||
}
|
||||
|
||||
public void updateBlockRemoving()
|
||||
{
|
||||
++this.curblockDamage;
|
||||
|
||||
if (this.receivedFinishDiggingPacket)
|
||||
{
|
||||
int i = this.curblockDamage - this.initialBlockDamage;
|
||||
IBlockState iblockstate = this.world.getBlockState(this.delayedDestroyPos);
|
||||
|
||||
if (iblockstate.getBlock().isAir(iblockstate, world, delayedDestroyPos))
|
||||
{
|
||||
this.receivedFinishDiggingPacket = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
float f = iblockstate.getPlayerRelativeBlockHardness(this.player, this.player.world, this.delayedDestroyPos) * (float)(i + 1);
|
||||
int j = (int)(f * 10.0F);
|
||||
|
||||
if (j != this.durabilityRemainingOnBlock)
|
||||
{
|
||||
this.world.sendBlockBreakProgress(this.player.getEntityId(), this.delayedDestroyPos, j);
|
||||
this.durabilityRemainingOnBlock = j;
|
||||
}
|
||||
|
||||
if (f >= 1.0F)
|
||||
{
|
||||
this.receivedFinishDiggingPacket = false;
|
||||
this.tryHarvestBlock(this.delayedDestroyPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.isDestroyingBlock)
|
||||
{
|
||||
IBlockState iblockstate1 = this.world.getBlockState(this.destroyPos);
|
||||
|
||||
if (iblockstate1.getBlock().isAir(iblockstate1, world, destroyPos))
|
||||
{
|
||||
this.world.sendBlockBreakProgress(this.player.getEntityId(), this.destroyPos, -1);
|
||||
this.durabilityRemainingOnBlock = -1;
|
||||
this.isDestroyingBlock = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
int k = this.curblockDamage - this.initialDamage;
|
||||
float f1 = iblockstate1.getPlayerRelativeBlockHardness(this.player, this.player.world, this.destroyPos) * (float)(k + 1); // Forge: Fix network break progress using wrong position
|
||||
int l = (int)(f1 * 10.0F);
|
||||
|
||||
if (l != this.durabilityRemainingOnBlock)
|
||||
{
|
||||
this.world.sendBlockBreakProgress(this.player.getEntityId(), this.destroyPos, l);
|
||||
this.durabilityRemainingOnBlock = l;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If not creative, it calls sendBlockBreakProgress until the block is broken first. tryHarvestBlock can also be the
|
||||
* result of this call.
|
||||
*/
|
||||
public void onBlockClicked(BlockPos pos, EnumFacing side)
|
||||
{
|
||||
double reachDist = player.getEntityAttribute(EntityPlayer.REACH_DISTANCE).getAttributeValue();
|
||||
net.minecraftforge.event.entity.player.PlayerInteractEvent.LeftClickBlock event = net.minecraftforge.common.ForgeHooks.onLeftClickBlock(player, pos, side, net.minecraftforge.common.ForgeHooks.rayTraceEyeHitVec(player, reachDist + 1));
|
||||
if (event.isCanceled())
|
||||
{
|
||||
// Restore block and te data
|
||||
player.connection.sendPacket(new SPacketBlockChange(world, pos));
|
||||
world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isCreative())
|
||||
{
|
||||
if (!this.world.extinguishFire((EntityPlayer)null, pos, side))
|
||||
{
|
||||
this.tryHarvestBlock(pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IBlockState iblockstate = this.world.getBlockState(pos);
|
||||
Block block = iblockstate.getBlock();
|
||||
|
||||
if (this.gameType.hasLimitedInteractions())
|
||||
{
|
||||
if (this.gameType == GameType.SPECTATOR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.player.isAllowEdit())
|
||||
{
|
||||
ItemStack itemstack = this.player.getHeldItemMainhand();
|
||||
|
||||
if (itemstack.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!itemstack.canDestroy(block))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.initialDamage = this.curblockDamage;
|
||||
float f = 1.0F;
|
||||
|
||||
if (!iblockstate.getBlock().isAir(iblockstate, world, pos))
|
||||
{
|
||||
if (event.getUseBlock() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY)
|
||||
{
|
||||
block.onBlockClicked(this.world, pos, this.player);
|
||||
this.world.extinguishFire((EntityPlayer)null, pos, side);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restore block and te data
|
||||
player.connection.sendPacket(new SPacketBlockChange(world, pos));
|
||||
world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3);
|
||||
}
|
||||
f = iblockstate.getPlayerRelativeBlockHardness(this.player, this.player.world, pos);
|
||||
}
|
||||
if (event.getUseItem() == net.minecraftforge.fml.common.eventhandler.Event.Result.DENY)
|
||||
{
|
||||
if (f >= 1.0F)
|
||||
{
|
||||
// Restore block and te data
|
||||
player.connection.sendPacket(new SPacketBlockChange(world, pos));
|
||||
world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iblockstate.getBlock().isAir(iblockstate, world, pos) && f >= 1.0F)
|
||||
{
|
||||
this.tryHarvestBlock(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.isDestroyingBlock = true;
|
||||
this.destroyPos = pos;
|
||||
int i = (int)(f * 10.0F);
|
||||
this.world.sendBlockBreakProgress(this.player.getEntityId(), pos, i);
|
||||
this.durabilityRemainingOnBlock = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void blockRemoving(BlockPos pos)
|
||||
{
|
||||
if (pos.equals(this.destroyPos))
|
||||
{
|
||||
int i = this.curblockDamage - this.initialDamage;
|
||||
IBlockState iblockstate = this.world.getBlockState(pos);
|
||||
|
||||
if (!iblockstate.getBlock().isAir(iblockstate, world, pos))
|
||||
{
|
||||
float f = iblockstate.getPlayerRelativeBlockHardness(this.player, this.player.world, pos) * (float)(i + 1);
|
||||
|
||||
if (f >= 0.7F)
|
||||
{
|
||||
this.isDestroyingBlock = false;
|
||||
this.world.sendBlockBreakProgress(this.player.getEntityId(), pos, -1);
|
||||
this.tryHarvestBlock(pos);
|
||||
}
|
||||
else if (!this.receivedFinishDiggingPacket)
|
||||
{
|
||||
this.isDestroyingBlock = false;
|
||||
this.receivedFinishDiggingPacket = true;
|
||||
this.delayedDestroyPos = pos;
|
||||
this.initialBlockDamage = this.initialDamage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the block breaking process
|
||||
*/
|
||||
public void cancelDestroyingBlock()
|
||||
{
|
||||
this.isDestroyingBlock = false;
|
||||
this.world.sendBlockBreakProgress(this.player.getEntityId(), this.destroyPos, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a block and triggers the appropriate events
|
||||
*/
|
||||
private boolean removeBlock(BlockPos pos)
|
||||
{
|
||||
return removeBlock(pos, false);
|
||||
}
|
||||
|
||||
private boolean removeBlock(BlockPos pos, boolean canHarvest)
|
||||
{
|
||||
IBlockState iblockstate = this.world.getBlockState(pos);
|
||||
boolean flag = iblockstate.getBlock().removedByPlayer(iblockstate, world, pos, player, canHarvest);
|
||||
|
||||
if (flag)
|
||||
{
|
||||
iblockstate.getBlock().onBlockDestroyedByPlayer(this.world, pos, iblockstate);
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to harvest a block
|
||||
*/
|
||||
public boolean tryHarvestBlock(BlockPos pos)
|
||||
{
|
||||
int exp = net.minecraftforge.common.ForgeHooks.onBlockBreakEvent(world, gameType, player, pos);
|
||||
if (exp == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
IBlockState iblockstate = this.world.getBlockState(pos);
|
||||
TileEntity tileentity = this.world.getTileEntity(pos);
|
||||
Block block = iblockstate.getBlock();
|
||||
|
||||
if ((block instanceof BlockCommandBlock || block instanceof BlockStructure) && !this.player.canUseCommandBlock())
|
||||
{
|
||||
this.world.notifyBlockUpdate(pos, iblockstate, iblockstate, 3);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemStack stack = player.getHeldItemMainhand();
|
||||
if (!stack.isEmpty() && stack.getItem().onBlockStartBreak(stack, pos, player)) return false;
|
||||
|
||||
this.world.playEvent(this.player, 2001, pos, Block.getStateId(iblockstate));
|
||||
boolean flag1 = false;
|
||||
|
||||
if (this.isCreative())
|
||||
{
|
||||
flag1 = this.removeBlock(pos);
|
||||
this.player.connection.sendPacket(new SPacketBlockChange(this.world, pos));
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemStack itemstack1 = this.player.getHeldItemMainhand();
|
||||
ItemStack itemstack2 = itemstack1.isEmpty() ? ItemStack.EMPTY : itemstack1.copy();
|
||||
boolean flag = iblockstate.getBlock().canHarvestBlock(world, pos, player);
|
||||
|
||||
if (!itemstack1.isEmpty())
|
||||
{
|
||||
itemstack1.onBlockDestroyed(this.world, iblockstate, pos, this.player);
|
||||
if (itemstack1.isEmpty()) net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(this.player, itemstack2, EnumHand.MAIN_HAND);
|
||||
}
|
||||
|
||||
flag1 = this.removeBlock(pos, flag);
|
||||
if (flag1 && flag)
|
||||
{
|
||||
iblockstate.getBlock().harvestBlock(this.world, this.player, pos, iblockstate, tileentity, itemstack2);
|
||||
}
|
||||
}
|
||||
|
||||
// Drop experience
|
||||
if (!this.isCreative() && flag1 && exp > 0)
|
||||
{
|
||||
iblockstate.getBlock().dropXpOnBlockBreak(world, pos, exp);
|
||||
}
|
||||
return flag1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EnumActionResult processRightClick(EntityPlayer player, World worldIn, ItemStack stack, EnumHand hand)
|
||||
{
|
||||
if (this.gameType == GameType.SPECTATOR)
|
||||
{
|
||||
return EnumActionResult.PASS;
|
||||
}
|
||||
else if (player.getCooldownTracker().hasCooldown(stack.getItem()))
|
||||
{
|
||||
return EnumActionResult.PASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
EnumActionResult cancelResult = net.minecraftforge.common.ForgeHooks.onItemRightClick(player, hand);
|
||||
if (cancelResult != null) return cancelResult;
|
||||
int i = stack.getCount();
|
||||
int j = stack.getMetadata();
|
||||
ItemStack copyBeforeUse = stack.copy();
|
||||
ActionResult<ItemStack> actionresult = stack.useItemRightClick(worldIn, player, hand);
|
||||
ItemStack itemstack = actionresult.getResult();
|
||||
|
||||
if (itemstack == stack && itemstack.getCount() == i && itemstack.getMaxItemUseDuration() <= 0 && itemstack.getMetadata() == j)
|
||||
{
|
||||
return actionresult.getType();
|
||||
}
|
||||
else if (actionresult.getType() == EnumActionResult.FAIL && itemstack.getMaxItemUseDuration() > 0 && !player.isHandActive())
|
||||
{
|
||||
return actionresult.getType();
|
||||
}
|
||||
else
|
||||
{
|
||||
player.setHeldItem(hand, itemstack);
|
||||
|
||||
if (this.isCreative())
|
||||
{
|
||||
itemstack.setCount(i);
|
||||
|
||||
if (itemstack.isItemStackDamageable())
|
||||
{
|
||||
itemstack.setItemDamage(j);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemstack.isEmpty())
|
||||
{
|
||||
net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(player, copyBeforeUse, hand);
|
||||
player.setHeldItem(hand, ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
if (!player.isHandActive())
|
||||
{
|
||||
((EntityPlayerMP)player).sendContainerToPlayer(player.inventoryContainer);
|
||||
}
|
||||
|
||||
return actionresult.getType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EnumActionResult processRightClickBlock(EntityPlayer player, World worldIn, ItemStack stack, EnumHand hand, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ)
|
||||
{
|
||||
if (this.gameType == GameType.SPECTATOR)
|
||||
{
|
||||
TileEntity tileentity = worldIn.getTileEntity(pos);
|
||||
|
||||
if (tileentity instanceof ILockableContainer)
|
||||
{
|
||||
Block block1 = worldIn.getBlockState(pos).getBlock();
|
||||
ILockableContainer ilockablecontainer = (ILockableContainer)tileentity;
|
||||
|
||||
if (ilockablecontainer instanceof TileEntityChest && block1 instanceof BlockChest)
|
||||
{
|
||||
ilockablecontainer = ((BlockChest)block1).getLockableContainer(worldIn, pos);
|
||||
}
|
||||
|
||||
if (ilockablecontainer != null)
|
||||
{
|
||||
player.displayGUIChest(ilockablecontainer);
|
||||
return EnumActionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
else if (tileentity instanceof IInventory)
|
||||
{
|
||||
player.displayGUIChest((IInventory)tileentity);
|
||||
return EnumActionResult.SUCCESS;
|
||||
}
|
||||
|
||||
return EnumActionResult.PASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
double reachDist = player.getEntityAttribute(EntityPlayer.REACH_DISTANCE).getAttributeValue();
|
||||
net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock event = net.minecraftforge.common.ForgeHooks
|
||||
.onRightClickBlock(player, hand, pos, facing, net.minecraftforge.common.ForgeHooks.rayTraceEyeHitVec(player, reachDist + 1));
|
||||
if (event.isCanceled()) return event.getCancellationResult();
|
||||
|
||||
EnumActionResult result = EnumActionResult.PASS;
|
||||
if (event.getUseItem() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY)
|
||||
{
|
||||
result = stack.onItemUseFirst(player, worldIn, pos, hand, facing, hitX, hitY, hitZ);
|
||||
if (result != EnumActionResult.PASS) return result ;
|
||||
}
|
||||
|
||||
boolean bypass = player.getHeldItemMainhand().doesSneakBypassUse(worldIn, pos, player) && player.getHeldItemOffhand().doesSneakBypassUse(worldIn, pos, player);
|
||||
|
||||
if (!player.isSneaking() || bypass || event.getUseBlock() == net.minecraftforge.fml.common.eventhandler.Event.Result.ALLOW)
|
||||
{
|
||||
IBlockState iblockstate = worldIn.getBlockState(pos);
|
||||
if(event.getUseBlock() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY)
|
||||
if (iblockstate.getBlock().onBlockActivated(worldIn, pos, iblockstate, player, hand, facing, hitX, hitY, hitZ))
|
||||
{
|
||||
result = EnumActionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.isEmpty())
|
||||
{
|
||||
return EnumActionResult.PASS;
|
||||
}
|
||||
else if (player.getCooldownTracker().hasCooldown(stack.getItem()))
|
||||
{
|
||||
return EnumActionResult.PASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stack.getItem() instanceof ItemBlock && !player.canUseCommandBlock())
|
||||
{
|
||||
Block block = ((ItemBlock)stack.getItem()).getBlock();
|
||||
|
||||
if (block instanceof BlockCommandBlock || block instanceof BlockStructure)
|
||||
{
|
||||
return EnumActionResult.FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isCreative())
|
||||
{
|
||||
int j = stack.getMetadata();
|
||||
int i = stack.getCount();
|
||||
if (result != EnumActionResult.SUCCESS && event.getUseItem() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY
|
||||
|| result == EnumActionResult.SUCCESS && event.getUseItem() == net.minecraftforge.fml.common.eventhandler.Event.Result.ALLOW) {
|
||||
EnumActionResult enumactionresult = stack.onItemUse(player, worldIn, pos, hand, facing, hitX, hitY, hitZ);
|
||||
stack.setItemDamage(j);
|
||||
stack.setCount(i);
|
||||
return enumactionresult;
|
||||
} else return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result != EnumActionResult.SUCCESS && event.getUseItem() != net.minecraftforge.fml.common.eventhandler.Event.Result.DENY
|
||||
|| result == EnumActionResult.SUCCESS && event.getUseItem() == net.minecraftforge.fml.common.eventhandler.Event.Result.ALLOW) {
|
||||
ItemStack copyBeforeUse = stack.copy();
|
||||
result = stack.onItemUse(player, worldIn, pos, hand, facing, hitX, hitY, hitZ);
|
||||
if (stack.isEmpty()) net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(player, copyBeforeUse, hand);
|
||||
} return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the world instance.
|
||||
*/
|
||||
public void setWorld(WorldServer serverWorld)
|
||||
{
|
||||
this.world = serverWorld;
|
||||
}
|
||||
|
||||
@Deprecated // use the attribute directly
|
||||
public double getBlockReachDistance()
|
||||
{
|
||||
return player.getEntityAttribute(EntityPlayer.REACH_DISTANCE).getAttributeValue();
|
||||
}
|
||||
|
||||
@Deprecated // use an attribute modifier
|
||||
public void setBlockReachDistance(double distance)
|
||||
{
|
||||
player.getEntityAttribute(EntityPlayer.REACH_DISTANCE).setBaseValue(distance);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,425 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.mojang.authlib.Agent;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.GameProfileRepository;
|
||||
import com.mojang.authlib.ProfileLookupCallback;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
public class PlayerProfileCache
|
||||
{
|
||||
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
|
||||
private static boolean onlineMode;
|
||||
/** A map between player usernames and {@link ProfileEntry profile entries} */
|
||||
private final Map<String, PlayerProfileCache.ProfileEntry> usernameToProfileEntryMap = Maps.<String, PlayerProfileCache.ProfileEntry>newHashMap();
|
||||
/** A map between {@link UUID UUID's} and {@link ProfileEntry ProfileEntries} */
|
||||
private final Map<UUID, PlayerProfileCache.ProfileEntry> uuidToProfileEntryMap = Maps.<UUID, PlayerProfileCache.ProfileEntry>newHashMap();
|
||||
/** A list of all the cached {@link GameProfile GameProfiles} */
|
||||
private final Deque<GameProfile> gameProfiles = Lists.<GameProfile>newLinkedList();
|
||||
private final GameProfileRepository profileRepo;
|
||||
protected final Gson gson;
|
||||
private final File usercacheFile;
|
||||
private static final ParameterizedType TYPE = new ParameterizedType()
|
||||
{
|
||||
public Type[] getActualTypeArguments()
|
||||
{
|
||||
return new Type[] {PlayerProfileCache.ProfileEntry.class};
|
||||
}
|
||||
public Type getRawType()
|
||||
{
|
||||
return List.class;
|
||||
}
|
||||
public Type getOwnerType()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public PlayerProfileCache(GameProfileRepository profileRepoIn, File usercacheFileIn)
|
||||
{
|
||||
this.profileRepo = profileRepoIn;
|
||||
this.usercacheFile = usercacheFileIn;
|
||||
GsonBuilder gsonbuilder = new GsonBuilder();
|
||||
gsonbuilder.registerTypeHierarchyAdapter(PlayerProfileCache.ProfileEntry.class, new PlayerProfileCache.Serializer());
|
||||
this.gson = gsonbuilder.create();
|
||||
this.load();
|
||||
}
|
||||
|
||||
private static GameProfile lookupProfile(GameProfileRepository profileRepoIn, String name)
|
||||
{
|
||||
final GameProfile[] agameprofile = new GameProfile[1];
|
||||
ProfileLookupCallback profilelookupcallback = new ProfileLookupCallback()
|
||||
{
|
||||
public void onProfileLookupSucceeded(GameProfile p_onProfileLookupSucceeded_1_)
|
||||
{
|
||||
agameprofile[0] = p_onProfileLookupSucceeded_1_;
|
||||
}
|
||||
public void onProfileLookupFailed(GameProfile p_onProfileLookupFailed_1_, Exception p_onProfileLookupFailed_2_)
|
||||
{
|
||||
agameprofile[0] = null;
|
||||
}
|
||||
};
|
||||
profileRepoIn.findProfilesByNames(new String[] {name}, Agent.MINECRAFT, profilelookupcallback);
|
||||
|
||||
if (!isOnlineMode() && agameprofile[0] == null)
|
||||
{
|
||||
UUID uuid = EntityPlayer.getUUID(new GameProfile((UUID)null, name));
|
||||
GameProfile gameprofile = new GameProfile(uuid, name);
|
||||
profilelookupcallback.onProfileLookupSucceeded(gameprofile);
|
||||
}
|
||||
|
||||
return agameprofile[0];
|
||||
}
|
||||
|
||||
public static void setOnlineMode(boolean onlineModeIn)
|
||||
{
|
||||
onlineMode = onlineModeIn;
|
||||
}
|
||||
|
||||
private static boolean isOnlineMode()
|
||||
{
|
||||
return onlineMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an entry to this cache
|
||||
*/
|
||||
public void addEntry(GameProfile gameProfile)
|
||||
{
|
||||
this.addEntry(gameProfile, (Date)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an entry to this cache
|
||||
*/
|
||||
private void addEntry(GameProfile gameProfile, Date expirationDate)
|
||||
{
|
||||
UUID uuid = gameProfile.getId();
|
||||
|
||||
if (expirationDate == null)
|
||||
{
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(new Date());
|
||||
calendar.add(2, 1);
|
||||
expirationDate = calendar.getTime();
|
||||
}
|
||||
|
||||
String s = gameProfile.getName().toLowerCase(Locale.ROOT);
|
||||
PlayerProfileCache.ProfileEntry playerprofilecache$profileentry = new PlayerProfileCache.ProfileEntry(gameProfile, expirationDate);
|
||||
|
||||
if (this.uuidToProfileEntryMap.containsKey(uuid))
|
||||
{
|
||||
PlayerProfileCache.ProfileEntry playerprofilecache$profileentry1 = this.uuidToProfileEntryMap.get(uuid);
|
||||
this.usernameToProfileEntryMap.remove(playerprofilecache$profileentry1.getGameProfile().getName().toLowerCase(Locale.ROOT));
|
||||
this.gameProfiles.remove(gameProfile);
|
||||
}
|
||||
|
||||
this.usernameToProfileEntryMap.put(gameProfile.getName().toLowerCase(Locale.ROOT), playerprofilecache$profileentry);
|
||||
this.uuidToProfileEntryMap.put(uuid, playerprofilecache$profileentry);
|
||||
this.gameProfiles.addFirst(gameProfile);
|
||||
this.save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a player's GameProfile given their username. Mojang's server's will be contacted if the entry is not cached
|
||||
* locally.
|
||||
*/
|
||||
@Nullable
|
||||
public GameProfile getGameProfileForUsername(String username)
|
||||
{
|
||||
String s = username.toLowerCase(Locale.ROOT);
|
||||
PlayerProfileCache.ProfileEntry playerprofilecache$profileentry = this.usernameToProfileEntryMap.get(s);
|
||||
|
||||
if (playerprofilecache$profileentry != null && (new Date()).getTime() >= playerprofilecache$profileentry.expirationDate.getTime())
|
||||
{
|
||||
this.uuidToProfileEntryMap.remove(playerprofilecache$profileentry.getGameProfile().getId());
|
||||
this.usernameToProfileEntryMap.remove(playerprofilecache$profileentry.getGameProfile().getName().toLowerCase(Locale.ROOT));
|
||||
this.gameProfiles.remove(playerprofilecache$profileentry.getGameProfile());
|
||||
playerprofilecache$profileentry = null;
|
||||
}
|
||||
|
||||
if (playerprofilecache$profileentry != null)
|
||||
{
|
||||
GameProfile gameprofile = playerprofilecache$profileentry.getGameProfile();
|
||||
this.gameProfiles.remove(gameprofile);
|
||||
this.gameProfiles.addFirst(gameprofile);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameProfile gameprofile1 = lookupProfile(this.profileRepo, s);
|
||||
|
||||
if (gameprofile1 != null)
|
||||
{
|
||||
this.addEntry(gameprofile1);
|
||||
playerprofilecache$profileentry = this.usernameToProfileEntryMap.get(s);
|
||||
}
|
||||
}
|
||||
|
||||
this.save();
|
||||
return playerprofilecache$profileentry == null ? null : playerprofilecache$profileentry.getGameProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of the usernames that are cached in this cache
|
||||
*/
|
||||
public String[] getUsernames()
|
||||
{
|
||||
List<String> list = Lists.newArrayList(this.usernameToProfileEntryMap.keySet());
|
||||
return (String[])list.toArray(new String[list.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a player's {@link GameProfile} given their UUID
|
||||
*/
|
||||
@Nullable
|
||||
public GameProfile getProfileByUUID(UUID uuid)
|
||||
{
|
||||
PlayerProfileCache.ProfileEntry playerprofilecache$profileentry = this.uuidToProfileEntryMap.get(uuid);
|
||||
return playerprofilecache$profileentry == null ? null : playerprofilecache$profileentry.getGameProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link ProfileEntry} by UUID
|
||||
*/
|
||||
private PlayerProfileCache.ProfileEntry getByUUID(UUID uuid)
|
||||
{
|
||||
PlayerProfileCache.ProfileEntry playerprofilecache$profileentry = this.uuidToProfileEntryMap.get(uuid);
|
||||
|
||||
if (playerprofilecache$profileentry != null)
|
||||
{
|
||||
GameProfile gameprofile = playerprofilecache$profileentry.getGameProfile();
|
||||
this.gameProfiles.remove(gameprofile);
|
||||
this.gameProfiles.addFirst(gameprofile);
|
||||
}
|
||||
|
||||
return playerprofilecache$profileentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the cached profiles from disk
|
||||
*/
|
||||
public void load()
|
||||
{
|
||||
BufferedReader bufferedreader = null;
|
||||
|
||||
try
|
||||
{
|
||||
bufferedreader = Files.newReader(this.usercacheFile, StandardCharsets.UTF_8);
|
||||
List<PlayerProfileCache.ProfileEntry> list = (List)JsonUtils.fromJson(this.gson, bufferedreader, TYPE);
|
||||
this.usernameToProfileEntryMap.clear();
|
||||
this.uuidToProfileEntryMap.clear();
|
||||
this.gameProfiles.clear();
|
||||
|
||||
if (list != null)
|
||||
{
|
||||
for (PlayerProfileCache.ProfileEntry playerprofilecache$profileentry : Lists.reverse(list))
|
||||
{
|
||||
if (playerprofilecache$profileentry != null)
|
||||
{
|
||||
this.addEntry(playerprofilecache$profileentry.getGameProfile(), playerprofilecache$profileentry.getExpirationDate());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException var9)
|
||||
{
|
||||
;
|
||||
}
|
||||
catch (JsonParseException var10)
|
||||
{
|
||||
;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly((Reader)bufferedreader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the cached profiles to disk
|
||||
*/
|
||||
public void save()
|
||||
{
|
||||
String s = this.gson.toJson(this.getEntriesWithLimit(1000));
|
||||
BufferedWriter bufferedwriter = null;
|
||||
|
||||
try
|
||||
{
|
||||
bufferedwriter = Files.newWriter(this.usercacheFile, StandardCharsets.UTF_8);
|
||||
bufferedwriter.write(s);
|
||||
return;
|
||||
}
|
||||
catch (FileNotFoundException var8)
|
||||
{
|
||||
;
|
||||
}
|
||||
catch (IOException var9)
|
||||
{
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly((Writer)bufferedwriter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link PlayerProfileCache.ProfileEntry entries} of this cache with a given limit
|
||||
*/
|
||||
private List<PlayerProfileCache.ProfileEntry> getEntriesWithLimit(int limitSize)
|
||||
{
|
||||
List<PlayerProfileCache.ProfileEntry> list = Lists.<PlayerProfileCache.ProfileEntry>newArrayList();
|
||||
|
||||
for (GameProfile gameprofile : Lists.newArrayList(Iterators.limit(this.gameProfiles.iterator(), limitSize)))
|
||||
{
|
||||
PlayerProfileCache.ProfileEntry playerprofilecache$profileentry = this.getByUUID(gameprofile.getId());
|
||||
|
||||
if (playerprofilecache$profileentry != null)
|
||||
{
|
||||
list.add(playerprofilecache$profileentry);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
class ProfileEntry
|
||||
{
|
||||
/** The player's GameProfile */
|
||||
private final GameProfile gameProfile;
|
||||
/** The date that this entry will expire */
|
||||
private final Date expirationDate;
|
||||
|
||||
private ProfileEntry(GameProfile gameProfileIn, Date expirationDateIn)
|
||||
{
|
||||
this.gameProfile = gameProfileIn;
|
||||
this.expirationDate = expirationDateIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the player's GameProfile
|
||||
*/
|
||||
public GameProfile getGameProfile()
|
||||
{
|
||||
return this.gameProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date that this entry will expire
|
||||
*/
|
||||
public Date getExpirationDate()
|
||||
{
|
||||
return this.expirationDate;
|
||||
}
|
||||
}
|
||||
|
||||
class Serializer implements JsonDeserializer<PlayerProfileCache.ProfileEntry>, JsonSerializer<PlayerProfileCache.ProfileEntry>
|
||||
{
|
||||
private Serializer()
|
||||
{
|
||||
}
|
||||
|
||||
public JsonElement serialize(PlayerProfileCache.ProfileEntry p_serialize_1_, Type p_serialize_2_, JsonSerializationContext p_serialize_3_)
|
||||
{
|
||||
JsonObject jsonobject = new JsonObject();
|
||||
jsonobject.addProperty("name", p_serialize_1_.getGameProfile().getName());
|
||||
UUID uuid = p_serialize_1_.getGameProfile().getId();
|
||||
jsonobject.addProperty("uuid", uuid == null ? "" : uuid.toString());
|
||||
jsonobject.addProperty("expiresOn", PlayerProfileCache.DATE_FORMAT.format(p_serialize_1_.getExpirationDate()));
|
||||
return jsonobject;
|
||||
}
|
||||
|
||||
public PlayerProfileCache.ProfileEntry deserialize(JsonElement p_deserialize_1_, Type p_deserialize_2_, JsonDeserializationContext p_deserialize_3_) throws JsonParseException
|
||||
{
|
||||
if (p_deserialize_1_.isJsonObject())
|
||||
{
|
||||
JsonObject jsonobject = p_deserialize_1_.getAsJsonObject();
|
||||
JsonElement jsonelement = jsonobject.get("name");
|
||||
JsonElement jsonelement1 = jsonobject.get("uuid");
|
||||
JsonElement jsonelement2 = jsonobject.get("expiresOn");
|
||||
|
||||
if (jsonelement != null && jsonelement1 != null)
|
||||
{
|
||||
String s = jsonelement1.getAsString();
|
||||
String s1 = jsonelement.getAsString();
|
||||
Date date = null;
|
||||
|
||||
if (jsonelement2 != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
date = PlayerProfileCache.DATE_FORMAT.parse(jsonelement2.getAsString());
|
||||
}
|
||||
catch (ParseException var14)
|
||||
{
|
||||
date = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (s1 != null && s != null)
|
||||
{
|
||||
UUID uuid;
|
||||
|
||||
try
|
||||
{
|
||||
uuid = UUID.fromString(s);
|
||||
}
|
||||
catch (Throwable var13)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return PlayerProfileCache.this.new ProfileEntry(new GameProfile(uuid, s1), date);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,633 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.Files;
|
||||
import com.mojang.authlib.Agent;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.ProfileLookupCallback;
|
||||
import com.mojang.authlib.yggdrasil.ProfileNotFoundException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.ParseException;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import net.minecraft.server.dedicated.PropertyManager;
|
||||
import net.minecraft.util.StringUtils;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class PreYggdrasilConverter
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
public static final File OLD_IPBAN_FILE = new File("banned-ips.txt");
|
||||
public static final File OLD_PLAYERBAN_FILE = new File("banned-players.txt");
|
||||
public static final File OLD_OPS_FILE = new File("ops.txt");
|
||||
public static final File OLD_WHITELIST_FILE = new File("white-list.txt");
|
||||
|
||||
private static void lookupNames(MinecraftServer server, Collection<String> names, ProfileLookupCallback callback)
|
||||
{
|
||||
String[] astring = (String[])Iterators.toArray(Iterators.filter(names.iterator(), new Predicate<String>()
|
||||
{
|
||||
public boolean apply(@Nullable String p_apply_1_)
|
||||
{
|
||||
return !StringUtils.isNullOrEmpty(p_apply_1_);
|
||||
}
|
||||
}), String.class);
|
||||
|
||||
if (server.isServerInOnlineMode())
|
||||
{
|
||||
server.getGameProfileRepository().findProfilesByNames(astring, Agent.MINECRAFT, callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (String s : astring)
|
||||
{
|
||||
UUID uuid = EntityPlayer.getUUID(new GameProfile((UUID)null, s));
|
||||
GameProfile gameprofile = new GameProfile(uuid, s);
|
||||
callback.onProfileLookupSucceeded(gameprofile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String convertMobOwnerIfNeeded(final MinecraftServer server, String username)
|
||||
{
|
||||
if (!StringUtils.isNullOrEmpty(username) && username.length() <= 16)
|
||||
{
|
||||
GameProfile gameprofile = server.getPlayerProfileCache().getGameProfileForUsername(username);
|
||||
|
||||
if (gameprofile != null && gameprofile.getId() != null)
|
||||
{
|
||||
return gameprofile.getId().toString();
|
||||
}
|
||||
else if (!server.isSinglePlayer() && server.isServerInOnlineMode())
|
||||
{
|
||||
final List<GameProfile> list = Lists.<GameProfile>newArrayList();
|
||||
ProfileLookupCallback profilelookupcallback = new ProfileLookupCallback()
|
||||
{
|
||||
public void onProfileLookupSucceeded(GameProfile p_onProfileLookupSucceeded_1_)
|
||||
{
|
||||
server.getPlayerProfileCache().addEntry(p_onProfileLookupSucceeded_1_);
|
||||
list.add(p_onProfileLookupSucceeded_1_);
|
||||
}
|
||||
public void onProfileLookupFailed(GameProfile p_onProfileLookupFailed_1_, Exception p_onProfileLookupFailed_2_)
|
||||
{
|
||||
PreYggdrasilConverter.LOGGER.warn("Could not lookup user whitelist entry for {}", p_onProfileLookupFailed_1_.getName(), p_onProfileLookupFailed_2_);
|
||||
}
|
||||
};
|
||||
lookupNames(server, Lists.newArrayList(username), profilelookupcallback);
|
||||
return !list.isEmpty() && ((GameProfile)list.get(0)).getId() != null ? ((GameProfile)list.get(0)).getId().toString() : "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return EntityPlayer.getUUID(new GameProfile((UUID)null, username)).toString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return username;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
static List<String> readFile(File inFile, Map<String, String[]> read) throws IOException
|
||||
{
|
||||
List<String> list = Files.readLines(inFile, StandardCharsets.UTF_8);
|
||||
|
||||
for (String s : list)
|
||||
{
|
||||
s = s.trim();
|
||||
|
||||
if (!s.startsWith("#") && s.length() >= 1)
|
||||
{
|
||||
String[] astring = s.split("\\|");
|
||||
read.put(astring[0].toLowerCase(Locale.ROOT), astring);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public static boolean convertUserBanlist(final MinecraftServer server) throws IOException
|
||||
{
|
||||
final UserListBans userlistbans = new UserListBans(PlayerList.FILE_PLAYERBANS);
|
||||
|
||||
if (OLD_PLAYERBAN_FILE.exists() && OLD_PLAYERBAN_FILE.isFile())
|
||||
{
|
||||
if (userlistbans.getSaveFile().exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
userlistbans.readSavedFile();
|
||||
}
|
||||
catch (FileNotFoundException filenotfoundexception)
|
||||
{
|
||||
LOGGER.warn("Could not load existing file {}", userlistbans.getSaveFile().getName(), filenotfoundexception);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
final Map<String, String[]> map = Maps.<String, String[]>newHashMap();
|
||||
readFile(OLD_PLAYERBAN_FILE, map);
|
||||
ProfileLookupCallback profilelookupcallback = new ProfileLookupCallback()
|
||||
{
|
||||
public void onProfileLookupSucceeded(GameProfile p_onProfileLookupSucceeded_1_)
|
||||
{
|
||||
server.getPlayerProfileCache().addEntry(p_onProfileLookupSucceeded_1_);
|
||||
String[] astring = map.get(p_onProfileLookupSucceeded_1_.getName().toLowerCase(Locale.ROOT));
|
||||
|
||||
if (astring == null)
|
||||
{
|
||||
PreYggdrasilConverter.LOGGER.warn("Could not convert user banlist entry for {}", (Object)p_onProfileLookupSucceeded_1_.getName());
|
||||
throw new PreYggdrasilConverter.ConversionError("Profile not in the conversionlist");
|
||||
}
|
||||
else
|
||||
{
|
||||
Date date = astring.length > 1 ? PreYggdrasilConverter.parseDate(astring[1], (Date)null) : null;
|
||||
String s = astring.length > 2 ? astring[2] : null;
|
||||
Date date1 = astring.length > 3 ? PreYggdrasilConverter.parseDate(astring[3], (Date)null) : null;
|
||||
String s1 = astring.length > 4 ? astring[4] : null;
|
||||
userlistbans.addEntry(new UserListBansEntry(p_onProfileLookupSucceeded_1_, date, s, date1, s1));
|
||||
}
|
||||
}
|
||||
public void onProfileLookupFailed(GameProfile p_onProfileLookupFailed_1_, Exception p_onProfileLookupFailed_2_)
|
||||
{
|
||||
PreYggdrasilConverter.LOGGER.warn("Could not lookup user banlist entry for {}", p_onProfileLookupFailed_1_.getName(), p_onProfileLookupFailed_2_);
|
||||
|
||||
if (!(p_onProfileLookupFailed_2_ instanceof ProfileNotFoundException))
|
||||
{
|
||||
throw new PreYggdrasilConverter.ConversionError("Could not request user " + p_onProfileLookupFailed_1_.getName() + " from backend systems", p_onProfileLookupFailed_2_);
|
||||
}
|
||||
}
|
||||
};
|
||||
lookupNames(server, map.keySet(), profilelookupcallback);
|
||||
userlistbans.writeChanges();
|
||||
backupConverted(OLD_PLAYERBAN_FILE);
|
||||
return true;
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("Could not read old user banlist to convert it!", (Throwable)ioexception);
|
||||
return false;
|
||||
}
|
||||
catch (PreYggdrasilConverter.ConversionError preyggdrasilconverter$conversionerror)
|
||||
{
|
||||
LOGGER.error("Conversion failed, please try again later", (Throwable)preyggdrasilconverter$conversionerror);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public static boolean convertIpBanlist(MinecraftServer server) throws IOException
|
||||
{
|
||||
UserListIPBans userlistipbans = new UserListIPBans(PlayerList.FILE_IPBANS);
|
||||
|
||||
if (OLD_IPBAN_FILE.exists() && OLD_IPBAN_FILE.isFile())
|
||||
{
|
||||
if (userlistipbans.getSaveFile().exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
userlistipbans.readSavedFile();
|
||||
}
|
||||
catch (FileNotFoundException filenotfoundexception)
|
||||
{
|
||||
LOGGER.warn("Could not load existing file {}", userlistipbans.getSaveFile().getName(), filenotfoundexception);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Map<String, String[]> map = Maps.<String, String[]>newHashMap();
|
||||
readFile(OLD_IPBAN_FILE, map);
|
||||
|
||||
for (String s : map.keySet())
|
||||
{
|
||||
String[] astring = map.get(s);
|
||||
Date date = astring.length > 1 ? parseDate(astring[1], (Date)null) : null;
|
||||
String s1 = astring.length > 2 ? astring[2] : null;
|
||||
Date date1 = astring.length > 3 ? parseDate(astring[3], (Date)null) : null;
|
||||
String s2 = astring.length > 4 ? astring[4] : null;
|
||||
userlistipbans.addEntry(new UserListIPBansEntry(s, date, s1, date1, s2));
|
||||
}
|
||||
|
||||
userlistipbans.writeChanges();
|
||||
backupConverted(OLD_IPBAN_FILE);
|
||||
return true;
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("Could not parse old ip banlist to convert it!", (Throwable)ioexception);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public static boolean convertOplist(final MinecraftServer server) throws IOException
|
||||
{
|
||||
final UserListOps userlistops = new UserListOps(PlayerList.FILE_OPS);
|
||||
|
||||
if (OLD_OPS_FILE.exists() && OLD_OPS_FILE.isFile())
|
||||
{
|
||||
if (userlistops.getSaveFile().exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
userlistops.readSavedFile();
|
||||
}
|
||||
catch (FileNotFoundException filenotfoundexception)
|
||||
{
|
||||
LOGGER.warn("Could not load existing file {}", userlistops.getSaveFile().getName(), filenotfoundexception);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
List<String> list = Files.readLines(OLD_OPS_FILE, StandardCharsets.UTF_8);
|
||||
ProfileLookupCallback profilelookupcallback = new ProfileLookupCallback()
|
||||
{
|
||||
public void onProfileLookupSucceeded(GameProfile p_onProfileLookupSucceeded_1_)
|
||||
{
|
||||
server.getPlayerProfileCache().addEntry(p_onProfileLookupSucceeded_1_);
|
||||
userlistops.addEntry(new UserListOpsEntry(p_onProfileLookupSucceeded_1_, server.getOpPermissionLevel(), false));
|
||||
}
|
||||
public void onProfileLookupFailed(GameProfile p_onProfileLookupFailed_1_, Exception p_onProfileLookupFailed_2_)
|
||||
{
|
||||
PreYggdrasilConverter.LOGGER.warn("Could not lookup oplist entry for {}", p_onProfileLookupFailed_1_.getName(), p_onProfileLookupFailed_2_);
|
||||
|
||||
if (!(p_onProfileLookupFailed_2_ instanceof ProfileNotFoundException))
|
||||
{
|
||||
throw new PreYggdrasilConverter.ConversionError("Could not request user " + p_onProfileLookupFailed_1_.getName() + " from backend systems", p_onProfileLookupFailed_2_);
|
||||
}
|
||||
}
|
||||
};
|
||||
lookupNames(server, list, profilelookupcallback);
|
||||
userlistops.writeChanges();
|
||||
backupConverted(OLD_OPS_FILE);
|
||||
return true;
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("Could not read old oplist to convert it!", (Throwable)ioexception);
|
||||
return false;
|
||||
}
|
||||
catch (PreYggdrasilConverter.ConversionError preyggdrasilconverter$conversionerror)
|
||||
{
|
||||
LOGGER.error("Conversion failed, please try again later", (Throwable)preyggdrasilconverter$conversionerror);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public static boolean convertWhitelist(final MinecraftServer server) throws IOException
|
||||
{
|
||||
final UserListWhitelist userlistwhitelist = new UserListWhitelist(PlayerList.FILE_WHITELIST);
|
||||
|
||||
if (OLD_WHITELIST_FILE.exists() && OLD_WHITELIST_FILE.isFile())
|
||||
{
|
||||
if (userlistwhitelist.getSaveFile().exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
userlistwhitelist.readSavedFile();
|
||||
}
|
||||
catch (FileNotFoundException filenotfoundexception)
|
||||
{
|
||||
LOGGER.warn("Could not load existing file {}", userlistwhitelist.getSaveFile().getName(), filenotfoundexception);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
List<String> list = Files.readLines(OLD_WHITELIST_FILE, StandardCharsets.UTF_8);
|
||||
ProfileLookupCallback profilelookupcallback = new ProfileLookupCallback()
|
||||
{
|
||||
public void onProfileLookupSucceeded(GameProfile p_onProfileLookupSucceeded_1_)
|
||||
{
|
||||
server.getPlayerProfileCache().addEntry(p_onProfileLookupSucceeded_1_);
|
||||
userlistwhitelist.addEntry(new UserListWhitelistEntry(p_onProfileLookupSucceeded_1_));
|
||||
}
|
||||
public void onProfileLookupFailed(GameProfile p_onProfileLookupFailed_1_, Exception p_onProfileLookupFailed_2_)
|
||||
{
|
||||
PreYggdrasilConverter.LOGGER.warn("Could not lookup user whitelist entry for {}", p_onProfileLookupFailed_1_.getName(), p_onProfileLookupFailed_2_);
|
||||
|
||||
if (!(p_onProfileLookupFailed_2_ instanceof ProfileNotFoundException))
|
||||
{
|
||||
throw new PreYggdrasilConverter.ConversionError("Could not request user " + p_onProfileLookupFailed_1_.getName() + " from backend systems", p_onProfileLookupFailed_2_);
|
||||
}
|
||||
}
|
||||
};
|
||||
lookupNames(server, list, profilelookupcallback);
|
||||
userlistwhitelist.writeChanges();
|
||||
backupConverted(OLD_WHITELIST_FILE);
|
||||
return true;
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("Could not read old whitelist to convert it!", (Throwable)ioexception);
|
||||
return false;
|
||||
}
|
||||
catch (PreYggdrasilConverter.ConversionError preyggdrasilconverter$conversionerror)
|
||||
{
|
||||
LOGGER.error("Conversion failed, please try again later", (Throwable)preyggdrasilconverter$conversionerror);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public static boolean convertSaveFiles(final DedicatedServer server, PropertyManager p_152723_1_)
|
||||
{
|
||||
final File file1 = getPlayersDirectory(p_152723_1_);
|
||||
final File file2 = new File(file1.getParentFile(), "playerdata");
|
||||
final File file3 = new File(file1.getParentFile(), "unknownplayers");
|
||||
|
||||
if (file1.exists() && file1.isDirectory())
|
||||
{
|
||||
File[] afile = file1.listFiles();
|
||||
List<String> list = Lists.<String>newArrayList();
|
||||
|
||||
for (File file4 : afile)
|
||||
{
|
||||
String s = file4.getName();
|
||||
|
||||
if (s.toLowerCase(Locale.ROOT).endsWith(".dat"))
|
||||
{
|
||||
String s1 = s.substring(0, s.length() - ".dat".length());
|
||||
|
||||
if (!s1.isEmpty())
|
||||
{
|
||||
list.add(s1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
final String[] astring = (String[])list.toArray(new String[list.size()]);
|
||||
ProfileLookupCallback profilelookupcallback = new ProfileLookupCallback()
|
||||
{
|
||||
public void onProfileLookupSucceeded(GameProfile p_onProfileLookupSucceeded_1_)
|
||||
{
|
||||
server.getPlayerProfileCache().addEntry(p_onProfileLookupSucceeded_1_);
|
||||
UUID uuid = p_onProfileLookupSucceeded_1_.getId();
|
||||
|
||||
if (uuid == null)
|
||||
{
|
||||
throw new PreYggdrasilConverter.ConversionError("Missing UUID for user profile " + p_onProfileLookupSucceeded_1_.getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.renamePlayerFile(file2, this.getFileNameForProfile(p_onProfileLookupSucceeded_1_), uuid.toString());
|
||||
}
|
||||
}
|
||||
public void onProfileLookupFailed(GameProfile p_onProfileLookupFailed_1_, Exception p_onProfileLookupFailed_2_)
|
||||
{
|
||||
PreYggdrasilConverter.LOGGER.warn("Could not lookup user uuid for {}", p_onProfileLookupFailed_1_.getName(), p_onProfileLookupFailed_2_);
|
||||
|
||||
if (p_onProfileLookupFailed_2_ instanceof ProfileNotFoundException)
|
||||
{
|
||||
String s2 = this.getFileNameForProfile(p_onProfileLookupFailed_1_);
|
||||
this.renamePlayerFile(file3, s2, s2);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PreYggdrasilConverter.ConversionError("Could not request user " + p_onProfileLookupFailed_1_.getName() + " from backend systems", p_onProfileLookupFailed_2_);
|
||||
}
|
||||
}
|
||||
private void renamePlayerFile(File p_152743_1_, String p_152743_2_, String p_152743_3_)
|
||||
{
|
||||
File file5 = new File(file1, p_152743_2_ + ".dat");
|
||||
File file6 = new File(p_152743_1_, p_152743_3_ + ".dat");
|
||||
PreYggdrasilConverter.mkdir(p_152743_1_);
|
||||
|
||||
if (!file5.renameTo(file6))
|
||||
{
|
||||
throw new PreYggdrasilConverter.ConversionError("Could not convert file for " + p_152743_2_);
|
||||
}
|
||||
}
|
||||
private String getFileNameForProfile(GameProfile p_152744_1_)
|
||||
{
|
||||
String s2 = null;
|
||||
|
||||
for (String s3 : astring)
|
||||
{
|
||||
if (s3 != null && s3.equalsIgnoreCase(p_152744_1_.getName()))
|
||||
{
|
||||
s2 = s3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (s2 == null)
|
||||
{
|
||||
throw new PreYggdrasilConverter.ConversionError("Could not find the filename for " + p_152744_1_.getName() + " anymore");
|
||||
}
|
||||
else
|
||||
{
|
||||
return s2;
|
||||
}
|
||||
}
|
||||
};
|
||||
lookupNames(server, Lists.newArrayList(astring), profilelookupcallback);
|
||||
return true;
|
||||
}
|
||||
catch (PreYggdrasilConverter.ConversionError preyggdrasilconverter$conversionerror)
|
||||
{
|
||||
LOGGER.error("Conversion failed, please try again later", (Throwable)preyggdrasilconverter$conversionerror);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
private static void mkdir(File dir)
|
||||
{
|
||||
if (dir.exists())
|
||||
{
|
||||
if (!dir.isDirectory())
|
||||
{
|
||||
throw new PreYggdrasilConverter.ConversionError("Can't create directory " + dir.getName() + " in world save directory.");
|
||||
}
|
||||
}
|
||||
else if (!dir.mkdirs())
|
||||
{
|
||||
throw new PreYggdrasilConverter.ConversionError("Can't create directory " + dir.getName() + " in world save directory.");
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public static boolean tryConvert(PropertyManager properties)
|
||||
{
|
||||
boolean flag = hasUnconvertableFiles(properties);
|
||||
flag = flag && hasUnconvertablePlayerFiles(properties);
|
||||
return flag;
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
private static boolean hasUnconvertableFiles(PropertyManager properties)
|
||||
{
|
||||
boolean flag = false;
|
||||
|
||||
if (OLD_PLAYERBAN_FILE.exists() && OLD_PLAYERBAN_FILE.isFile())
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
|
||||
boolean flag1 = false;
|
||||
|
||||
if (OLD_IPBAN_FILE.exists() && OLD_IPBAN_FILE.isFile())
|
||||
{
|
||||
flag1 = true;
|
||||
}
|
||||
|
||||
boolean flag2 = false;
|
||||
|
||||
if (OLD_OPS_FILE.exists() && OLD_OPS_FILE.isFile())
|
||||
{
|
||||
flag2 = true;
|
||||
}
|
||||
|
||||
boolean flag3 = false;
|
||||
|
||||
if (OLD_WHITELIST_FILE.exists() && OLD_WHITELIST_FILE.isFile())
|
||||
{
|
||||
flag3 = true;
|
||||
}
|
||||
|
||||
if (!flag && !flag1 && !flag2 && !flag3)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("**** FAILED TO START THE SERVER AFTER ACCOUNT CONVERSION!");
|
||||
LOGGER.warn("** please remove the following files and restart the server:");
|
||||
|
||||
if (flag)
|
||||
{
|
||||
LOGGER.warn("* {}", (Object)OLD_PLAYERBAN_FILE.getName());
|
||||
}
|
||||
|
||||
if (flag1)
|
||||
{
|
||||
LOGGER.warn("* {}", (Object)OLD_IPBAN_FILE.getName());
|
||||
}
|
||||
|
||||
if (flag2)
|
||||
{
|
||||
LOGGER.warn("* {}", (Object)OLD_OPS_FILE.getName());
|
||||
}
|
||||
|
||||
if (flag3)
|
||||
{
|
||||
LOGGER.warn("* {}", (Object)OLD_WHITELIST_FILE.getName());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
private static boolean hasUnconvertablePlayerFiles(PropertyManager properties)
|
||||
{
|
||||
File file1 = getPlayersDirectory(properties);
|
||||
|
||||
if (!file1.exists() || !file1.isDirectory() || file1.list().length <= 0 && file1.delete())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("**** DETECTED OLD PLAYER DIRECTORY IN THE WORLD SAVE");
|
||||
LOGGER.warn("**** THIS USUALLY HAPPENS WHEN THE AUTOMATIC CONVERSION FAILED IN SOME WAY");
|
||||
LOGGER.warn("** please restart the server and if the problem persists, remove the directory '{}'", (Object)file1.getPath());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
private static File getPlayersDirectory(PropertyManager properties)
|
||||
{
|
||||
String s = properties.getStringProperty("level-name", "world");
|
||||
File file1 = new File(s);
|
||||
return new File(file1, "players");
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
private static void backupConverted(File convertedFile)
|
||||
{
|
||||
File file1 = new File(convertedFile.getName() + ".converted");
|
||||
convertedFile.renameTo(file1);
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
private static Date parseDate(String input, Date defaultValue)
|
||||
{
|
||||
Date date;
|
||||
|
||||
try
|
||||
{
|
||||
date = UserListEntryBan.DATE_FORMAT.parse(input);
|
||||
}
|
||||
catch (ParseException var4)
|
||||
{
|
||||
date = defaultValue;
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
static class ConversionError extends RuntimeException
|
||||
{
|
||||
private ConversionError(String message, Throwable cause)
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
private ConversionError(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class UserList<K, V extends UserListEntry<K>>
|
||||
{
|
||||
protected static final Logger LOGGER = LogManager.getLogger();
|
||||
protected final Gson gson;
|
||||
private final File saveFile;
|
||||
private final Map<String, V> values = Maps.<String, V>newHashMap();
|
||||
private boolean lanServer = true;
|
||||
private static final ParameterizedType USER_LIST_ENTRY_TYPE = new ParameterizedType()
|
||||
{
|
||||
public Type[] getActualTypeArguments()
|
||||
{
|
||||
return new Type[] {UserListEntry.class};
|
||||
}
|
||||
public Type getRawType()
|
||||
{
|
||||
return List.class;
|
||||
}
|
||||
public Type getOwnerType()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public UserList(File saveFile)
|
||||
{
|
||||
this.saveFile = saveFile;
|
||||
GsonBuilder gsonbuilder = (new GsonBuilder()).setPrettyPrinting();
|
||||
gsonbuilder.registerTypeHierarchyAdapter(UserListEntry.class, new UserList.Serializer());
|
||||
this.gson = gsonbuilder.create();
|
||||
}
|
||||
|
||||
public boolean isLanServer()
|
||||
{
|
||||
return this.lanServer;
|
||||
}
|
||||
|
||||
public void setLanServer(boolean state)
|
||||
{
|
||||
this.lanServer = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the list
|
||||
*/
|
||||
public void addEntry(V entry)
|
||||
{
|
||||
this.values.put(this.getObjectKey(entry.getValue()), entry);
|
||||
|
||||
try
|
||||
{
|
||||
this.writeChanges();
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("Could not save the list after adding a user.", (Throwable)ioexception);
|
||||
}
|
||||
}
|
||||
|
||||
public V getEntry(K obj)
|
||||
{
|
||||
this.removeExpired();
|
||||
return (V)(this.values.get(this.getObjectKey(obj)));
|
||||
}
|
||||
|
||||
public void removeEntry(K entry)
|
||||
{
|
||||
this.values.remove(this.getObjectKey(entry));
|
||||
|
||||
try
|
||||
{
|
||||
this.writeChanges();
|
||||
}
|
||||
catch (IOException ioexception)
|
||||
{
|
||||
LOGGER.warn("Could not save the list after removing a user.", (Throwable)ioexception);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public File getSaveFile()
|
||||
{
|
||||
return this.saveFile;
|
||||
}
|
||||
|
||||
public String[] getKeys()
|
||||
{
|
||||
return (String[])this.values.keySet().toArray(new String[this.values.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key value for the given object
|
||||
*/
|
||||
protected String getObjectKey(K obj)
|
||||
{
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
protected boolean hasEntry(K entry)
|
||||
{
|
||||
return this.values.containsKey(this.getObjectKey(entry));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes expired bans from the list. See {@link BanEntry#hasBanExpired}
|
||||
*/
|
||||
private void removeExpired()
|
||||
{
|
||||
List<K> list = Lists.<K>newArrayList();
|
||||
|
||||
for (V v : this.values.values())
|
||||
{
|
||||
if (v.hasBanExpired())
|
||||
{
|
||||
list.add(v.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
for (K k : list)
|
||||
{
|
||||
this.values.remove(k);
|
||||
}
|
||||
}
|
||||
|
||||
protected UserListEntry<K> createEntry(JsonObject entryData)
|
||||
{
|
||||
return new UserListEntry<K>(null, entryData);
|
||||
}
|
||||
|
||||
protected Map<String, V> getValues()
|
||||
{
|
||||
return this.values;
|
||||
}
|
||||
|
||||
public void writeChanges() throws IOException
|
||||
{
|
||||
Collection<V> collection = this.values.values();
|
||||
String s = this.gson.toJson(collection);
|
||||
BufferedWriter bufferedwriter = null;
|
||||
|
||||
try
|
||||
{
|
||||
bufferedwriter = Files.newWriter(this.saveFile, StandardCharsets.UTF_8);
|
||||
bufferedwriter.write(s);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly((Writer)bufferedwriter);
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return this.values.size() < 1;
|
||||
}
|
||||
|
||||
@SideOnly(Side.SERVER)
|
||||
public void readSavedFile() throws IOException, FileNotFoundException
|
||||
{
|
||||
if (this.saveFile.exists())
|
||||
{
|
||||
Collection<UserListEntry<K>> collection = null;
|
||||
BufferedReader bufferedreader = null;
|
||||
|
||||
try
|
||||
{
|
||||
bufferedreader = Files.newReader(this.saveFile, StandardCharsets.UTF_8);
|
||||
collection = (Collection)JsonUtils.fromJson(this.gson, bufferedreader, USER_LIST_ENTRY_TYPE);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IOUtils.closeQuietly((Reader)bufferedreader);
|
||||
}
|
||||
|
||||
if (collection != null)
|
||||
{
|
||||
this.values.clear();
|
||||
|
||||
for (UserListEntry<K> userlistentry : collection)
|
||||
{
|
||||
if (userlistentry.getValue() != null)
|
||||
{
|
||||
this.values.put(this.getObjectKey(userlistentry.getValue()), (V)userlistentry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Serializer implements JsonDeserializer<UserListEntry<K>>, JsonSerializer<UserListEntry<K>>
|
||||
{
|
||||
private Serializer()
|
||||
{
|
||||
}
|
||||
|
||||
public JsonElement serialize(UserListEntry<K> p_serialize_1_, Type p_serialize_2_, JsonSerializationContext p_serialize_3_)
|
||||
{
|
||||
JsonObject jsonobject = new JsonObject();
|
||||
p_serialize_1_.onSerialization(jsonobject);
|
||||
return jsonobject;
|
||||
}
|
||||
|
||||
public UserListEntry<K> deserialize(JsonElement p_deserialize_1_, Type p_deserialize_2_, JsonDeserializationContext p_deserialize_3_) throws JsonParseException
|
||||
{
|
||||
if (p_deserialize_1_.isJsonObject())
|
||||
{
|
||||
JsonObject jsonobject = p_deserialize_1_.getAsJsonObject();
|
||||
return UserList.this.createEntry(jsonobject);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import java.io.File;
|
||||
|
||||
public class UserListBans extends UserList<GameProfile, UserListBansEntry>
|
||||
{
|
||||
public UserListBans(File bansFile)
|
||||
{
|
||||
super(bansFile);
|
||||
}
|
||||
|
||||
protected UserListEntry<GameProfile> createEntry(JsonObject entryData)
|
||||
{
|
||||
return new UserListBansEntry(entryData);
|
||||
}
|
||||
|
||||
public boolean isBanned(GameProfile profile)
|
||||
{
|
||||
return this.hasEntry(profile);
|
||||
}
|
||||
|
||||
public String[] getKeys()
|
||||
{
|
||||
String[] astring = new String[this.getValues().size()];
|
||||
int i = 0;
|
||||
|
||||
for (UserListBansEntry userlistbansentry : this.getValues().values())
|
||||
{
|
||||
astring[i++] = ((GameProfile)userlistbansentry.getValue()).getName();
|
||||
}
|
||||
|
||||
return astring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key value for the given object
|
||||
*/
|
||||
protected String getObjectKey(GameProfile obj)
|
||||
{
|
||||
return obj.getId().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link GameProfile} that is a member of this list by its user name. Returns {@code null} if no entry was
|
||||
* found.
|
||||
*/
|
||||
public GameProfile getBannedProfile(String username)
|
||||
{
|
||||
for (UserListBansEntry userlistbansentry : this.getValues().values())
|
||||
{
|
||||
if (username.equalsIgnoreCase(((GameProfile)userlistbansentry.getValue()).getName()))
|
||||
{
|
||||
return (GameProfile)userlistbansentry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UserListBansEntry extends UserListEntryBan<GameProfile>
|
||||
{
|
||||
public UserListBansEntry(GameProfile profile)
|
||||
{
|
||||
this(profile, (Date)null, (String)null, (Date)null, (String)null);
|
||||
}
|
||||
|
||||
public UserListBansEntry(GameProfile profile, Date startDate, String banner, Date endDate, String banReason)
|
||||
{
|
||||
super(profile, endDate, banner, endDate, banReason);
|
||||
}
|
||||
|
||||
public UserListBansEntry(JsonObject json)
|
||||
{
|
||||
super(toGameProfile(json), json);
|
||||
}
|
||||
|
||||
protected void onSerialization(JsonObject data)
|
||||
{
|
||||
if (this.getValue() != null)
|
||||
{
|
||||
data.addProperty("uuid", ((GameProfile)this.getValue()).getId() == null ? "" : ((GameProfile)this.getValue()).getId().toString());
|
||||
data.addProperty("name", ((GameProfile)this.getValue()).getName());
|
||||
super.onSerialization(data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a {@linkplain com.google.gson.JsonObject JsonObject} into a {@linkplain com.mojang.authlib.GameProfile}.
|
||||
* The json object must have {@code uuid} and {@code name} attributes or {@code null} will be returned.
|
||||
*/
|
||||
private static GameProfile toGameProfile(JsonObject json)
|
||||
{
|
||||
if (json.has("uuid") && json.has("name"))
|
||||
{
|
||||
String s = json.get("uuid").getAsString();
|
||||
UUID uuid;
|
||||
|
||||
try
|
||||
{
|
||||
uuid = UUID.fromString(s);
|
||||
}
|
||||
catch (Throwable var4)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GameProfile(uuid, json.get("name").getAsString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class UserListEntry<T>
|
||||
{
|
||||
private final T value;
|
||||
|
||||
public UserListEntry(T valueIn)
|
||||
{
|
||||
this.value = valueIn;
|
||||
}
|
||||
|
||||
protected UserListEntry(T valueIn, JsonObject json)
|
||||
{
|
||||
this.value = valueIn;
|
||||
}
|
||||
|
||||
T getValue()
|
||||
{
|
||||
return this.value;
|
||||
}
|
||||
|
||||
boolean hasBanExpired()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void onSerialization(JsonObject data)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public abstract class UserListEntryBan<T> extends UserListEntry<T>
|
||||
{
|
||||
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
|
||||
protected final Date banStartDate;
|
||||
protected final String bannedBy;
|
||||
protected final Date banEndDate;
|
||||
protected final String reason;
|
||||
|
||||
public UserListEntryBan(T valueIn, Date startDate, String banner, Date endDate, String banReason)
|
||||
{
|
||||
super(valueIn);
|
||||
this.banStartDate = startDate == null ? new Date() : startDate;
|
||||
this.bannedBy = banner == null ? "(Unknown)" : banner;
|
||||
this.banEndDate = endDate;
|
||||
this.reason = banReason == null ? "Banned by an operator." : banReason;
|
||||
}
|
||||
|
||||
protected UserListEntryBan(T valueIn, JsonObject json)
|
||||
{
|
||||
super(valueIn, json);
|
||||
Date date;
|
||||
|
||||
try
|
||||
{
|
||||
date = json.has("created") ? DATE_FORMAT.parse(json.get("created").getAsString()) : new Date();
|
||||
}
|
||||
catch (ParseException var7)
|
||||
{
|
||||
date = new Date();
|
||||
}
|
||||
|
||||
this.banStartDate = date;
|
||||
this.bannedBy = json.has("source") ? json.get("source").getAsString() : "(Unknown)";
|
||||
Date date1;
|
||||
|
||||
try
|
||||
{
|
||||
date1 = json.has("expires") ? DATE_FORMAT.parse(json.get("expires").getAsString()) : null;
|
||||
}
|
||||
catch (ParseException var6)
|
||||
{
|
||||
date1 = null;
|
||||
}
|
||||
|
||||
this.banEndDate = date1;
|
||||
this.reason = json.has("reason") ? json.get("reason").getAsString() : "Banned by an operator.";
|
||||
}
|
||||
|
||||
public Date getBanEndDate()
|
||||
{
|
||||
return this.banEndDate;
|
||||
}
|
||||
|
||||
public String getBanReason()
|
||||
{
|
||||
return this.reason;
|
||||
}
|
||||
|
||||
boolean hasBanExpired()
|
||||
{
|
||||
return this.banEndDate == null ? false : this.banEndDate.before(new Date());
|
||||
}
|
||||
|
||||
protected void onSerialization(JsonObject data)
|
||||
{
|
||||
data.addProperty("created", DATE_FORMAT.format(this.banStartDate));
|
||||
data.addProperty("source", this.bannedBy);
|
||||
data.addProperty("expires", this.banEndDate == null ? "forever" : DATE_FORMAT.format(this.banEndDate));
|
||||
data.addProperty("reason", this.reason);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import java.io.File;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
public class UserListIPBans extends UserList<String, UserListIPBansEntry>
|
||||
{
|
||||
public UserListIPBans(File bansFile)
|
||||
{
|
||||
super(bansFile);
|
||||
}
|
||||
|
||||
protected UserListEntry<String> createEntry(JsonObject entryData)
|
||||
{
|
||||
return new UserListIPBansEntry(entryData);
|
||||
}
|
||||
|
||||
public boolean isBanned(SocketAddress address)
|
||||
{
|
||||
String s = this.addressToString(address);
|
||||
return this.hasEntry(s);
|
||||
}
|
||||
|
||||
public UserListIPBansEntry getBanEntry(SocketAddress address)
|
||||
{
|
||||
String s = this.addressToString(address);
|
||||
return (UserListIPBansEntry)this.getEntry(s);
|
||||
}
|
||||
|
||||
private String addressToString(SocketAddress address)
|
||||
{
|
||||
String s = address.toString();
|
||||
|
||||
if (s.contains("/"))
|
||||
{
|
||||
s = s.substring(s.indexOf(47) + 1);
|
||||
}
|
||||
|
||||
if (s.contains(":"))
|
||||
{
|
||||
s = s.substring(0, s.indexOf(58));
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import java.util.Date;
|
||||
|
||||
public class UserListIPBansEntry extends UserListEntryBan<String>
|
||||
{
|
||||
public UserListIPBansEntry(String valueIn)
|
||||
{
|
||||
this(valueIn, (Date)null, (String)null, (Date)null, (String)null);
|
||||
}
|
||||
|
||||
public UserListIPBansEntry(String valueIn, Date startDate, String banner, Date endDate, String banReason)
|
||||
{
|
||||
super(valueIn, startDate, banner, endDate, banReason);
|
||||
}
|
||||
|
||||
public UserListIPBansEntry(JsonObject json)
|
||||
{
|
||||
super(getIPFromJson(json), json);
|
||||
}
|
||||
|
||||
private static String getIPFromJson(JsonObject json)
|
||||
{
|
||||
return json.has("ip") ? json.get("ip").getAsString() : null;
|
||||
}
|
||||
|
||||
protected void onSerialization(JsonObject data)
|
||||
{
|
||||
if (this.getValue() != null)
|
||||
{
|
||||
data.addProperty("ip", (String)this.getValue());
|
||||
super.onSerialization(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import java.io.File;
|
||||
|
||||
public class UserListOps extends UserList<GameProfile, UserListOpsEntry>
|
||||
{
|
||||
public UserListOps(File saveFile)
|
||||
{
|
||||
super(saveFile);
|
||||
}
|
||||
|
||||
protected UserListEntry<GameProfile> createEntry(JsonObject entryData)
|
||||
{
|
||||
return new UserListOpsEntry(entryData);
|
||||
}
|
||||
|
||||
public String[] getKeys()
|
||||
{
|
||||
String[] astring = new String[this.getValues().size()];
|
||||
int i = 0;
|
||||
|
||||
for (UserListOpsEntry userlistopsentry : this.getValues().values())
|
||||
{
|
||||
astring[i++] = ((GameProfile)userlistopsentry.getValue()).getName();
|
||||
}
|
||||
|
||||
return astring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the OP permission level this player has
|
||||
*/
|
||||
public int getPermissionLevel(GameProfile profile)
|
||||
{
|
||||
UserListOpsEntry userlistopsentry = (UserListOpsEntry)this.getEntry(profile);
|
||||
return userlistopsentry != null ? userlistopsentry.getPermissionLevel() : 0;
|
||||
}
|
||||
|
||||
public boolean bypassesPlayerLimit(GameProfile profile)
|
||||
{
|
||||
UserListOpsEntry userlistopsentry = (UserListOpsEntry)this.getEntry(profile);
|
||||
return userlistopsentry != null ? userlistopsentry.bypassesPlayerLimit() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key value for the given object
|
||||
*/
|
||||
protected String getObjectKey(GameProfile obj)
|
||||
{
|
||||
return obj.getId().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the GameProfile of based on the provided username.
|
||||
*/
|
||||
public GameProfile getGameProfileFromName(String username)
|
||||
{
|
||||
for (UserListOpsEntry userlistopsentry : this.getValues().values())
|
||||
{
|
||||
if (username.equalsIgnoreCase(((GameProfile)userlistopsentry.getValue()).getName()))
|
||||
{
|
||||
return (GameProfile)userlistopsentry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UserListOpsEntry extends UserListEntry<GameProfile>
|
||||
{
|
||||
private final int permissionLevel;
|
||||
private final boolean bypassesPlayerLimit;
|
||||
|
||||
public UserListOpsEntry(GameProfile player, int permissionLevelIn, boolean bypassesPlayerLimitIn)
|
||||
{
|
||||
super(player);
|
||||
this.permissionLevel = permissionLevelIn;
|
||||
this.bypassesPlayerLimit = bypassesPlayerLimitIn;
|
||||
}
|
||||
|
||||
public UserListOpsEntry(JsonObject p_i1150_1_)
|
||||
{
|
||||
super(constructProfile(p_i1150_1_), p_i1150_1_);
|
||||
this.permissionLevel = p_i1150_1_.has("level") ? p_i1150_1_.get("level").getAsInt() : 0;
|
||||
this.bypassesPlayerLimit = p_i1150_1_.has("bypassesPlayerLimit") && p_i1150_1_.get("bypassesPlayerLimit").getAsBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the permission level of the user, as defined in the "level" attribute of the ops.json file
|
||||
*/
|
||||
public int getPermissionLevel()
|
||||
{
|
||||
return this.permissionLevel;
|
||||
}
|
||||
|
||||
public boolean bypassesPlayerLimit()
|
||||
{
|
||||
return this.bypassesPlayerLimit;
|
||||
}
|
||||
|
||||
protected void onSerialization(JsonObject data)
|
||||
{
|
||||
if (this.getValue() != null)
|
||||
{
|
||||
data.addProperty("uuid", ((GameProfile)this.getValue()).getId() == null ? "" : ((GameProfile)this.getValue()).getId().toString());
|
||||
data.addProperty("name", ((GameProfile)this.getValue()).getName());
|
||||
super.onSerialization(data);
|
||||
data.addProperty("level", Integer.valueOf(this.permissionLevel));
|
||||
data.addProperty("bypassesPlayerLimit", Boolean.valueOf(this.bypassesPlayerLimit));
|
||||
}
|
||||
}
|
||||
|
||||
private static GameProfile constructProfile(JsonObject p_152643_0_)
|
||||
{
|
||||
if (p_152643_0_.has("uuid") && p_152643_0_.has("name"))
|
||||
{
|
||||
String s = p_152643_0_.get("uuid").getAsString();
|
||||
UUID uuid;
|
||||
|
||||
try
|
||||
{
|
||||
uuid = UUID.fromString(s);
|
||||
}
|
||||
catch (Throwable var4)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GameProfile(uuid, p_152643_0_.get("name").getAsString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import java.io.File;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class UserListWhitelist extends UserList<GameProfile, UserListWhitelistEntry>
|
||||
{
|
||||
public UserListWhitelist(File p_i1132_1_)
|
||||
{
|
||||
super(p_i1132_1_);
|
||||
}
|
||||
|
||||
protected UserListEntry<GameProfile> createEntry(JsonObject entryData)
|
||||
{
|
||||
return new UserListWhitelistEntry(entryData);
|
||||
}
|
||||
|
||||
public String[] getKeys()
|
||||
{
|
||||
String[] astring = new String[this.getValues().size()];
|
||||
int i = 0;
|
||||
|
||||
for (UserListWhitelistEntry userlistwhitelistentry : this.getValues().values())
|
||||
{
|
||||
astring[i++] = ((GameProfile)userlistwhitelistentry.getValue()).getName();
|
||||
}
|
||||
|
||||
return astring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the profile is in the whitelist.
|
||||
*/
|
||||
@SideOnly(Side.SERVER)
|
||||
public boolean isWhitelisted(GameProfile profile)
|
||||
{
|
||||
return this.hasEntry(profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the key value for the given object
|
||||
*/
|
||||
protected String getObjectKey(GameProfile obj)
|
||||
{
|
||||
return obj.getId().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a GameProfile entry by its name
|
||||
*/
|
||||
public GameProfile getByName(String profileName)
|
||||
{
|
||||
for (UserListWhitelistEntry userlistwhitelistentry : this.getValues().values())
|
||||
{
|
||||
if (profileName.equalsIgnoreCase(((GameProfile)userlistwhitelistentry.getValue()).getName()))
|
||||
{
|
||||
return (GameProfile)userlistwhitelistentry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UserListWhitelistEntry extends UserListEntry<GameProfile>
|
||||
{
|
||||
public UserListWhitelistEntry(GameProfile profile)
|
||||
{
|
||||
super(profile);
|
||||
}
|
||||
|
||||
public UserListWhitelistEntry(JsonObject json)
|
||||
{
|
||||
super(gameProfileFromJsonObject(json), json);
|
||||
}
|
||||
|
||||
protected void onSerialization(JsonObject data)
|
||||
{
|
||||
if (this.getValue() != null)
|
||||
{
|
||||
data.addProperty("uuid", ((GameProfile)this.getValue()).getId() == null ? "" : ((GameProfile)this.getValue()).getId().toString());
|
||||
data.addProperty("name", ((GameProfile)this.getValue()).getName());
|
||||
super.onSerialization(data);
|
||||
}
|
||||
}
|
||||
|
||||
private static GameProfile gameProfileFromJsonObject(JsonObject json)
|
||||
{
|
||||
if (json.has("uuid") && json.has("name"))
|
||||
{
|
||||
String s = json.get("uuid").getAsString();
|
||||
UUID uuid;
|
||||
|
||||
try
|
||||
{
|
||||
uuid = UUID.fromString(s);
|
||||
}
|
||||
catch (Throwable var4)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GameProfile(uuid, json.get("name").getAsString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Auto generated package-info by MCP
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraft.server.management;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -0,0 +1,70 @@
|
||||
package net.minecraft.server.network;
|
||||
|
||||
import net.minecraft.network.EnumConnectionState;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.handshake.INetHandlerHandshakeServer;
|
||||
import net.minecraft.network.handshake.client.C00Handshake;
|
||||
import net.minecraft.network.login.server.SPacketDisconnect;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
|
||||
public class NetHandlerHandshakeTCP implements INetHandlerHandshakeServer
|
||||
{
|
||||
private final MinecraftServer server;
|
||||
private final NetworkManager networkManager;
|
||||
|
||||
public NetHandlerHandshakeTCP(MinecraftServer serverIn, NetworkManager netManager)
|
||||
{
|
||||
this.server = serverIn;
|
||||
this.networkManager = netManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* There are two recognized intentions for initiating a handshake: logging in and acquiring server status. The
|
||||
* NetworkManager's protocol will be reconfigured according to the specified intention, although a login-intention
|
||||
* must pass a versioncheck or receive a disconnect otherwise
|
||||
*/
|
||||
public void processHandshake(C00Handshake packetIn)
|
||||
{
|
||||
if (!net.minecraftforge.fml.common.FMLCommonHandler.instance().handleServerHandshake(packetIn, this.networkManager)) return;
|
||||
|
||||
switch (packetIn.getRequestedState())
|
||||
{
|
||||
case LOGIN:
|
||||
this.networkManager.setConnectionState(EnumConnectionState.LOGIN);
|
||||
|
||||
if (packetIn.getProtocolVersion() > 340)
|
||||
{
|
||||
ITextComponent itextcomponent = new TextComponentTranslation("multiplayer.disconnect.outdated_server", new Object[] {"1.12.2"});
|
||||
this.networkManager.sendPacket(new SPacketDisconnect(itextcomponent));
|
||||
this.networkManager.closeChannel(itextcomponent);
|
||||
}
|
||||
else if (packetIn.getProtocolVersion() < 340)
|
||||
{
|
||||
ITextComponent itextcomponent1 = new TextComponentTranslation("multiplayer.disconnect.outdated_client", new Object[] {"1.12.2"});
|
||||
this.networkManager.sendPacket(new SPacketDisconnect(itextcomponent1));
|
||||
this.networkManager.closeChannel(itextcomponent1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.networkManager.setNetHandler(new NetHandlerLoginServer(this.server, this.networkManager));
|
||||
}
|
||||
|
||||
break;
|
||||
case STATUS:
|
||||
this.networkManager.setConnectionState(EnumConnectionState.STATUS);
|
||||
this.networkManager.setNetHandler(new NetHandlerStatusServer(this.server, this.networkManager));
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Invalid intention " + packetIn.getRequestedState());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when disconnecting, the parameter is a ChatComponent describing the reason for termination
|
||||
*/
|
||||
public void onDisconnect(ITextComponent reason)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
package net.minecraft.server.network;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.PrivateKey;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.crypto.SecretKey;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.login.INetHandlerLoginServer;
|
||||
import net.minecraft.network.login.client.CPacketEncryptionResponse;
|
||||
import net.minecraft.network.login.client.CPacketLoginStart;
|
||||
import net.minecraft.network.login.server.SPacketDisconnect;
|
||||
import net.minecraft.network.login.server.SPacketEnableCompression;
|
||||
import net.minecraft.network.login.server.SPacketEncryptionRequest;
|
||||
import net.minecraft.network.login.server.SPacketLoginSuccess;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.CryptManager;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class NetHandlerLoginServer implements INetHandlerLoginServer, ITickable
|
||||
{
|
||||
private static final AtomicInteger AUTHENTICATOR_THREAD_ID = new AtomicInteger(0);
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Random RANDOM = new Random();
|
||||
private final byte[] verifyToken = new byte[4];
|
||||
private final MinecraftServer server;
|
||||
public final NetworkManager networkManager;
|
||||
private NetHandlerLoginServer.LoginState currentLoginState = NetHandlerLoginServer.LoginState.HELLO;
|
||||
/** How long has player been trying to login into the server. */
|
||||
private int connectionTimer;
|
||||
private GameProfile loginGameProfile;
|
||||
private final String serverId = "";
|
||||
private SecretKey secretKey;
|
||||
private EntityPlayerMP player;
|
||||
|
||||
public NetHandlerLoginServer(MinecraftServer serverIn, NetworkManager networkManagerIn)
|
||||
{
|
||||
this.server = serverIn;
|
||||
this.networkManager = networkManagerIn;
|
||||
RANDOM.nextBytes(this.verifyToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the old updateEntity(), except more generic.
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
if (this.currentLoginState == NetHandlerLoginServer.LoginState.READY_TO_ACCEPT)
|
||||
{
|
||||
this.tryAcceptPlayer();
|
||||
}
|
||||
else if (this.currentLoginState == NetHandlerLoginServer.LoginState.DELAY_ACCEPT)
|
||||
{
|
||||
EntityPlayerMP entityplayermp = this.server.getPlayerList().getPlayerByUUID(this.loginGameProfile.getId());
|
||||
|
||||
if (entityplayermp == null)
|
||||
{
|
||||
this.currentLoginState = NetHandlerLoginServer.LoginState.READY_TO_ACCEPT;
|
||||
net.minecraftforge.fml.common.network.internal.FMLNetworkHandler.fmlServerHandshake(this.server.getPlayerList(), this.networkManager, this.player);
|
||||
this.player = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.connectionTimer++ == 600)
|
||||
{
|
||||
this.disconnect(new TextComponentTranslation("multiplayer.disconnect.slow_login", new Object[0]));
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnect(ITextComponent reason)
|
||||
{
|
||||
try
|
||||
{
|
||||
LOGGER.info("Disconnecting {}: {}", this.getConnectionInfo(), reason.getUnformattedText());
|
||||
this.networkManager.sendPacket(new SPacketDisconnect(reason));
|
||||
this.networkManager.closeChannel(reason);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LOGGER.error("Error whilst disconnecting player", (Throwable)exception);
|
||||
}
|
||||
}
|
||||
|
||||
public void tryAcceptPlayer()
|
||||
{
|
||||
if (!this.loginGameProfile.isComplete())
|
||||
{
|
||||
this.loginGameProfile = this.getOfflineProfile(this.loginGameProfile);
|
||||
}
|
||||
|
||||
String s = this.server.getPlayerList().allowUserToConnect(this.networkManager.getRemoteAddress(), this.loginGameProfile);
|
||||
|
||||
if (s != null)
|
||||
{
|
||||
this.disconnect(new TextComponentTranslation(s, new Object[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.currentLoginState = NetHandlerLoginServer.LoginState.ACCEPTED;
|
||||
|
||||
if (this.server.getNetworkCompressionThreshold() >= 0 && !this.networkManager.isLocalChannel())
|
||||
{
|
||||
this.networkManager.sendPacket(new SPacketEnableCompression(this.server.getNetworkCompressionThreshold()), new ChannelFutureListener()
|
||||
{
|
||||
public void operationComplete(ChannelFuture p_operationComplete_1_) throws Exception
|
||||
{
|
||||
NetHandlerLoginServer.this.networkManager.setCompressionThreshold(NetHandlerLoginServer.this.server.getNetworkCompressionThreshold());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.networkManager.sendPacket(new SPacketLoginSuccess(this.loginGameProfile));
|
||||
EntityPlayerMP entityplayermp = this.server.getPlayerList().getPlayerByUUID(this.loginGameProfile.getId());
|
||||
|
||||
if (entityplayermp != null)
|
||||
{
|
||||
this.currentLoginState = NetHandlerLoginServer.LoginState.DELAY_ACCEPT;
|
||||
this.player = this.server.getPlayerList().createPlayerForUser(this.loginGameProfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
net.minecraftforge.fml.common.network.internal.FMLNetworkHandler.fmlServerHandshake(this.server.getPlayerList(), this.networkManager, this.server.getPlayerList().createPlayerForUser(this.loginGameProfile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when disconnecting, the parameter is a ChatComponent describing the reason for termination
|
||||
*/
|
||||
public void onDisconnect(ITextComponent reason)
|
||||
{
|
||||
LOGGER.info("{} lost connection: {}", this.getConnectionInfo(), reason.getUnformattedText());
|
||||
}
|
||||
|
||||
public String getConnectionInfo()
|
||||
{
|
||||
return this.loginGameProfile != null ? this.loginGameProfile + " (" + this.networkManager.getRemoteAddress() + ")" : String.valueOf((Object)this.networkManager.getRemoteAddress());
|
||||
}
|
||||
|
||||
public void processLoginStart(CPacketLoginStart packetIn)
|
||||
{
|
||||
Validate.validState(this.currentLoginState == NetHandlerLoginServer.LoginState.HELLO, "Unexpected hello packet");
|
||||
this.loginGameProfile = packetIn.getProfile();
|
||||
|
||||
if (this.server.isServerInOnlineMode() && !this.networkManager.isLocalChannel())
|
||||
{
|
||||
this.currentLoginState = NetHandlerLoginServer.LoginState.KEY;
|
||||
this.networkManager.sendPacket(new SPacketEncryptionRequest("", this.server.getKeyPair().getPublic(), this.verifyToken));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.currentLoginState = NetHandlerLoginServer.LoginState.READY_TO_ACCEPT;
|
||||
}
|
||||
}
|
||||
|
||||
public void processEncryptionResponse(CPacketEncryptionResponse packetIn)
|
||||
{
|
||||
Validate.validState(this.currentLoginState == NetHandlerLoginServer.LoginState.KEY, "Unexpected key packet");
|
||||
PrivateKey privatekey = this.server.getKeyPair().getPrivate();
|
||||
|
||||
if (!Arrays.equals(this.verifyToken, packetIn.getVerifyToken(privatekey)))
|
||||
{
|
||||
throw new IllegalStateException("Invalid nonce!");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.secretKey = packetIn.getSecretKey(privatekey);
|
||||
this.currentLoginState = NetHandlerLoginServer.LoginState.AUTHENTICATING;
|
||||
this.networkManager.enableEncryption(this.secretKey);
|
||||
(new Thread(net.minecraftforge.fml.common.thread.SidedThreadGroups.SERVER, "User Authenticator #" + AUTHENTICATOR_THREAD_ID.incrementAndGet())
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
GameProfile gameprofile = NetHandlerLoginServer.this.loginGameProfile;
|
||||
|
||||
try
|
||||
{
|
||||
String s = (new BigInteger(CryptManager.getServerIdHash("", NetHandlerLoginServer.this.server.getKeyPair().getPublic(), NetHandlerLoginServer.this.secretKey))).toString(16);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
catch (AuthenticationUnavailableException var3)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
NetHandlerLoginServer.this.disconnect(new TextComponentTranslation("multiplayer.disconnect.authservers_down", new Object[0]));
|
||||
NetHandlerLoginServer.LOGGER.error("Couldn't verify username because servers are unavailable");
|
||||
}
|
||||
}
|
||||
}
|
||||
@Nullable
|
||||
private InetAddress getAddress()
|
||||
{
|
||||
SocketAddress socketaddress = NetHandlerLoginServer.this.networkManager.getRemoteAddress();
|
||||
return NetHandlerLoginServer.this.server.getPreventProxyConnections() && socketaddress instanceof InetSocketAddress ? ((InetSocketAddress)socketaddress).getAddress() : null;
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
protected GameProfile getOfflineProfile(GameProfile original)
|
||||
{
|
||||
UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + original.getName()).getBytes(StandardCharsets.UTF_8));
|
||||
return new GameProfile(uuid, original.getName());
|
||||
}
|
||||
|
||||
static enum LoginState
|
||||
{
|
||||
HELLO,
|
||||
KEY,
|
||||
AUTHENTICATING,
|
||||
READY_TO_ACCEPT,
|
||||
DELAY_ACCEPT,
|
||||
ACCEPTED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package net.minecraft.server.network;
|
||||
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.status.INetHandlerStatusServer;
|
||||
import net.minecraft.network.status.client.CPacketPing;
|
||||
import net.minecraft.network.status.client.CPacketServerQuery;
|
||||
import net.minecraft.network.status.server.SPacketPong;
|
||||
import net.minecraft.network.status.server.SPacketServerInfo;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
|
||||
public class NetHandlerStatusServer implements INetHandlerStatusServer
|
||||
{
|
||||
private static final ITextComponent EXIT_MESSAGE = new TextComponentString("Status request has been handled.");
|
||||
private final MinecraftServer server;
|
||||
private final NetworkManager networkManager;
|
||||
private boolean handled;
|
||||
|
||||
public NetHandlerStatusServer(MinecraftServer serverIn, NetworkManager netManager)
|
||||
{
|
||||
this.server = serverIn;
|
||||
this.networkManager = netManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when disconnecting, the parameter is a ChatComponent describing the reason for termination
|
||||
*/
|
||||
public void onDisconnect(ITextComponent reason)
|
||||
{
|
||||
}
|
||||
|
||||
public void processServerQuery(CPacketServerQuery packetIn)
|
||||
{
|
||||
if (this.handled)
|
||||
{
|
||||
this.networkManager.closeChannel(EXIT_MESSAGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.handled = true;
|
||||
this.networkManager.sendPacket(new SPacketServerInfo(this.server.getServerStatusResponse()));
|
||||
}
|
||||
}
|
||||
|
||||
public void processPing(CPacketPing packetIn)
|
||||
{
|
||||
this.networkManager.sendPacket(new SPacketPong(packetIn.getClientTime()));
|
||||
this.networkManager.closeChannel(EXIT_MESSAGE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Auto generated package-info by MCP
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraft.server.network;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
@@ -0,0 +1,7 @@
|
||||
// Auto generated package-info by MCP
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
package net.minecraft.server;
|
||||
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
Reference in New Issue
Block a user