Custom map providers / Added next map specification command

This commit is contained in:
Anuken
2019-11-18 18:56:49 -05:00
parent ad25cd8074
commit 134fea445c
2 changed files with 129 additions and 59 deletions

View File

@@ -8,10 +8,12 @@ import io.anuke.arc.collection.IntSet.*;
import io.anuke.arc.files.*; import io.anuke.arc.files.*;
import io.anuke.arc.func.*; import io.anuke.arc.func.*;
import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.*;
import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.arc.util.async.*; import io.anuke.arc.util.async.*;
import io.anuke.arc.util.io.*; import io.anuke.arc.util.io.*;
import io.anuke.arc.util.serialization.*; import io.anuke.arc.util.serialization.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.content.*; import io.anuke.mindustry.content.*;
import io.anuke.mindustry.ctype.*; import io.anuke.mindustry.ctype.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
@@ -34,9 +36,30 @@ public class Maps{
/** Serializer for meta. */ /** Serializer for meta. */
private Json json = new Json(); private Json json = new Json();
private ShuffleMode shuffleMode = ShuffleMode.all;
private @Nullable MapProvider shuffler;
private AsyncExecutor executor = new AsyncExecutor(2); private AsyncExecutor executor = new AsyncExecutor(2);
private ObjectSet<Map> previewList = new ObjectSet<>(); private ObjectSet<Map> previewList = new ObjectSet<>();
public ShuffleMode getShuffleMode(){
return shuffleMode;
}
public void setShuffleMode(ShuffleMode mode){
this.shuffleMode = mode;
}
/** Set the provider for the map(s) to be played on. Will override the default shuffle mode setting.*/
public void setMapProvider(MapProvider provider){
this.shuffler = provider;
}
/** @return the next map to shuffle to. May be null, in which case the server should be stopped. */
public @Nullable Map getNextMap(@Nullable Map previous){
return shuffler != null ? shuffler.next(previous) : shuffleMode.next(previous);
}
/** Returns a list of all maps, including custom ones. */ /** Returns a list of all maps, including custom ones. */
public Array<Map> all(){ public Array<Map> all(){
return maps; return maps;
@@ -422,4 +445,37 @@ public class Maps{
return map; return map;
} }
public interface MapProvider{
@Nullable Map next(@Nullable Map previous);
}
public enum ShuffleMode implements MapProvider{
none(map -> null),
all(prev -> {
Array<Map> maps = Array.withArrays(Vars.maps.defaultMaps(), Vars.maps.customMaps());
maps.shuffle();
return maps.find(m -> m != prev || maps.size == 1);
}),
custom(prev -> {
Array<Map> maps = Array.withArrays(Vars.maps.customMaps());
maps.shuffle();
return maps.find(m -> m != prev || maps.size == 1);
}),
builtin(prev -> {
Array<Map> maps = Array.withArrays(Vars.maps.defaultMaps());
maps.shuffle();
return maps.find(m -> m != prev || maps.size == 1);
});
private final MapProvider provider;
ShuffleMode(MapProvider provider){
this.provider = provider;
}
@Override
public Map next(@Nullable Map previous){
return provider.next(previous);
}
}
} }

View File

@@ -5,6 +5,7 @@ import io.anuke.arc.collection.*;
import io.anuke.arc.collection.Array.*; import io.anuke.arc.collection.Array.*;
import io.anuke.arc.files.*; import io.anuke.arc.files.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.arc.util.Timer; import io.anuke.arc.util.Timer;
import io.anuke.arc.util.CommandHandler.*; import io.anuke.arc.util.CommandHandler.*;
import io.anuke.arc.util.Timer.*; import io.anuke.arc.util.Timer.*;
@@ -21,6 +22,7 @@ import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.io.*; import io.anuke.mindustry.io.*;
import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.maps.*; import io.anuke.mindustry.maps.*;
import io.anuke.mindustry.maps.Maps.*;
import io.anuke.mindustry.mod.Mods.*; import io.anuke.mindustry.mod.Mods.*;
import io.anuke.mindustry.net.Administration.*; import io.anuke.mindustry.net.Administration.*;
import io.anuke.mindustry.net.Packets.*; import io.anuke.mindustry.net.Packets.*;
@@ -48,6 +50,7 @@ public class ServerControl implements ApplicationListener{
private boolean inExtraRound; private boolean inExtraRound;
private Task lastTask; private Task lastTask;
private Gamemode lastMode = Gamemode.survival; private Gamemode lastMode = Gamemode.survival;
private @Nullable Map nextMapOverride;
private Thread socketThread; private Thread socketThread;
private PrintWriter socketOutput; private PrintWriter socketOutput;
@@ -57,7 +60,7 @@ public class ServerControl implements ApplicationListener{
"shufflemode", "normal", "shufflemode", "normal",
"bans", "", "bans", "",
"admins", "", "admins", "",
"shuffle", true, "shufflemode", "all",
"crashreport", false, "crashreport", false,
"port", port, "port", port,
"logging", true, "logging", true,
@@ -142,21 +145,25 @@ public class ServerControl implements ApplicationListener{
warn("&lyIt is highly advised to specify which version you're using by building with gradle args &lc-Pbuildversion=&lm<build>&ly."); warn("&lyIt is highly advised to specify which version you're using by building with gradle args &lc-Pbuildversion=&lm<build>&ly.");
} }
//set up default shuffle mode
try{
maps.setShuffleMode(ShuffleMode.valueOf(Core.settings.getString("shufflemode")));
}catch(Exception e){
maps.setShuffleMode(ShuffleMode.all);
}
Events.on(GameOverEvent.class, event -> { Events.on(GameOverEvent.class, event -> {
if(inExtraRound) return; if(inExtraRound) return;
info("Game over!"); if(state.rules.waves){
displayStatus(); info("&lcGame over! Reached wave &ly{0}&lc with &ly{1}&lc players online on map &ly{2}&lc.", state.wave, playerGroup.size(), Strings.capitalize(world.getMap().name()));
}else{
if(Core.settings.getBool("shuffle")){ info("&lcGame over! Team &ly{0}&lc is victorious with &ly{1}&lc players online on map &ly{2}&lc.", event.winner.name(), playerGroup.size(), Strings.capitalize(world.getMap().name()));
if(maps.all().size > 0){ }
Array<Map> maps = Array.with(Vars.maps.customMaps().size == 0 ? Vars.maps.defaultMaps() : Vars.maps.customMaps());
maps.shuffle();
Map previous = world.getMap();
Map map = maps.find(m -> m != previous || maps.size == 1);
//set next map to be played
Map map = nextMapOverride != null ? nextMapOverride : maps.getNextMap(world.getMap());
nextMapOverride = null;
if(map != null){ if(map != null){
Call.onInfoMessage((state.rules.pvp Call.onInfoMessage((state.rules.pvp
? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]") ? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]")
+ "\nNext selected map:[accent] " + map.name() + "[]" + "\nNext selected map:[accent] " + map.name() + "[]"
@@ -166,10 +173,6 @@ public class ServerControl implements ApplicationListener{
info("Selected next map to be {0}.", map.name()); info("Selected next map to be {0}.", map.name());
play(true, () -> world.loadMap(map, map.applyRules(lastMode))); play(true, () -> world.loadMap(map, map.applyRules(lastMode)));
}else{
Log.err("No suitable map found.");
}
}
}else{ }else{
netServer.kickAll(KickReason.gameover); netServer.kickAll(KickReason.gameover);
state.set(State.menu); state.set(State.menu);
@@ -304,7 +307,29 @@ public class ServerControl implements ApplicationListener{
}); });
handler.register("status", "Display server status.", arg -> { handler.register("status", "Display server status.", arg -> {
displayStatus(); if(state.is(State.menu)){
info("Status: &rserver closed");
}else{
info("Status:");
info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1}", Strings.capitalize(world.getMap().name()), state.wave);
if(state.rules.waves){
info("&ly {0} enemies.", unitGroups[Team.crux.ordinal()].size());
}else{
info("&ly {0} seconds until next wave.", (int)(state.wavetime / 60));
}
info(" &ly{0} FPS, {1} MB used.", (int)(60f / Time.delta()), Core.app.getJavaHeap() / 1024 / 1024);
if(playerGroup.size() > 0){
info(" &lyPlayers: {0}", playerGroup.size());
for(Player p : playerGroup.all()){
info(" &y{0} / {1}", p.name, p.uuid);
}
}else{
info(" &lyNo players connected.");
}
}
}); });
handler.register("mods", "Display all loaded mods.", arg -> { handler.register("mods", "Display all loaded mods.", arg -> {
@@ -553,14 +578,29 @@ public class ServerControl implements ApplicationListener{
} }
}); });
handler.register("shuffle", "<on/off>", "Set map shuffling.", arg -> { handler.register("shuffle", "[none/all/custom/builtin]", "Set map shuffling mode.", arg -> {
if(!arg[0].equals("on") && !arg[0].equals("off")){ if(arg.length == 0){
info("Shuffle mode current set to &ly'{0}'&lg.", maps.getShuffleMode());
}else{
try{
ShuffleMode mode = ShuffleMode.valueOf(arg[0]);
Core.settings.putSave("shufflemode", mode.name());
maps.setShuffleMode(mode);
info("Shuffle mode set to &ly'{0}'&lg.", arg[0]);
}catch(Exception e){
err("Invalid shuffle mode."); err("Invalid shuffle mode.");
return;
} }
Core.settings.put("shuffle", arg[0].equals("on")); }
Core.settings.save(); });
info("Shuffle mode set to '{0}'.", arg[0]);
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.name().equalsIgnoreCase(arg[0].replace('_', ' ')) || map.name().equalsIgnoreCase(arg[0]));
if(res != null){
nextMapOverride = res;
Log.info("Next map set to &ly'{0}'.", res.name());
}else{
Log.err("No map '{0}' found.", arg[0]);
}
}); });
handler.register("kick", "<username...>", "Kick a person by name.", arg -> { handler.register("kick", "<username...>", "Kick a person by name.", arg -> {
@@ -759,7 +799,7 @@ public class ServerControl implements ApplicationListener{
handler.register("gameover", "Force a game over.", arg -> { handler.register("gameover", "Force a game over.", arg -> {
if(state.is(State.menu)){ if(state.is(State.menu)){
info("Not playing a map."); err("Not playing a map.");
return; return;
} }
@@ -809,32 +849,6 @@ public class ServerControl implements ApplicationListener{
} }
} }
private void displayStatus() {
if(state.is(State.menu)){
info("Status: &rserver closed");
}else{
info("Status:");
info(" &lyPlaying on map &fi{0}&fb &lb/&ly Wave {1}", Strings.capitalize(world.getMap().name()), state.wave);
if(state.rules.waves){
info("&ly {0} enemies.", unitGroups[Team.crux.ordinal()].size());
}else{
info("&ly {0} seconds until next wave.", (int)(state.wavetime / 60));
}
info(" &ly{0} FPS, {1} MB used.", (int)(60f / Time.delta()), Core.app.getJavaHeap() / 1024 / 1024);
if(playerGroup.size() > 0){
info(" &lyPlayers: {0}", playerGroup.size());
for(Player p : playerGroup.all()){
info(" &y{0} / {1}", p.name, p.uuid);
}
}else{
info(" &lyNo players connected.");
}
}
}
private void readCommands(){ private void readCommands(){
Scanner scan = new Scanner(System.in); Scanner scan = new Scanner(System.in);