add server

This commit is contained in:
Sen 2025-05-01 15:13:38 +02:00
parent d5269922b9
commit 76ecfb39ab
25 changed files with 603 additions and 520 deletions

View file

@ -1,34 +1,25 @@
package game;
import java.awt.Desktop;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.net.IDN;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.ArrayDeque;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
@ -40,8 +31,6 @@ import java.util.concurrent.FutureTask;
import java.util.function.Function;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
@ -92,7 +81,6 @@ import game.item.ItemStack;
import game.log.Log;
import game.log.LogLevel;
import game.log.Message;
import game.log.NettyLogger;
import game.material.Material;
import game.model.ModelManager;
import game.network.IThreadListener;
@ -167,7 +155,6 @@ import game.world.Region;
import game.world.State;
import game.world.World;
import game.world.WorldClient;
import game.world.WorldServer;
/*
Een net ganz funktionierndes Programm ...
@ -409,8 +396,7 @@ public class Game implements IThreadListener {
@Variable(name = "srv_port", category = CVarCategory.SYSTEM, min = 0, max = 65535, display = "Standard Hosting-Port")
public int port = Config.PORT;
public int bind = -1;
@Variable(name = "snd_enabled", category = CVarCategory.SOUND, display = "Tonausgabe")
public boolean soundEnabled = true;
@Variable(name = "snd_buffer_size", category = CVarCategory.SOUND, min = 0, max = 1048576, display = "Puffergröße")
@ -418,12 +404,13 @@ public class Game implements IThreadListener {
@Variable(name = "snd_frame_size", category = CVarCategory.SOUND, min = 2, max = 8192, display = "PCM-Intervall")
public int soundFrameSize = 32;
private Server server;
private ServerProcess server;
private String serverInfo;
private int lastServerTick;
private AudioInterface audio;
private long start;
private boolean cfgDirty;
private String buffer = "";
private boolean crashed;
private boolean waitingForFile;
private boolean refreshing;
@ -450,20 +437,20 @@ public class Game implements IThreadListener {
return INSTANCE;
}
public void connect(String address, int port, String user, String pass, String access) {
Log.JNI.info("Verbinde zu " + address + ":" + port);
public void connect(String address, int port, String user, String pass, String access, byte[] local) {
Log.JNI.info("Verbinde zu " + (address == null ? "localhost" : address) + ":" + port);
NetConnection connection = null;
try
{
connection = NetConnection.createNetworkManagerAndConnect(InetAddress.getByName(IDN.toASCII(address)), port);
connection = NetConnection.createNetworkManagerAndConnect(address == null ? InetAddress.getLoopbackAddress() : InetAddress.getByName(IDN.toASCII(address)), port);
connection.setNetHandler(new ClientLoginHandler(connection, this));
connection.sendPacket(new HPacketHandshake(Config.PROTOCOL));
connection.sendPacket(new LPacketPasswordResponse(user, access, pass));
connection.sendPacket(new LPacketPasswordResponse(user, access, pass, local));
}
catch (UnknownHostException u)
{
Log.JNI.error(u, "Konnte nicht zu Server verbinden");
this.disconnected("Unbekannter Hostname: " + address);
this.disconnected("Unbekannter Hostname: " + (address == null ? "localhost" : address));
return;
}
catch (Exception e)
@ -475,17 +462,6 @@ public class Game implements IThreadListener {
this.connection = connection;
}
public void connectToIntegrated(Server server, String user) {
this.debugWorld = server.getFolder() == null;
// this.displayGuiScreen(null);
SocketAddress socket = server.setLocalEndpoint();
NetConnection connection = NetConnection.provideLocalClient(socket);
connection.setNetHandler(new ClientLoginHandler(connection, this));
connection.sendPacket(new HPacketHandshake(Config.PROTOCOL));
connection.sendPacket(new LPacketPasswordResponse(user, "", ""));
this.connection = connection;
}
public void unloadWorld() {
ClientPlayer netHandler = this.getNetHandler();
if(netHandler != null)
@ -496,6 +472,7 @@ public class Game implements IThreadListener {
this.connection = null;
this.theWorld = null;
this.thePlayer = null;
this.serverInfo = null;
this.soundManager.stopSounds();
}
@ -1013,7 +990,7 @@ public class Game implements IThreadListener {
int y1 = 0;
int y2 = this.fb_y;
// int pos = 0;
String str = this.getLeft(this.server);
String str = this.getLeft();
// if(jstr)
// str = (*jsys.env)->GetStringUTFChars(jsys.env, jstr, NULL);
// elem->r_dirty = 1;
@ -1624,8 +1601,14 @@ public class Game implements IThreadListener {
return this.itemRenderer;
}
public void setTicked() {
public void setTicked(String info) {
this.lastTicked = System.currentTimeMillis();
this.serverInfo = info;
}
public void setLastTick(int tick) {
this.lastTicked = System.currentTimeMillis();
this.lastServerTick = tick;
}
public void updatePlayerMoveState()
@ -1664,7 +1647,7 @@ public class Game implements IThreadListener {
}
}
public String getLeft(Server server) {
public String getLeft() {
long maxMem = Runtime.getRuntime().maxMemory();
long totalMem = Runtime.getRuntime().totalMemory();
long freeMem = Runtime.getRuntime().freeMemory();
@ -1767,13 +1750,8 @@ public class Game implements IThreadListener {
) + "\n" +
String.format("Letzte Zeitsynch.: + %d.%d s",
ticked / 1000L, (ticked / 100L) % 10L
) + "\n" +
(server != null ?
String.format("Server: %.3f T/s (%.1fx), Z: %.1f T/s, D: %.3f ms", server.getTpsRate(),
server.getTpsRate() / 20.0f,
server.getTpsTarget(), server.getAverageTps()) : "Server: <remote>") + "\n" +
(server != null ? "Geladen: " + server.getWorlds().size() + " Welten, " + WorldServer.getLoadedInfo(server) :
"Geladen: <?>")
) +
(this.serverInfo != null ? "\n" + this.serverInfo : "")
// WorldServer world = this.server.getWorld(this.theWorld.dimension.getDimensionId());
// if(world != null)
// list.add("Seed: " + world.getSeed());
@ -2100,7 +2078,7 @@ public class Game implements IThreadListener {
return;
this.frameWait = 50000000L - ((n - (this.frameLast + this.frameWait)) < 50000000L ? (n - (this.frameLast + this.frameWait)) : 0L);
this.frameLast = n;
this.tickTimes[this.tickIndex++] = this.server != null ? (int)this.server.getLastTick() : 0;
this.tickTimes[this.tickIndex++] = this.lastServerTick;
if(this.tickIndex == 240) {
this.tickIndex = 0;
}
@ -2369,11 +2347,13 @@ public class Game implements IThreadListener {
public void unload(boolean loading) {
if(this.theWorld != null) {
if(server != null)
this.performAction(Action.SHUTDOWN);
if(server == null && this.getNetHandler() != null)
this.getNetHandler().getNetworkManager().closeChannel("Quitting");
this.unloadWorld();
if(server != null)
server.shutdown();
// if(server != null)
// server.shutdown();
}
if(server != null) {
if(loading) {
@ -2396,9 +2376,11 @@ public class Game implements IThreadListener {
}
public void startServer(File dir, String user) {
server = new Server(dir);
byte[] key = new byte[256];
new SecureRandom().nextBytes(key);
server = new ServerProcess(dir, 1024, 4096, this.port, this.renderDistance, key);
server.start();
this.displayGuiScreen(GuiLoading.makeLoadTask(server, user));
this.displayGuiScreen(GuiLoading.makeLoadTask(server, user, key));
// while(server != null && !server.isStarted()) {
// try {
// Thread.sleep(10L);
@ -2450,17 +2432,12 @@ public class Game implements IThreadListener {
public double ftime() {
return ((double)rtime()) / 1000000.0;
}
public void bind(int port) {
if(server != null)
server.bind(port);
}
public void distance(int distance) {
if(this.renderGlobal != null)
this.renderGlobal.setDisplayListEntitiesDirty();
if(this.server != null)
this.server.setVar("viewDistance", "" + distance);
if(this.server != null && this.thePlayer != null)
this.thePlayer.sendQueue.addToSendQueue(new CPacketAction(Action.SET_VIEWDIST, distance));
}
private void registerDebug(Keysym key, String help, DebugRunner runner) {
@ -2575,13 +2552,7 @@ public class Game implements IThreadListener {
});
this.registerDebug(Keysym.W, "Server-Tick-Limit umschalten (Welt beschleunigen / Warpmodus)", new DebugRunner() {
public void execute(Keysym key) {
if(server != null) {
server.schedule(new Runnable() {
public void run() {
server.setTpsTarget(server.getTpsTarget() < 10000.0f ? 10000.0f : 20.0f);
}
});
}
Game.this.performAction(Action.WARP_MODE);
}
});
this.registerDebug(Keysym.M, "Alle Gegenstände herbei ziehen (Magnetmodus)", new DebugRunner() {
@ -2662,116 +2633,9 @@ public class Game implements IThreadListener {
public static void main(String[] args) {
if(System.getProperty("os.name").startsWith("Windows") || System.getProperty("os.name").startsWith("Mac")) {
String info = "Inkompatibles Betriebssystem";
String msg = "Linux oder *BSD ist erforderlich, um dieses Programm auszuführen.\n" +
"Alle Versionen von Windows und Mac OS (X) sind nicht kompatibel.";
System.err.println("#################################################################");
System.err.println("*** " + info + " ***");
System.err.println(msg);
System.err.println("#################################################################");
if(!GraphicsEnvironment.isHeadless())
JOptionPane.showMessageDialog(null, msg, info, JOptionPane.ERROR_MESSAGE);
return;
}
Util.checkOs();
Window.init();
Locale.setDefault(Locale.ROOT);
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable e) {
System.err.println("Fehler in Thread '" + thread.getName() + "'");
e.printStackTrace(System.err);
if(INSTANCE.crashed)
System.exit(1);
if(e instanceof OutOfMemoryError) {
System.gc();
System.gc();
}
if(!thread.getName().startsWith("Thread-") || e instanceof OutOfMemoryError) {
System.err.println("Beende!");
INSTANCE.crashed = true;
if(System.getProperty("crash.nodump") == null) {
PrintStream ps = null;
File report = null;
try {
Date date = new Date();
File file = new File("crash-" + new SimpleDateFormat("dd.MM.yyyy_HH.mm.ss").format(date) + ".txt");
FileOutputStream out = new FileOutputStream(file);
ps = new PrintStream(out);
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] info = bean.dumpAllThreads(true, true);
StringBuilder sb = new StringBuilder();
Error error = new Error();
for(ThreadInfo threadinfo : info) {
if(threadinfo.getThreadId() == thread.getId())
error.setStackTrace(threadinfo.getStackTrace());
sb.append(threadinfo);
}
ps.println("************************************************ " + new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(date) + " ************************************************");
ps.println();
ps.println("\"Wie haste das denn nu wieder geschafft, Bursche?\"");
ps.println("Unerwarteter Fehler in Thread '" + thread.getName() + "':");
e.printStackTrace(ps);
ps.println();
ps.println("---------------------------------------------- Thread-Dump (" + info.length + " Threads) ---------------------------------------------");
ps.println();
ps.print(sb.toString());
ps.println("*********************************************************************************************************************");
report = file;
}
catch(Throwable t) {
System.err.println("Konnte Absturzbericht nicht speichern:");
t.printStackTrace(System.err);
}
finally {
if(ps != null)
ps.close();
}
if(report != null) {
System.err.println("Absturzbericht gespeichert unter " + report.getPath());
try {
Desktop.getDesktop().browse(report.toURI());
}
catch(Throwable e1) {
System.err.println("Konnte " + report + " nicht öffnen: " + e1);
}
}
}
System.exit(1);
}
}
});
ImageIO.setUseCache(false);
Thread timer = new Thread("Timer Hack Thread") {
public void run() {
while(true) {
try {
Thread.sleep(2147483647L);
}
catch(InterruptedException e) {
;
}
}
}
};
timer.setDaemon(true);
timer.start();
System.setProperty("java.net.preferIPv4Stack", "true");
NettyLogger.init();
Registry.register();
// game = new Game();
Runtime.getRuntime().addShutdownHook(new Thread("Game Shutdown Thread") {
public void run() {
if(!INSTANCE.crashed && INSTANCE.server != null) {
try {
INSTANCE.server.stopServer();
}
catch(Throwable e) {
e.printStackTrace();
}
}
}
});
Thread.currentThread().setName("Render thread");
Registry.setup("Render thread");
INSTANCE.run();
Window.end();
}

View file

@ -3,7 +3,6 @@ package game;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
@ -32,6 +31,7 @@ import game.entity.npc.EntityHuman;
import game.entity.npc.EntityNPC;
import game.init.Config;
import game.init.EntityRegistry;
import game.init.Registry;
import game.init.UniverseRegistry;
import game.log.Log;
import game.nbt.NBTLoader;
@ -41,8 +41,7 @@ import game.network.IThreadListener;
import game.network.LazyLoadBase;
import game.network.NetConnection;
import game.network.NetHandler.ThreadQuickExitException;
import game.network.HandshakeHandlerMemory;
import game.network.HandshakeHandlerTCP;
import game.network.HandshakeHandler;
import game.network.Player;
import game.network.Packet;
import game.network.PacketDecoder;
@ -65,6 +64,7 @@ import game.packet.SPacketTimeUpdate;
import game.packet.SPacketWorld;
import game.potion.PotionEffect;
import game.util.ExtMath;
import game.util.Util;
import game.world.BlockPos;
import game.world.PortalType;
import game.world.Position;
@ -81,23 +81,20 @@ import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.local.LocalAddress;
import io.netty.channel.local.LocalServerChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
public final class Server implements Runnable, IThreadListener {
public final class Server implements IThreadListener {
private static final LazyLoadBase<NioEventLoopGroup> SERVER_NIO_EVENTLOOP = new LazyLoadBase<NioEventLoopGroup>() {
protected NioEventLoopGroup load() {
return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).build());
}
};
private final Thread serverThread;
private final Thread serverThread = Thread.currentThread();
private final List<NetConnection> clients = Collections.<NetConnection>synchronizedList(Lists.<NetConnection>newArrayList());
private final List<Player> players = Lists.<Player>newArrayList();
private final Map<String, Player> usermap = Maps.<String, Player>newHashMap();
@ -109,17 +106,11 @@ public final class Server implements Runnable, IThreadListener {
private final List<Dimension> unload = Lists.<Dimension>newArrayList();
private final Map<String, Position> warps = Maps.<String, Position>newTreeMap();
private final CommandEnvironment scriptEnv = new CommandEnvironment(this);
// private final String owner;
private final File playerDir;
private final File baseDir;
// private final int port;
private final boolean debug;
private WorldServer space;
private ChannelFuture endpoint;
private ChannelFuture localEndpoint;
private String localUser;
private String message;
private boolean running = true;
private boolean stopped;
@ -140,28 +131,29 @@ public final class Server implements Runnable, IThreadListener {
private int pingTimer;
private int syncTimer;
private int perfTimer;
private int progress = -1;
private int total = 0;
public static void main(String[] args) {
Util.checkOs();
Registry.setup("Server thread");
final Server server = new Server(false);
Registry.addShutdownHook(new Runnable() {
public void run() {
server.stopServer();
}
});
server.run();
}
Server(File dir) {
// this.owner = owner;
this.serverThread = new Thread(this, "Server thread");
this.baseDir = dir; // dir != null ? new File(dir) : null;
this.playerDir = new File(this.baseDir, "players");
this.debug = this.baseDir == null;
// this.port = port;
private Server(boolean debug) {
this.debug = debug;
}
public CommandEnvironment getScriptEnvironment() {
return this.scriptEnv;
}
public boolean isStarted() {
return this.started;
}
public String[] getUsers() {
String[] list = this.debug ? null : this.playerDir.list();
String[] list = this.debug ? null : new File("players").list();
if(list == null) {
list = new String[0];
}
@ -182,8 +174,8 @@ public final class Server implements Runnable, IThreadListener {
public void saveWorldInfo() {
if(!this.debug) {
Region.saveWorldInfo(this.baseDir, this.space.getDayTime(), this.localUser);
WorldServer.saveWarps(this.baseDir, this.warps);
Region.saveWorldInfo(null, this.space.getDayTime(), this.localUser);
WorldServer.saveWarps(this.warps);
}
}
@ -192,7 +184,7 @@ public final class Server implements Runnable, IThreadListener {
return null;
NBTTagCompound tag = null;
try {
File dat = new File(this.playerDir, user + ".nbt");
File dat = new File(new File("players"), user + ".nbt");
if(dat.exists() && dat.isFile()) {
tag = NBTLoader.readGZip(dat);
@ -235,7 +227,7 @@ public final class Server implements Runnable, IThreadListener {
private void startProgress(boolean save, int amount) {
this.setTotal(amount);
this.setProgress(0);
Log.JNI.info((save ? "Speichere" : "Generiere und lade") + " Level " + (this.baseDir == null ? "." : this.baseDir.getName()));
Log.JNI.info((save ? "Speichere" : "Generiere und lade") + " Welt");
}
public void unloadWorld(WorldServer world) {
@ -258,15 +250,15 @@ public final class Server implements Runnable, IThreadListener {
Log.JNI.info("Starte Server Version " + Config.VERSION);
if(!this.debug) {
this.setMessage("Welt wird erstellt und geladen");
FolderInfo info = Region.loadWorldInfo(this.baseDir);
FolderInfo info = Region.loadWorldInfo(null);
// if(dtime == -1L) // {
// dtime = World.START_TIME;
//// Config.set("spawnDim", "1", null);
//// }
this.worlds.add(this.space = new WorldServer(this, this.baseDir, info == null ? World.START_TIME : info.time,
this.worlds.add(this.space = new WorldServer(this, info == null ? World.START_TIME : info.time,
Space.INSTANCE, false));
this.dimensions.put(this.space.dimension.getDimensionId(), this.space);
this.playerDir.mkdirs();
new File("players").mkdirs();
// if(Config.spawnY < 0) {
// WorldServer world = this.getWorld(Config.spawnDim);
// world = world == null ? this.space : world;
@ -297,17 +289,17 @@ public final class Server implements Runnable, IThreadListener {
Config.set("weatherChanges", "false", null);
Config.set("mobSpawning", "false", null);
Config.set("spawnRadius", "0", null);
this.worlds.add(this.space = new WorldServer(this, null, World.START_TIME,
this.worlds.add(this.space = new WorldServer(this, World.START_TIME,
Space.INSTANCE, true));
this.dimensions.put(this.space.dimension.getDimensionId(), this.space);
}
this.setTpsTarget(20.0f);
if(!this.debug) {
for(Dimension dim : UniverseRegistry.getDimensions()) {
if(WorldServer.needsLoading(this.baseDir, dim)) {
if(WorldServer.needsLoading(dim)) {
this.getWorld(dim.getDimensionId()).loadForcedChunks();
}
WorldServer.loadWarps(this.baseDir, dim, this.warps);
WorldServer.loadWarps(dim, this.warps);
}
// this.openLAN();
}
@ -339,17 +331,22 @@ public final class Server implements Runnable, IThreadListener {
this.lastPoll = this.currentTime;
this.ticksDone = 0L;
}
this.started = true;
if(!this.started) {
this.started = true;
this.sendPipeIPC("running", true);
}
}
try {
this.stopServer();
this.stopped = true;
this.sendPipeIPC("running", false);
}
catch(Throwable e) {
Log.JNI.error(e, "Fehler beim Beenden des Servers");
}
finally {
this.stopped = true;
this.sendPipeIPC("running", false);
Log.JNI.info("Server wurde beendet");
}
}
@ -365,8 +362,8 @@ public final class Server implements Runnable, IThreadListener {
bx = bx >> 4;
bz = bz >> 4;
long last = System.currentTimeMillis();
for(int x = -Config.distance; x <= Config.distance && this.running; x++) {
for(int z = -Config.distance; z <= Config.distance && this.running; z++) {
for(int x = -Config.distance; x <= Config.distance; x++) {
for(int z = -Config.distance; z <= Config.distance; z++) {
long time = System.currentTimeMillis();
if(time - last >= 10L) {
this.setProgress(done);
@ -436,7 +433,7 @@ public final class Server implements Runnable, IThreadListener {
}
}
if(++this.syncTimer == 20) {
this.sendPacket(new SPacketTimeUpdate(this.space.getDayTime()));
this.sendPacket(new SPacketTimeUpdate(this.space.getDayTime(), this.getInfo()));
this.syncTimer = 0;
}
this.ticked.clear();
@ -477,7 +474,7 @@ public final class Server implements Runnable, IThreadListener {
Dimension dim = UniverseRegistry.getDimension(dimension);
if(dim == null)
return null;
world = new WorldServer(this, this.baseDir, this.space.getDayTime(),
world = new WorldServer(this, this.space.getDayTime(),
dim, this.debug);
this.worlds.add(world);
this.dimensions.put(dimension, world);
@ -497,11 +494,7 @@ public final class Server implements Runnable, IThreadListener {
public List<WorldServer> getWorlds() {
return this.worlds;
}
public boolean isStopped() {
return this.stopped;
}
public long[] getTickTimes() {
return this.tickTimes;
}
@ -547,41 +540,17 @@ public final class Server implements Runnable, IThreadListener {
public Player getPlayer(String user) {
return this.usermap.get(user);
}
public String getMessage() {
synchronized(this) {
return this.message;
}
}
public int getProgress() {
synchronized(this) {
return this.progress;
}
}
public int getTotal() {
synchronized(this) {
return this.total;
}
}
private void setMessage(String message) {
synchronized(this) {
this.message = message;
}
this.sendPipeIPC("message", message);
}
private void setProgress(int progress) {
synchronized(this) {
this.progress = progress;
}
this.sendPipeIPC("progress", progress);
}
private void setTotal(int total) {
synchronized(this) {
this.total = total;
}
this.sendPipeIPC("total", total);
}
public void setVar(String cv, String value) {
@ -591,11 +560,7 @@ public final class Server implements Runnable, IThreadListener {
}
});
}
public File getFolder() {
return this.baseDir;
}
private <V> ListenableFuture<V> callFromMainThread(Callable<V> callable) {
if(!this.isMainThread() && !this.stopped) {
ListenableFutureTask<V> task = ListenableFutureTask.<V>create(callable);
@ -661,35 +626,33 @@ public final class Server implements Runnable, IThreadListener {
Player conn = new Player(this, connection, loginUser);
if(tag != null)
conn.readFromNBT(tag);
if(!connection.isLocalChannel()) {
if(Config.playerLimit > 0 && this.players.size() >= Config.playerLimit && !conn.getAdmin())
return String.format("Der Server ist voll (%d/%d)!", this.players.size(), Config.playerLimit);
if(Config.auth) {
if(conn.getPassword() == null) {
if(!Config.register)
return "Anmeldung neuer Accounts ist auf diesem Server deaktiviert (Whitelisted)";
if(loginPass.length() == 0)
return "Ein neues Passwort ist erforderlich um diesen Server zu betreten (mindestens 8 Zeichen)";
if(loginPass.length() < 8)
return "Passwort ist zu kurz, mindestens 8 Zeichen";
conn.setPassword(loginPass);
Log.JNI.info(loginUser + " registrierte sich mit Passwort");
}
else if(!conn.getPassword().equals(loginPass)) {
return "Falsches Passwort";
}
else {
Log.JNI.info(loginUser + " loggte sich mit Passwort ein");
}
}
if(Config.compression >= 0) {
connection.sendPacket(new RPacketEnableCompression(Config.compression), new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
connection.setCompressionTreshold(Config.compression);
}
});
}
}
if(Config.playerLimit > 0 && this.players.size() >= Config.playerLimit && !conn.isAdmin())
return String.format("Der Server ist voll (%d/%d)!", this.players.size(), Config.playerLimit);
if(!connection.isLocalChannel() && Config.auth) {
if(conn.getPassword() == null) {
if(!Config.register)
return "Anmeldung neuer Accounts ist auf diesem Server deaktiviert (Whitelisted)";
if(loginPass.length() == 0)
return "Ein neues Passwort ist erforderlich um diesen Server zu betreten (mindestens 8 Zeichen)";
if(loginPass.length() < 8)
return "Passwort ist zu kurz, mindestens 8 Zeichen";
conn.setPassword(loginPass);
Log.JNI.info(loginUser + " registrierte sich mit Passwort");
}
else if(!conn.getPassword().equals(loginPass)) {
return "Falsches Passwort";
}
else {
Log.JNI.info(loginUser + " loggte sich mit Passwort ein");
}
}
if(Config.compression >= 0) {
connection.sendPacket(new RPacketEnableCompression(Config.compression), new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
connection.setCompressionTreshold(Config.compression);
}
});
}
connection.sendPacket(new RPacketLoginSuccess());
connection.setNetHandler(conn);
this.players.add(conn);
@ -766,7 +729,7 @@ public final class Server implements Runnable, IThreadListener {
return null;
NBTTagCompound tag = null;
try {
File dat = new File(this.playerDir, user + ".nbt");
File dat = new File(new File("players"), user + ".nbt");
if(dat.exists() && dat.isFile()) {
tag = NBTLoader.readGZip(dat);
@ -794,8 +757,8 @@ public final class Server implements Runnable, IThreadListener {
// else
// etag = new NBTTagCompound();
conn.writeToNBT(tag);
File tmp = new File(this.playerDir, conn.getUser() + ".nbt.tmp");
File dat = new File(this.playerDir, conn.getUser() + ".nbt");
File tmp = new File(new File("players"), conn.getUser() + ".nbt.tmp");
File dat = new File(new File("players"), conn.getUser() + ".nbt");
NBTLoader.writeGZip(tag, tmp);
if(dat.exists()) {
dat.delete();
@ -1020,7 +983,7 @@ public final class Server implements Runnable, IThreadListener {
}
private void updateTimeAndWeatherForPlayer(Player conn, WorldServer world) {
conn.sendPacket(new SPacketTimeUpdate(world.getDayTime()));
conn.sendPacket(new SPacketTimeUpdate(world.getDayTime(), this.getInfo()));
conn.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.SET_WEATHER, world.getWeather().getID()));
conn.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.RAIN_STRENGTH, world.getRainStrength()));
conn.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.DARKNESS, world.getDarkness()));
@ -1055,41 +1018,21 @@ public final class Server implements Runnable, IThreadListener {
NetConnection manager = new NetConnection();
Server.this.clients.add(manager);
channel.pipeline().addLast((String)"packet_handler", (ChannelHandler)manager);
manager.setNetHandler(new HandshakeHandlerTCP(Server.this, manager));
manager.setNetHandler(new HandshakeHandler(Server.this, manager));
}
}).group(SERVER_NIO_EVENTLOOP.getValue()).localAddress((InetAddress)null, port)).bind().syncUninterruptibly();
}
}
public SocketAddress setLocalEndpoint() {
// ChannelFuture future;
synchronized(this.serverThread) {
if(this.localEndpoint == null) {
// throw new IllegalStateException("Lokaler Eingangspunkt bereits gesetzt");
// }
this.localEndpoint = ((ServerBootstrap)((ServerBootstrap)(new ServerBootstrap()).channel(LocalServerChannel.class)).childHandler(new ChannelInitializer<Channel>() {
protected void initChannel(Channel channel) throws Exception {
NetConnection manager = new NetConnection();
manager.setNetHandler(new HandshakeHandlerMemory(Server.this, manager));
Server.this.clients.add(manager);
channel.pipeline().addLast((String)"packet_handler", (ChannelHandler)manager);
}
}).group((EventLoopGroup)SERVER_NIO_EVENTLOOP.getValue()).localAddress(LocalAddress.ANY)).bind().syncUninterruptibly();
// this.localEndpoint = future;
}
}
return this.localEndpoint.channel().localAddress();
}
private void unsetLanEndpoint() {
for(Player conn : Lists.newArrayList(this.players)) {
if(!conn.isLocal())
conn.disconnect();
}
this.terminateEndpoints(false);
this.terminateEndpoint();
}
private void terminateEndpoints(boolean local) {
private void terminateEndpoint() {
synchronized(this.serverThread) {
if(this.endpoint != null) {
Log.JNI.info("Schließe Port");
@ -1101,15 +1044,6 @@ public final class Server implements Runnable, IThreadListener {
Log.JNI.warn("Unterbrochen beim Schließen des Kanals");
}
}
if(local && this.localEndpoint != null) {
try {
this.localEndpoint.channel().close().sync();
this.localEndpoint = null;
}
catch(InterruptedException e) {
Log.JNI.warn("Unterbrochen beim Schließen des lokalen Kanals");
}
}
}
}
@ -1128,9 +1062,6 @@ public final class Server implements Runnable, IThreadListener {
manager.processReceivedPackets();
}
catch(Exception e) {
if(manager.isLocalChannel()) {
throw e;
}
Log.JNI.error(e, "Konnte Paket von " + manager.getCutAddress() + " nicht verarbeiten");
manager.sendPacket(new SPacketDisconnect(), new GenericFutureListener<Future<? super Void>>() {
public void operationComplete(Future<? super Void> future) throws Exception {
@ -1148,12 +1079,12 @@ public final class Server implements Runnable, IThreadListener {
public Map<String, Position> getWarps() {
return this.warps;
}
public void start() {
this.serverThread.start();
}
//
// public void start() {
// this.serverThread.start();
// }
void stopServer() {
private void stopServer() {
if(!this.stopped) {
this.setProgress(-1);
this.setMessage("Stoppe server");
@ -1162,7 +1093,7 @@ public final class Server implements Runnable, IThreadListener {
for(Player conn : Lists.newArrayList(this.players)) {
conn.disconnect();
}
this.terminateEndpoints(true);
this.terminateEndpoint();
if(this.started) {
Log.JNI.info("Speichere Spieler");
this.saveAllPlayerData(true);
@ -1203,4 +1134,14 @@ public final class Server implements Runnable, IThreadListener {
}));
this.running = false;
}
public String getInfo() {
return String.format("Server: %.3f T/s (%.1fx), Z: %.1f T/s, D: %.3f ms", this.getTpsRate(), this.getTpsRate() / 20.0f, this.getTpsTarget(), this.getAverageTps()) + "\n" +
"Geladen: " + this.getWorlds().size() + " Welten, " + WorldServer.getLoadedInfo(this);
}
private void sendPipeIPC(String key, Object value) {
System.out.println("#" + key + (value == null ? "" : " " + String.valueOf(value)));
System.out.flush();
}
}

View file

@ -0,0 +1,114 @@
package game;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import game.log.Log;
import game.util.Tuple;
import game.util.Util;
public class ServerProcess {
private final ProcessBuilder builder;
private Process process;
private BufferedWriter writer;
private boolean running;
private String message;
private int total;
private int progress = -1;
public ServerProcess(File dir, int minMem, int maxMem, int port, int distance, byte[] key) {
StringBuilder sb = new StringBuilder();
for(int z = 0; z < key.length; z++) {
sb.append(String.format("%02x", key[z] & 255));
}
this.builder = new ProcessBuilder("java", "-Xms", minMem + "M", "-Xmx", maxMem + "M", "-jar", "game.jar", "game.Server",
"-p", "" + port, "-d", "" + distance, "-t", sb.toString()).directory(dir).redirectErrorStream(true);
}
public void start() {
this.builder.directory().mkdirs();
try {
this.process = this.builder.start();
}
catch(IOException e) {
Log.SYSTEM.error(e, "Konnte Server nicht starten");
this.process = null;
}
// this.builder = null;
if(this.process == null)
return;
Thread con = new Thread(new Runnable() {
private final BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(ServerProcess.this.process.getInputStream())));
public void run() {
while(true) {
String line;
try {
line = this.reader.readLine();
}
catch(IOException e) {
line = null;
}
if(line == null)
break;
if(line.startsWith("#")) {
line = line.substring(1);
Tuple<String, String> data = Util.getKeyValue(line);
if(data.first.equals("running"))
ServerProcess.this.running = Boolean.parseBoolean(data.second);
if(data.first.equals("message"))
ServerProcess.this.message = data.second;
if(data.first.equals("total"))
ServerProcess.this.total = Integer.parseInt(data.second);
if(data.first.equals("progress"))
ServerProcess.this.progress = Integer.parseInt(data.second);
continue;
}
Log.SYSTEM.info("==SERVER== %s", line);
}
}
}, "Server console listener");
con.setDaemon(true);
con.start();
this.writer = new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(this.process.getOutputStream())));
}
public File getFolder() {
return this.builder.directory();
}
public boolean isStarted() {
return this.running;
}
public boolean isStopped() {
return !this.running;
}
public String getMessage() {
return this.message;
}
public int getProgress() {
return this.progress;
}
public int getTotal() {
return this.total;
}
public void shutdown() {
try {
this.writer.write("end\n");
}
catch(IOException e) {
}
}
}

View file

@ -1,7 +1,7 @@
package game.gui;
import game.Game;
import game.Server;
import game.ServerProcess;
import game.gui.element.Bar;
import game.gui.element.Label;
@ -18,7 +18,7 @@ public class GuiLoading extends Gui {
private Bar progressBar1;
private Bar progressBar2;
public static GuiLoading makeLoadTask(final Server server, final String user) {
public static GuiLoading makeLoadTask(final ServerProcess server, final String user, final byte[] key) {
return new GuiLoading("Lade Welt ...", new Callback() {
boolean started = false;
@ -26,8 +26,8 @@ public class GuiLoading extends Gui {
if(!this.started && server.isStarted()) {
this.started = true;
// gm.displayGuiScreen(null);
server.setVar("viewDistance", "" + gm.renderDistance);
gm.connectToIntegrated(server, user);
gm.debugWorld = server.getFolder() == null;
gm.connect(null, gm.port, user, "", "", key);
// return;
}
int progress = server.getProgress();
@ -43,7 +43,7 @@ public class GuiLoading extends Gui {
});
}
public static GuiLoading makeIntermittentTask(final Server server) {
public static GuiLoading makeIntermittentTask(final ServerProcess server) {
return new GuiLoading("Lade Welt ...", new Callback() {
public void poll(Game gm, GuiLoading gui) {
int progress = server.getProgress();
@ -63,7 +63,7 @@ public class GuiLoading extends Gui {
});
}
public static GuiLoading makeSaveTask(final Server server) {
public static GuiLoading makeSaveTask(final ServerProcess server) {
return new GuiLoading("Speichere Welt ...", new Callback() {
public void poll(Game gm, GuiLoading gui) {
if(server.isStopped()) {

View file

@ -8,7 +8,6 @@ import game.gui.element.ActButton.Mode;
import game.gui.element.Label;
import game.gui.element.NavButton;
import game.gui.element.Textbox;
import game.gui.element.Textbox.Action;
import game.gui.options.GuiOptions;
import game.gui.server.GuiConnect;
import game.gui.world.GuiWorlds;
@ -114,32 +113,6 @@ public class GuiMenu extends Gui {
this.add(new NavButton(0, 28, this.gm.charEditor ? 400 : 198, 24, GuiOptions.getPage(), "Einstellungen"));
if(!this.gm.charEditor)
this.add(new NavButton(202, 28, 198, 24, GuiCharacters.INSTANCE, "Charakter"));
if(!this.gm.isRemote() && !this.gm.debugWorld) {
final Textbox portBox = this.add(new Textbox(0, 56, 96, 24, 5, true, new Textbox.Callback() {
public void use(Textbox elem, Action value) {
if(value == Action.SEND || value == Action.UNFOCUS) {
int port = -1;
try {
port = Integer.parseInt(elem.getText());
}
catch(NumberFormatException e) {
}
if(port < 0 || port > 65535)
elem.setText("" + GuiMenu.this.gm.port);
else
GuiMenu.this.gm.port = port;
}
}
}, "" + this.gm.port)); // "srv_port"
portBox.enabled = this.gm.bind == -1;
this.add(new ActButton(100, 56, 300, 24, new ActButton.Callback() {
public void use(ActButton elem, ActButton.Mode action) {
GuiMenu.this.gm.bind(GuiMenu.this.gm.bind = (GuiMenu.this.gm.bind != -1 ? -1 : GuiMenu.this.gm.port));
elem.setText(GuiMenu.this.gm.bind != -1 ? "LAN-Welt schließen" : "LAN-Welt öffnen");
portBox.enabled = GuiMenu.this.gm.bind == -1;
}
}, this.gm.bind != -1 ? "LAN-Welt schließen" : "LAN-Welt öffnen"));
}
this.add(new ActButton(0, 102, 400, 24, new ActButton.Callback() {
public void use(ActButton elem, ActButton.Mode action) {
GuiMenu.this.gm.unload(true);

View file

@ -0,0 +1,38 @@
package game.gui.options;
import game.gui.element.Textbox;
import game.gui.element.Label;
import game.gui.element.Textbox.Action;
public class GuiNetwork extends GuiOptions {
protected GuiNetwork() {
}
public void init(int width, int height) {
this.add(new Label(30, 360, 440, 20, "Server-Port für lokale Welten", true));
final Textbox portBox = this.add(new Textbox(30, 380, 440, 24, 5, true, new Textbox.Callback() {
public void use(Textbox elem, Action value) {
if(value == Action.SEND || value == Action.UNFOCUS) {
int port = -1;
try {
port = Integer.parseInt(elem.getText());
}
catch(NumberFormatException e) {
}
if(port < 0 || port > 65535) {
elem.setText("" + GuiNetwork.this.gm.port);
}
else {
GuiNetwork.this.gm.port = port;
GuiNetwork.this.gm.setDirty();
}
}
}
}, "" + this.gm.port));
super.init(width, height);
}
public String getTitle() {
return "Server und Netzwerk";
}
}

View file

@ -5,7 +5,7 @@ import game.gui.GuiMenu;
import game.gui.element.NavButton;
public abstract class GuiOptions extends Gui {
private static final GuiOptions[] PAGES = {lastPage = new GuiBinds(), new GuiStyle(), new GuiDisplay(), new GuiSound()};
private static final GuiOptions[] PAGES = {lastPage = new GuiBinds(), new GuiStyle(), new GuiDisplay(), new GuiSound(), new GuiNetwork()};
private static GuiOptions lastPage;

View file

@ -105,7 +105,7 @@ public class GuiConnect extends Gui implements Textbox.Callback {
this.lastPass = pass;
this.lastAcc = acc;
this.gm.setDirty();
this.gm.connect(addr, port, user, pass, acc);
this.gm.connect(addr, port, user, pass, acc, null);
}
public void use(Textbox elem, Action value) {

View file

@ -1,7 +1,25 @@
package game.init;
import java.awt.Desktop;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.Thread.UncaughtExceptionHandler;
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.Locale;
import javax.imageio.ImageIO;
import game.log.NettyLogger;
public abstract class Registry {
public static void register() {
private static boolean crashed;
private static void register() {
NameRegistry.register();
BlockRegistry.register();
FlammabilityRegistry.register();
@ -17,4 +35,106 @@ public abstract class Registry {
RotationRegistry.register();
ReorderRegistry.register();
}
public static void setup(String thread) {
Thread.currentThread().setName(thread);
Locale.setDefault(Locale.ROOT);
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable e) {
System.err.println("Fehler in Thread '" + thread.getName() + "'");
e.printStackTrace(System.err);
if(crashed)
System.exit(1);
if(e instanceof OutOfMemoryError) {
System.gc();
System.gc();
}
if(!thread.getName().startsWith("Thread-") || e instanceof OutOfMemoryError) {
System.err.println("Beende!");
crashed = true;
if(System.getProperty("crash.nodump") == null) {
PrintStream ps = null;
File report = null;
try {
Date date = new Date();
File file = new File("crash-" + new SimpleDateFormat("dd.MM.yyyy_HH.mm.ss").format(date) + ".txt");
FileOutputStream out = new FileOutputStream(file);
ps = new PrintStream(out);
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] info = bean.dumpAllThreads(true, true);
StringBuilder sb = new StringBuilder();
Error error = new Error();
for(ThreadInfo threadinfo : info) {
if(threadinfo.getThreadId() == thread.getId())
error.setStackTrace(threadinfo.getStackTrace());
sb.append(threadinfo);
}
ps.println("************************************************ " + new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(date) + " ************************************************");
ps.println();
ps.println("\"Wie haste das denn nu wieder geschafft, Bursche?\"");
ps.println("Unerwarteter Fehler in Thread '" + thread.getName() + "':");
e.printStackTrace(ps);
ps.println();
ps.println("---------------------------------------------- Thread-Dump (" + info.length + " Threads) ---------------------------------------------");
ps.println();
ps.print(sb.toString());
ps.println("*********************************************************************************************************************");
report = file;
}
catch(Throwable t) {
System.err.println("Konnte Absturzbericht nicht speichern:");
t.printStackTrace(System.err);
}
finally {
if(ps != null)
ps.close();
}
if(report != null) {
System.err.println("Absturzbericht gespeichert unter " + report.getPath());
try {
Desktop.getDesktop().browse(report.toURI());
}
catch(Throwable e1) {
System.err.println("Konnte " + report + " nicht öffnen: " + e1);
}
}
}
System.exit(1);
}
}
});
ImageIO.setUseCache(false);
Thread timer = new Thread("Timer Hack Thread") {
public void run() {
while(true) {
try {
Thread.sleep(2147483647L);
}
catch(InterruptedException e) {
;
}
}
}
};
timer.setDaemon(true);
timer.start();
System.setProperty("java.net.preferIPv4Stack", "true");
NettyLogger.init();
register();
}
public static void addShutdownHook(final Runnable hook) {
Runtime.getRuntime().addShutdownHook(new Thread("Game Shutdown Thread") {
public void run() {
if(!crashed) {
try {
hook.run();
}
catch(Throwable e) {
e.printStackTrace();
}
}
}
});
}
}

View file

@ -32,10 +32,7 @@ public class ClientLoginHandler extends NetHandler {
public final void handleEnableCompression(RPacketEnableCompression packetIn)
{
if (!this.networkManager.isLocalChannel())
{
this.networkManager.setCompressionTreshold(packetIn.getValue());
}
this.networkManager.setCompressionTreshold(packetIn.getValue());
}
// public void handlePasswordRequest(RPacketPasswordRequest packetIn) {

View file

@ -94,6 +94,7 @@ import game.packet.SPacketMessage;
import game.packet.SPacketMultiBlockChange;
import game.packet.SPacketPlayerPosLook;
import game.packet.SPacketRespawn;
import game.packet.SPacketServerTick;
import game.packet.SPacketSetExperience;
import game.packet.SPacketSkin;
import game.packet.SPacketSpawnMob;
@ -903,7 +904,7 @@ public class ClientPlayer extends NetHandler
NetHandler.checkThread(packetIn, this, this.gameController, this.clientWorldController);
// this.gameController.theWorld.getWorldInfo().setTime(packetIn.getTotalWorldTime());
this.gameController.theWorld.setDayTime(packetIn.getWorldTime());
this.gameController.setTicked();
this.gameController.setTicked(packetIn.getServerinfo());
}
// public void handleCompass(SPacketCompass packetIn)
@ -1881,6 +1882,11 @@ public class ClientPlayer extends NetHandler
this.clientWorldController.dimension.setFullName(packetIn.getFullName());
this.clientWorldController.dimension.setCustomName(packetIn.getCustomName());
}
public void handleServerTick(SPacketServerTick packet) {
NetHandler.checkThread(packet, this, this.gameController);
this.gameController.setLastTick(packet.getTime());
}
/**
* Returns this the NetworkManager instance registered with this NetworkHandlerPlayClient

View file

@ -1,12 +1,45 @@
package game.network;
import game.Server;
import game.init.Config;
import game.packet.HPacketHandshake;
import game.packet.RPacketDisconnect;
public abstract class HandshakeHandler extends NetHandler
public class HandshakeHandler extends NetHandler
{
public abstract void processHandshake(HPacketHandshake packetIn);
private final Server server;
private final NetConnection networkManager;
public HandshakeHandler(Server serverIn, NetConnection netManager)
{
this.server = serverIn;
this.networkManager = netManager;
}
public void onDisconnect(String reason)
{
}
public void processHandshake(HPacketHandshake packetIn)
{
if(packetIn.getProtocolVersion() == 0) {
this.networkManager.closeChannel("Inkompatibel!");
return;
}
this.networkManager.setConnectionState(PacketRegistry.LOGIN);
if (packetIn.getProtocolVersion() != Config.PROTOCOL)
{
String comp;
if(packetIn.getProtocolVersion() < Config.PROTOCOL)
comp = "Der Server nutzt eine neuere Version: " + Config.VERSION;
else
comp = "Der Server nutzt eine ältere Version: " + Config.VERSION;
this.networkManager.sendPacket(new RPacketDisconnect(comp));
this.networkManager.closeChannel(comp);
}
else
{
this.networkManager.setNetHandler(new LoginHandler(this.server, this.networkManager));
}
}
}

View file

@ -1,22 +0,0 @@
package game.network;
import game.Server;
import game.packet.HPacketHandshake;
public class HandshakeHandlerMemory extends HandshakeHandler
{
private final Server gmServer;
private final NetConnection networkManager;
public HandshakeHandlerMemory(Server gmServerIn, NetConnection networkManagerIn)
{
this.gmServer = gmServerIn;
this.networkManager = networkManagerIn;
}
public void processHandshake(HPacketHandshake packetIn)
{
this.networkManager.setConnectionState(PacketRegistry.LOGIN);
this.networkManager.setNetHandler(new LoginHandler(this.gmServer, this.networkManager));
}
}

View file

@ -1,41 +0,0 @@
package game.network;
import game.Server;
import game.init.Config;
import game.packet.HPacketHandshake;
import game.packet.RPacketDisconnect;
public class HandshakeHandlerTCP extends HandshakeHandler
{
private final Server server;
private final NetConnection networkManager;
public HandshakeHandlerTCP(Server serverIn, NetConnection netManager)
{
this.server = serverIn;
this.networkManager = netManager;
}
public void processHandshake(HPacketHandshake packetIn)
{
if(packetIn.getProtocolVersion() == 0) {
this.networkManager.closeChannel("Inkompatibel!");
return;
}
this.networkManager.setConnectionState(PacketRegistry.LOGIN);
if (packetIn.getProtocolVersion() != Config.PROTOCOL)
{
String comp;
if(packetIn.getProtocolVersion() < Config.PROTOCOL)
comp = "Der Server nutzt eine neuere Version: " + Config.VERSION;
else
comp = "Der Server nutzt eine ältere Version: " + Config.VERSION;
this.networkManager.sendPacket(new RPacketDisconnect(comp));
this.networkManager.closeChannel(comp);
}
else
{
this.networkManager.setNetHandler(new LoginHandler(this.server, this.networkManager));
}
}
}

View file

@ -72,23 +72,10 @@ public class LoginHandler extends NetHandler
private void tryAcceptPlayer()
{
if(!this.netManager.isLocalChannel()) {
// SocketAddress address = this.netManager.getRemoteAddress();
// if(this.server.isBanned(address)) {
//// Ban ban = this.server.getBanEntryIp(address);
// this.closeConnection("Deine IP-Adresse ist von diesem Server gebannt");
// return;
// }
// if(this.server.isBanned(this.loginUser)) {
// Ban ban = this.server.getBanEntry(this.loginUser);
// this.closeConnection(ban.format(true, 0L));
// return;
// }
if(this.server.getPlayer(this.loginUser) != null) {
this.closeConnection("Nutzername '" + this.loginUser + "' ist bereits vergeben.");
return;
}
}
if(this.server.getPlayer(this.loginUser) != null) {
this.closeConnection("Nutzername '" + this.loginUser + "' ist bereits vergeben.");
return;
}
// if (this.server.getPlayer(this.loginUser) != null)
// {
// this.closeConnection("Nutzername '" + this.loginUser + "' ist bereits vergeben.");
@ -118,7 +105,9 @@ public class LoginHandler extends NetHandler
if(this.state != LoginState.PASSWORD)
throw new IllegalStateException("Unerwartetes Passwort-Paket");
this.loginUser = packetIn.getUser();
if(this.netManager.isLocalChannel()) {
if(packetIn.getLocal() != null) {
// TODO: key verification
this.netManager.setLocal();
this.loginPass = "";
// this.loginUser = Config.localUser;
if(this.loginUser.length() > Player.MAX_USER_LENGTH || (!this.loginUser.isEmpty() && !Player.isValidUser(this.loginUser))) {

View file

@ -22,9 +22,6 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.local.LocalChannel;
import io.netty.channel.local.LocalEventLoopGroup;
import io.netty.channel.local.LocalServerChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
@ -45,21 +42,6 @@ public class NetConnection extends SimpleChannelInboundHandler<Packet>
return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).build());
}
};
// public static final LazyLoadBase<EpollEventLoopGroup> CLIENT_EPOLL_EVENTLOOP = new LazyLoadBase<EpollEventLoopGroup>()
// {
// protected EpollEventLoopGroup load()
// {
// return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).build());
// }
// };
public static final LazyLoadBase<LocalEventLoopGroup> CLIENT_LOCAL_EVENTLOOP = new LazyLoadBase<LocalEventLoopGroup>()
{
protected LocalEventLoopGroup load()
{
return new LocalEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).build());
}
};
// private final PacketDirection direction;
private final Queue<NetConnection.InboundHandlerTuplePacketListener> outboundPacketsQueue = new ConcurrentLinkedQueue<InboundHandlerTuplePacketListener>();
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
@ -69,17 +51,12 @@ public class NetConnection extends SimpleChannelInboundHandler<Packet>
private String terminationReason;
private boolean disconnected;
private boolean local;
// public NetConnection(PacketDirection packetDirection)
// {
// this.direction = packetDirection;
// }
public void channelActive(ChannelHandlerContext p_channelActive_1_) throws Exception
{
super.channelActive(p_channelActive_1_);
this.channel = p_channelActive_1_.channel();
this.local = this.channel instanceof LocalChannel || this.channel instanceof LocalServerChannel;
this.local = false; // this.channel instanceof LocalChannel || this.channel instanceof LocalServerChannel;
this.socketAddress = this.channel.remoteAddress();
try
@ -324,6 +301,11 @@ public class NetConnection extends SimpleChannelInboundHandler<Packet>
return this.local;
}
public void setLocal()
{
this.local = true;
}
/**
* Create a new NetworkManager from the server host and connect it to the server
*
@ -366,26 +348,6 @@ public class NetConnection extends SimpleChannelInboundHandler<Packet>
return networkmanager;
}
/**
* Prepares a clientside NetworkManager: establishes a connection to the socket supplied and configures the channel
* pipeline. Returns the newly created instance.
*/
public static NetConnection provideLocalClient(SocketAddress address)
{
final NetConnection networkmanager = new NetConnection();
((Bootstrap)((Bootstrap)((Bootstrap)(new Bootstrap()).group((EventLoopGroup)CLIENT_LOCAL_EVENTLOOP.getValue())).handler(new ChannelInitializer<Channel>()
{
protected void initChannel(Channel p_initChannel_1_) throws Exception
{
p_initChannel_1_.pipeline().addLast((String)"packet_handler", (ChannelHandler)networkmanager);
}
})).channel(LocalChannel.class)).connect(address).syncUninterruptibly();
return networkmanager;
}
/**
* Returns true if this NetworkManager has an active channel, false otherwise
*/
public boolean isChannelOpen()
{
return this.channel != null && this.channel.isOpen();

View file

@ -74,6 +74,7 @@ import game.packet.SPacketMessage;
import game.packet.SPacketMultiBlockChange;
import game.packet.SPacketPlayerPosLook;
import game.packet.SPacketRespawn;
import game.packet.SPacketServerTick;
import game.packet.SPacketSetExperience;
import game.packet.SPacketSkin;
import game.packet.SPacketSpawnMob;
@ -178,6 +179,7 @@ public enum PacketRegistry
// this.server(SPacketNotify.class);
this.server(SPacketDimensionName.class);
this.server(SPacketCharacterList.class);
this.server(SPacketServerTick.class);
this.client(CPacketKeepAlive.class);
this.client(CPacketMessage.class);

View file

@ -274,6 +274,8 @@ public class Player extends NetHandler implements ICrafting, Executor
this.pingKey = (int)this.lastPingTime;
this.sendPacket(new SPacketKeepAlive(this.pingKey));
}
if(this.local)
if(this.respawnTimer > 0) {
if(--this.respawnTimer == 0) {
this.respawnPlayer();
@ -2511,7 +2513,7 @@ public class Player extends NetHandler implements ICrafting, Executor
NetHandler.checkThread(packetIn, this, this.server);
CPacketAction.Action action = packetIn.getAction();
if(this.charEditor != (action == Action.SET_ALIGN || action == Action.SET_SPECIES || action == Action.SET_CLASS || action == Action.SET_HEIGHT || action == Action.CLOSE_EDITOR)) // {
if(action != Action.SET_VIEWDIST && action != Action.SHUTDOWN && (this.charEditor != (action == Action.SET_ALIGN || action == Action.SET_SPECIES || action == Action.SET_CLASS || action == Action.SET_HEIGHT || action == Action.CLOSE_EDITOR))) // {
// if(this.local && action == Action.CLOSE_EDITOR)
// this.server.setDone();
return;
@ -2873,7 +2875,27 @@ public class Player extends NetHandler implements ICrafting, Executor
this.entity.setNpcClass(classes[packetIn.getAuxData()]);
}
break;
case WARP_MODE:
if(this.isLocal()) {
this.server.schedule(new Runnable() {
public void run() {
Player.this.server.setTpsTarget(Player.this.server.getTpsTarget() < 10000.0f ? 10000.0f : 20.0f);
}
});
}
break;
case SET_VIEWDIST:
if(this.isLocal())
this.server.setVar("viewDistance", "" + packetIn.getAuxData());
break;
case SHUTDOWN:
if(this.isLocal())
this.server.shutdown();
break;
default:
throw new IllegalArgumentException("Ungültige Aktion!");
}

View file

@ -93,6 +93,9 @@ public class CPacketAction implements Packet<Player>
HEAL,
REPAIR,
PERF,
MAGNET;
MAGNET,
SET_VIEWDIST,
WARP_MODE,
SHUTDOWN;
}
}

View file

@ -12,16 +12,18 @@ public class LPacketPasswordResponse implements Packet<LoginHandler>
private String user;
private String access;
private String password;
private byte[] local;
public LPacketPasswordResponse()
{
}
public LPacketPasswordResponse(String userIn, String accessIn, String passwordIn)
public LPacketPasswordResponse(String userIn, String accessIn, String passwordIn, byte[] local)
{
this.user = userIn;
this.access = accessIn;
this.password = passwordIn;
this.local = local;
}
/**
@ -32,6 +34,8 @@ public class LPacketPasswordResponse implements Packet<LoginHandler>
this.user = buf.readStringFromBuffer(Player.MAX_USER_LENGTH);
this.access = buf.readStringFromBuffer(Player.MAX_PASS_LENGTH);
this.password = buf.readStringFromBuffer(Player.MAX_PASS_LENGTH);
this.local = buf.readByteArray();
this.local = this.local.length == 0 ? null : this.local;
}
/**
@ -42,6 +46,7 @@ public class LPacketPasswordResponse implements Packet<LoginHandler>
buf.writeString(this.user);
buf.writeString(this.access);
buf.writeString(this.password);
buf.writeByteArray(this.local == null ? new byte[0] : this.local);
}
/**
@ -66,4 +71,9 @@ public class LPacketPasswordResponse implements Packet<LoginHandler>
{
return this.password;
}
public byte[] getLocal()
{
return this.local;
}
}

View file

@ -0,0 +1,34 @@
package game.packet;
import java.io.IOException;
import game.network.ClientPlayer;
import game.network.Packet;
import game.network.PacketBuffer;
public class SPacketServerTick implements Packet<ClientPlayer> {
private int time;
public SPacketServerTick() {
}
public SPacketServerTick(int time) {
this.time = time;
}
public void readPacketData(PacketBuffer buf) throws IOException {
this.time = buf.readInt();
}
public void writePacketData(PacketBuffer buf) throws IOException {
buf.writeInt(this.time);
}
public void processPacket(ClientPlayer handler) {
handler.handleServerTick(this);
}
public int getTime() {
return this.time;
}
}

View file

@ -7,36 +7,36 @@ import game.network.Packet;
import game.network.PacketBuffer;
public class SPacketTimeUpdate implements Packet<ClientPlayer> {
// private long totalWorldTime;
private long worldTime;
private String serverInfo;
public SPacketTimeUpdate() {
}
public SPacketTimeUpdate(long totalTimeIn) {
// this.totalWorldTime = totalWorldTimeIn;
this.worldTime = totalTimeIn;
public SPacketTimeUpdate(long time, String info) {
this.worldTime = time;
this.serverInfo = info;
}
public void readPacketData(PacketBuffer buf) throws IOException {
// this.totalWorldTime = buf.readLong();
this.worldTime = buf.readLong();
this.serverInfo = buf.readStringFromBuffer(512);
}
public void writePacketData(PacketBuffer buf) throws IOException {
// buf.writeLong(this.totalWorldTime);
buf.writeLong(this.worldTime);
buf.writeString(this.serverInfo);
}
public void processPacket(ClientPlayer handler) {
handler.handleTimeUpdate(this);
}
// public long getTotalWorldTime() {
// return this.totalWorldTime;
// }
public long getWorldTime() {
return this.worldTime;
}
public String getServerinfo() {
return this.serverInfo;
}
}

View file

@ -0,0 +1,11 @@
package game.util;
public class Tuple<S, T> {
public final S first;
public final T second;
public Tuple(S first, T second) {
this.first = first;
this.second = second;
}
}

View file

@ -1,7 +1,10 @@
package game.util;
import java.awt.GraphicsEnvironment;
import java.util.function.Function;
import javax.swing.JOptionPane;
import game.log.Log;
import game.properties.IStringSerializable;
@ -293,4 +296,30 @@ int utf_len(const char *str) {
return (color & 0xff000000) | ((((color >> 16 & 255) * mul) / 255) << 16) | ((((color >> 8 & 255) * mul) / 255) << 8) |
(((color & 255) * mul) / 255);
}
public static void checkOs() {
if(System.getProperty("os.name").startsWith("Windows") || System.getProperty("os.name").startsWith("Mac")) {
String info = "Inkompatibles Betriebssystem";
String msg = "Linux oder *BSD ist erforderlich, um dieses Programm auszuführen.\n" +
"Alle Versionen von Windows und Mac OS (X) sind nicht kompatibel.";
System.err.println("#################################################################");
System.err.println("*** " + info + " ***");
System.err.println(msg);
System.err.println("#################################################################");
if(!GraphicsEnvironment.isHeadless())
JOptionPane.showMessageDialog(null, msg, info, JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
}
public static Tuple<String, String> getKeyValue(String text, char separator) {
int index = text.indexOf(separator);
if(index == -1)
return new Tuple<String, String>(text, null);
return new Tuple<String, String>(text.substring(0, index), text.substring(index + 1));
}
public static Tuple<String, String> getKeyValue(String text) {
return getKeyValue(text, ' ');
}
}

View file

@ -93,7 +93,6 @@ public final class WorldServer extends World {
private static final int[][] XZ_DIRS = new int[][] {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
private final Server server;
private final File dir;
private final File chunkDir;
private final Random grng;
private final Set<NextTickListEntry> ticks = Sets.<NextTickListEntry>newHashSet();
@ -156,14 +155,13 @@ public final class WorldServer extends World {
private long prevUpdate;
private long time;
public WorldServer(Server server, File dir, long dtime, Dimension dim, boolean debug) {
public WorldServer(Server server, long dtime, Dimension dim, boolean debug) {
super(dim, false, debug);
this.server = server;
this.dir = dir;
// this.time = time;
this.daytime = dtime;
this.updateViewRadius();
this.chunkDir = new File(new File(this.dir, "chunk"), dim.getDimensionName());
this.chunkDir = new File(new File("chunk"), dim.getDimensionName());
if(!debug) {
this.chunkDir.mkdirs();
this.seed = this.rand.longv();
@ -800,10 +798,10 @@ public final class WorldServer extends World {
return list;
}
public static boolean needsLoading(File dir, Dimension dim) {
public static boolean needsLoading(Dimension dim) {
NBTTagCompound tag = null;
try {
File dat = new File(new File(new File(dir, "chunk"), dim.getDimensionName()), "loaders.nbt");
File dat = new File(new File(new File("chunk"), dim.getDimensionName()), "loaders.nbt");
if(dat.exists() && dat.isFile())
tag = NBTLoader.readGZip(dat);
}
@ -813,10 +811,10 @@ public final class WorldServer extends World {
return tag != null && tag.hasKey("Loaders", 9) && !tag.getTagList("Loaders", 10).hasNoTags();
}
public static void loadWarps(File dir, Dimension dim, Map<String, Position> warps) {
public static void loadWarps(Dimension dim, Map<String, Position> warps) {
NBTTagCompound tag = null;
try {
File dat = new File(new File(new File(dir, "chunk"), dim.getDimensionName()), "warps.nbt");
File dat = new File(new File(new File("chunk"), dim.getDimensionName()), "warps.nbt");
if(dat.exists() && dat.isFile())
tag = NBTLoader.readGZip(dat);
}
@ -834,7 +832,7 @@ public final class WorldServer extends World {
}
}
public static void saveWarps(File dir, Map<String, Position> warps) {
public static void saveWarps(Map<String, Position> warps) {
Map<Integer, NBTTagList> map = Maps.newHashMap();
for(Entry<String, Position> pos : warps.entrySet()) {
Dimension dim = UniverseRegistry.getDimension(pos.getValue().dim);
@ -854,7 +852,7 @@ public final class WorldServer extends World {
}
for(Dimension dim : UniverseRegistry.getDimensions()) {
NBTTagList list = map.get(dim.getDimensionId());
File file = new File(new File(new File(dir, "chunk"), dim.getDimensionName()), "warps.nbt");
File file = new File(new File(new File("chunk"), dim.getDimensionName()), "warps.nbt");
if(list == null) {
file.delete();
}