This commit is contained in:
Anuken
2019-09-06 13:58:32 -04:00
77 changed files with 2674 additions and 2256 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

+12 -6
View File
@@ -64,16 +64,18 @@ techtree = Tech Tree
research.list = [lightgray]Research:
research = Research
researched = [lightgray]{0} researched.
players = {0} players online
players.single = {0} player online
players = {0} players
players.single = {0} player
server.closing = [accent]Closing server...
server.kicked.kick = You have been kicked from the server!
server.kicked.whitelist = You are not whitelisted here.
server.kicked.serverClose = Server closed.
server.kicked.vote = You have been vote-kicked. Goodbye.
server.kicked.clientOutdated = Outdated client! Update your game!
server.kicked.serverOutdated = Outdated server! Ask the host to update!
server.kicked.banned = You are banned on this server.
server.kicked.typeMismatch = This server is not compatible with your build type.
server.kicked.playerLimit = This server is full. Wait for an empty slot.
server.kicked.recentKick = You have been kicked recently.\nWait before connecting again.
server.kicked.nameInUse = There is someone with that name\nalready on this server.
server.kicked.nameEmpty = Your chosen name is invalid.
@@ -110,7 +112,7 @@ server.edit = Edit Server
server.outdated = [crimson]Outdated Server![]
server.outdated.client = [crimson]Outdated Client![]
server.version = [gray]v{0} {1}
server.custombuild = [yellow]Custom Build
server.custombuild = [accent]Custom Build
confirmban = Are you sure you want to ban this player?
confirmkick = Are you sure you want to kick this player?
confirmunban = Are you sure you want to unban this player?
@@ -119,6 +121,9 @@ confirmunadmin = Are you sure you want to remove admin status from this player?
joingame.title = Join Game
joingame.ip = Address:
disconnect = Disconnected.
disconnect.error = Connection error.
disconnect.closed = Connection closed.
disconnect.timeout = Timed out.
disconnect.data = Failed to load world data!
connecting = [accent]Connecting...
connecting.data = [accent]Loading world data...
@@ -152,7 +157,7 @@ off = Off
save.autosave = Autosave: {0}
save.map = Map: {0}
save.wave = Wave {0}
save.difficulty = Difficulty: {0}
save.mode = Gamemode: {0}
save.date = Last Saved: {0}
save.playtime = Playtime: {0}
warning = Warning.
@@ -446,6 +451,7 @@ blocks.boosteffect = Boost Effect
blocks.maxunits = Max Active Units
blocks.health = Health
blocks.buildtime = Build Time
blocks.buildcost = Build Cost
blocks.inaccuracy = Inaccuracy
blocks.shots = Shots
blocks.reload = Shots/Second
@@ -890,8 +896,8 @@ tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nBegin by[a
tutorial.drill = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nClick the drill tab in the bottom right.\nSelect the[accent] mechanical drill[]. Place it on a copper vein by clicking.\n[accent]Right-click[] to stop building.
tutorial.drill.mobile = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nTap the drill tab in the bottom right.\nSelect the[accent] mechanical drill[].\nPlace it on a copper vein by tapping, then press the[accent] checkmark[] below to confirm your selection.\nPress the[accent] X button[] to cancel placement.
tutorial.blockinfo = Each block has different stats. Each drill can only mine certain ores.\nTo check a block's info and stats,[accent] tap the "?" button while selecting it in the build menu.[]\n\n[accent]Access the Mechanical Drill's stats now.[]
tutorial.conveyor = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent]Hold down the mouse to place in a line.[]\nHold[accent] CTRL[] while selecting a line to place diagonally.\n\n[accent]{0}/{1} conveyors placed in line\n[accent]0/1 items delivered
tutorial.conveyor.mobile = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent] Place in a line by holding down your finger for a few seconds[] and dragging in a direction.\n\n[accent]{0}/{1} conveyors placed in line\n[accent]0/1 items delivered
tutorial.conveyor = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent]Hold down the mouse to place in a line.[]\nHold[accent] CTRL[] while selecting a line to place diagonally.\n\n[accent]Place 2 conveyors with the line tool, then deliver an item into the core.
tutorial.conveyor.mobile = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent] Place in a line by holding down your finger for a few seconds[] and dragging in a direction.\n\n[accent]Place 2 conveyors with the line tool, then deliver an item into the core.
tutorial.turret = Once an item enters your core, it can be used for building.\nKeep in mind that not all items can be used for building.\nItems that are not used for building, such as[accent] coal[] or[accent] scrap[], cannot be put into the core.\nDefensive structures must be built to repel the[lightgray] enemy[].\nBuild a[accent] duo turret[] near your base.
tutorial.drillturret = Duo turrets require[accent] copper ammo []to shoot.\nPlace a drill near the turret.\nLead conveyors into the turret to supply it with copper.\n\n[accent]Ammo delivered: 0/1
tutorial.pause = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press space to pause.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 719 B

After

Width:  |  Height:  |  Size: 718 B

File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 682 KiB

After

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 579 KiB

After

Width:  |  Height:  |  Size: 566 KiB

@@ -84,10 +84,12 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
@Override
public void resize(int width, int height){
super.resize(width, height);
if(assets == null) return;
if(!assets.isFinished()){
Draw.proj().setOrtho(0, 0, width, height);
}else{
super.resize(width, height);
}
}
@@ -100,6 +102,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
for(ApplicationListener listener : modules){
listener.init();
}
super.resize(graphics.getWidth(), graphics.getHeight());
finished = true;
Events.fire(new ClientLoadEvent());
}
+3
View File
@@ -3,6 +3,7 @@ package io.anuke.mindustry;
import io.anuke.arc.Application.*;
import io.anuke.arc.*;
import io.anuke.arc.assets.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.files.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.scene.ui.layout.*;
@@ -43,6 +44,8 @@ public class Vars implements Loadable{
public static final String discordURL = "https://discord.gg/mindustry";
/** URL for sending crash reports to */
public static final String crashReportURL = "http://mins.us.to/report";
/** list of built-in servers.*/
public static final Array<String> defaultServers = Array.with(/*"mins.us.to"*/);
/** maximum distance between mine and core that supports automatic transferring */
public static final float mineTransferRange = 220f;
/** team of the player by default */
@@ -242,14 +242,13 @@ public class BlockIndexer{
int quadrantY = tile.y / quadrantSize;
itemSet.clear();
Tile rounded = world.tile(Mathf.clamp(quadrantX * quadrantSize + quadrantSize / 2, 0, world.width() - 1),
Mathf.clamp(quadrantY * quadrantSize + quadrantSize / 2, 0, world.height() - 1));
Tile rounded = world.tile(Mathf.clamp(quadrantX * quadrantSize + quadrantSize / 2, 0, world.width() - 1), Mathf.clamp(quadrantY * quadrantSize + quadrantSize / 2, 0, world.height() - 1));
//find all items that this quadrant contains
for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){
for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){
for(int x = Math.max(0, rounded.x - quadrantSize / 2); x < rounded.x + quadrantSize / 2 && x < world.width(); x++){
for(int y = Math.max(0, rounded.y - quadrantSize / 2); y < rounded.y + quadrantSize / 2 && y < world.height(); y++){
Tile result = world.tile(x, y);
if(result == null || result.drop() == null || !scanOres.contains(result.drop())) continue;
if(result == null || result.drop() == null || !scanOres.contains(result.drop()) || result.block() != Blocks.air) continue;
itemSet.add(result.drop());
}
@@ -500,6 +500,7 @@ public class Blocks implements ContentList{
consumes.items(new ItemStack(Items.thorium, 4), new ItemStack(Items.sand, 10));
consumes.power(5f);
itemCapacity = 20;
int bottomRegion = reg("-bottom"), weaveRegion = reg("-weave");
@@ -982,7 +983,6 @@ public class Blocks implements ContentList{
pulseConduit = new Conduit("pulse-conduit"){{
requirements(Category.liquid, ItemStack.with(Items.titanium, 1, Items.metaglass, 1));
liquidCapacity = 16f;
liquidFlowFactor = 4.9f;
health = 90;
}};
@@ -1405,14 +1405,14 @@ public class Blocks implements ContentList{
}};
arc = new PowerTurret("arc"){{
requirements(Category.turret, ItemStack.with(Items.copper, 35, Items.lead, 35));
requirements(Category.turret, ItemStack.with(Items.copper, 35, Items.lead, 50));
shootType = Bullets.arc;
reload = 24f;
reload = 35f;
shootCone = 40f;
rotatespeed = 8f;
powerUse = 0.9f;
powerUse = 1.5f;
targetAir = false;
range = 95f;
range = 90f;
shootEffect = Fx.lightningShoot;
heatColor = Color.RED;
recoil = 1f;
@@ -1775,4 +1775,4 @@ public class Blocks implements ContentList{
//endregion
}
}
}
@@ -7,12 +7,13 @@ import io.anuke.arc.util.*;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.bullet.*;
import io.anuke.mindustry.entities.effect.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*;
import static io.anuke.mindustry.Vars.world;
import static io.anuke.mindustry.Vars.*;
public class Bullets implements ContentList{
public static BulletType
@@ -631,7 +632,7 @@ public class Bullets implements ContentList{
@Override
public void init(Bullet b){
Lightning.create(b.getTeam(), Pal.lancerLaser, damage, b.x, b.y, b.rot(), 30);
Lightning.create(b.getTeam(), Pal.lancerLaser, damage * (b.getOwner() instanceof Player ? state.rules.playerDamageMultiplier : 1f), b.x, b.y, b.rot(), 30);
}
};
@@ -48,6 +48,10 @@ public class Control implements ApplicationListener, Loadable{
private boolean wasPaused = false;
public Control(){
saves = new Saves();
tutorial = new Tutorial();
music = new MusicControl();
Events.on(StateChangeEvent.class, event -> {
if((event.from == State.playing && event.to == State.menu) || (event.from == State.menu && event.to != State.menu)){
Time.runTask(5f, platform::updateRPC);
@@ -152,10 +156,6 @@ public class Control implements ApplicationListener, Loadable{
@Override
public void loadAsync(){
saves = new Saves();
tutorial = new Tutorial();
music = new MusicControl();
Draw.scl = 1f / Core.atlas.find("scale_marker").getWidth();
Core.input.setCatch(KeyCode.BACK, true);
@@ -107,7 +107,17 @@ public class NetClient implements ApplicationListener{
Time.runTask(3f, ui.loadfrag::hide);
ui.showError("$disconnect");
if(packet.reason != null){
if(packet.reason.equals("closed")){
ui.showSmall("$disconnect", "$disconnect.closed");
}else if(packet.reason.equals("timeout")){
ui.showSmall("$disconnect", "$disconnect.timeout");
}else if(packet.reason.equals("error")){
ui.showSmall("$disconnect", "$disconnect.error");
}
}else{
ui.showError("$disconnect");
}
});
Net.handleClient(WorldStream.class, data -> {
+102 -53
View File
@@ -1,39 +1,32 @@
package io.anuke.mindustry.core;
import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.arc.ApplicationListener;
import io.anuke.arc.Events;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.Colors;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Rectangle;
import io.anuke.arc.math.geom.Vector2;
import io.anuke.arc.graphics.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
import io.anuke.arc.util.CommandHandler.*;
import io.anuke.arc.util.io.*;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.EntityGroup;
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
import io.anuke.mindustry.entities.traits.Entity;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.entities.type.Player;
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.gen.RemoteReadServer;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.net.Administration.PlayerInfo;
import io.anuke.mindustry.net.Administration.TraceInfo;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.Administration.*;
import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.*;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.zip.DeflaterOutputStream;
import java.nio.*;
import java.util.zip.*;
import static io.anuke.mindustry.Vars.*;
@@ -76,7 +69,7 @@ public class NetServer implements ApplicationListener{
Net.handleServer(Disconnect.class, (id, packet) -> {
Player player = connections.get(id);
if(player != null){
onDisconnect(player);
onDisconnect(player, packet.reason);
}
connections.remove(id);
});
@@ -111,6 +104,27 @@ public class NetServer implements ApplicationListener{
return;
}
if(admins.isIDBanned(uuid)){
kick(id, KickReason.banned);
return;
}
if(admins.getPlayerLimit() > 0 && playerGroup.size() >= admins.getPlayerLimit()){
kick(id, KickReason.playerLimit);
return;
}
if(!admins.isWhitelisted(packet.uuid, packet.usid)){
info.adminUsid = packet.usid;
info.lastName = packet.name;
info.id = packet.uuid;
admins.save();
Call.onInfoMessage(id, "You are not whitelisted here.");
Log.info("&lcDo &lywhitelist-add {0}&lc to whitelist the player &lb'{1}'", packet.uuid, packet.name);
kick(id, KickReason.whitelist);
return;
}
if(packet.versionType == null || ((packet.version == -1 || !packet.versionType.equals(Version.type)) && Version.build != -1 && !admins.allowsCustomClients())){
kick(id, !Version.type.equals(packet.versionType) ? KickReason.typeMismatch : KickReason.customClient);
return;
@@ -184,6 +198,8 @@ public class NetServer implements ApplicationListener{
sendWorldData(player, id);
platform.updateRPC();
Events.fire(new PlayerJoin(player));
});
Net.handleServer(InvokePacket.class, (id, packet) -> {
@@ -227,25 +243,34 @@ public class NetServer implements ApplicationListener{
});
//duration of a a kick in seconds
int kickDuration = 10 * 60;
int kickDuration = 15 * 60;
class VoteSession{
Player target;
ObjectSet<String> voted = new ObjectSet<>();
ObjectMap<Player, VoteSession> map;
VoteSession[] map;
Timer.Task task;
int votes;
public VoteSession(ObjectMap<Player, VoteSession> map, Player target){
public VoteSession(VoteSession[] map, Player target){
this.target = target;
this.map = map;
this.task = Timer.schedule(() -> {
if(!checkPass()){
Call.sendMessage(Strings.format("[lightgray]Vote failed. Not enough votes to kick[orange] {0}[lightgray].", target.name));
map[0] = null;
task.cancel();
}
map.remove(target);
task.cancel();
}, 60 * 1.5f);
}, 60 * 1);
}
void vote(Player player, int d){
votes += d;
voted.addAll(player.uuid, admins.getInfo(player.uuid).lastIP);
Call.sendMessage(Strings.format("[orange]{0}[lightgray] has voted to kick[orange] {1}[].[accent] ({2}/{3})\n[lightgray]Type[orange] /vote <y/n>[] to agree.",
player.name, target.name, votes, votesRequired()));
//checkPass();
}
boolean checkPass(){
@@ -253,6 +278,8 @@ public class NetServer implements ApplicationListener{
Call.sendMessage(Strings.format("[orange]Vote passed.[scarlet] {0}[orange] will be kicked from the server.", target.name));
admins.getInfo(target.uuid).lastKicked = Time.millis() + kickDuration*1000;
kick(target.con.id, KickReason.vote);
map[0] = null;
task.cancel();
return true;
}
return false;
@@ -260,10 +287,10 @@ public class NetServer implements ApplicationListener{
}
//cooldown between votes
int voteTime = 60 * 10;
int voteTime = 60 * 5;
Timekeeper vtime = new Timekeeper(voteTime);
//current kick sessions
ObjectMap<Player, VoteSession> currentlyKicking = new ObjectMap<>();
VoteSession[] currentlyKicking = {null};
clientCommands.<Player>register("votekick", "[player...]", "Vote to kick a player, with a cooldown.", (args, player) -> {
if(playerGroup.size() < 3){
@@ -271,8 +298,8 @@ public class NetServer implements ApplicationListener{
return;
}
if(currentlyKicking.values().toArray().contains(v -> v.voted.contains(player.uuid) || v.voted.contains(admins.getInfo(player.uuid).lastIP))){
player.sendMessage("[scarlet]You've already voted. Sit down.");
if(player.isLocal){
player.sendMessage("[scarlet]Just kick them yourself if you're the host.");
return;
}
@@ -295,24 +322,20 @@ public class NetServer implements ApplicationListener{
}
if(found != null){
if(player == found){
player.sendMessage("[scarlet]If you're interested in kicking yourself, just leave.");
}else if(found.isAdmin){
if(found.isAdmin){
player.sendMessage("[scarlet]Did you really expect to be able to kick an admin?");
}else if(found.isLocal){
player.sendMessage("[scarlet]Local players cannot be kicked.");
}else{
if(!currentlyKicking.containsKey(found) && !vtime.get()){
if(!vtime.get()){
player.sendMessage("[scarlet]You must wait " + voteTime/60 + " minutes between votekicks.");
return;
}
VoteSession session = currentlyKicking.getOr(found, () -> new VoteSession(currentlyKicking, found));
session.votes ++;
session.voted.addAll(player.uuid, admins.getInfo(player.uuid).lastIP);
Call.sendMessage(Strings.format("[orange]{0}[lightgray] has voted to kick[orange] {1}[].[accent] ({2}/{3})\n[lightgray]Type[orange] /votekick #{4}[] to agree.",
player.name, found.name, session.votes, votesRequired(), found.con.id));
session.checkPass();
vtime.reset();
VoteSession session = new VoteSession(currentlyKicking, found);
session.vote(player, 1);
vtime.reset();
currentlyKicking[0] = session;
}
}else{
player.sendMessage("[scarlet]No player[orange]'" + args[0] + "'[scarlet] found.");
@@ -320,6 +343,31 @@ public class NetServer implements ApplicationListener{
}
});
clientCommands.<Player>register("vote", "<y/n>", "Vote to kick the current player.", (arg, player) -> {
if(currentlyKicking[0] == null){
player.sendMessage("[scarlet]Nobody is being voted on.");
}else{
if(currentlyKicking[0].voted.contains(player.uuid) || currentlyKicking[0].voted.contains(admins.getInfo(player.uuid).lastIP)){
player.sendMessage("[scarlet]You've already voted. Sit down.");
return;
}
if(currentlyKicking[0].target == player){
player.sendMessage("[scarlet]You can't vote on your own trial.");
return;
}
if(!arg[0].toLowerCase().equals("y") && !arg[0].toLowerCase().equals("n")){
player.sendMessage("[scarlet]Vote either 'y' (yes) or 'n' (no).");
return;
}
int sign = arg[0].toLowerCase().equals("y") ? 1 : -1;
currentlyKicking[0].vote(player, sign);
}
});
clientCommands.<Player>register("sync", "Re-synchronize world state.", (args, player) -> {
if(player.isLocal){
player.sendMessage("[scarlet]Re-synchronizing as the host is pointless.");
@@ -331,7 +379,7 @@ public class NetServer implements ApplicationListener{
}
public int votesRequired(){
return playerGroup.size() * 2 / 3;
return 2 + (playerGroup.size() > 4 ? 1 : 0);
}
public Team assignTeam(Player current, Iterable<Player> players){
@@ -361,7 +409,7 @@ public class NetServer implements ApplicationListener{
Log.debug("Packed {0} compressed bytes of world data.", stream.size());
}
public static void onDisconnect(Player player){
public static void onDisconnect(Player player, String reason){
//singleplayer multiplayer wierdness
if(player.con == null){
player.remove();
@@ -369,12 +417,13 @@ public class NetServer implements ApplicationListener{
}
if(player.con.hasConnected){
Events.fire(new PlayerLeave(player));
Call.sendMessage("[accent]" + player.name + "[accent] has disconnected.");
Call.onPlayerDisconnect(player.id);
}
player.remove();
netServer.connections.remove(player.con.id);
Log.info("&lm[{1}] &lc{0} has disconnected.", player.name, player.uuid);
Log.info("&lm[{1}] &lc{0} has disconnected. &lg&fi({2})", player.name, player.uuid, reason);
}
private static float compound(float speed, float drag){
@@ -700,7 +749,7 @@ public class NetServer implements ApplicationListener{
if(connection == null || !connection.isConnected() || !connections.containsKey(connection.id)){
//player disconnected, call d/c event
onDisconnect(player);
onDisconnect(player, "disappeared");
return;
}
+9
View File
@@ -360,6 +360,15 @@ public class UI implements ApplicationListener, Loadable{
}}.show();
}
public void showSmall(String titleText, String text){
new Dialog(titleText, "dialog"){{
cont.margin(10).add(text);
titleTable.row();
titleTable.addImage("whiteui").color(Pal.accent).height(3f).growX().pad(2f);
buttons.addButton("$ok", this::hide).size(90, 50).pad(4);
}}.show();
}
public void showConfirm(String title, String text, Runnable confirmed){
showConfirm(title, text, null, confirmed);
}
@@ -186,7 +186,6 @@ public class MapEditorDialog extends Dialog implements Disposable{
clearChildren();
margin(0);
shown(this::build);
update(() -> {
if(Core.scene.getKeyboardFocus() instanceof Dialog && Core.scene.getKeyboardFocus() != this){
@@ -228,6 +227,8 @@ public class MapEditorDialog extends Dialog implements Disposable{
platform.updateRPC();
if(!Core.settings.getBool("landscape")) platform.endForceLandscape();
});
shown(this::build);
}
@Override
@@ -1,7 +1,7 @@
package io.anuke.mindustry.entities.traits;
import io.anuke.arc.math.geom.Position;
import io.anuke.mindustry.entities.type.Player;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.world.Tile;
public interface SpawnerTrait extends TargetTrait, Position{
@@ -9,6 +9,8 @@ public interface SpawnerTrait extends TargetTrait, Position{
void updateSpawning(Player unit);
boolean hasUnit(Unit unit);
@Override
default boolean isValid(){
return getTile().entity instanceof SpawnerTrait;
@@ -58,7 +58,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
//visual only.
if(Net.client()){
Tile tile = world.tile(unit.spawner);
if(tile != null && !Net.client()){
if(tile != null){
tile.block().unitRemoved(tile, unit);
}
@@ -125,8 +125,8 @@ public abstract class FlyingUnit extends BaseUnit{
if(!Net.client()){
updateRotation();
wobble();
}
wobble();
}
@Override
@@ -23,6 +23,7 @@ import io.anuke.mindustry.graphics.Pal;
import io.anuke.mindustry.input.*;
import io.anuke.mindustry.input.InputHandler.PlaceDraw;
import io.anuke.mindustry.io.TypeIO;
import io.anuke.mindustry.net.Administration.*;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetConnection;
import io.anuke.mindustry.type.*;
@@ -37,6 +38,7 @@ import static io.anuke.mindustry.Vars.*;
public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public static final int timerSync = 2;
public static final int timerAbility = 3;
public static final int timerTransfer = 4;
private static final int timerShootLeft = 0;
private static final int timerShootRight = 1;
private static final float liftoffBoost = 0.2f;
@@ -59,7 +61,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public NetConnection con;
public boolean isLocal = false;
public Interval timer = new Interval(4);
public Interval timer = new Interval(6);
public TargetTrait target;
public TargetTrait moveTarget;
@@ -800,6 +802,14 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
}
}
public PlayerInfo getInfo(){
if(uuid == null){
throw new IllegalArgumentException("Local players cannot be traced and do not have info.");
}else{
return netServer.admins.getInfo(uuid);
}
}
/** Resets all values of the player. */
public void reset(){
resetNoAdd();
@@ -909,7 +919,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
buffer.writeInt(Color.rgba8888(color));
buffer.writeByte(mech.id);
buffer.writeInt(mining == null ? noSpawner : mining.pos());
buffer.writeInt(spawner == null ? noSpawner : spawner.getTile().pos());
buffer.writeInt(spawner == null || !spawner.hasUnit(this) ? noSpawner : spawner.getTile().pos());
buffer.writeShort((short)(baseRotation * 2));
writeBuilding(buffer);
@@ -5,6 +5,7 @@ import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.entities.type.Unit;
import io.anuke.mindustry.type.Zone;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.entities.type.Player;
public class EventType{
@@ -184,5 +185,22 @@ public class EventType{
public static class ResizeEvent{
}
public static class PlayerJoin{
public final Player player;
public PlayerJoin(Player player){
this.player = player;
}
}
public static class PlayerLeave{
public final Player player;
public PlayerLeave(Player player){
this.player = player;
}
}
}
@@ -69,6 +69,20 @@ public enum Gamemode{
this.validator = validator;
}
public static Gamemode bestFit(Rules rules){
if(rules.pvp){
return pvp;
}else if(rules.editor){
return editor;
}else if(rules.attackMode){
return attack;
}else if(rules.infiniteResources){
return sandbox;
}else{
return survival;
}
}
/** Applies this preset to this ruleset. */
public Rules apply(Rules in){
rules.accept(in);
@@ -14,7 +14,7 @@ import static io.anuke.mindustry.Vars.*;
/** Controls playback of multiple music tracks.*/
public class MusicControl{
private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.5f, musicWaveChance = 0.4f;
private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.6f, musicWaveChance = 0.5f;
/** normal, ambient music, plays at any time */
public final Array<Music> ambientMusic = Array.with(Musics.game1, Musics.game3, Musics.game4, Musics.game6);
@@ -266,6 +266,10 @@ public class Saves{
return meta == null || meta.rules == null ? null : meta.rules.zone;
}
public Gamemode mode(){
return Gamemode.bestFit(meta.rules);
}
public int getBuild(){
return meta.build;
}
@@ -115,9 +115,7 @@ public class Tutorial{
outline("blockinfo");
}
},
conveyor(
line -> Strings.format(line, Math.min(placed(Blocks.conveyor), 2), 2),
() -> placed(Blocks.conveyor, 2) && event("lineconfirm") && event("coreitem")){
conveyor(() -> placed(Blocks.conveyor, 2) && event("lineconfirm") && event("coreitem")){
void draw(){
outline("category-distribution");
outline("block-conveyor");
@@ -190,13 +188,12 @@ public class Tutorial{
protected final String line = Core.bundle.has("tutorial." + name() + ".mobile") && mobile ? "tutorial." + name() + ".mobile" : "tutorial." + name();
protected final Function<String, String> text;
protected final Array<String> sentences;
protected Array<String> sentences;
protected final BooleanProvider done;
TutorialStage(Function<String, String> text, BooleanProvider done){
this.text = text;
this.done = done;
this.sentences = Array.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty());
}
TutorialStage(BooleanProvider done){
@@ -205,6 +202,7 @@ public class Tutorial{
/** displayed tutorial stage text.*/
public String text(){
if(sentences == null) this.sentences = Array.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty());
String line = sentences.get(control.tutorial.sentence);
return line.contains("{") ? text.get(line) : line;
}
@@ -59,6 +59,7 @@ public abstract class InputHandler implements InputProcessor{
@Remote(targets = Loc.both, forward = true, called = Loc.server)
public static void transferInventory(Player player, Tile tile){
if(!player.timer.get(Player.timerTransfer, 40)) return;
if(Net.server() && (player.item().amount <= 0 || player.isTransferring)){
throw new ValidateException(player, "Player cannot transfer an item.");
}
@@ -288,7 +289,7 @@ public abstract class InputHandler implements InputProcessor{
}
public void tryDropItems(Tile tile, float x, float y){
if(!droppingItem || player.item().amount <= 0 || canTapPlayer(x, y) || state.isPaused()){
if(!droppingItem || player.item().amount <= 0 || canTapPlayer(x, y) || state.isPaused() || !player.timer.check(Player.timerTransfer, 40)){
droppingItem = false;
return;
}
+4 -3
View File
@@ -184,7 +184,7 @@ public class Maps{
FileHandle dest = findFile();
file.copyTo(dest);
loadMap(dest, true);
createNewPreview(loadMap(dest, true));
}
/** Attempts to run the following code;
@@ -356,7 +356,7 @@ public class Maps{
//if it's here, then the preview failed to load or doesn't exist, make it
//this has to be done synchronously!
Pixmap pix = MapIO.generatePreview(map);
Core.app.post(() -> map.texture = new Texture(pix));
map.texture = new Texture(pix);
executor.submit(() -> {
try{
map.previewFile().writePNG(pix);
@@ -404,7 +404,7 @@ public class Maps{
return customMapDirectory.child("map_" + i + "." + mapExtension);
}
private void loadMap(FileHandle file, boolean custom) throws IOException{
private Map loadMap(FileHandle file, boolean custom) throws IOException{
Map map = MapIO.createMap(file, custom);
if(map.name() == null){
@@ -413,6 +413,7 @@ public class Maps{
maps.add(map);
maps.sort();
return map;
}
private void loadCustomMaps(){
@@ -1,7 +1,7 @@
package io.anuke.mindustry.net;
import io.anuke.annotations.Annotations.Serialize;
import io.anuke.arc.Core;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import static io.anuke.mindustry.Vars.headless;
@@ -10,6 +10,7 @@ public class Administration{
/** All player info. Maps UUIDs to info. This persists throughout restarts. */
private ObjectMap<String, PlayerInfo> playerInfo = new ObjectMap<>();
private Array<String> bannedIPs = new Array<>();
private Array<String> whitelist = new Array<>();
public Administration(){
Core.settings.defaults(
@@ -20,9 +21,16 @@ public class Administration{
load();
}
public int getPlayerLimit(){
return Core.settings.getInt("playerlimit", 0);
}
public void setPlayerLimit(int limit){
Core.settings.putSave("playerlimit", limit);
}
public void setStrict(boolean on){
Core.settings.put("strict", on);
Core.settings.save();
Core.settings.putSave("strict", on);
}
public boolean getStrict(){
@@ -186,6 +194,36 @@ public class Administration{
return true;
}
public boolean isWhitelistEnabled(){
return Core.settings.getBool("whitelist", false);
}
public void setWhitelist(boolean enabled){
Core.settings.putSave("whitelist", enabled);
}
public boolean isWhitelisted(String id, String usid){
return !isWhitelistEnabled() || whitelist.contains(usid + id);
}
public boolean whitelist(String id){
PlayerInfo info = getCreateInfo(id);
if(whitelist.contains(info.adminUsid + id)) return false;
whitelist.add(info.adminUsid + id);
save();
return true;
}
public boolean unwhitelist(String id){
PlayerInfo info = getCreateInfo(id);
if(whitelist.contains(info.adminUsid + id)){
whitelist.remove(info.adminUsid + id);
save();
return true;
}
return false;
}
public boolean isIPBanned(String ip){
return bannedIPs.contains(ip, false) || (findByIP(ip) != null && findByIP(ip).banned);
}
@@ -242,6 +280,10 @@ public class Administration{
return null;
}
public Array<PlayerInfo> getWhitelisted(){
return playerInfo.values().toArray().select(p -> isWhitelisted(p.id, p.adminUsid));
}
private PlayerInfo getCreateInfo(String id){
if(playerInfo.containsKey(id)){
return playerInfo.get(id);
@@ -256,6 +298,7 @@ public class Administration{
public void save(){
Core.settings.putObject("player-info", playerInfo);
Core.settings.putObject("banned-ips", bannedIPs);
Core.settings.putObject("whitelisted", whitelist);
Core.settings.save();
}
@@ -263,6 +306,7 @@ public class Administration{
private void load(){
playerInfo = Core.settings.getObject("player-info", ObjectMap.class, ObjectMap::new);
bannedIPs = Core.settings.getObject("banned-ips", Array.class, Array::new);
whitelist = Core.settings.getObject("whitelisted", Array.class, Array::new);
}
@Serialize
+7 -2
View File
@@ -1,15 +1,18 @@
package io.anuke.mindustry.net;
import io.anuke.mindustry.game.*;
public class Host{
public final String name;
public final String address;
public final String mapname;
public final int wave;
public final int players;
public final int players, playerLimit;
public final int version;
public final String versionType;
public final Gamemode mode;
public Host(String name, String address, String mapname, int wave, int players, int version, String versionType){
public Host(String name, String address, String mapname, int wave, int players, int version, String versionType, Gamemode mode, int playerLimit){
this.name = name;
this.address = address;
this.players = players;
@@ -17,5 +20,7 @@ public class Host{
this.wave = wave;
this.version = version;
this.versionType = versionType;
this.playerLimit = playerLimit;
this.mode = mode;
}
}
+13 -12
View File
@@ -1,17 +1,15 @@
package io.anuke.mindustry.net;
import io.anuke.arc.Core;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.entities.Entities;
import io.anuke.mindustry.entities.type.Player;
import io.anuke.arc.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.io.JsonIO;
import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.io.*;
import io.anuke.mindustry.maps.Map;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.nio.*;
import java.util.*;
import static io.anuke.mindustry.Vars.*;
@@ -71,8 +69,9 @@ public class NetworkIO{
buffer.putInt(state.wave);
buffer.putInt(Version.build);
writeString(buffer, Version.type);
//TODO additional information:
// - gamemode ID/name (just pick the closest one?)
buffer.put((byte)Gamemode.bestFit(state.rules).ordinal());
buffer.putInt(netServer.admins.getPlayerLimit());
return buffer;
}
@@ -83,13 +82,15 @@ public class NetworkIO{
int wave = buffer.getInt();
int version = buffer.getInt();
String vertype = readString(buffer);
Gamemode gamemode = Gamemode.all[buffer.get()];
int limit = buffer.getInt();
return new Host(host, hostAddress, map, wave, players, version, vertype);
return new Host(host, hostAddress, map, wave, players, version, vertype, gamemode, limit);
}
private static void writeString(ByteBuffer buffer, String string, int maxlen){
byte[] bytes = string.getBytes(charset);
//truncating this way may lead to wierd encoding errors at the ends of strings...
//todo truncating this way may lead to wierd encoding errors at the ends of strings...
if(bytes.length > maxlen){
bytes = Arrays.copyOfRange(bytes, 0, maxlen);
}
+2 -1
View File
@@ -14,7 +14,7 @@ public class Packets{
public enum KickReason{
kick, clientOutdated, serverOutdated, banned, gameover(true), recentKick,
nameInUse, idInUse, nameEmpty, customClient, serverClose, vote, typeMismatch;
nameInUse, idInUse, nameEmpty, customClient, serverClose, vote, typeMismatch, whitelist, playerLimit;
public final boolean quiet;
@@ -52,6 +52,7 @@ public class Packets{
public static class Disconnect implements Packet{
public int id;
public String reason;
@Override
public boolean isImportant(){
@@ -1,12 +1,11 @@
package io.anuke.mindustry.plugin;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.*;
import io.anuke.arc.files.*;
import io.anuke.arc.function.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.io.*;
import java.lang.reflect.*;
import java.net.*;
import static io.anuke.mindustry.Vars.pluginDirectory;
@@ -50,12 +49,9 @@ public class Plugins{
PluginMeta meta = JsonIO.read(PluginMeta.class, metaf.readString());
URLClassLoader classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, jar.file().toURI().toURL());
Class<?> main = Class.forName(meta.main);
URLClassLoader classLoader = new URLClassLoader(new URL[]{jar.file().toURI().toURL()}, ClassLoader.getSystemClassLoader());
Class<?> main = classLoader.loadClass(meta.main);
return new LoadedPlugin(jar, zip, (Plugin)main.newInstance(), meta);
}
+1 -1
View File
@@ -42,7 +42,7 @@ public class Zone extends UnlockableContent{
@Override
public void load(){
preview = Core.atlas.find(name);
preview = Core.atlas.find("zone-" + name);
}
public Rules getRules(){
@@ -13,11 +13,15 @@ public class ItemDisplay extends Table{
this(item, 0);
}
public ItemDisplay(Item item, int amount){
add(new ItemImage(new ItemStack(item, amount))).size(8 * 4);
add(item.localizedName()).padLeft(4);
public ItemDisplay(Item item, int amount, boolean showName){
add(new ItemImage(new ItemStack(item, amount))).size(8 * 4).padRight(amount > 99 ? 12 : 0);
if(showName) add(item.localizedName()).padLeft(4 + amount > 99 ? 4 : 0);
this.item = item;
this.amount = amount;
}
public ItemDisplay(Item item, int amount){
this(item, amount, true);
}
}
@@ -27,7 +27,7 @@ public class LiquidDisplay extends Table{
t.add(Strings.autoFixed(amount, 1));
add(t);
}
}}).size(8 * 4).padRight(3);
}}).size(8 * 4).padRight(3 + (amount != 0 && Strings.autoFixed(amount, 1).length() > 2 ? 8 : 0));
if(perSecond){
add(StatUnit.perSecond.localized()).padLeft(2).padRight(5).color(Color.LIGHT_GRAY);
@@ -182,10 +182,10 @@ public class JoinDialog extends FloatingDialog{
void setupServer(Server server, Host host){
server.lastHost = host;
server.content.clear();
server.content.table(t -> setupHostTable(t, host)).expand().left().bottom().padLeft(12f).padBottom(8);
buildServer(host, server.content);
}
void setupHostTable(Table content, Host host){
void buildServer(Host host, Table content){
String versionString;
if(host.version == -1){
@@ -202,12 +202,14 @@ public class JoinDialog extends FloatingDialog{
versionString = Core.bundle.format("server.version", host.version, host.versionType);
}
content.add("[lightgray]" + host.name + " " + versionString).width(targetWidth() - 10f).left().get().setEllipsis(true);
content.row();
content.add("[lightgray]" + (host.players != 1 ? Core.bundle.format("players", host.players == 0 ? host.players : "[accent]" + host.players + "[lightgray]") : Core.bundle.format("players.single", "[accent]" + host.players + "[lightgray]"))).left();
content.row();
content.add("[lightgray]" + Core.bundle.format("save.map", host.mapname) + "[lightgray] / " + Core.bundle.format("save.wave", host.wave)).width(targetWidth() - 10f).left().get().setEllipsis(true);
content.table(t -> {
t.add("[lightgray]" + host.name + " " + versionString).width(targetWidth() - 10f).left().get().setEllipsis(true);
t.row();
t.add("[lightgray]" + (Core.bundle.format("players" + (host.players == 1 ? ".single" : ""), (host.players == 0 ? "[lightgray]" : "[accent]") + host.players + (host.playerLimit > 0 ? "[lightgray]/[accent]" + host.playerLimit : "")+ "[lightgray]"))).left();
t.row();
t.add("[lightgray]" + Core.bundle.format("save.map", host.mapname) + "[lightgray] / " + host.mode.toString()).width(targetWidth() - 10f).left().get().setEllipsis(true);
}).expand().left().bottom().padLeft(12f).padBottom(8);
}
void setup(){
@@ -275,6 +277,9 @@ public class JoinDialog extends FloatingDialog{
local.background((Drawable)null);
local.table("button", t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering.any") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX();
Net.discoverServers(this::addLocalHost, this::finishLocalHosts);
for(String host : defaultServers){
Net.pingHost(host, port, this::addLocalHost, e -> {});
}
}
void finishLocalHosts(){
@@ -299,11 +304,10 @@ public class JoinDialog extends FloatingDialog{
local.row();
local.addButton(b -> {
b.margin(5f);
b.left();
setupHostTable(b, host);
}, "clear", () -> connect(host.address, port)).width(w).pad(4f).get();
TextButton button = local.addButton("", "clear", () -> connect(host.address, port))
.width(w).pad(5f).get();
button.clearChildren();
buildServer(host, button);
}
void connect(String ip, int port){
@@ -137,13 +137,13 @@ public class LoadDialog extends FloatingDialog{
meta.row();
meta.labelWrap(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().name())));
meta.row();
meta.labelWrap(Core.bundle.format("save.wave", color + slot.getWave()));
meta.labelWrap(slot.mode().toString() + " /" + color + " " + Core.bundle.format("save.wave", color + slot.getWave()));
meta.row();
meta.labelWrap(() -> Core.bundle.format("save.autosave", color + Core.bundle.get(slot.isAutosave() ? "on" : "off")));
meta.row();
meta.labelWrap(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
meta.row();
meta.labelWrap(Core.bundle.format("save.date", color + slot.getDate()));
meta.labelWrap(color + slot.getDate());
meta.row();
}).left().growX().width(250f);
@@ -62,49 +62,52 @@ public class MapsDialog extends FloatingDialog{
if(!ios){
buttons.addImageTextButton("$editor.importmap", "icon-load", iconsize, () -> {
platform.showFileChooser("$editor.importmap", "Map File", file -> {
maps.tryCatchMapError(() -> {
if(MapIO.isImage(file)){
ui.showError("$editor.errorimage");
return;
}
ui.loadAnd(() -> {
maps.tryCatchMapError(() -> {
if(MapIO.isImage(file)){
ui.showError("$editor.errorimage");
return;
}
Map map;
if(file.extension().equalsIgnoreCase(mapExtension)){
map = MapIO.createMap(file, true);
}else{
map = maps.makeLegacyMap(file);
}
Map map;
if(file.extension().equalsIgnoreCase(mapExtension)){
map = MapIO.createMap(file, true);
}else{
map = maps.makeLegacyMap(file);
}
//when you attempt to import a save, it will have no name, so generate one
String name = map.tags.getOr("name", () -> {
String result = "unknown";
int number = 0;
while(maps.byName(result + number++) != null) ;
return result + number;
});
//this will never actually get called, but it remains just in case
if(name == null){
ui.showError("$editor.errorname");
return;
}
Map conflict = maps.all().find(m -> m.name().equals(name));
if(conflict != null && !conflict.custom){
ui.showInfo(Core.bundle.format("editor.import.exists", name));
}else if(conflict != null){
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
maps.tryCatchMapError(() -> {
maps.importMap(file);
setup();
});
//when you attempt to import a save, it will have no name, so generate one
String name = map.tags.getOr("name", () -> {
String result = "unknown";
int number = 0;
while(maps.byName(result + number++) != null);
return result + number;
});
}else{
maps.importMap(map.file);
setup();
}
//this will never actually get called, but it remains just in case
if(name == null){
ui.showError("$editor.errorname");
return;
}
Map conflict = maps.all().find(m -> m.name().equals(name));
if(conflict != null && !conflict.custom){
ui.showInfo(Core.bundle.format("editor.import.exists", name));
}else if(conflict != null){
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
maps.tryCatchMapError(() -> {
maps.removeMap(conflict);
maps.importMap(map.file);
setup();
});
});
}else{
maps.importMap(map.file);
setup();
}
});
});
}, true, FileChooser.anyMapFiles);
}).size(210f, 64f);
@@ -5,6 +5,7 @@ import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.input.*;
import io.anuke.arc.scene.event.*;
import io.anuke.arc.scene.ui.layout.*;
import static io.anuke.mindustry.Vars.renderer;
@@ -40,7 +41,7 @@ public class MinimapDialog extends FloatingDialog{
renderer.minimap.drawEntities(x, y, width, height);
}
}).grow();
}).size(Math.min(Core.graphics.getWidth() / 1.1f, Core.graphics.getHeight() / 1.3f)).padTop(-20f);
}).size(Math.min(Core.graphics.getWidth() / 1.1f, Core.graphics.getHeight() / 1.3f) / UnitScl.dp.scl(1f)).padTop(-20f);
cont.addListener(new InputListener(){
@Override
@@ -139,7 +139,7 @@ public class SettingsMenuDialog extends SettingsDialog{
t.row();
//iOS doesn't have a file chooser.
if(!ios){
//if(!ios){
t.addButton("$data.import", style, () -> ui.showConfirm("$confirm", "$data.import.confirm", () -> platform.showFileChooser("$data.import", "Zip Files", file -> {
try{
data.importData(file);
@@ -151,7 +151,7 @@ public class SettingsMenuDialog extends SettingsDialog{
ui.showError(Strings.parseException(e, true));
}
}, true, f -> f.equalsIgnoreCase("zip"))));
}
//}
});
ScrollPane pane = new ScrollPane(prefs);
@@ -40,7 +40,7 @@ public class BlockInventoryFragment extends Fragment{
@Remote(called = Loc.server, targets = Loc.both, forward = true)
public static void requestItem(Player player, Tile tile, Item item, int amount){
if(player == null || tile == null) return;
if(player == null || tile == null || !player.timer.get(Player.timerTransfer, 20)) return;
int removed = tile.block().removeStack(tile, item, amount);
@@ -71,6 +71,8 @@ public class BlockInventoryFragment extends Fragment{
}
public void hide(){
if(table == null) return;
table.actions(Actions.scaleTo(0f, 1f, 0.06f, Interpolation.pow3Out), Actions.run(() -> {
table.clearChildren();
table.clearListeners();
+7 -4
View File
@@ -19,7 +19,6 @@ import io.anuke.arc.util.pooling.*;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.bullet.*;
import io.anuke.mindustry.entities.effect.*;
import io.anuke.mindustry.entities.type.Unit;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
@@ -32,6 +31,7 @@ import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.blocks.power.*;
import io.anuke.mindustry.world.consumers.*;
import io.anuke.mindustry.world.meta.*;
import io.anuke.mindustry.world.meta.values.*;
import java.util.*;
@@ -251,7 +251,7 @@ public class Block extends BlockStorage{
public void drawPlace(int x, int y, int rotation, boolean valid){
}
protected float drawPlaceText(String text, int x, int y, boolean valid){
public float drawPlaceText(String text, int x, int y, boolean valid){
if(renderer.pixelator.enabled()) return 0;
Color color = valid ? Pal.accent : Pal.remove;
@@ -476,7 +476,10 @@ public class Block extends BlockStorage{
public void setStats(){
stats.add(BlockStat.size, "{0}x{0}", size);
stats.add(BlockStat.health, health, StatUnit.none);
stats.add(BlockStat.buildTime, buildCost / 60, StatUnit.seconds);
if(isBuildable()){
stats.add(BlockStat.buildTime, buildCost / 60, StatUnit.seconds);
stats.add(BlockStat.buildCost, new ItemListValue(false, buildRequirements));
}
consumes.display(stats);
@@ -581,7 +584,7 @@ public class Block extends BlockStorage{
});
}
Damage.dynamicExplosion(x, y, flammability, explosiveness, power, tilesize * size / 2f, Pal.darkFlame);
Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * size / 2f, Pal.darkFlame);
if(!tile.floor().solid && !tile.floor().isLiquid){
RubbleDecal.create(tile.drawx(), tile.drawy(), size);
}
@@ -28,7 +28,6 @@ public abstract class BlockStorage extends UnlockableContent{
public int itemCapacity = 10;
public float liquidCapacity = 10f;
public float liquidFlowFactor = 4.9f;
public final BlockStats stats = new BlockStats();
public final BlockBars bars = new BlockBars();
@@ -0,0 +1,71 @@
package io.anuke.mindustry.world.blocks;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*;
public class RespawnBlock{
public static void drawRespawn(Tile tile, float heat, float progress, float time, Player player, Mech to){
progress = Mathf.clamp(progress);
Draw.color(Pal.darkMetal);
Lines.stroke(2f * heat);
Fill.poly(tile.drawx(), tile.drawy(), 4, 10f * heat);
Draw.reset();
if(player != null){
TextureRegion region = to.iconRegion;
Draw.color(0f, 0f, 0f, 0.4f * progress);
Draw.rect("circle-shadow", tile.drawx(), tile.drawy(), region.getWidth() / 3f, region.getWidth() / 3f);
Draw.color();
Shaders.build.region = region;
Shaders.build.progress = progress;
Shaders.build.color.set(Pal.accent);
Shaders.build.time = -time / 10f;
Draw.shader(Shaders.build, true);
Draw.rect(region, tile.drawx(), tile.drawy());
Draw.shader();
Draw.color(Pal.accentBack);
float pos = Mathf.sin(time, 6f, 8f);
Lines.lineAngleCenter(tile.drawx() + pos, tile.drawy(), 90, 16f - Math.abs(pos) * 2f);
Draw.reset();
}
Lines.stroke(2f * heat);
Draw.color(Pal.accentBack);
Lines.poly(tile.drawx(), tile.drawy(), 4, 8f * heat);
float oy = -7f, len = 6f * heat;
Lines.stroke(5f);
Draw.color(Pal.darkMetal);
Lines.line(tile.drawx() - len, tile.drawy() + oy, tile.drawx() + len, tile.drawy() + oy, CapStyle.none);
for(int i : Mathf.signs){
Fill.tri(tile.drawx() + len * i, tile.drawy() + oy - Lines.getStroke()/2f, tile.drawx() + len * i, tile.drawy() + oy + Lines.getStroke()/2f, tile.drawx() + (len + Lines.getStroke() * heat) * i, tile.drawy() + oy);
}
Lines.stroke(3f);
Draw.color(Pal.accent);
Lines.line(tile.drawx() - len, tile.drawy() + oy, tile.drawx() - len + len*2 * progress, tile.drawy() + oy, CapStyle.none);
for(int i : Mathf.signs){
Fill.tri(tile.drawx() + len * i, tile.drawy() + oy - Lines.getStroke()/2f, tile.drawx() + len * i, tile.drawy() + oy + Lines.getStroke()/2f, tile.drawx() + (len + Lines.getStroke() * heat) * i, tile.drawy() + oy);
}
Draw.reset();
if(Net.active() && player != null){
tile.block().drawPlaceText(player.name, tile.x, tile.y - (Math.max((tile.block().size-1)/2, 0)), true);
}
}
}
@@ -44,7 +44,7 @@ public class CooledTurret extends Turret{
TurretEntity entity = tile.entity();
Liquid liquid = entity.liquids.current();
float used = Math.min(Math.min(entity.liquids.get(liquid), maxUsed * Time.delta()), Math.max(0, ((reload - entity.reload) / coolantMultiplier) / liquid.heatCapacity));
float used = Math.min(Math.min(entity.liquids.get(liquid), maxUsed * Time.delta()), Math.max(0, ((reload - entity.reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed(tile);
entity.reload += (used * liquid.heatCapacity) / liquid.heatCapacity;
entity.liquids.remove(liquid, used);
@@ -201,7 +201,7 @@ public abstract class Turret extends Block{
protected void turnToTarget(Tile tile, float targetRot){
TurretEntity entity = tile.entity();
entity.rotation = Angles.moveToward(entity.rotation, targetRot, rotatespeed * entity.delta());
entity.rotation = Angles.moveToward(entity.rotation, targetRot, rotatespeed * entity.delta() * baseReloadSpeed(tile));
}
public boolean shouldTurn(Tile tile){
@@ -37,7 +37,7 @@ public class ItemLiquidGenerator extends PowerGenerator{
protected Effects.Effect explodeEffect = Fx.generatespark;
protected Color heatColor = Color.valueOf("ff9b59");
protected TextureRegion topRegion, liquidRegion;
protected boolean randomlyExplode = false;
protected boolean randomlyExplode = true;
public ItemLiquidGenerator(boolean hasItems, boolean hasLiquids, String name){
super(name);
@@ -127,8 +127,10 @@ public class ItemLiquidGenerator extends PowerGenerator{
if(randomlyExplode && Mathf.chance(entity.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.5f))){
//this block is run last so that in the event of a block destruction, no code relies on the block type
entity.damage(Mathf.random(11f));
Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f));
Core.app.post(() -> {
entity.damage(Mathf.random(11f));
Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f));
});
}
}else{
entity.productionEfficiency = 0.0f;
@@ -22,7 +22,6 @@ public class Pump extends LiquidBlock{
public Pump(String name){
super(name);
layer = Layer.overlay;
liquidFlowFactor = 3f;
group = BlockGroup.liquids;
floating = true;
}
@@ -3,9 +3,7 @@ package io.anuke.mindustry.world.blocks.storage;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.traits.*;
@@ -16,6 +14,7 @@ import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.meta.*;
import static io.anuke.mindustry.Vars.*;
@@ -32,6 +31,7 @@ public class CoreBlock extends StorageBlock{
flags = EnumSet.of(BlockFlag.target, BlockFlag.producer);
activeSound = Sounds.respawning;
activeSoundVolume = 1f;
layer = Layer.overlay;
}
@Remote(called = Loc.server)
@@ -84,41 +84,11 @@ public class CoreBlock extends StorageBlock{
}
@Override
public void draw(Tile tile){
public void drawLayer(Tile tile){
CoreEntity entity = tile.entity();
Draw.rect(region, tile.drawx(), tile.drawy());
if(entity.heat > 0){
Draw.color(Pal.darkMetal);
Lines.stroke(2f * entity.heat);
Lines.poly(tile.drawx(), tile.drawy(), 4, 8f * entity.heat);
Draw.reset();
}
if(entity.spawnPlayer != null){
Unit player = entity.spawnPlayer;
TextureRegion region = player.getIconRegion();
Shaders.build.region = region;
Shaders.build.progress = entity.progress;
Shaders.build.color.set(Pal.accent);
Shaders.build.time = -entity.time / 10f;
Draw.shader(Shaders.build, true);
Draw.rect(region, tile.drawx(), tile.drawy());
Draw.shader();
Draw.color(Pal.accent);
Lines.lineAngleCenter(
tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize / 3f * size),
tile.drawy(),
90,
size * Vars.tilesize / 2f);
Draw.reset();
if(entity.heat > 0.001f){
RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.spawnPlayer, mech);
}
}
@@ -173,6 +143,11 @@ public class CoreBlock extends StorageBlock{
float time;
float heat;
@Override
public boolean hasUnit(Unit unit){
return unit == spawnPlayer;
}
@Override
public void updateSpawning(Player player){
if(!netServer.isWaitingForPlayers() && spawnPlayer == null){
@@ -1,32 +1,24 @@
package io.anuke.mindustry.world.blocks.units;
import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.arc.Core;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Geometry;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.entities.Effects;
import io.anuke.mindustry.entities.traits.SpawnerTrait;
import io.anuke.mindustry.entities.type.Player;
import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Pal;
import io.anuke.mindustry.graphics.Shaders;
import io.anuke.mindustry.type.Mech;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.mindustry.world.meta.StatUnit;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.meta.*;
import java.io.*;
import static io.anuke.mindustry.Vars.mobile;
import static io.anuke.mindustry.Vars.tilesize;
import static io.anuke.mindustry.Vars.*;
public class MechPad extends Block{
protected Mech mech;
@@ -37,6 +29,7 @@ public class MechPad extends Block{
update = true;
solid = false;
hasPower = true;
layer = Layer.overlay;
}
@Override
@@ -110,32 +103,11 @@ public class MechPad extends Block{
}
@Override
public void draw(Tile tile){
public void drawLayer(Tile tile){
MechFactoryEntity entity = tile.entity();
Draw.rect(Core.atlas.find(name), tile.drawx(), tile.drawy());
if(entity.player != null){
TextureRegion region = (!entity.sameMech && entity.player.mech == mech ? Mechs.starter.iconRegion : mech.iconRegion);
Shaders.build.region = region;
Shaders.build.progress = entity.progress;
Shaders.build.time = -entity.time / 5f;
Shaders.build.color.set(Pal.accent);
Draw.shader(Shaders.build);
Draw.rect(region, tile.drawx(), tile.drawy());
Draw.shader();
Draw.color(Pal.accent);
Lines.lineAngleCenter(
tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize / 3f * size),
tile.drawy(),
90,
size * Vars.tilesize / 2f + 1f);
Draw.reset();
RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.player, (!entity.sameMech && entity.player.mech == mech ? Mechs.starter : mech));
}
}
@@ -170,6 +142,11 @@ public class MechPad extends Block{
float time;
float heat;
@Override
public boolean hasUnit(Unit unit){
return unit == player;
}
@Override
public void updateSpawning(Player unit){
if(player == null){
@@ -9,6 +9,7 @@ public enum BlockStat{
health(StatCategory.general),
size(StatCategory.general),
buildTime(StatCategory.general),
buildCost(StatCategory.general),
itemCapacity(StatCategory.items),
itemsMoved(StatCategory.items),
@@ -7,15 +7,21 @@ import io.anuke.mindustry.world.meta.StatValue;
public class ItemListValue implements StatValue{
private final ItemStack[] stacks;
private final boolean displayName;
public ItemListValue(ItemStack... stacks){
this(true, stacks);
}
public ItemListValue(boolean displayName, ItemStack... stacks){
this.stacks = stacks;
this.displayName = displayName;
}
@Override
public void display(Table table){
for(ItemStack stack : stacks){
table.add(new ItemDisplay(stack.item, stack.amount)).padRight(5);
table.add(new ItemDisplay(stack.item, stack.amount, displayName)).padRight(5);
}
}
}