add server
This commit is contained in:
parent
d5269922b9
commit
76ecfb39ab
25 changed files with 603 additions and 520 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue