diff --git a/SERVERLIST.md b/SERVERLIST.md new file mode 100644 index 0000000000..58e717fb01 --- /dev/null +++ b/SERVERLIST.md @@ -0,0 +1,26 @@ +### Adding a server to the list + +Mindustry now has a public list of servers that everyone can see and connect to. +This is done by letting clients `GET` a [JSON list of servers](https://github.com/Anuken/Mindustry/blob/master/servers.json) in this repository. + +You may want to add your server to this list. The steps for getting this done are as follows: + +1. **Ensure your server is properly moderated.** For the most part, this applies to survival servers, but PvP servers can be affected as well. +You'll need to either hire some moderators, or make use of (currently non-existent) anti-grief and anti-curse plugins. +*Consider enabling a rate limit:* `config messageRateLimit 2` will make it so that players can only send messages every 2 seconds, for example. +2. **Set an approppriate MOTD, name and description.** This is set with `config `. "Approppriate" means that: + - Your name or description must reflect the type of server you're hosting. + Since new players may be exposed to the server list early on, put in a phrase like "Co-op survival" or "PvP" so players know what they're getting into. Yes, this is also displayed in the server mode info text, but having extra info in the name doesn't hurt. + - Make sure players know where to refer to for server support. It should be fairly clear that the server owner is not me, but you. + - Try to be professional in your text; use common sense. +3. **Get some good maps.** *(optional, but highly recommended)*. Add some maps to your server and set the map rotation to custom-only. You can get maps from the Steam workshop by subscribing and exporting them; using the `#maps` channel on Discord is also an option. +4. **Check your server configuration.** *(optional)* I would recommend adding a message rate limit of 1 second (`config messageRateLimit 1`), and disabling connect/disconnect messages to reduce spam (`config showConnectMessages false`). +5. Finally, **submit a pull request** to add your server's IP to the list. +This should be fairly straightforward: Press the edit button on the [server file](https://github.com/Anuken/Mindustry/blob/master/servers.json), then add a JSON object with a single key, indicating your server address. +For example, if your server address is `google.com`, you would add a comma after the last entry and insert: +```json + { + "address": "google.com" + } +``` +Then, press the *'submit pull request'* button and I'll take a look at your server. If I have any issues with it, I'll let you know in the PR comments. diff --git a/core/assets/fonts/fontello.ttf b/core/assets/fonts/fontello.ttf new file mode 100644 index 0000000000..7eaf076f22 Binary files /dev/null and b/core/assets/fonts/fontello.ttf differ diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index a16ac8f410..b40e3543da 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -33,8 +33,7 @@ public class Pathfinder implements Runnable{ /** handles task scheduling on the update thread. */ private TaskQueue queue = new TaskQueue(); /** current pathfinding thread */ - private @Nullable - Thread thread; + private @Nullable Thread thread; public Pathfinder(){ Events.on(WorldLoadEvent.class, event -> { diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java index 878b076dc4..6ecce095e9 100644 --- a/core/src/mindustry/core/NetClient.java +++ b/core/src/mindustry/core/NetClient.java @@ -1,30 +1,29 @@ package mindustry.core; import arc.*; -import mindustry.annotations.Annotations.*; -import arc.struct.*; import arc.graphics.*; import arc.math.*; -import arc.util.CommandHandler.*; +import arc.struct.*; import arc.util.*; +import arc.util.CommandHandler.*; import arc.util.io.*; import arc.util.serialization.*; import mindustry.*; +import mindustry.annotations.Annotations.*; import mindustry.core.GameState.*; -import mindustry.ctype.ContentType; +import mindustry.ctype.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; import mindustry.entities.traits.BuilderTrait.*; import mindustry.entities.traits.*; import mindustry.entities.type.*; -import mindustry.game.*; import mindustry.game.EventType.*; +import mindustry.game.*; import mindustry.gen.*; import mindustry.net.Administration.*; import mindustry.net.Net.*; import mindustry.net.*; import mindustry.net.Packets.*; -import mindustry.type.TypeID; +import mindustry.type.*; import mindustry.world.*; import mindustry.world.modules.*; @@ -267,6 +266,9 @@ public class NetClient implements ApplicationListener{ ui.showText("", message); } + //TODO these are commented out to enforce compatibility with 103! uncomment before 104 release + /* + @Remote(variants = Variant.both) public static void onInfoPopup(String message, float duration, int align, int top, int left, int bottom, int right){ ui.showInfoPopup(message, duration, align, top, left, bottom, right); @@ -285,7 +287,7 @@ public class NetClient implements ApplicationListener{ @Remote(variants = Variant.both) public static void onEffectReliable(Effect effect, float x, float y, float rotation, Color color){ Effects.effect(effect, color, x, y, rotation); - } + }*/ @Remote(variants = Variant.both) public static void onInfoToast(String message, float duration){ diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index 3f7e0d02ee..2faf856171 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -284,11 +284,11 @@ public class NetServer implements ApplicationListener{ }); //duration of a a kick in seconds - int kickDuration = 20 * 60; + int kickDuration = 60 * 60; //voting round duration in seconds float voteDuration = 0.5f * 60; //cooldown between votes - int voteCooldown = 60 * 2; + int voteCooldown = 60 * 1; class VoteSession{ Player target; diff --git a/core/src/mindustry/entities/type/TileEntity.java b/core/src/mindustry/entities/type/TileEntity.java index cf5a2f4bdb..d83c038e70 100644 --- a/core/src/mindustry/entities/type/TileEntity.java +++ b/core/src/mindustry/entities/type/TileEntity.java @@ -24,7 +24,7 @@ import java.io.*; import static mindustry.Vars.*; public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ - public static final float timeToSleep = 60f * 4; //4 seconds to fall asleep + public static final float timeToSleep = 60f * 1; //1 second to fall asleep private static final ObjectSet tmpTiles = new ObjectSet<>(); /** This value is only used for debugging. */ public static int sleepingEntities = 0; diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index e4c7aa2c05..62479c66ec 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -17,6 +17,10 @@ public class Teams{ /** Active teams. */ private Array active = new Array<>(); + public Teams(){ + active.add(get(Team.crux)); + } + public @Nullable CoreEntity closestEnemyCore(float x, float y, Team team){ for(TeamData data : active){ if(areEnemies(team, data.team)){ @@ -85,7 +89,6 @@ public class Teams{ /** Returns whether {@param other} is an enemy of {@param #team}. */ public boolean areEnemies(Team team, Team other){ - //todo what about derelict? return team != other; } diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index b48080484d..68c6db1edb 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -41,7 +41,6 @@ public class Administration{ if(player.getInfo().messageInfractions >= Config.messageSpamKick.num() && Config.messageSpamKick.num() != 0){ player.con.kick("You have been kicked for spamming.", 1000 * 60 * 2); } - player.getInfo().lastSentMessage = message; return null; }else{ player.getInfo().messageInfractions = 0; diff --git a/core/src/mindustry/world/blocks/distribution/Conveyor.java b/core/src/mindustry/world/blocks/distribution/Conveyor.java index 6a784b0a71..983db90810 100644 --- a/core/src/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/mindustry/world/blocks/distribution/Conveyor.java @@ -190,7 +190,7 @@ public class Conveyor extends Block implements Autotiler{ if(e.ys[i] > nextMax) e.ys[i] = nextMax; if(e.ys[i] > 0.5 && i > 0) e.mid = i - 1; - e.xs[i] = Mathf.approachDelta(e.xs[i], 0, 0.1f); + e.xs[i] = Mathf.approachDelta(e.xs[i], 0, speed*2); if(e.ys[i] >= 1f && offloadDir(tile, e.ids[i])){ //align X position if passing forwards @@ -198,14 +198,14 @@ public class Conveyor extends Block implements Autotiler{ e.nextc.xs[e.nextc.lastInserted] = e.xs[i]; } //remove last item + e.items.remove(e.ids[i], e.len - i); e.len = Math.min(i, e.len); - e.items.remove(e.ids[i], 1); }else if(e.ys[i] < e.minitem){ e.minitem = e.ys[i]; } } - if(e.minitem < itemSpace + (e.blendbits == 1 ? 0.5f : 0f)){ + if(e.minitem < itemSpace + (e.blendbits == 1 ? 0.3f : 0f)){ e.clogHeat = Mathf.lerpDelta(e.clogHeat, 1f, 0.02f); }else{ e.clogHeat = 0f; @@ -281,7 +281,7 @@ public class Conveyor extends Block implements Autotiler{ ConveyorEntity e = tile.ent(); if(e.len >= capacity) return false; int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.rotation()); - return (((direction == 0) && e.minitem >= itemSpace) || ((direction % 2 == 1) && e.minitem > 0.5f + itemSpace)) && (source == null || !(source.block().rotate && (source.rotation() + 2) % 4 == tile.rotation())); + return (((direction == 0) && e.minitem >= itemSpace) || ((direction % 2 == 1) && e.minitem > 0.7f)) && (source == null || !(source.block().rotate && (source.rotation() + 2) % 4 == tile.rotation())); } @Override diff --git a/desktop/src/mindustry/desktop/DesktopLauncher.java b/desktop/src/mindustry/desktop/DesktopLauncher.java index b09894e521..0ada554894 100644 --- a/desktop/src/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/mindustry/desktop/DesktopLauncher.java @@ -243,36 +243,65 @@ public class DesktopLauncher extends ClientLauncher{ @Override public void updateRPC(){ - if(!useDiscord) return; + //if we're using neither discord nor steam, do no work + if(!useDiscord && !steam) return; - DiscordRichPresence presence = new DiscordRichPresence(); + //common elements they each share + boolean inGame = !state.is(State.menu); + String gameMapWithWave = "Unknown Map"; + String gameMode = ""; + String gamePlayersSuffix = ""; + String uiState = ""; - if(!state.is(State.menu)){ - String map = world.getMap() == null ? "Unknown Map" : world.isZone() ? world.getZone().localizedName : Strings.capitalize(world.getMap().name()); - String mode = state.rules.pvp ? "PvP" : state.rules.attackMode ? "Attack" : "Survival"; - String players = net.active() && playerGroup.size() > 1 ? " | " + playerGroup.size() + " Players" : ""; - - presence.state = mode + players; - - if(!state.rules.waves){ - presence.details = map; - }else{ - presence.details = map + " | Wave " + state.wave; - presence.largeImageText = "Wave " + state.wave; + if(inGame){ + if(world.getMap() != null){ + gameMapWithWave = world.isZone() ? world.getZone().localizedName : Strings.capitalize(world.getMap().name()); + } + if(state.rules.waves){ + gameMapWithWave += " | Wave " + state.wave; + } + gameMode = state.rules.pvp ? "PvP" : state.rules.attackMode ? "Attack" : "Survival"; + if(net.active() && playerGroup.size() > 1){ + gamePlayersSuffix = " | " + playerGroup.size() + " Players"; } }else{ if(ui.editor != null && ui.editor.isShown()){ - presence.state = "In Editor"; + uiState = "In Editor"; }else if(ui.deploy != null && ui.deploy.isShown()){ - presence.state = "In Launch Selection"; + uiState = "In Launch Selection"; }else{ - presence.state = "In Menu"; + uiState = "In Menu"; } } - presence.largeImageKey = "logo"; + if(useDiscord){ + DiscordRichPresence presence = new DiscordRichPresence(); - DiscordRPC.INSTANCE.Discord_UpdatePresence(presence); + if(inGame){ + presence.state = gameMode + gamePlayersSuffix; + presence.details = gameMapWithWave; + if(state.rules.waves){ + presence.largeImageText = "Wave " + state.wave; + } + }else{ + presence.state = uiState; + } + + presence.largeImageKey = "logo"; + + DiscordRPC.INSTANCE.Discord_UpdatePresence(presence); + } + + if(steam){ + //Steam mostly just expects us to give it a nice string, but it apparently expects "steam_display" to always be a loc token, so I've uploaded this one which just passes through 'steam_status' raw. + SVars.net.friends.setRichPresence("steam_display", "#steam_status_raw"); + + if(inGame){ + SVars.net.friends.setRichPresence("steam_status", gameMapWithWave); + }else{ + SVars.net.friends.setRichPresence("steam_status", uiState); + } + } } @Override diff --git a/servers.json b/servers.json index 81ea4bf021..cada39c4c8 100644 --- a/servers.json +++ b/servers.json @@ -1,5 +1,14 @@ [ { "address": "mindustry.us.to" + }, + { + "address": "mindustry.ecansol.com:6597" + }, + { + "address": "mindustry.ecansol.com:6499" + }, + { + "address": "mindustry.ru" } ]