diff --git a/build.gradle b/build.gradle index 99e54b0611..e70a369b41 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ allprojects { version = 'release' ext { - versionNumber = '3.4' + versionNumber = '3.5' versionType = 'release' appName = 'Mindustry' gdxVersion = '1.9.8' diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 0faf77a349..023cf42e36 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -42,6 +42,8 @@ text.server.kicked.recentKick=You have been kicked recently.\nWait before connec text.server.connected={0} has joined. text.server.disconnected={0} has disconnected. text.nohost=Can't host server on a custom map! +text.host.info=The [accent]host[] button hosts a server on ports [scarlet]6567[] and [scarlet]6568.[]\nAnybody on the same [LIGHT_GRAY]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[LIGHT_GRAY]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. +text.join.info=Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[LIGHT_GRAY]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. text.hostserver=Host Server text.host=Host text.hosting=[accent]Opening server... diff --git a/core/assets/shaders/shield.fragment b/core/assets/shaders/shield.fragment index b32e5a76bb..ba57b130ef 100644 --- a/core/assets/shaders/shield.fragment +++ b/core/assets/shaders/shield.fragment @@ -64,11 +64,11 @@ void main() { if(i >= u_hitamount) break; vec3 hit = u_hits[i]; float rad = hit.z * HIT_RADIUS; - float fract = 1.0 - hit.z; + float fin = 1.0 - hit.z; if(abs(distance(vec2(hit.x, hit.y), coords - u_texsize/2.0) - rad) < 1.0){ - color = mix(color, u_color* vec4(si, si, si, 1.0), (1.0 * fract)); - color.a = ALPHA + 0.82 *fract; + color = mix(color, u_color* vec4(si, si, si, 1.0), (1.0 * fin)); + color.a = ALPHA + 0.82 *fin; } } } diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index 59943bf2c8..5eea259aca 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -3,6 +3,7 @@ package io.anuke.mindustry.core; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.IntMap; import com.badlogic.gdx.utils.IntSet; +import io.anuke.mindustry.content.UpgradeRecipes; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.entities.BulletType; import io.anuke.mindustry.entities.Player; @@ -13,9 +14,12 @@ import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net.SendMode; import io.anuke.mindustry.net.NetworkIO; import io.anuke.mindustry.net.Packets.*; +import io.anuke.mindustry.resource.Upgrade; +import io.anuke.mindustry.resource.Weapon; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Placement; import io.anuke.mindustry.world.Tile; +import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Timers; import io.anuke.ucore.entities.BaseBulletType; import io.anuke.ucore.entities.Entities; @@ -261,6 +265,15 @@ public class NetClient extends Module { Player player = playerGroup.getByID(packet.info.playerid); ui.traces.show(player, packet.info); }); + + Net.handleClient(UpgradePacket.class, packet -> { + Weapon weapon = Upgrade.getByID(packet.id); + + state.inventory.removeItems(UpgradeRecipes.get(weapon)); + control.upgrades().addWeapon(weapon); + ui.hudfrag.updateWeapons(); + Effects.sound("purchase"); + }); } @Override diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index 3197dacdef..acd7b34570 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -68,6 +68,8 @@ public class NetServer extends Module{ TraceInfo trace = admins.getTrace(Net.getConnection(id).address); PlayerInfo info = admins.getInfo(uuid); + trace.uuid = uuid; + trace.android = packet.android; if(admins.isIDBanned(uuid)){ kick(id, KickReason.banned); @@ -82,8 +84,6 @@ public class NetServer extends Module{ String ip = Net.getConnection(id).address; admins.updatePlayerJoined(uuid, ip, packet.name); - trace.uuid = uuid; - trace.android = packet.android; if(packet.version != Version.build && Version.build != -1 && packet.version != -1){ kick(id, packet.version > Version.build ? KickReason.serverOutdated : KickReason.clientOutdated); @@ -111,7 +111,7 @@ public class NetServer extends Module{ //TODO try DeflaterOutputStream ByteArrayOutputStream stream = new ByteArrayOutputStream(); - NetworkIO.writeWorld(player, weapons.get(player.name, new ByteArray()), stream); + NetworkIO.writeWorld(player, weapons.get(admins.getTrace(Net.getConnection(id).address).uuid, new ByteArray()), stream); WorldData data = new WorldData(); data.stream = new ByteArrayInputStream(stream.toByteArray()); Net.sendStream(id, data); @@ -165,17 +165,16 @@ public class NetServer extends Module{ TraceInfo info = admins.getTrace(Net.getConnection(id).address); Weapon weapon = Upgrade.getByID((byte)packet.data); - float wtrc = 40f; + float wtrc = 60; - if(!Timers.get(info.ip + "-weapontrace", wtrc)){ - info.fastShots ++; - }else{ + if(!Timers.get("fastshoot-" + id + "-" + weapon.id, wtrc)){ + info.fastShots.getAndIncrement(weapon.id, 0, 1); - if(info.fastShots - 2 > (int)(wtrc / (weapon.getReload() / 2f))){ + if(info.fastShots.get(weapon.id, 0) > (int)(wtrc / (weapon.getReload() / 2f)) + 2){ kick(id, KickReason.kick); } - - info.fastShots = 0; + }else{ + info.fastShots.put(weapon.id, 0); } packet.entityid = connections.get(id).id; @@ -241,14 +240,27 @@ public class NetServer extends Module{ Player player = connections.get(id); Weapon weapon = Upgrade.getByID(packet.id); + String uuid = admins.getTrace(Net.getConnection(id).address).uuid; - if (!weapons.containsKey(player.name)) weapons.put(player.name, new ByteArray()); - if (!weapons.get(player.name).contains(weapon.id)) weapons.get(player.name).add(weapon.id); + if(!state.inventory.hasItems(UpgradeRecipes.get(weapon))){ + return; + } + + if (!weapons.containsKey(uuid)) weapons.put(uuid, new ByteArray()); + + if (!weapons.get(uuid).contains(weapon.id)){ + weapons.get(uuid).add(weapon.id); + }else{ + return; + } state.inventory.removeItems(UpgradeRecipes.get(weapon)); + Net.sendTo(id, packet, SendMode.tcp); }); Net.handleServer(WeaponSwitchPacket.class, (id, packet) -> { + TraceInfo info = admins.getTrace(Net.getConnection(id).address); + packet.playerid = connections.get(id).id; Net.sendExcept(id, packet, SendMode.tcp); }); @@ -344,9 +356,8 @@ public class NetServer extends Module{ Log.info("Kicking connection #{0} / IP: {1}. Reason: {2}", connection, con.address, reason); } - PlayerInfo info = admins.getInfo(admins.getTrace(con.address).uuid); - - if(reason == KickReason.kick || reason == KickReason.banned){ + if((reason == KickReason.kick || reason == KickReason.banned) && admins.getTrace(con.address).uuid != null){ + PlayerInfo info = admins.getInfo(admins.getTrace(con.address).uuid); info.timesKicked ++; info.lastKicked = TimeUtils.millis(); } diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index c931547458..97be7d9bab 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -566,14 +566,14 @@ public class Renderer extends RendererModule{ } //TODO optimize! - public void drawBar(Color color, float x, float y, float fraction){ - fraction = Mathf.clamp(fraction); + public void drawBar(Color color, float x, float y, float finion){ + finion = Mathf.clamp(finion); - if(fraction > 0) fraction = Mathf.clamp(fraction + 0.2f, 0.24f, 1f); + if(finion > 0) finion = Mathf.clamp(finion + 0.2f, 0.24f, 1f); float len = 3; - float w = (int) (len * 2 * fraction) + 0.5f; + float w = (int) (len * 2 * finion) + 0.5f; x -= 0.5f; y += 0.5f; diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index a6f1585b32..24bbbcdcb0 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -223,8 +223,8 @@ public class UI extends SceneModule{ public void showInfo(String info){ new Dialog("$text.info.title", "dialog"){{ - content().margin(15).add(info); - buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4).get().getLabelCell().width(400f).get().setWrap(true); + content().margin(15).add(info).width(600f).get().setWrap(true); + buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4); }}.show(); } diff --git a/core/src/io/anuke/mindustry/core/World.java b/core/src/io/anuke/mindustry/core/World.java index 23014bc62c..806d1e8983 100644 --- a/core/src/io/anuke/mindustry/core/World.java +++ b/core/src/io/anuke/mindustry/core/World.java @@ -180,7 +180,7 @@ public class World extends Module{ Array removals = target.getLinkedTiles(tempTiles); for(Tile toremove : removals){ //note that setting a new block automatically unlinks it - toremove.setBlock(Blocks.air); + if(toremove != null) toremove.setBlock(Blocks.air); } } } diff --git a/core/src/io/anuke/mindustry/entities/BulletType.java b/core/src/io/anuke/mindustry/entities/BulletType.java index 0c0b3a12af..eac6270104 100644 --- a/core/src/io/anuke/mindustry/entities/BulletType.java +++ b/core/src/io/anuke/mindustry/entities/BulletType.java @@ -9,7 +9,7 @@ public abstract class BulletType extends BaseBulletType{ public float knockback; public StatusEffect status = StatusEffects.none; public float statusIntensity = 0.5f; - + public BulletType(float speed, int damage){ this.speed = speed; this.damage = damage; diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index a9272378ca..72252f8ee1 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -45,7 +45,6 @@ public class Player extends Unit{ public Mech mech = Mechs.standard; public float targetAngle = 0f; - public float stucktime = 0f; public boolean dashing = false; public int clientid = -1; @@ -58,7 +57,7 @@ public class Player extends Unit{ public Player(){ hitbox.setSize(5); - hitboxTile.setSize(5f); + hitboxTile.setSize(4f); maxhealth = 200; heal(); @@ -215,15 +214,8 @@ public class Player extends Unit{ Tile tile = world.tileWorld(x, y); //if player is in solid block - if(tile != null && tile.solid()){ - stucktime += Timers.delta(); - }else{ - stucktime = 0f; - } - - if(stucktime > 15f){ - damage(health+1); //die instantly - stucktime = 0f; + if(tile != null && tile.solid())) { + damage(health + 1); //die instantly } if(ui.chatfrag.chatOpen()) return; diff --git a/core/src/io/anuke/mindustry/input/DefaultKeybinds.java b/core/src/io/anuke/mindustry/input/DefaultKeybinds.java index 72608d7d20..1f6870bfb7 100644 --- a/core/src/io/anuke/mindustry/input/DefaultKeybinds.java +++ b/core/src/io/anuke/mindustry/input/DefaultKeybinds.java @@ -26,8 +26,9 @@ public class DefaultKeybinds { "block_info", Input.CONTROL_LEFT, "player_list", Input.TAB, "chat", Input.ENTER, - "chat_scroll_up", Input.UP, - "chat_scroll_down", Input.DOWN, + "chat_history_prev", Input.UP, + "chat_history_next", Input.DOWN, + "chat_scroll", new Axis(Input.SCROLL), "console", Input.GRAVE, "weapon_1", Input.NUM_1, "weapon_2", Input.NUM_2, @@ -55,8 +56,9 @@ public class DefaultKeybinds { "rotate", new Axis(Input.CONTROLLER_A, Input.CONTROLLER_B), "player_list", Input.CONTROLLER_START, "chat", Input.ENTER, - "chat_scroll_up", Input.UP, - "chat_scroll_down", Input.DOWN, + "chat_history_prev", Input.UP, + "chat_history_next", Input.DOWN, + "chat_scroll", new Axis(Input.SCROLL), "console", Input.GRAVE, "weapon_1", Input.NUM_1, "weapon_2", Input.NUM_2, diff --git a/core/src/io/anuke/mindustry/input/PlaceMode.java b/core/src/io/anuke/mindustry/input/PlaceMode.java index 48039b889e..02a6cc03b2 100644 --- a/core/src/io/anuke/mindustry/input/PlaceMode.java +++ b/core/src/io/anuke/mindustry/input/PlaceMode.java @@ -85,11 +85,11 @@ public enum PlaceMode{ if(tile != null && control.input().validBreak(tilex, tiley)){ if(tile.isLinked()) tile = tile.getLinked(); - float fract = control.input().breaktime / tile.getBreakTime(); + float fin = control.input().breaktime / tile.getBreakTime(); if(android && control.input().breaktime > 0){ - Draw.color(Colors.get("breakStart"), Colors.get("break"), fract); - Lines.poly(tile.drawx(), tile.drawy(), 25, 4 + (1f - fract) * 26); + Draw.color(Colors.get("breakStart"), Colors.get("break"), fin); + Lines.poly(tile.drawx(), tile.drawy(), 25, 4 + (1f - fin) * 26); } Draw.reset(); } diff --git a/core/src/io/anuke/mindustry/net/Administration.java b/core/src/io/anuke/mindustry/net/Administration.java index f34fe8aafb..59aa64fb75 100644 --- a/core/src/io/anuke/mindustry/net/Administration.java +++ b/core/src/io/anuke/mindustry/net/Administration.java @@ -172,6 +172,18 @@ public class Administration { return info.admin && ip.equals(info.validAdminIP); } + public Array findByName(String name, boolean last){ + Array result = new Array<>(); + + for(PlayerInfo info : playerInfo.values()){ + if(info.lastName.toLowerCase().equals(name.toLowerCase()) || (last && info.names.contains(name, false))){ + result.add(info); + } + } + + return result; + } + public PlayerInfo getInfo(String id){ return getCreateInfo(id); } diff --git a/core/src/io/anuke/mindustry/net/NetEvents.java b/core/src/io/anuke/mindustry/net/NetEvents.java index 7c63462956..359d521650 100644 --- a/core/src/io/anuke/mindustry/net/NetEvents.java +++ b/core/src/io/anuke/mindustry/net/NetEvents.java @@ -78,9 +78,13 @@ public class NetEvents { public static void handleSendMessage(String message){ ChatPacket packet = new ChatPacket(); packet.text = message; - packet.name = Vars.player.name; - packet.id = Vars.player.id; + packet.name = player.name; + packet.id = player.id; Net.send(packet, SendMode.tcp); + + if(Net.server() && !headless){ + ui.chatfrag.addMessage(message, netCommon.colorizeName(player.id, player.name)); + } } public static void handleShoot(SyncEntity entity, float x, float y, float angle, short data){ diff --git a/core/src/io/anuke/mindustry/net/TraceInfo.java b/core/src/io/anuke/mindustry/net/TraceInfo.java index e0dab07ada..996363e1a7 100644 --- a/core/src/io/anuke/mindustry/net/TraceInfo.java +++ b/core/src/io/anuke/mindustry/net/TraceInfo.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.net; +import com.badlogic.gdx.utils.IntIntMap; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.content.blocks.Blocks; @@ -9,7 +10,7 @@ public class TraceInfo { public boolean modclient; public boolean android; - public int fastShots; + public IntIntMap fastShots = new IntIntMap(); public int totalBlocksBroken; public int structureBlocksBroken; diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java index 244dc944ea..2711c74b73 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.ui.dialogs; +import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.graphics.Color; import io.anuke.ucore.function.Consumer; import io.anuke.ucore.scene.ui.Dialog; @@ -35,6 +36,12 @@ public class ColorPickDialog extends Dialog{ table.row(); } } + + keyDown(key->{ + if(key == Keys.ESCAPE || key == Keys.BACK) + hide(); + }); + } public void show(Consumer cons){ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java b/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java index de20ce240e..097c9e484d 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java @@ -160,7 +160,7 @@ public class FileChooser extends FloatingDialog { Arrays.sort(handles, (a, b) ->{ if(a.isDirectory() && !b.isDirectory()) return -1; if( !a.isDirectory() && b.isDirectory()) return 1; - return a.name().compareTo(b.name()); + return a.name().toUpperCase().compareTo(b.name().toUpperCase()); }); return handles; } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java index 657a8858e8..d1263f9089 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java @@ -3,8 +3,6 @@ package io.anuke.mindustry.ui.dialogs; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.graphics.Colors; import com.badlogic.gdx.utils.Align; - -import io.anuke.ucore.core.Inputs; import io.anuke.ucore.scene.ui.Dialog; public class FloatingDialog extends Dialog{ @@ -26,11 +24,5 @@ public class FloatingDialog extends Dialog{ if(key == Keys.ESCAPE || key == Keys.BACK) hide(); }); - - update(() -> { - if(Inputs.keyTap("menu")){ - hide(); - } - }); } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java index 51ee677775..0bf06a6dbf 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java @@ -40,10 +40,12 @@ public class HostDialog extends FloatingDialog{ }); }).size(50f, 54f).get(); button.update(() -> button.getStyle().imageUpColor = player.getColor()); - }).width(w).height(70f).pad(4); + }).width(w).height(70f).pad(4).colspan(3); content().row(); + content().add().width(65f); + content().addButton("$text.host", () -> { ui.loadfrag.show("$text.hosting"); Timers.runTask(5f, () -> { @@ -57,5 +59,7 @@ public class HostDialog extends FloatingDialog{ hide(); }); }).width(w).height(70f); + + content().addButton("?", () -> ui.showInfo("$text.host.info")).size(65f, 70f).padLeft(6f); } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java index c86285f8cf..270d911f26 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java @@ -38,8 +38,14 @@ public class JoinDialog extends FloatingDialog { loadServers(); + buttons().add().width(60f); + buttons().add().growX(); + addCloseButton(); + buttons().add().growX(); + buttons().addButton("?", () -> ui.showInfo("$text.join.info")).size(60f, 64f); + add = new FloatingDialog("$text.joingame.title"); add.content().add("$text.joingame.ip").padRight(5f).left(); diff --git a/core/src/io/anuke/mindustry/ui/fragments/BackgroundFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BackgroundFragment.java index a786df7686..e920593899 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BackgroundFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BackgroundFragment.java @@ -18,7 +18,7 @@ public class BackgroundFragment implements Fragment { Draw.color(); TextureRegion back = Draw.region("background"); - float backscl = Math.max(Gdx.graphics.getWidth() / (float)back.getRegionWidth() * 1.5f, Unit.dp.scl(5f)); + float backscl = (int)Math.max(Gdx.graphics.getWidth() / (float)back.getRegionWidth() * 1.5f, Unit.dp.scl(5f)); Draw.alpha(0.5f); Core.batch.draw(back, w/2 - back.getRegionWidth()*backscl/2, h/2 - back.getRegionHeight()*backscl/2, @@ -31,7 +31,7 @@ public class BackgroundFragment implements Fragment { float logoh = logo.getRegionHeight()*logoscl; Draw.color(); - Core.batch.draw(logo, w/2 - logow/2, h - logoh + 15 - Unit.dp.scl(portrait ? 30f : 0), logow, logoh); + Core.batch.draw(logo, (int)(w/2 - logow/2), (int)(h - logoh + 15 - Unit.dp.scl(portrait ? 30f : 0)), logow, logoh); }).visible(() -> state.is(State.menu)).grow(); } } diff --git a/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java b/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java index 2f7f5d71c4..f4acb97e59 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java @@ -19,8 +19,7 @@ import io.anuke.ucore.scene.ui.Label.LabelStyle; import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.scene.ui.layout.Unit; -import io.anuke.ucore.util.Log; -import java.util.Arrays; +import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.state; import static io.anuke.ucore.core.Core.scene; @@ -30,7 +29,7 @@ public class ChatFragment extends Table implements Fragment{ private final static int messagesShown = 10; private final static int maxLength = 150; private Array messages = new Array<>(); - private float fadetime, lastfade; + private float fadetime; private boolean chatOpen = false; private TextField chatfield; private Label fieldlabel = new Label(">"); @@ -42,6 +41,7 @@ public class ChatFragment extends Table implements Fragment{ private float textspacing = Unit.dp.scl(10); private Array history = new Array(); private int historyPos = 0; + private int scrollPos = 0; public ChatFragment(){ super(); @@ -62,15 +62,16 @@ public class ChatFragment extends Table implements Fragment{ } if (chatOpen) { - if (Inputs.keyTap("chat_scroll_up") && historyPos < history.size - 1) { + if (Inputs.keyTap("chat_history_prev") && historyPos < history.size - 1) { if (historyPos == 0) history.set(0, chatfield.getText()); historyPos++; updateChat(); } - if (Inputs.keyTap("chat_scroll_down") && historyPos > 0) { + if (Inputs.keyTap("chat_history_next") && historyPos > 0) { historyPos--; updateChat(); } + scrollPos = (int)Mathf.clamp(scrollPos + Inputs.getAxis("chat_scroll"), 0, Math.max(0, messages.size - messagesShown)); } }); @@ -134,16 +135,16 @@ public class ChatFragment extends Table implements Fragment{ batch.setColor(shadowColor); float theight = offsety + spacing + getMarginBottom(); - for(int i = 0; i < messagesShown && i < messages.size && i < fadetime; i ++){ + for(int i = scrollPos; i < messages.size && i < messagesShown + scrollPos && (i < fadetime || chatOpen); i++){ layout.setText(font, messages.get(i).formattedMessage, Color.WHITE, textWidth, Align.bottomLeft, true); theight += layout.height+textspacing; - if(i == 0) theight -= textspacing+1; + if(i - scrollPos == 0) theight -= textspacing+1; font.getCache().clear(); font.getCache().addText(messages.get(i).formattedMessage, fontoffsetx + offsetx, offsety + theight, textWidth, Align.bottomLeft, true); - if(fadetime-i < 1f && fadetime-i >= 0f){ + if(!chatOpen && fadetime-i < 1f && fadetime-i >= 0f){ font.getCache().setAlphas(fadetime-i); batch.setColor(0, 0, 0, shadowColor.a*(fadetime-i)); } @@ -163,10 +164,10 @@ public class ChatFragment extends Table implements Fragment{ private void sendMessage(){ String message = chatfield.getText(); clearChatInput(); - history.insert(1, message); if(message.replaceAll(" ", "").isEmpty()) return; + history.insert(1, message); NetEvents.handleSendMessage(message); } @@ -176,12 +177,10 @@ public class ChatFragment extends Table implements Fragment{ scene.setKeyboardFocus(chatfield); chatfield.fireClick(); chatOpen = !chatOpen; - lastfade = fadetime; - fadetime = messagesShown + 1; }else{ scene.setKeyboardFocus(null); chatOpen = !chatOpen; - fadetime = lastfade; + scrollPos = 0; sendMessage(); } } diff --git a/core/src/io/anuke/mindustry/world/Placement.java b/core/src/io/anuke/mindustry/world/Placement.java index d63f937b9f..7db7438ba4 100644 --- a/core/src/io/anuke/mindustry/world/Placement.java +++ b/core/src/io/anuke/mindustry/world/Placement.java @@ -102,19 +102,24 @@ public class Placement { if(type.solid || type.solidifes) synchronized (Entities.entityLock) { - rect.setSize(tilesize*2f).setCenter(x*tilesize + type.getPlaceOffset().x, y*tilesize + type.getPlaceOffset().y); - boolean[] result = {false}; + try { - Units.getNearby(rect, e -> { - if (e == null) return; //not sure why this happens? - Rectangle rect = e.hitbox.getRect(e.x, e.y); + rect.setSize(tilesize * 2f).setCenter(x * tilesize + type.getPlaceOffset().x, y * tilesize + type.getPlaceOffset().y); + boolean[] result = {false}; - if (Placement.rect.overlaps(rect) && !e.isFlying()) { - result[0] = true; - } - }); + Units.getNearby(rect, e -> { + if (e == null) return; //not sure why this happens? + Rectangle rect = e.hitbox.getRect(e.x, e.y); - if(result[0]) return false; + if (Placement.rect.overlaps(rect) && !e.isFlying()) { + result[0] = true; + } + }); + + if (result[0]) return false; + }catch (Exception e){ + return false; + } } Tile tile = world.tile(x, y); diff --git a/core/src/io/anuke/mindustry/world/blocks/types/distribution/TunnelConveyor.java b/core/src/io/anuke/mindustry/world/blocks/types/distribution/TunnelConveyor.java index ce0351d6d8..e75fcaa616 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/distribution/TunnelConveyor.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/distribution/TunnelConveyor.java @@ -1,12 +1,11 @@ package io.anuke.mindustry.world.blocks.types.distribution; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.NumberUtils; import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.resource.Item; -import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.BlockGroup; -import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.*; import io.anuke.ucore.core.Timers; import io.anuke.ucore.util.Bits; @@ -22,6 +21,7 @@ public class TunnelConveyor extends Block{ solid = true; health = 70; instantTransfer = true; + bars.add(new BlockBar(BarType.inventory, true, tile -> (float)tile.entity().index/capacity)); group = BlockGroup.transportation; } @@ -31,11 +31,6 @@ public class TunnelConveyor extends Block{ if(entity.index >= entity.buffer.length) return; - Tile tunnel = getDestTunnel(tile, item); - if(tunnel == null) return; - Tile to = tunnel.getNearby(tunnel.getRotation()); - if(to == null) return; - entity.buffer[entity.index ++] = Bits.packLong(NumberUtils.floatToIntBits(Timers.time()), item.id); } @@ -68,19 +63,9 @@ public class TunnelConveyor extends Block{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ TunnelEntity entity = tile.entity(); - - if(entity.index >= entity.buffer.length - 1) return false; - int rot = source.relativeTo(tile.x, tile.y); if(rot != (tile.getRotation() + 2)%4) return false; - Tile tunnel = getDestTunnel(tile, item); - - if(tunnel != null){ - Tile to = tunnel.getNearby(tunnel.getRotation()); - return to != null && to.block().acceptItem(item, to, tunnel); - }else{ - return false; - } + return entity.index < entity.buffer.length - 1; } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/types/production/WeaponFactory.java b/core/src/io/anuke/mindustry/world/blocks/types/production/WeaponFactory.java index fae1dbe0b3..29b6d3e6e9 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/production/WeaponFactory.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/production/WeaponFactory.java @@ -108,14 +108,15 @@ public class WeaponFactory extends Block{ tip.setInstant(true); ImageButton button = content.addImageButton("white", 8*4, () -> { - state.inventory.removeItems(requirements); - control.upgrades().addWeapon(weapon); - ui.hudfrag.updateWeapons(); - run.listen(); - Effects.sound("purchase"); if(Net.client()){ NetEvents.handleUpgrade(weapon); + }else{ + state.inventory.removeItems(requirements); + control.upgrades().addWeapon(weapon); + ui.hudfrag.updateWeapons(); + run.listen(); + Effects.sound("purchase"); } }).size(49f, 54f).padBottom(-5).get(); diff --git a/kryonet/src/io/anuke/kryonet/KryoServer.java b/kryonet/src/io/anuke/kryonet/KryoServer.java index c7aa93921b..46a2ebe6f0 100644 --- a/kryonet/src/io/anuke/kryonet/KryoServer.java +++ b/kryonet/src/io/anuke/kryonet/KryoServer.java @@ -423,7 +423,13 @@ public class KryoServer implements ServerProvider { byte[] out = Base64Coder.decode(message); ByteBuffer buffer = ByteBuffer.wrap(out); Object o = serializer.read(buffer); - Gdx.app.postRunnable(() -> Net.handleServerReceived(id, o)); + Gdx.app.postRunnable(() -> { + try { + Net.handleServerReceived(id, o); + }catch (Exception e){ + e.printStackTrace(); + } + }); } }catch (Exception e){ Log.err(e); diff --git a/server/src/io/anuke/mindustry/server/ServerControl.java b/server/src/io/anuke/mindustry/server/ServerControl.java index bf97973641..f1743f2fd3 100644 --- a/server/src/io/anuke/mindustry/server/ServerControl.java +++ b/server/src/io/anuke/mindustry/server/ServerControl.java @@ -146,9 +146,10 @@ public class ServerControl extends Module { } }else{ result = world.maps().all().random(); + Log.info("&ly&fiNo map specified, so &lb{0}&ly was chosen randomly.", result.name); } - GameMode mode = null; + GameMode mode; try{ mode = arg.length < 2 ? GameMode.waves : GameMode.valueOf(arg[1]); }catch (IllegalArgumentException e){ @@ -438,7 +439,7 @@ public class ServerControl extends Module { }else{ Log.info("&lyAdmins:"); for(PlayerInfo info : admins){ - Log.info(" &luy {0} / ID: '{1}' / IP: '{2}'", info.lastName, info.id, info.lastIP); + Log.info(" &lm {0} / ID: '{1}' / IP: '{2}'", info.lastName, info.id, info.lastIP); } } }); @@ -534,6 +535,33 @@ public class ServerControl extends Module { } }); + handler.register("find", " [check-all-names]", "Find player info(s) by name. Can optionally check for all names a player has had.", arg -> { + boolean checkAll = arg.length == 2 && arg[1].equals("true"); + + Array infos = netServer.admins.findByName(arg[0], checkAll); + + if(infos.size == 1) { + PlayerInfo info = infos.peek(); + Log.info("&lcTrace info for player '{0}' / UUID {1}:", info.lastName, info.id); + Log.info(" &lyall names used: {0}", info.names); + Log.info(" &lyIP: {0}", info.lastIP); + Log.info(" &lyall IPs used: {0}", info.ips); + Log.info(" &lytimes joined: {0}", info.timesJoined); + Log.info(" &lytimes kicked: {0}", info.timesKicked); + Log.info(""); + Log.info(" &lytotal blocks broken: {0}", info.totalBlocksBroken); + Log.info(" &lytotal blocks placed: {0}", info.totalBlockPlaced); + }else if(infos.size > 1){ + Log.info("&lcMultiple people have been found with that name:"); + for(PlayerInfo info : infos){ + Log.info(" &ly{0}", info.id); + } + Log.info("&lcUse the info command to examine each person individually."); + }else{ + info("Nobody with that name could be found."); + } + }); + handler.register("info", "", "Get global info for a player's UUID.", arg -> { PlayerInfo info = netServer.admins.getInfoOptional(arg[0]); @@ -543,6 +571,7 @@ public class ServerControl extends Module { Log.info(" &lyIP: {0}", info.lastIP); Log.info(" &lyall IPs used: {0}", info.ips); Log.info(" &lytimes joined: {0}", info.timesJoined); + Log.info(" &lytimes kicked: {0}", info.timesKicked); Log.info(""); Log.info(" &lytotal blocks broken: {0}", info.totalBlocksBroken); Log.info(" &lytotal blocks placed: {0}", info.totalBlockPlaced);