Added configurable global server rules
This commit is contained in:
@@ -705,6 +705,7 @@ mode.attack.description = Destroy the enemy's base. No waves.\n[gray]Requires a
|
|||||||
mode.custom = Custom Rules
|
mode.custom = Custom Rules
|
||||||
|
|
||||||
rules.infiniteresources = Infinite Resources
|
rules.infiniteresources = Infinite Resources
|
||||||
|
rules.reactorexplosions = Reactor Explosions
|
||||||
rules.wavetimer = Wave Timer
|
rules.wavetimer = Wave Timer
|
||||||
rules.waves = Waves
|
rules.waves = Waves
|
||||||
rules.attack = Attack Mode
|
rules.attack = Attack Mode
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ public class Rules{
|
|||||||
public boolean pvp;
|
public boolean pvp;
|
||||||
/** Whether enemy units drop random items on death. */
|
/** Whether enemy units drop random items on death. */
|
||||||
public boolean unitDrops = true;
|
public boolean unitDrops = true;
|
||||||
|
/** Whether reactors can explode and damage other blocks. */
|
||||||
|
public boolean reactorExplosions = true;
|
||||||
/** How fast unit pads build units. */
|
/** How fast unit pads build units. */
|
||||||
public float unitBuildSpeedMultiplier = 1f;
|
public float unitBuildSpeedMultiplier = 1f;
|
||||||
/** How much health units start with. */
|
/** How much health units start with. */
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import io.anuke.arc.util.serialization.*;
|
|||||||
import io.anuke.arc.util.serialization.Json.*;
|
import io.anuke.arc.util.serialization.Json.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.ctype.MappableContent;
|
import io.anuke.mindustry.ctype.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
@@ -31,6 +31,10 @@ public class JsonIO{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static Json json(){
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
public static String write(Object object){
|
public static String write(Object object){
|
||||||
return json.toJson(object, object.getClass());
|
return json.toJson(object, object.getClass());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ 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.ArcAnnotate.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.arc.util.reflect.Field;
|
|
||||||
import io.anuke.arc.util.reflect.*;
|
|
||||||
import io.anuke.arc.util.serialization.*;
|
import io.anuke.arc.util.serialization.*;
|
||||||
import io.anuke.arc.util.serialization.Json.*;
|
import io.anuke.arc.util.serialization.Json.*;
|
||||||
import io.anuke.arc.util.serialization.Jval.*;
|
import io.anuke.arc.util.serialization.Jval.*;
|
||||||
@@ -361,7 +359,7 @@ public class ContentParser{
|
|||||||
|
|
||||||
private <T> T make(Class<T> type){
|
private <T> T make(Class<T> type){
|
||||||
try{
|
try{
|
||||||
java.lang.reflect.Constructor<T> cons = type.getDeclaredConstructor();
|
Constructor<T> cons = type.getDeclaredConstructor();
|
||||||
cons.setAccessible(true);
|
cons.setAccessible(true);
|
||||||
return cons.newInstance();
|
return cons.newInstance();
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -371,7 +369,7 @@ public class ContentParser{
|
|||||||
|
|
||||||
private <T> T make(Class<T> type, String name){
|
private <T> T make(Class<T> type, String name){
|
||||||
try{
|
try{
|
||||||
java.lang.reflect.Constructor<T> cons = type.getDeclaredConstructor(String.class);
|
Constructor<T> cons = type.getDeclaredConstructor(String.class);
|
||||||
cons.setAccessible(true);
|
cons.setAccessible(true);
|
||||||
return cons.newInstance(name);
|
return cons.newInstance(name);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -381,7 +379,7 @@ public class ContentParser{
|
|||||||
|
|
||||||
private <T> Prov<T> supply(Class<T> type){
|
private <T> Prov<T> supply(Class<T> type){
|
||||||
try{
|
try{
|
||||||
java.lang.reflect.Constructor<T> cons = type.getDeclaredConstructor();
|
Constructor<T> cons = type.getDeclaredConstructor();
|
||||||
return () -> {
|
return () -> {
|
||||||
try{
|
try{
|
||||||
return cons.newInstance();
|
return cons.newInstance();
|
||||||
@@ -457,7 +455,7 @@ public class ContentParser{
|
|||||||
Field field = metadata.field;
|
Field field = metadata.field;
|
||||||
try{
|
try{
|
||||||
field.set(object, parser.readValue(field.getType(), metadata.elementType, child, metadata.keyType));
|
field.set(object, parser.readValue(field.getType(), metadata.elementType, child, metadata.keyType));
|
||||||
}catch(ReflectionException ex){
|
}catch(IllegalAccessException ex){
|
||||||
throw new SerializationException("Error accessing field: " + field.getName() + " (" + type.getName() + ")", ex);
|
throw new SerializationException("Error accessing field: " + field.getName() + " (" + type.getName() + ")", ex);
|
||||||
}catch(SerializationException ex){
|
}catch(SerializationException ex){
|
||||||
ex.addTrace(field.getName() + " (" + type.getName() + ")");
|
ex.addTrace(field.getName() + " (" + type.getName() + ")");
|
||||||
|
|||||||
@@ -135,13 +135,11 @@ public class CustomRulesDialog extends FloatingDialog{
|
|||||||
number("$rules.dropzoneradius", false, f -> rules.dropZoneRadius = f * tilesize, () -> rules.dropZoneRadius / tilesize, () -> true);
|
number("$rules.dropzoneradius", false, f -> rules.dropZoneRadius = f * tilesize, () -> rules.dropZoneRadius / tilesize, () -> true);
|
||||||
|
|
||||||
title("$rules.title.respawns");
|
title("$rules.title.respawns");
|
||||||
//limited respawns don't work on PvP, commented out until they're fixed
|
|
||||||
//check("$rules.limitedRespawns", b -> rules.limitedRespawns = b, () -> rules.limitedRespawns);
|
|
||||||
//number("$rules.respawns", true, f -> rules.respawns = (int)f, () -> rules.respawns, () -> rules.limitedRespawns);
|
|
||||||
number("$rules.respawntime", f -> rules.respawnTime = f * 60f, () -> rules.respawnTime / 60f);
|
number("$rules.respawntime", f -> rules.respawnTime = f * 60f, () -> rules.respawnTime / 60f);
|
||||||
|
|
||||||
title("$rules.title.resourcesbuilding");
|
title("$rules.title.resourcesbuilding");
|
||||||
check("$rules.infiniteresources", b -> rules.infiniteResources = b, () -> rules.infiniteResources);
|
check("$rules.infiniteresources", b -> rules.infiniteResources = b, () -> rules.infiniteResources);
|
||||||
|
check("$rules.reactorexplosions", b -> rules.reactorExplosions = b, () -> rules.reactorExplosions);
|
||||||
number("$rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources);
|
number("$rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources);
|
||||||
number("$rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier);
|
number("$rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import io.anuke.mindustry.world.meta.StatUnit;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.tilesize;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class NuclearReactor extends PowerGenerator{
|
public class NuclearReactor extends PowerGenerator{
|
||||||
protected final int timerFuel = timers++;
|
protected final int timerFuel = timers++;
|
||||||
@@ -127,7 +127,7 @@ public class NuclearReactor extends PowerGenerator{
|
|||||||
|
|
||||||
int fuel = entity.items.get(consumes.<ConsumeItems>get(ConsumeType.item).items[0].item);
|
int fuel = entity.items.get(consumes.<ConsumeItems>get(ConsumeType.item).items[0].item);
|
||||||
|
|
||||||
if(fuel < 5 && entity.heat < 0.5f) return;
|
if((fuel < 5 && entity.heat < 0.5f) || !state.rules.reactorExplosions) return;
|
||||||
|
|
||||||
Effects.shake(6f, 16f, tile.worldx(), tile.worldy());
|
Effects.shake(6f, 16f, tile.worldx(), tile.worldy());
|
||||||
Effects.effect(Fx.nuclearShockwave, tile.worldx(), tile.worldy());
|
Effects.effect(Fx.nuclearShockwave, tile.worldx(), tile.worldy());
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||||
archash=9cde8aeb1f4913d5f9c1ed1792d5c5c5d522298c
|
archash=68a64d9e8a3016ad433d0959be78f6acdcdaa385
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import io.anuke.arc.util.*;
|
|||||||
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.*;
|
||||||
|
import io.anuke.arc.util.serialization.*;
|
||||||
|
import io.anuke.arc.util.serialization.JsonValue.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.core.GameState.*;
|
import io.anuke.mindustry.core.GameState.*;
|
||||||
import io.anuke.mindustry.core.*;
|
import io.anuke.mindustry.core.*;
|
||||||
@@ -59,7 +61,8 @@ public class ServerControl implements ApplicationListener{
|
|||||||
"crashreport", false,
|
"crashreport", false,
|
||||||
"port", port,
|
"port", port,
|
||||||
"logging", true,
|
"logging", true,
|
||||||
"socket", false
|
"socket", false,
|
||||||
|
"globalrules", "{}"
|
||||||
);
|
);
|
||||||
|
|
||||||
Log.setLogger(new LogHandler(){
|
Log.setLogger(new LogHandler(){
|
||||||
@@ -250,8 +253,9 @@ public class ServerControl implements ApplicationListener{
|
|||||||
logic.reset();
|
logic.reset();
|
||||||
lastMode = preset;
|
lastMode = preset;
|
||||||
try{
|
try{
|
||||||
world.loadMap(result, result.applyRules(lastMode));
|
world.loadMap(result, result.applyRules(lastMode));
|
||||||
state.rules = result.applyRules(preset);
|
state.rules = result.applyRules(preset);
|
||||||
|
applyRules();
|
||||||
logic.play();
|
logic.play();
|
||||||
|
|
||||||
info("Map loaded.");
|
info("Map loaded.");
|
||||||
@@ -348,6 +352,58 @@ public class ServerControl implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
handler.register("rules", "[remove/add] [name] [value...]", "List, remove or add global rules. These will apply regardless of map.", arg -> {
|
||||||
|
String rules = Core.settings.getString("globalrules");
|
||||||
|
JsonValue base = JsonIO.json().fromJson(null, rules);
|
||||||
|
|
||||||
|
if(arg.length == 0){
|
||||||
|
Log.info("&lyRules:\n{0}", JsonIO.print(rules));
|
||||||
|
}else if(arg.length == 1){
|
||||||
|
Log.err("Invalid usage. Specify which rule to remove or add.");
|
||||||
|
}else{
|
||||||
|
if(!(arg[0].equals("remove") || arg[0].equals("add"))){
|
||||||
|
Log.err("Invalid usage. Either add or remove rules.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean remove = arg[0].equals("remove");
|
||||||
|
if(remove){
|
||||||
|
if(base.has(arg[1])){
|
||||||
|
Log.info("Rule &lc'{0}'&lg removed.", arg[1]);
|
||||||
|
base.remove(arg[1]);
|
||||||
|
}else{
|
||||||
|
Log.err("Rule not defined, so not removed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(arg.length < 3){
|
||||||
|
Log.err("Missing last argument. Specify which value to set the rule to.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
JsonValue value = new JsonReader().parse(arg[2]);
|
||||||
|
value.name = arg[1];
|
||||||
|
|
||||||
|
JsonValue parent = new JsonValue(ValueType.object);
|
||||||
|
parent.addChild(value);
|
||||||
|
|
||||||
|
JsonIO.json().readField(state.rules, value.name, parent);
|
||||||
|
if(base.has(value.name)){
|
||||||
|
base.remove(value.name);
|
||||||
|
}
|
||||||
|
base.addChild(arg[1], value);
|
||||||
|
Log.info("Changed rule: &ly{0}", value.toString().replace("\n", " "));
|
||||||
|
}catch(Throwable e){
|
||||||
|
Log.err("Error parsing rule JSON", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Core.settings.putSave("globalrules", base.toString());
|
||||||
|
Call.onSetRules(state.rules);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
handler.register("fillitems", "[team]", "Fill the core with items.", arg -> {
|
handler.register("fillitems", "[team]", "Fill the core with items.", arg -> {
|
||||||
if(!state.is(State.playing)){
|
if(!state.is(State.playing)){
|
||||||
err("Not playing. Host first.");
|
err("Not playing. Host first.");
|
||||||
@@ -744,6 +800,15 @@ public class ServerControl implements ApplicationListener{
|
|||||||
mods.each(p -> p.registerClientCommands(netServer.clientCommands));
|
mods.each(p -> p.registerClientCommands(netServer.clientCommands));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyRules(){
|
||||||
|
try{
|
||||||
|
JsonValue value = JsonIO.json().fromJson(null, Core.settings.getString("globalrules"));
|
||||||
|
JsonIO.json().readFields(state.rules, value);
|
||||||
|
}catch(Throwable t){
|
||||||
|
Log.err("Error applying custom rules, proceeding without them.", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void displayStatus() {
|
private void displayStatus() {
|
||||||
if(state.is(State.menu)){
|
if(state.is(State.menu)){
|
||||||
info("Status: &rserver closed");
|
info("Status: &rserver closed");
|
||||||
@@ -824,6 +889,7 @@ public class ServerControl implements ApplicationListener{
|
|||||||
run.run();
|
run.run();
|
||||||
logic.play();
|
logic.play();
|
||||||
state.rules = world.getMap().applyRules(lastMode);
|
state.rules = world.getMap().applyRules(lastMode);
|
||||||
|
applyRules();
|
||||||
|
|
||||||
for(Player p : players){
|
for(Player p : players){
|
||||||
if(p.con == null) continue;
|
if(p.con == null) continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user