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; package game;
import java.awt.Desktop;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; 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.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.net.IDN; import java.net.IDN;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.security.SecureRandom;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Date; import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Queue; import java.util.Queue;
@ -40,8 +31,6 @@ import java.util.concurrent.FutureTask;
import java.util.function.Function; import java.util.function.Function;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL13;
@ -92,7 +81,6 @@ import game.item.ItemStack;
import game.log.Log; import game.log.Log;
import game.log.LogLevel; import game.log.LogLevel;
import game.log.Message; import game.log.Message;
import game.log.NettyLogger;
import game.material.Material; import game.material.Material;
import game.model.ModelManager; import game.model.ModelManager;
import game.network.IThreadListener; import game.network.IThreadListener;
@ -167,7 +155,6 @@ import game.world.Region;
import game.world.State; import game.world.State;
import game.world.World; import game.world.World;
import game.world.WorldClient; import game.world.WorldClient;
import game.world.WorldServer;
/* /*
Een net ganz funktionierndes Programm ... Een net ganz funktionierndes Programm ...
@ -409,7 +396,6 @@ public class Game implements IThreadListener {
@Variable(name = "srv_port", category = CVarCategory.SYSTEM, min = 0, max = 65535, display = "Standard Hosting-Port") @Variable(name = "srv_port", category = CVarCategory.SYSTEM, min = 0, max = 65535, display = "Standard Hosting-Port")
public int port = Config.PORT; public int port = Config.PORT;
public int bind = -1;
@Variable(name = "snd_enabled", category = CVarCategory.SOUND, display = "Tonausgabe") @Variable(name = "snd_enabled", category = CVarCategory.SOUND, display = "Tonausgabe")
public boolean soundEnabled = true; public boolean soundEnabled = true;
@ -418,12 +404,13 @@ public class Game implements IThreadListener {
@Variable(name = "snd_frame_size", category = CVarCategory.SOUND, min = 2, max = 8192, display = "PCM-Intervall") @Variable(name = "snd_frame_size", category = CVarCategory.SOUND, min = 2, max = 8192, display = "PCM-Intervall")
public int soundFrameSize = 32; public int soundFrameSize = 32;
private Server server; private ServerProcess server;
private String serverInfo;
private int lastServerTick;
private AudioInterface audio; private AudioInterface audio;
private long start; private long start;
private boolean cfgDirty; private boolean cfgDirty;
private String buffer = ""; private String buffer = "";
private boolean crashed;
private boolean waitingForFile; private boolean waitingForFile;
private boolean refreshing; private boolean refreshing;
@ -450,20 +437,20 @@ public class Game implements IThreadListener {
return INSTANCE; return INSTANCE;
} }
public void connect(String address, int port, String user, String pass, String access) { public void connect(String address, int port, String user, String pass, String access, byte[] local) {
Log.JNI.info("Verbinde zu " + address + ":" + port); Log.JNI.info("Verbinde zu " + (address == null ? "localhost" : address) + ":" + port);
NetConnection connection = null; NetConnection connection = null;
try 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.setNetHandler(new ClientLoginHandler(connection, this));
connection.sendPacket(new HPacketHandshake(Config.PROTOCOL)); connection.sendPacket(new HPacketHandshake(Config.PROTOCOL));
connection.sendPacket(new LPacketPasswordResponse(user, access, pass)); connection.sendPacket(new LPacketPasswordResponse(user, access, pass, local));
} }
catch (UnknownHostException u) catch (UnknownHostException u)
{ {
Log.JNI.error(u, "Konnte nicht zu Server verbinden"); Log.JNI.error(u, "Konnte nicht zu Server verbinden");
this.disconnected("Unbekannter Hostname: " + address); this.disconnected("Unbekannter Hostname: " + (address == null ? "localhost" : address));
return; return;
} }
catch (Exception e) catch (Exception e)
@ -475,17 +462,6 @@ public class Game implements IThreadListener {
this.connection = connection; 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() { public void unloadWorld() {
ClientPlayer netHandler = this.getNetHandler(); ClientPlayer netHandler = this.getNetHandler();
if(netHandler != null) if(netHandler != null)
@ -496,6 +472,7 @@ public class Game implements IThreadListener {
this.connection = null; this.connection = null;
this.theWorld = null; this.theWorld = null;
this.thePlayer = null; this.thePlayer = null;
this.serverInfo = null;
this.soundManager.stopSounds(); this.soundManager.stopSounds();
} }
@ -1013,7 +990,7 @@ public class Game implements IThreadListener {
int y1 = 0; int y1 = 0;
int y2 = this.fb_y; int y2 = this.fb_y;
// int pos = 0; // int pos = 0;
String str = this.getLeft(this.server); String str = this.getLeft();
// if(jstr) // if(jstr)
// str = (*jsys.env)->GetStringUTFChars(jsys.env, jstr, NULL); // str = (*jsys.env)->GetStringUTFChars(jsys.env, jstr, NULL);
// elem->r_dirty = 1; // elem->r_dirty = 1;
@ -1624,8 +1601,14 @@ public class Game implements IThreadListener {
return this.itemRenderer; return this.itemRenderer;
} }
public void setTicked() { public void setTicked(String info) {
this.lastTicked = System.currentTimeMillis(); this.lastTicked = System.currentTimeMillis();
this.serverInfo = info;
}
public void setLastTick(int tick) {
this.lastTicked = System.currentTimeMillis();
this.lastServerTick = tick;
} }
public void updatePlayerMoveState() 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 maxMem = Runtime.getRuntime().maxMemory();
long totalMem = Runtime.getRuntime().totalMemory(); long totalMem = Runtime.getRuntime().totalMemory();
long freeMem = Runtime.getRuntime().freeMemory(); long freeMem = Runtime.getRuntime().freeMemory();
@ -1767,13 +1750,8 @@ public class Game implements IThreadListener {
) + "\n" + ) + "\n" +
String.format("Letzte Zeitsynch.: + %d.%d s", String.format("Letzte Zeitsynch.: + %d.%d s",
ticked / 1000L, (ticked / 100L) % 10L ticked / 1000L, (ticked / 100L) % 10L
) + "\n" + ) +
(server != null ? (this.serverInfo != null ? "\n" + this.serverInfo : "")
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: <?>")
// WorldServer world = this.server.getWorld(this.theWorld.dimension.getDimensionId()); // WorldServer world = this.server.getWorld(this.theWorld.dimension.getDimensionId());
// if(world != null) // if(world != null)
// list.add("Seed: " + world.getSeed()); // list.add("Seed: " + world.getSeed());
@ -2100,7 +2078,7 @@ public class Game implements IThreadListener {
return; return;
this.frameWait = 50000000L - ((n - (this.frameLast + this.frameWait)) < 50000000L ? (n - (this.frameLast + this.frameWait)) : 0L); this.frameWait = 50000000L - ((n - (this.frameLast + this.frameWait)) < 50000000L ? (n - (this.frameLast + this.frameWait)) : 0L);
this.frameLast = n; 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) { if(this.tickIndex == 240) {
this.tickIndex = 0; this.tickIndex = 0;
} }
@ -2369,11 +2347,13 @@ public class Game implements IThreadListener {
public void unload(boolean loading) { public void unload(boolean loading) {
if(this.theWorld != null) { if(this.theWorld != null) {
if(server != null)
this.performAction(Action.SHUTDOWN);
if(server == null && this.getNetHandler() != null) if(server == null && this.getNetHandler() != null)
this.getNetHandler().getNetworkManager().closeChannel("Quitting"); this.getNetHandler().getNetworkManager().closeChannel("Quitting");
this.unloadWorld(); this.unloadWorld();
if(server != null) // if(server != null)
server.shutdown(); // server.shutdown();
} }
if(server != null) { if(server != null) {
if(loading) { if(loading) {
@ -2396,9 +2376,11 @@ public class Game implements IThreadListener {
} }
public void startServer(File dir, String user) { 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(); server.start();
this.displayGuiScreen(GuiLoading.makeLoadTask(server, user)); this.displayGuiScreen(GuiLoading.makeLoadTask(server, user, key));
// while(server != null && !server.isStarted()) { // while(server != null && !server.isStarted()) {
// try { // try {
// Thread.sleep(10L); // Thread.sleep(10L);
@ -2451,16 +2433,11 @@ public class Game implements IThreadListener {
return ((double)rtime()) / 1000000.0; return ((double)rtime()) / 1000000.0;
} }
public void bind(int port) {
if(server != null)
server.bind(port);
}
public void distance(int distance) { public void distance(int distance) {
if(this.renderGlobal != null) if(this.renderGlobal != null)
this.renderGlobal.setDisplayListEntitiesDirty(); this.renderGlobal.setDisplayListEntitiesDirty();
if(this.server != null) if(this.server != null && this.thePlayer != null)
this.server.setVar("viewDistance", "" + distance); this.thePlayer.sendQueue.addToSendQueue(new CPacketAction(Action.SET_VIEWDIST, distance));
} }
private void registerDebug(Keysym key, String help, DebugRunner runner) { 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() { this.registerDebug(Keysym.W, "Server-Tick-Limit umschalten (Welt beschleunigen / Warpmodus)", new DebugRunner() {
public void execute(Keysym key) { public void execute(Keysym key) {
if(server != null) { Game.this.performAction(Action.WARP_MODE);
server.schedule(new Runnable() {
public void run() {
server.setTpsTarget(server.getTpsTarget() < 10000.0f ? 10000.0f : 20.0f);
}
});
}
} }
}); });
this.registerDebug(Keysym.M, "Alle Gegenstände herbei ziehen (Magnetmodus)", new DebugRunner() { 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) { public static void main(String[] args) {
if(System.getProperty("os.name").startsWith("Windows") || System.getProperty("os.name").startsWith("Mac")) { Util.checkOs();
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;
}
Window.init(); Window.init();
Locale.setDefault(Locale.ROOT); Registry.setup("Render thread");
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");
INSTANCE.run(); INSTANCE.run();
Window.end(); Window.end();
} }

View file

@ -3,7 +3,6 @@ package game;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.SocketAddress;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -32,6 +31,7 @@ import game.entity.npc.EntityHuman;
import game.entity.npc.EntityNPC; import game.entity.npc.EntityNPC;
import game.init.Config; import game.init.Config;
import game.init.EntityRegistry; import game.init.EntityRegistry;
import game.init.Registry;
import game.init.UniverseRegistry; import game.init.UniverseRegistry;
import game.log.Log; import game.log.Log;
import game.nbt.NBTLoader; import game.nbt.NBTLoader;
@ -41,8 +41,7 @@ import game.network.IThreadListener;
import game.network.LazyLoadBase; import game.network.LazyLoadBase;
import game.network.NetConnection; import game.network.NetConnection;
import game.network.NetHandler.ThreadQuickExitException; import game.network.NetHandler.ThreadQuickExitException;
import game.network.HandshakeHandlerMemory; import game.network.HandshakeHandler;
import game.network.HandshakeHandlerTCP;
import game.network.Player; import game.network.Player;
import game.network.Packet; import game.network.Packet;
import game.network.PacketDecoder; import game.network.PacketDecoder;
@ -65,6 +64,7 @@ import game.packet.SPacketTimeUpdate;
import game.packet.SPacketWorld; import game.packet.SPacketWorld;
import game.potion.PotionEffect; import game.potion.PotionEffect;
import game.util.ExtMath; import game.util.ExtMath;
import game.util.Util;
import game.world.BlockPos; import game.world.BlockPos;
import game.world.PortalType; import game.world.PortalType;
import game.world.Position; import game.world.Position;
@ -81,23 +81,20 @@ import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption; 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.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener; 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>() { private static final LazyLoadBase<NioEventLoopGroup> SERVER_NIO_EVENTLOOP = new LazyLoadBase<NioEventLoopGroup>() {
protected NioEventLoopGroup load() { protected NioEventLoopGroup load() {
return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).build()); 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<NetConnection> clients = Collections.<NetConnection>synchronizedList(Lists.<NetConnection>newArrayList());
private final List<Player> players = Lists.<Player>newArrayList(); private final List<Player> players = Lists.<Player>newArrayList();
private final Map<String, Player> usermap = Maps.<String, Player>newHashMap(); 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 List<Dimension> unload = Lists.<Dimension>newArrayList();
private final Map<String, Position> warps = Maps.<String, Position>newTreeMap(); private final Map<String, Position> warps = Maps.<String, Position>newTreeMap();
private final CommandEnvironment scriptEnv = new CommandEnvironment(this); 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 final boolean debug;
private WorldServer space; private WorldServer space;
private ChannelFuture endpoint; private ChannelFuture endpoint;
private ChannelFuture localEndpoint;
private String localUser; private String localUser;
private String message;
private boolean running = true; private boolean running = true;
private boolean stopped; private boolean stopped;
@ -140,28 +131,29 @@ public final class Server implements Runnable, IThreadListener {
private int pingTimer; private int pingTimer;
private int syncTimer; private int syncTimer;
private int perfTimer; private int perfTimer;
private int progress = -1;
private int total = 0;
Server(File dir) { public static void main(String[] args) {
// this.owner = owner; Util.checkOs();
this.serverThread = new Thread(this, "Server thread"); Registry.setup("Server thread");
this.baseDir = dir; // dir != null ? new File(dir) : null; final Server server = new Server(false);
this.playerDir = new File(this.baseDir, "players"); Registry.addShutdownHook(new Runnable() {
this.debug = this.baseDir == null; public void run() {
// this.port = port; server.stopServer();
}
});
server.run();
}
private Server(boolean debug) {
this.debug = debug;
} }
public CommandEnvironment getScriptEnvironment() { public CommandEnvironment getScriptEnvironment() {
return this.scriptEnv; return this.scriptEnv;
} }
public boolean isStarted() {
return this.started;
}
public String[] getUsers() { public String[] getUsers() {
String[] list = this.debug ? null : this.playerDir.list(); String[] list = this.debug ? null : new File("players").list();
if(list == null) { if(list == null) {
list = new String[0]; list = new String[0];
} }
@ -182,8 +174,8 @@ public final class Server implements Runnable, IThreadListener {
public void saveWorldInfo() { public void saveWorldInfo() {
if(!this.debug) { if(!this.debug) {
Region.saveWorldInfo(this.baseDir, this.space.getDayTime(), this.localUser); Region.saveWorldInfo(null, this.space.getDayTime(), this.localUser);
WorldServer.saveWarps(this.baseDir, this.warps); WorldServer.saveWarps(this.warps);
} }
} }
@ -192,7 +184,7 @@ public final class Server implements Runnable, IThreadListener {
return null; return null;
NBTTagCompound tag = null; NBTTagCompound tag = null;
try { try {
File dat = new File(this.playerDir, user + ".nbt"); File dat = new File(new File("players"), user + ".nbt");
if(dat.exists() && dat.isFile()) { if(dat.exists() && dat.isFile()) {
tag = NBTLoader.readGZip(dat); tag = NBTLoader.readGZip(dat);
@ -235,7 +227,7 @@ public final class Server implements Runnable, IThreadListener {
private void startProgress(boolean save, int amount) { private void startProgress(boolean save, int amount) {
this.setTotal(amount); this.setTotal(amount);
this.setProgress(0); 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) { public void unloadWorld(WorldServer world) {
@ -258,15 +250,15 @@ public final class Server implements Runnable, IThreadListener {
Log.JNI.info("Starte Server Version " + Config.VERSION); Log.JNI.info("Starte Server Version " + Config.VERSION);
if(!this.debug) { if(!this.debug) {
this.setMessage("Welt wird erstellt und geladen"); this.setMessage("Welt wird erstellt und geladen");
FolderInfo info = Region.loadWorldInfo(this.baseDir); FolderInfo info = Region.loadWorldInfo(null);
// if(dtime == -1L) // { // if(dtime == -1L) // {
// dtime = World.START_TIME; // dtime = World.START_TIME;
//// Config.set("spawnDim", "1", null); //// 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)); Space.INSTANCE, false));
this.dimensions.put(this.space.dimension.getDimensionId(), this.space); this.dimensions.put(this.space.dimension.getDimensionId(), this.space);
this.playerDir.mkdirs(); new File("players").mkdirs();
// if(Config.spawnY < 0) { // if(Config.spawnY < 0) {
// WorldServer world = this.getWorld(Config.spawnDim); // WorldServer world = this.getWorld(Config.spawnDim);
// world = world == null ? this.space : world; // world = world == null ? this.space : world;
@ -297,17 +289,17 @@ public final class Server implements Runnable, IThreadListener {
Config.set("weatherChanges", "false", null); Config.set("weatherChanges", "false", null);
Config.set("mobSpawning", "false", null); Config.set("mobSpawning", "false", null);
Config.set("spawnRadius", "0", 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)); Space.INSTANCE, true));
this.dimensions.put(this.space.dimension.getDimensionId(), this.space); this.dimensions.put(this.space.dimension.getDimensionId(), this.space);
} }
this.setTpsTarget(20.0f); this.setTpsTarget(20.0f);
if(!this.debug) { if(!this.debug) {
for(Dimension dim : UniverseRegistry.getDimensions()) { for(Dimension dim : UniverseRegistry.getDimensions()) {
if(WorldServer.needsLoading(this.baseDir, dim)) { if(WorldServer.needsLoading(dim)) {
this.getWorld(dim.getDimensionId()).loadForcedChunks(); this.getWorld(dim.getDimensionId()).loadForcedChunks();
} }
WorldServer.loadWarps(this.baseDir, dim, this.warps); WorldServer.loadWarps(dim, this.warps);
} }
// this.openLAN(); // this.openLAN();
} }
@ -339,17 +331,22 @@ public final class Server implements Runnable, IThreadListener {
this.lastPoll = this.currentTime; this.lastPoll = this.currentTime;
this.ticksDone = 0L; this.ticksDone = 0L;
} }
if(!this.started) {
this.started = true; this.started = true;
this.sendPipeIPC("running", true);
}
} }
try { try {
this.stopServer(); this.stopServer();
this.stopped = true; this.stopped = true;
this.sendPipeIPC("running", false);
} }
catch(Throwable e) { catch(Throwable e) {
Log.JNI.error(e, "Fehler beim Beenden des Servers"); Log.JNI.error(e, "Fehler beim Beenden des Servers");
} }
finally { finally {
this.stopped = true; this.stopped = true;
this.sendPipeIPC("running", false);
Log.JNI.info("Server wurde beendet"); Log.JNI.info("Server wurde beendet");
} }
} }
@ -365,8 +362,8 @@ public final class Server implements Runnable, IThreadListener {
bx = bx >> 4; bx = bx >> 4;
bz = bz >> 4; bz = bz >> 4;
long last = System.currentTimeMillis(); long last = System.currentTimeMillis();
for(int x = -Config.distance; x <= Config.distance && this.running; x++) { for(int x = -Config.distance; x <= Config.distance; x++) {
for(int z = -Config.distance; z <= Config.distance && this.running; z++) { for(int z = -Config.distance; z <= Config.distance; z++) {
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
if(time - last >= 10L) { if(time - last >= 10L) {
this.setProgress(done); this.setProgress(done);
@ -436,7 +433,7 @@ public final class Server implements Runnable, IThreadListener {
} }
} }
if(++this.syncTimer == 20) { if(++this.syncTimer == 20) {
this.sendPacket(new SPacketTimeUpdate(this.space.getDayTime())); this.sendPacket(new SPacketTimeUpdate(this.space.getDayTime(), this.getInfo()));
this.syncTimer = 0; this.syncTimer = 0;
} }
this.ticked.clear(); this.ticked.clear();
@ -477,7 +474,7 @@ public final class Server implements Runnable, IThreadListener {
Dimension dim = UniverseRegistry.getDimension(dimension); Dimension dim = UniverseRegistry.getDimension(dimension);
if(dim == null) if(dim == null)
return null; return null;
world = new WorldServer(this, this.baseDir, this.space.getDayTime(), world = new WorldServer(this, this.space.getDayTime(),
dim, this.debug); dim, this.debug);
this.worlds.add(world); this.worlds.add(world);
this.dimensions.put(dimension, world); this.dimensions.put(dimension, world);
@ -498,10 +495,6 @@ public final class Server implements Runnable, IThreadListener {
return this.worlds; return this.worlds;
} }
public boolean isStopped() {
return this.stopped;
}
public long[] getTickTimes() { public long[] getTickTimes() {
return this.tickTimes; return this.tickTimes;
} }
@ -548,40 +541,16 @@ public final class Server implements Runnable, IThreadListener {
return this.usermap.get(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) { private void setMessage(String message) {
synchronized(this) { this.sendPipeIPC("message", message);
this.message = message;
}
} }
private void setProgress(int progress) { private void setProgress(int progress) {
synchronized(this) { this.sendPipeIPC("progress", progress);
this.progress = progress;
}
} }
private void setTotal(int total) { private void setTotal(int total) {
synchronized(this) { this.sendPipeIPC("total", total);
this.total = total;
}
} }
public void setVar(String cv, String value) { public void setVar(String cv, String value) {
@ -592,10 +561,6 @@ public final class Server implements Runnable, IThreadListener {
}); });
} }
public File getFolder() {
return this.baseDir;
}
private <V> ListenableFuture<V> callFromMainThread(Callable<V> callable) { private <V> ListenableFuture<V> callFromMainThread(Callable<V> callable) {
if(!this.isMainThread() && !this.stopped) { if(!this.isMainThread() && !this.stopped) {
ListenableFutureTask<V> task = ListenableFutureTask.<V>create(callable); ListenableFutureTask<V> task = ListenableFutureTask.<V>create(callable);
@ -661,10 +626,9 @@ public final class Server implements Runnable, IThreadListener {
Player conn = new Player(this, connection, loginUser); Player conn = new Player(this, connection, loginUser);
if(tag != null) if(tag != null)
conn.readFromNBT(tag); conn.readFromNBT(tag);
if(!connection.isLocalChannel()) { if(Config.playerLimit > 0 && this.players.size() >= Config.playerLimit && !conn.isAdmin())
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); return String.format("Der Server ist voll (%d/%d)!", this.players.size(), Config.playerLimit);
if(Config.auth) { if(!connection.isLocalChannel() && Config.auth) {
if(conn.getPassword() == null) { if(conn.getPassword() == null) {
if(!Config.register) if(!Config.register)
return "Anmeldung neuer Accounts ist auf diesem Server deaktiviert (Whitelisted)"; return "Anmeldung neuer Accounts ist auf diesem Server deaktiviert (Whitelisted)";
@ -689,7 +653,6 @@ public final class Server implements Runnable, IThreadListener {
} }
}); });
} }
}
connection.sendPacket(new RPacketLoginSuccess()); connection.sendPacket(new RPacketLoginSuccess());
connection.setNetHandler(conn); connection.setNetHandler(conn);
this.players.add(conn); this.players.add(conn);
@ -766,7 +729,7 @@ public final class Server implements Runnable, IThreadListener {
return null; return null;
NBTTagCompound tag = null; NBTTagCompound tag = null;
try { try {
File dat = new File(this.playerDir, user + ".nbt"); File dat = new File(new File("players"), user + ".nbt");
if(dat.exists() && dat.isFile()) { if(dat.exists() && dat.isFile()) {
tag = NBTLoader.readGZip(dat); tag = NBTLoader.readGZip(dat);
@ -794,8 +757,8 @@ public final class Server implements Runnable, IThreadListener {
// else // else
// etag = new NBTTagCompound(); // etag = new NBTTagCompound();
conn.writeToNBT(tag); conn.writeToNBT(tag);
File tmp = new File(this.playerDir, conn.getUser() + ".nbt.tmp"); File tmp = new File(new File("players"), conn.getUser() + ".nbt.tmp");
File dat = new File(this.playerDir, conn.getUser() + ".nbt"); File dat = new File(new File("players"), conn.getUser() + ".nbt");
NBTLoader.writeGZip(tag, tmp); NBTLoader.writeGZip(tag, tmp);
if(dat.exists()) { if(dat.exists()) {
dat.delete(); dat.delete();
@ -1020,7 +983,7 @@ public final class Server implements Runnable, IThreadListener {
} }
private void updateTimeAndWeatherForPlayer(Player conn, WorldServer world) { 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.SET_WEATHER, world.getWeather().getID()));
conn.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.RAIN_STRENGTH, world.getRainStrength())); conn.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.RAIN_STRENGTH, world.getRainStrength()));
conn.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.DARKNESS, world.getDarkness())); conn.sendPacket(new S2BPacketChangeGameState(S2BPacketChangeGameState.Action.DARKNESS, world.getDarkness()));
@ -1055,41 +1018,21 @@ public final class Server implements Runnable, IThreadListener {
NetConnection manager = new NetConnection(); NetConnection manager = new NetConnection();
Server.this.clients.add(manager); Server.this.clients.add(manager);
channel.pipeline().addLast((String)"packet_handler", (ChannelHandler)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(); }).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() { private void unsetLanEndpoint() {
for(Player conn : Lists.newArrayList(this.players)) { for(Player conn : Lists.newArrayList(this.players)) {
if(!conn.isLocal()) if(!conn.isLocal())
conn.disconnect(); conn.disconnect();
} }
this.terminateEndpoints(false); this.terminateEndpoint();
} }
private void terminateEndpoints(boolean local) { private void terminateEndpoint() {
synchronized(this.serverThread) { synchronized(this.serverThread) {
if(this.endpoint != null) { if(this.endpoint != null) {
Log.JNI.info("Schließe Port"); 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"); 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(); manager.processReceivedPackets();
} }
catch(Exception e) { catch(Exception e) {
if(manager.isLocalChannel()) {
throw e;
}
Log.JNI.error(e, "Konnte Paket von " + manager.getCutAddress() + " nicht verarbeiten"); Log.JNI.error(e, "Konnte Paket von " + manager.getCutAddress() + " nicht verarbeiten");
manager.sendPacket(new SPacketDisconnect(), new GenericFutureListener<Future<? super Void>>() { manager.sendPacket(new SPacketDisconnect(), new GenericFutureListener<Future<? super Void>>() {
public void operationComplete(Future<? super Void> future) throws Exception { 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() { public Map<String, Position> getWarps() {
return this.warps; return this.warps;
} }
//
// public void start() {
// this.serverThread.start();
// }
public void start() { private void stopServer() {
this.serverThread.start();
}
void stopServer() {
if(!this.stopped) { if(!this.stopped) {
this.setProgress(-1); this.setProgress(-1);
this.setMessage("Stoppe server"); this.setMessage("Stoppe server");
@ -1162,7 +1093,7 @@ public final class Server implements Runnable, IThreadListener {
for(Player conn : Lists.newArrayList(this.players)) { for(Player conn : Lists.newArrayList(this.players)) {
conn.disconnect(); conn.disconnect();
} }
this.terminateEndpoints(true); this.terminateEndpoint();
if(this.started) { if(this.started) {
Log.JNI.info("Speichere Spieler"); Log.JNI.info("Speichere Spieler");
this.saveAllPlayerData(true); this.saveAllPlayerData(true);
@ -1203,4 +1134,14 @@ public final class Server implements Runnable, IThreadListener {
})); }));
this.running = false; 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; package game.gui;
import game.Game; import game.Game;
import game.Server; import game.ServerProcess;
import game.gui.element.Bar; import game.gui.element.Bar;
import game.gui.element.Label; import game.gui.element.Label;
@ -18,7 +18,7 @@ public class GuiLoading extends Gui {
private Bar progressBar1; private Bar progressBar1;
private Bar progressBar2; 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() { return new GuiLoading("Lade Welt ...", new Callback() {
boolean started = false; boolean started = false;
@ -26,8 +26,8 @@ public class GuiLoading extends Gui {
if(!this.started && server.isStarted()) { if(!this.started && server.isStarted()) {
this.started = true; this.started = true;
// gm.displayGuiScreen(null); // gm.displayGuiScreen(null);
server.setVar("viewDistance", "" + gm.renderDistance); gm.debugWorld = server.getFolder() == null;
gm.connectToIntegrated(server, user); gm.connect(null, gm.port, user, "", "", key);
// return; // return;
} }
int progress = server.getProgress(); 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() { return new GuiLoading("Lade Welt ...", new Callback() {
public void poll(Game gm, GuiLoading gui) { public void poll(Game gm, GuiLoading gui) {
int progress = server.getProgress(); 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() { return new GuiLoading("Speichere Welt ...", new Callback() {
public void poll(Game gm, GuiLoading gui) { public void poll(Game gm, GuiLoading gui) {
if(server.isStopped()) { if(server.isStopped()) {

View file

@ -8,7 +8,6 @@ import game.gui.element.ActButton.Mode;
import game.gui.element.Label; import game.gui.element.Label;
import game.gui.element.NavButton; import game.gui.element.NavButton;
import game.gui.element.Textbox; import game.gui.element.Textbox;
import game.gui.element.Textbox.Action;
import game.gui.options.GuiOptions; import game.gui.options.GuiOptions;
import game.gui.server.GuiConnect; import game.gui.server.GuiConnect;
import game.gui.world.GuiWorlds; 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")); this.add(new NavButton(0, 28, this.gm.charEditor ? 400 : 198, 24, GuiOptions.getPage(), "Einstellungen"));
if(!this.gm.charEditor) if(!this.gm.charEditor)
this.add(new NavButton(202, 28, 198, 24, GuiCharacters.INSTANCE, "Charakter")); 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() { this.add(new ActButton(0, 102, 400, 24, new ActButton.Callback() {
public void use(ActButton elem, ActButton.Mode action) { public void use(ActButton elem, ActButton.Mode action) {
GuiMenu.this.gm.unload(true); 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; import game.gui.element.NavButton;
public abstract class GuiOptions extends Gui { 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; private static GuiOptions lastPage;

View file

@ -105,7 +105,7 @@ public class GuiConnect extends Gui implements Textbox.Callback {
this.lastPass = pass; this.lastPass = pass;
this.lastAcc = acc; this.lastAcc = acc;
this.gm.setDirty(); 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) { public void use(Textbox elem, Action value) {

View file

@ -1,7 +1,25 @@
package game.init; 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 abstract class Registry {
public static void register() { private static boolean crashed;
private static void register() {
NameRegistry.register(); NameRegistry.register();
BlockRegistry.register(); BlockRegistry.register();
FlammabilityRegistry.register(); FlammabilityRegistry.register();
@ -17,4 +35,106 @@ public abstract class Registry {
RotationRegistry.register(); RotationRegistry.register();
ReorderRegistry.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

@ -31,12 +31,9 @@ public class ClientLoginHandler extends NetHandler {
} }
public final void handleEnableCompression(RPacketEnableCompression packetIn) 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) { // public void handlePasswordRequest(RPacketPasswordRequest packetIn) {
// if(this.server == null) { // if(this.server == null) {

View file

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

View file

@ -1,12 +1,45 @@
package game.network; package game.network;
import game.Server;
import game.init.Config;
import game.packet.HPacketHandshake; 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 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() 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) { if(this.server.getPlayer(this.loginUser) != null) {
this.closeConnection("Nutzername '" + this.loginUser + "' ist bereits vergeben."); this.closeConnection("Nutzername '" + this.loginUser + "' ist bereits vergeben.");
return; return;
} }
}
// if (this.server.getPlayer(this.loginUser) != null) // if (this.server.getPlayer(this.loginUser) != null)
// { // {
// this.closeConnection("Nutzername '" + this.loginUser + "' ist bereits vergeben."); // this.closeConnection("Nutzername '" + this.loginUser + "' ist bereits vergeben.");
@ -118,7 +105,9 @@ public class LoginHandler extends NetHandler
if(this.state != LoginState.PASSWORD) if(this.state != LoginState.PASSWORD)
throw new IllegalStateException("Unerwartetes Passwort-Paket"); throw new IllegalStateException("Unerwartetes Passwort-Paket");
this.loginUser = packetIn.getUser(); this.loginUser = packetIn.getUser();
if(this.netManager.isLocalChannel()) { if(packetIn.getLocal() != null) {
// TODO: key verification
this.netManager.setLocal();
this.loginPass = ""; this.loginPass = "";
// this.loginUser = Config.localUser; // this.loginUser = Config.localUser;
if(this.loginUser.length() > Player.MAX_USER_LENGTH || (!this.loginUser.isEmpty() && !Player.isValidUser(this.loginUser))) { 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.ChannelOption;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler; 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.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; 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()); 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 Queue<NetConnection.InboundHandlerTuplePacketListener> outboundPacketsQueue = new ConcurrentLinkedQueue<InboundHandlerTuplePacketListener>();
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
@ -70,16 +52,11 @@ public class NetConnection extends SimpleChannelInboundHandler<Packet>
private boolean disconnected; private boolean disconnected;
private boolean local; private boolean local;
// public NetConnection(PacketDirection packetDirection)
// {
// this.direction = packetDirection;
// }
public void channelActive(ChannelHandlerContext p_channelActive_1_) throws Exception public void channelActive(ChannelHandlerContext p_channelActive_1_) throws Exception
{ {
super.channelActive(p_channelActive_1_); super.channelActive(p_channelActive_1_);
this.channel = p_channelActive_1_.channel(); 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(); this.socketAddress = this.channel.remoteAddress();
try try
@ -324,6 +301,11 @@ public class NetConnection extends SimpleChannelInboundHandler<Packet>
return this.local; return this.local;
} }
public void setLocal()
{
this.local = true;
}
/** /**
* Create a new NetworkManager from the server host and connect it to the server * 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; 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() public boolean isChannelOpen()
{ {
return this.channel != null && this.channel.isOpen(); return this.channel != null && this.channel.isOpen();

View file

@ -74,6 +74,7 @@ import game.packet.SPacketMessage;
import game.packet.SPacketMultiBlockChange; import game.packet.SPacketMultiBlockChange;
import game.packet.SPacketPlayerPosLook; import game.packet.SPacketPlayerPosLook;
import game.packet.SPacketRespawn; import game.packet.SPacketRespawn;
import game.packet.SPacketServerTick;
import game.packet.SPacketSetExperience; import game.packet.SPacketSetExperience;
import game.packet.SPacketSkin; import game.packet.SPacketSkin;
import game.packet.SPacketSpawnMob; import game.packet.SPacketSpawnMob;
@ -178,6 +179,7 @@ public enum PacketRegistry
// this.server(SPacketNotify.class); // this.server(SPacketNotify.class);
this.server(SPacketDimensionName.class); this.server(SPacketDimensionName.class);
this.server(SPacketCharacterList.class); this.server(SPacketCharacterList.class);
this.server(SPacketServerTick.class);
this.client(CPacketKeepAlive.class); this.client(CPacketKeepAlive.class);
this.client(CPacketMessage.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.pingKey = (int)this.lastPingTime;
this.sendPacket(new SPacketKeepAlive(this.pingKey)); this.sendPacket(new SPacketKeepAlive(this.pingKey));
} }
if(this.local)
if(this.respawnTimer > 0) { if(this.respawnTimer > 0) {
if(--this.respawnTimer == 0) { if(--this.respawnTimer == 0) {
this.respawnPlayer(); this.respawnPlayer();
@ -2511,7 +2513,7 @@ public class Player extends NetHandler implements ICrafting, Executor
NetHandler.checkThread(packetIn, this, this.server); NetHandler.checkThread(packetIn, this, this.server);
CPacketAction.Action action = packetIn.getAction(); 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) // if(this.local && action == Action.CLOSE_EDITOR)
// this.server.setDone(); // this.server.setDone();
return; return;
@ -2874,6 +2876,26 @@ public class Player extends NetHandler implements ICrafting, Executor
} }
break; 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: default:
throw new IllegalArgumentException("Ungültige Aktion!"); throw new IllegalArgumentException("Ungültige Aktion!");
} }

View file

@ -93,6 +93,9 @@ public class CPacketAction implements Packet<Player>
HEAL, HEAL,
REPAIR, REPAIR,
PERF, 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 user;
private String access; private String access;
private String password; private String password;
private byte[] local;
public LPacketPasswordResponse() public LPacketPasswordResponse()
{ {
} }
public LPacketPasswordResponse(String userIn, String accessIn, String passwordIn) public LPacketPasswordResponse(String userIn, String accessIn, String passwordIn, byte[] local)
{ {
this.user = userIn; this.user = userIn;
this.access = accessIn; this.access = accessIn;
this.password = passwordIn; 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.user = buf.readStringFromBuffer(Player.MAX_USER_LENGTH);
this.access = buf.readStringFromBuffer(Player.MAX_PASS_LENGTH); this.access = buf.readStringFromBuffer(Player.MAX_PASS_LENGTH);
this.password = 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.user);
buf.writeString(this.access); buf.writeString(this.access);
buf.writeString(this.password); 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; 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; import game.network.PacketBuffer;
public class SPacketTimeUpdate implements Packet<ClientPlayer> { public class SPacketTimeUpdate implements Packet<ClientPlayer> {
// private long totalWorldTime;
private long worldTime; private long worldTime;
private String serverInfo;
public SPacketTimeUpdate() { public SPacketTimeUpdate() {
} }
public SPacketTimeUpdate(long totalTimeIn) { public SPacketTimeUpdate(long time, String info) {
// this.totalWorldTime = totalWorldTimeIn; this.worldTime = time;
this.worldTime = totalTimeIn; this.serverInfo = info;
} }
public void readPacketData(PacketBuffer buf) throws IOException { public void readPacketData(PacketBuffer buf) throws IOException {
// this.totalWorldTime = buf.readLong();
this.worldTime = buf.readLong(); this.worldTime = buf.readLong();
this.serverInfo = buf.readStringFromBuffer(512);
} }
public void writePacketData(PacketBuffer buf) throws IOException { public void writePacketData(PacketBuffer buf) throws IOException {
// buf.writeLong(this.totalWorldTime);
buf.writeLong(this.worldTime); buf.writeLong(this.worldTime);
buf.writeString(this.serverInfo);
} }
public void processPacket(ClientPlayer handler) { public void processPacket(ClientPlayer handler) {
handler.handleTimeUpdate(this); handler.handleTimeUpdate(this);
} }
// public long getTotalWorldTime() {
// return this.totalWorldTime;
// }
public long getWorldTime() { public long getWorldTime() {
return this.worldTime; 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; package game.util;
import java.awt.GraphicsEnvironment;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.JOptionPane;
import game.log.Log; import game.log.Log;
import game.properties.IStringSerializable; 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) | return (color & 0xff000000) | ((((color >> 16 & 255) * mul) / 255) << 16) | ((((color >> 8 & 255) * mul) / 255) << 8) |
(((color & 255) * mul) / 255); (((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 static final int[][] XZ_DIRS = new int[][] {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
private final Server server; private final Server server;
private final File dir;
private final File chunkDir; private final File chunkDir;
private final Random grng; private final Random grng;
private final Set<NextTickListEntry> ticks = Sets.<NextTickListEntry>newHashSet(); private final Set<NextTickListEntry> ticks = Sets.<NextTickListEntry>newHashSet();
@ -156,14 +155,13 @@ public final class WorldServer extends World {
private long prevUpdate; private long prevUpdate;
private long time; 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); super(dim, false, debug);
this.server = server; this.server = server;
this.dir = dir;
// this.time = time; // this.time = time;
this.daytime = dtime; this.daytime = dtime;
this.updateViewRadius(); this.updateViewRadius();
this.chunkDir = new File(new File(this.dir, "chunk"), dim.getDimensionName()); this.chunkDir = new File(new File("chunk"), dim.getDimensionName());
if(!debug) { if(!debug) {
this.chunkDir.mkdirs(); this.chunkDir.mkdirs();
this.seed = this.rand.longv(); this.seed = this.rand.longv();
@ -800,10 +798,10 @@ public final class WorldServer extends World {
return list; return list;
} }
public static boolean needsLoading(File dir, Dimension dim) { public static boolean needsLoading(Dimension dim) {
NBTTagCompound tag = null; NBTTagCompound tag = null;
try { 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()) if(dat.exists() && dat.isFile())
tag = NBTLoader.readGZip(dat); 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(); 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; NBTTagCompound tag = null;
try { 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()) if(dat.exists() && dat.isFile())
tag = NBTLoader.readGZip(dat); 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(); Map<Integer, NBTTagList> map = Maps.newHashMap();
for(Entry<String, Position> pos : warps.entrySet()) { for(Entry<String, Position> pos : warps.entrySet()) {
Dimension dim = UniverseRegistry.getDimension(pos.getValue().dim); Dimension dim = UniverseRegistry.getDimension(pos.getValue().dim);
@ -854,7 +852,7 @@ public final class WorldServer extends World {
} }
for(Dimension dim : UniverseRegistry.getDimensions()) { for(Dimension dim : UniverseRegistry.getDimensions()) {
NBTTagList list = map.get(dim.getDimensionId()); 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) { if(list == null) {
file.delete(); file.delete();
} }