Merge branch 'v103.3' of https://github.com/PetrGasparik/Mindustry; branch 'master' of https://github.com/Anuken/Mindustry into v103.3
This commit is contained in:
26
SERVERLIST.md
Normal file
26
SERVERLIST.md
Normal file
@@ -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 <name/desc/motd> <value>`. "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.
|
||||||
BIN
core/assets/fonts/fontello.ttf
Normal file
BIN
core/assets/fonts/fontello.ttf
Normal file
Binary file not shown.
@@ -33,8 +33,7 @@ public class Pathfinder implements Runnable{
|
|||||||
/** handles task scheduling on the update thread. */
|
/** handles task scheduling on the update thread. */
|
||||||
private TaskQueue queue = new TaskQueue();
|
private TaskQueue queue = new TaskQueue();
|
||||||
/** current pathfinding thread */
|
/** current pathfinding thread */
|
||||||
private @Nullable
|
private @Nullable Thread thread;
|
||||||
Thread thread;
|
|
||||||
|
|
||||||
public Pathfinder(){
|
public Pathfinder(){
|
||||||
Events.on(WorldLoadEvent.class, event -> {
|
Events.on(WorldLoadEvent.class, event -> {
|
||||||
|
|||||||
@@ -1,30 +1,29 @@
|
|||||||
package mindustry.core;
|
package mindustry.core;
|
||||||
|
|
||||||
import arc.*;
|
import arc.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
|
||||||
import arc.struct.*;
|
|
||||||
import arc.graphics.*;
|
import arc.graphics.*;
|
||||||
import arc.math.*;
|
import arc.math.*;
|
||||||
import arc.util.CommandHandler.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
|
import arc.util.CommandHandler.*;
|
||||||
import arc.util.io.*;
|
import arc.util.io.*;
|
||||||
import arc.util.serialization.*;
|
import arc.util.serialization.*;
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
import mindustry.core.GameState.*;
|
import mindustry.core.GameState.*;
|
||||||
import mindustry.ctype.ContentType;
|
import mindustry.ctype.*;
|
||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
import mindustry.entities.Effects.*;
|
|
||||||
import mindustry.entities.traits.BuilderTrait.*;
|
import mindustry.entities.traits.BuilderTrait.*;
|
||||||
import mindustry.entities.traits.*;
|
import mindustry.entities.traits.*;
|
||||||
import mindustry.entities.type.*;
|
import mindustry.entities.type.*;
|
||||||
import mindustry.game.*;
|
|
||||||
import mindustry.game.EventType.*;
|
import mindustry.game.EventType.*;
|
||||||
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.net.Administration.*;
|
import mindustry.net.Administration.*;
|
||||||
import mindustry.net.Net.*;
|
import mindustry.net.Net.*;
|
||||||
import mindustry.net.*;
|
import mindustry.net.*;
|
||||||
import mindustry.net.Packets.*;
|
import mindustry.net.Packets.*;
|
||||||
import mindustry.type.TypeID;
|
import mindustry.type.*;
|
||||||
import mindustry.world.*;
|
import mindustry.world.*;
|
||||||
import mindustry.world.modules.*;
|
import mindustry.world.modules.*;
|
||||||
|
|
||||||
@@ -267,6 +266,9 @@ public class NetClient implements ApplicationListener{
|
|||||||
ui.showText("", message);
|
ui.showText("", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO these are commented out to enforce compatibility with 103! uncomment before 104 release
|
||||||
|
/*
|
||||||
|
|
||||||
@Remote(variants = Variant.both)
|
@Remote(variants = Variant.both)
|
||||||
public static void onInfoPopup(String message, float duration, int align, int top, int left, int bottom, int right){
|
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);
|
ui.showInfoPopup(message, duration, align, top, left, bottom, right);
|
||||||
@@ -285,7 +287,7 @@ public class NetClient implements ApplicationListener{
|
|||||||
@Remote(variants = Variant.both)
|
@Remote(variants = Variant.both)
|
||||||
public static void onEffectReliable(Effect effect, float x, float y, float rotation, Color color){
|
public static void onEffectReliable(Effect effect, float x, float y, float rotation, Color color){
|
||||||
Effects.effect(effect, color, x, y, rotation);
|
Effects.effect(effect, color, x, y, rotation);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
@Remote(variants = Variant.both)
|
@Remote(variants = Variant.both)
|
||||||
public static void onInfoToast(String message, float duration){
|
public static void onInfoToast(String message, float duration){
|
||||||
|
|||||||
@@ -284,11 +284,11 @@ public class NetServer implements ApplicationListener{
|
|||||||
});
|
});
|
||||||
|
|
||||||
//duration of a a kick in seconds
|
//duration of a a kick in seconds
|
||||||
int kickDuration = 20 * 60;
|
int kickDuration = 60 * 60;
|
||||||
//voting round duration in seconds
|
//voting round duration in seconds
|
||||||
float voteDuration = 0.5f * 60;
|
float voteDuration = 0.5f * 60;
|
||||||
//cooldown between votes
|
//cooldown between votes
|
||||||
int voteCooldown = 60 * 2;
|
int voteCooldown = 60 * 1;
|
||||||
|
|
||||||
class VoteSession{
|
class VoteSession{
|
||||||
Player target;
|
Player target;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import java.io.*;
|
|||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
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<Tile> tmpTiles = new ObjectSet<>();
|
private static final ObjectSet<Tile> tmpTiles = new ObjectSet<>();
|
||||||
/** This value is only used for debugging. */
|
/** This value is only used for debugging. */
|
||||||
public static int sleepingEntities = 0;
|
public static int sleepingEntities = 0;
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ public class Teams{
|
|||||||
/** Active teams. */
|
/** Active teams. */
|
||||||
private Array<TeamData> active = new Array<>();
|
private Array<TeamData> active = new Array<>();
|
||||||
|
|
||||||
|
public Teams(){
|
||||||
|
active.add(get(Team.crux));
|
||||||
|
}
|
||||||
|
|
||||||
public @Nullable CoreEntity closestEnemyCore(float x, float y, Team team){
|
public @Nullable CoreEntity closestEnemyCore(float x, float y, Team team){
|
||||||
for(TeamData data : active){
|
for(TeamData data : active){
|
||||||
if(areEnemies(team, data.team)){
|
if(areEnemies(team, data.team)){
|
||||||
@@ -85,7 +89,6 @@ public class Teams{
|
|||||||
|
|
||||||
/** Returns whether {@param other} is an enemy of {@param #team}. */
|
/** Returns whether {@param other} is an enemy of {@param #team}. */
|
||||||
public boolean areEnemies(Team team, Team other){
|
public boolean areEnemies(Team team, Team other){
|
||||||
//todo what about derelict?
|
|
||||||
return team != other;
|
return team != other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public class Administration{
|
|||||||
if(player.getInfo().messageInfractions >= Config.messageSpamKick.num() && Config.messageSpamKick.num() != 0){
|
if(player.getInfo().messageInfractions >= Config.messageSpamKick.num() && Config.messageSpamKick.num() != 0){
|
||||||
player.con.kick("You have been kicked for spamming.", 1000 * 60 * 2);
|
player.con.kick("You have been kicked for spamming.", 1000 * 60 * 2);
|
||||||
}
|
}
|
||||||
player.getInfo().lastSentMessage = message;
|
|
||||||
return null;
|
return null;
|
||||||
}else{
|
}else{
|
||||||
player.getInfo().messageInfractions = 0;
|
player.getInfo().messageInfractions = 0;
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ public class Conveyor extends Block implements Autotiler{
|
|||||||
|
|
||||||
if(e.ys[i] > nextMax) e.ys[i] = nextMax;
|
if(e.ys[i] > nextMax) e.ys[i] = nextMax;
|
||||||
if(e.ys[i] > 0.5 && i > 0) e.mid = i - 1;
|
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])){
|
if(e.ys[i] >= 1f && offloadDir(tile, e.ids[i])){
|
||||||
//align X position if passing forwards
|
//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];
|
e.nextc.xs[e.nextc.lastInserted] = e.xs[i];
|
||||||
}
|
}
|
||||||
//remove last item
|
//remove last item
|
||||||
|
e.items.remove(e.ids[i], e.len - i);
|
||||||
e.len = Math.min(i, e.len);
|
e.len = Math.min(i, e.len);
|
||||||
e.items.remove(e.ids[i], 1);
|
|
||||||
}else if(e.ys[i] < e.minitem){
|
}else if(e.ys[i] < e.minitem){
|
||||||
e.minitem = e.ys[i];
|
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);
|
e.clogHeat = Mathf.lerpDelta(e.clogHeat, 1f, 0.02f);
|
||||||
}else{
|
}else{
|
||||||
e.clogHeat = 0f;
|
e.clogHeat = 0f;
|
||||||
@@ -281,7 +281,7 @@ public class Conveyor extends Block implements Autotiler{
|
|||||||
ConveyorEntity e = tile.ent();
|
ConveyorEntity e = tile.ent();
|
||||||
if(e.len >= capacity) return false;
|
if(e.len >= capacity) return false;
|
||||||
int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.rotation());
|
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
|
@Override
|
||||||
|
|||||||
@@ -243,36 +243,65 @@ public class DesktopLauncher extends ClientLauncher{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateRPC(){
|
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)){
|
if(inGame){
|
||||||
String map = world.getMap() == null ? "Unknown Map" : world.isZone() ? world.getZone().localizedName : Strings.capitalize(world.getMap().name());
|
if(world.getMap() != null){
|
||||||
String mode = state.rules.pvp ? "PvP" : state.rules.attackMode ? "Attack" : "Survival";
|
gameMapWithWave = world.isZone() ? world.getZone().localizedName : Strings.capitalize(world.getMap().name());
|
||||||
String players = net.active() && playerGroup.size() > 1 ? " | " + playerGroup.size() + " Players" : "";
|
}
|
||||||
|
if(state.rules.waves){
|
||||||
presence.state = mode + players;
|
gameMapWithWave += " | Wave " + state.wave;
|
||||||
|
}
|
||||||
if(!state.rules.waves){
|
gameMode = state.rules.pvp ? "PvP" : state.rules.attackMode ? "Attack" : "Survival";
|
||||||
presence.details = map;
|
if(net.active() && playerGroup.size() > 1){
|
||||||
}else{
|
gamePlayersSuffix = " | " + playerGroup.size() + " Players";
|
||||||
presence.details = map + " | Wave " + state.wave;
|
|
||||||
presence.largeImageText = "Wave " + state.wave;
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(ui.editor != null && ui.editor.isShown()){
|
if(ui.editor != null && ui.editor.isShown()){
|
||||||
presence.state = "In Editor";
|
uiState = "In Editor";
|
||||||
}else if(ui.deploy != null && ui.deploy.isShown()){
|
}else if(ui.deploy != null && ui.deploy.isShown()){
|
||||||
presence.state = "In Launch Selection";
|
uiState = "In Launch Selection";
|
||||||
}else{
|
}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
|
@Override
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"address": "mindustry.us.to"
|
"address": "mindustry.us.to"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "mindustry.ecansol.com:6597"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "mindustry.ecansol.com:6499"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "mindustry.ru"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user