mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-07-28 13:47:32 +07:00
ServerControl improvements (#8928)
* Update ServerControl.java * Update Administration.java * Update Maps.java * Update ServerControl.java * Update ServerControl.java * Update Administration.java * Update ServerControl.java * Update Maps.java
This commit is contained in:
@ -44,7 +44,9 @@ public class Maps{
|
||||
/** All maps stored in an ordered array. */
|
||||
private Seq<Map> maps = new Seq<>();
|
||||
private ShuffleMode shuffleMode = ShuffleMode.all;
|
||||
|
||||
private @Nullable MapProvider shuffler;
|
||||
private @Nullable Map nextMapOverride;
|
||||
|
||||
private ObjectSet<Map> previewList = new ObjectSet<>();
|
||||
|
||||
@ -61,8 +63,19 @@ public class Maps{
|
||||
this.shuffler = provider;
|
||||
}
|
||||
|
||||
/** Set the map that will override the next selected map. */
|
||||
public void setNextMapOverride(Map nextMapOverride){
|
||||
this.nextMapOverride = nextMapOverride;
|
||||
}
|
||||
|
||||
/** @return the next map to shuffle to. May be null, in which case the server should be stopped. */
|
||||
public @Nullable Map getNextMap(Gamemode mode, @Nullable Map previous){
|
||||
if(nextMapOverride != null){
|
||||
Map next = nextMapOverride;
|
||||
nextMapOverride = null;
|
||||
return next;
|
||||
}
|
||||
|
||||
if(shuffler != null) return shuffler.next(mode, previous);
|
||||
return shuffleMode.next(mode, previous);
|
||||
}
|
||||
|
@ -513,7 +513,9 @@ public class Administration{
|
||||
autosaveSpacing = new Config("autosaveSpacing", "Spacing between autosaves in seconds.", 60 * 5),
|
||||
debug = new Config("debug", "Enable debug logging.", false, () -> Log.level = debug() ? LogLevel.debug : LogLevel.info),
|
||||
snapshotInterval = new Config("snapshotInterval", "Client entity snapshot interval in ms.", 200),
|
||||
autoPause = new Config("autoPause", "Whether the game should pause when nobody is online.", false);
|
||||
autoPause = new Config("autoPause", "Whether the game should pause when nobody is online.", false),
|
||||
roundExtraTime = new Config("roundExtraTime", "Time before loading a new map after the gameover, in seconds.", 12),
|
||||
maxLogLength = new Config("maxLogLength", "The Maximum log file size, in bytes.", 1024 * 1024 * 5);
|
||||
|
||||
public final Object defaultValue;
|
||||
public final String name, key, description;
|
||||
|
@ -2,6 +2,7 @@ package mindustry.server;
|
||||
|
||||
import arc.*;
|
||||
import arc.files.*;
|
||||
import arc.func.Cons;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.Timer;
|
||||
@ -35,9 +36,6 @@ import static arc.util.Log.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class ServerControl implements ApplicationListener{
|
||||
private static final int roundExtraTime = 12;
|
||||
private static final int maxLogLength = 1024 * 1024 * 5;
|
||||
|
||||
protected static String[] tags = {"&lc&fb[D]&fr", "&lb&fb[I]&fr", "&ly&fb[W]&fr", "&lr&fb[E]", ""};
|
||||
protected static DateTimeFormatter dateTime = DateTimeFormatter.ofPattern("MM-dd-yyyy HH:mm:ss"),
|
||||
autosaveDate = DateTimeFormatter.ofPattern("MM-dd-yyyy_HH-mm-ss");
|
||||
@ -48,6 +46,8 @@ public class ServerControl implements ApplicationListener{
|
||||
public final CommandHandler handler = new CommandHandler("");
|
||||
public final Fi logFolder = Core.settings.getDataDirectory().child("logs/");
|
||||
|
||||
private final Interval autosaveCount = new Interval();
|
||||
|
||||
public Runnable serverInput = () -> {
|
||||
Scanner scan = new Scanner(System.in);
|
||||
while(scan.hasNext()){
|
||||
@ -56,19 +56,51 @@ public class ServerControl implements ApplicationListener{
|
||||
}
|
||||
};
|
||||
|
||||
private Fi currentLogFile;
|
||||
private boolean inGameOverWait;
|
||||
private Task lastTask;
|
||||
private Gamemode lastMode;
|
||||
private @Nullable Map nextMapOverride;
|
||||
private Interval autosaveCount = new Interval();
|
||||
/** The file to which the logs are currently being written. */
|
||||
public Fi currentLogFile;
|
||||
|
||||
/** Whether the server is currently waiting for the next map to be loaded. */
|
||||
public boolean inGameOverWait;
|
||||
|
||||
/** The last gamemode loaded on this server. */
|
||||
public Gamemode lastMode;
|
||||
|
||||
private Task lastTask;
|
||||
private Thread socketThread;
|
||||
private ServerSocket serverSocket;
|
||||
private PrintWriter socketOutput;
|
||||
private String suggested;
|
||||
private boolean autoPaused = false;
|
||||
|
||||
public Cons<GameOverEvent> gameOverListener = event -> {
|
||||
if(state.rules.waves){
|
||||
info("Game over! Reached wave @ with @ players online on map @.", state.wave, Groups.player.size(), Strings.capitalize(state.map.plainName()));
|
||||
}else{
|
||||
info("Game over! Team @ is victorious with @ players online on map @.", event.winner.name, Groups.player.size(), Strings.capitalize(state.map.plainName()));
|
||||
}
|
||||
|
||||
//set the next map to be played
|
||||
Map map = maps.getNextMap(lastMode, state.map);
|
||||
if(map != null){
|
||||
Call.infoMessage((state.rules.pvp
|
||||
? "[accent]The " + event.winner.coloredName() + " team is victorious![]\n" : "[scarlet]Game over![]\n")
|
||||
+ "\nNext selected map: [accent]" + map.name() + "[white]"
|
||||
+ (map.hasTag("author") ? " by[accent] " + map.author() + "[white]" : "") + "." +
|
||||
"\nNew game begins in " + Config.roundExtraTime.num() + " seconds.");
|
||||
|
||||
state.gameOver = true;
|
||||
Call.updateGameOver(event.winner);
|
||||
|
||||
info("Selected next map to be @.", map.plainName());
|
||||
|
||||
play(() -> world.loadMap(map, map.applyRules(lastMode)));
|
||||
}else{
|
||||
netServer.kickAll(KickReason.gameover);
|
||||
state.set(State.menu);
|
||||
net.closeServer();
|
||||
}
|
||||
};
|
||||
|
||||
public ServerControl(String[] args){
|
||||
setup(args);
|
||||
instance = this;
|
||||
@ -173,33 +205,8 @@ public class ServerControl implements ApplicationListener{
|
||||
}
|
||||
|
||||
Events.on(GameOverEvent.class, event -> {
|
||||
if(inGameOverWait) return;
|
||||
if(state.rules.waves){
|
||||
info("Game over! Reached wave @ with @ players online on map @.", state.wave, Groups.player.size(), Strings.capitalize(state.map.plainName()));
|
||||
}else{
|
||||
info("Game over! Team @ is victorious with @ players online on map @.", event.winner.name, Groups.player.size(), Strings.capitalize(state.map.plainName()));
|
||||
}
|
||||
|
||||
//set next map to be played
|
||||
Map map = nextMapOverride != null ? nextMapOverride : maps.getNextMap(lastMode, state.map);
|
||||
nextMapOverride = null;
|
||||
if(map != null){
|
||||
Call.infoMessage((state.rules.pvp
|
||||
? "[accent]The " + event.winner.coloredName() + " team is victorious![]\n" : "[scarlet]Game over![]\n")
|
||||
+ "\nNext selected map: [accent]" + map.name() + "[white]"
|
||||
+ (map.hasTag("author") ? " by[accent] " + map.author() + "[white]" : "") + "." +
|
||||
"\nNew game begins in " + roundExtraTime + " seconds.");
|
||||
|
||||
state.gameOver = true;
|
||||
Call.updateGameOver(event.winner);
|
||||
|
||||
info("Selected next map to be @.", map.plainName());
|
||||
|
||||
play(true, () -> world.loadMap(map, map.applyRules(lastMode)));
|
||||
}else{
|
||||
netServer.kickAll(KickReason.gameover);
|
||||
state.set(State.menu);
|
||||
net.closeServer();
|
||||
if(!inGameOverWait && gameOverListener != null){
|
||||
gameOverListener.get(event);
|
||||
}
|
||||
});
|
||||
|
||||
@ -248,7 +255,6 @@ public class ServerControl implements ApplicationListener{
|
||||
});
|
||||
|
||||
Events.on(PlayEvent.class, e -> {
|
||||
|
||||
try{
|
||||
JsonValue value = JsonIO.json.fromJson(null, Core.settings.getString("globalrules"));
|
||||
JsonIO.json.readFields(state.rules, value);
|
||||
@ -280,9 +286,11 @@ public class ServerControl implements ApplicationListener{
|
||||
toggleSocket(Config.socketInput.bool());
|
||||
|
||||
Events.on(ServerLoadEvent.class, e -> {
|
||||
Thread thread = new Thread(serverInput, "Server Controls");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
if(serverInput != null){
|
||||
Thread thread = new Thread(serverInput, "Server Controls");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
info("Server loaded. Type @ for help.", "'help'");
|
||||
});
|
||||
@ -302,7 +310,6 @@ public class ServerControl implements ApplicationListener{
|
||||
autoPaused = true;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected void registerCommands(){
|
||||
@ -392,7 +399,7 @@ public class ServerControl implements ApplicationListener{
|
||||
autoPaused = true;
|
||||
}
|
||||
}catch(MapException e){
|
||||
err(e.map.plainName() + ": " + e.getMessage());
|
||||
err("@: @", e.map.plainName(), e.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
@ -735,7 +742,7 @@ public class ServerControl implements ApplicationListener{
|
||||
handler.register("nextmap", "<mapname...>", "Set the next map to be played after a game-over. Overrides shuffling.", arg -> {
|
||||
Map res = maps.all().find(map -> map.plainName().replace('_', ' ').equalsIgnoreCase(Strings.stripColors(arg[0]).replace('_', ' ')));
|
||||
if(res != null){
|
||||
nextMapOverride = res;
|
||||
maps.setNextMapOverride(res);
|
||||
info("Next map set to '@'.", res.plainName());
|
||||
}else{
|
||||
err("No map '@' found.", arg[0]);
|
||||
@ -889,8 +896,7 @@ public class ServerControl implements ApplicationListener{
|
||||
}else{
|
||||
info("Players: @", Groups.player.size());
|
||||
for(Player user : Groups.player){
|
||||
PlayerInfo userInfo = user.getInfo();
|
||||
info(" @&lm @ / ID: @ / IP: @", userInfo.admin ? "&r[A]&c" : "&b[P]&c", userInfo.plainLastName(), userInfo.id, userInfo.lastIP, userInfo.admin);
|
||||
info(" @&lm @ / ID: @ / IP: @", user.admin ? "&r[A]&c" : "&b[P]&c", user.plainName(), user.uuid(), user.ip());
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1048,12 +1054,32 @@ public class ServerControl implements ApplicationListener{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Use {@link Maps#setNextMapOverride(Map)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setNextMap(Map map){
|
||||
nextMapOverride = map;
|
||||
maps.setNextMapOverride(map);
|
||||
}
|
||||
|
||||
private void play(boolean wait, Runnable run){
|
||||
/**
|
||||
* Resets the world state, starts a new game.
|
||||
* @param run What task to run to load a new world.
|
||||
*/
|
||||
public void play(Runnable run){
|
||||
play(true, run);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the world state, starts a new game.
|
||||
* @param wait Whether to wait for {@link Config#roundExtraTime} seconds before starting a new game.
|
||||
* @param run What task to run to load a new world.
|
||||
*/
|
||||
public void play(boolean wait, Runnable run){
|
||||
inGameOverWait = true;
|
||||
if(lastTask != null) lastTask.cancel();
|
||||
|
||||
Runnable r = () -> {
|
||||
WorldReloader reloader = new WorldReloader();
|
||||
|
||||
@ -1075,20 +1101,20 @@ public class ServerControl implements ApplicationListener{
|
||||
try{
|
||||
r.run();
|
||||
}catch(MapException e){
|
||||
err(e.map.plainName() + ": " + e.getMessage());
|
||||
err("@: @", e.map.plainName(), e.getMessage());
|
||||
net.closeServer();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Timer.schedule(lastTask, roundExtraTime);
|
||||
Timer.schedule(lastTask, Config.roundExtraTime.num());
|
||||
}else{
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
|
||||
private void logToFile(String text){
|
||||
if(currentLogFile != null && currentLogFile.length() > maxLogLength){
|
||||
public void logToFile(String text){
|
||||
if(currentLogFile != null && currentLogFile.length() > Config.maxLogLength.num()){
|
||||
currentLogFile.writeString("[End of log file. Date: " + dateTime.format(LocalDateTime.now()) + "]\n", true);
|
||||
currentLogFile = null;
|
||||
}
|
||||
@ -1099,7 +1125,7 @@ public class ServerControl implements ApplicationListener{
|
||||
|
||||
if(currentLogFile == null){
|
||||
int i = 0;
|
||||
while(logFolder.child("log-" + i + ".txt").length() >= maxLogLength){
|
||||
while(logFolder.child("log-" + i + ".txt").length() >= Config.maxLogLength.num()){
|
||||
i++;
|
||||
}
|
||||
|
||||
@ -1109,7 +1135,7 @@ public class ServerControl implements ApplicationListener{
|
||||
currentLogFile.writeString(text + "\n", true);
|
||||
}
|
||||
|
||||
private void toggleSocket(boolean on){
|
||||
public void toggleSocket(boolean on){
|
||||
if(on && socketThread == null){
|
||||
socketThread = new Thread(() -> {
|
||||
try{
|
||||
|
Reference in New Issue
Block a user