Compare commits

..

27 Commits
v88 ... v89

Author SHA1 Message Date
Anuken
66ff7b1592 Fixed minimization 2019-08-20 20:47:28 -04:00
Anuken
be32810608 on second thought, no 2019-08-20 19:57:42 -04:00
Anuken
88f48599a0 Names updated 2019-08-20 19:52:08 -04:00
Anuken
014e2ac8b8 Bugfixes 2019-08-20 19:42:39 -04:00
Anuken
bae88ec416 iPhone X splash images 2019-08-20 19:14:30 -04:00
Anuken
46230ad307 nothing 2019-08-20 18:31:56 -04:00
Anuken
963a207194 New power node link system 2019-08-20 10:52:06 -04:00
Anuken
59419e13d9 Networking fixes 2019-08-20 10:23:22 -04:00
Anuken
b370e04035 UI fix 2019-08-19 22:21:22 -04:00
Anuken
dfd6e7a07b Merge remote-tracking branch 'origin/master' 2019-08-19 22:16:51 -04:00
Anuken
a873560d4e Multiplayer: Smooth building + rotation / Disabled UDP / Cleanup 2019-08-19 22:16:43 -04:00
Anuken
c6777bd219 Update bundle.properties 2019-08-19 18:03:21 -04:00
Anuken
8eb4d25638 Fixed error on exiting with custom map on server 2019-08-19 09:42:45 -04:00
Anuken
191c6e9016 crash fix 2019-08-19 09:23:16 -04:00
Anuken
52af0b1db9 Merge remote-tracking branch 'origin/master' 2019-08-18 22:52:50 -04:00
Anuken
492cb49805 bugfixes 2019-08-18 22:52:46 -04:00
Anuken
b2e70a44be Update TRANSLATING.md 2019-08-18 12:31:54 -04:00
Anuken
452a8aaa0c Fixed dialog scrolling 2019-08-18 10:16:31 -04:00
Anuken
c3f392a01c Merge remote-tracking branch 'origin/master' 2019-08-17 20:26:30 -04:00
Anuken
7d9b6a41fc Actual prediction fix 2019-08-17 20:26:17 -04:00
Samuele Esposito
f4f4cf3947 Possibly a small typo? (#592) 2019-08-17 17:00:20 -04:00
Anuken
28e930eb4b Merge remote-tracking branch 'origin/master' 2019-08-17 15:39:45 -04:00
Anuken
301387fb32 Fixed low rank on attack map completion 2019-08-17 15:39:41 -04:00
Anuken
5955387bdd map tweaks 2019-08-17 14:08:13 -04:00
Anuken
150491ff2c bugfixes 2019-08-17 12:09:18 -04:00
Anuken
ddef78c7d8 Merge remote-tracking branch 'origin/master' 2019-08-16 14:50:04 -04:00
Anuken
dc435d88f4 Fixed massive music files on iOS, now using MP3 2019-08-16 14:49:35 -04:00
48 changed files with 319 additions and 363 deletions

View File

@@ -1,8 +1,5 @@
## Translating for Mindustry ## Translating for Mindustry
**DISCLAIMER:** *Currently, 4.0 is far from done, which means that things such as block names, descriptions, and core text will be changing often. If you begin translating now, you might have to re-do large chunks of the bundle before final release.*
To begin, log in to your GitHub account, or if you don't have one yet, create it [here](https://github.com/). To begin, log in to your GitHub account, or if you don't have one yet, create it [here](https://github.com/).
Consult [this list](https://www.science.co.il/language/Locale-codes.php) to find the locale code for your language. Once you've found it, Consult [this list](https://www.science.co.il/language/Locale-codes.php) to find the locale code for your language. Once you've found it,

View File

@@ -80,7 +80,7 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{
} }
load.addStatement(name + " = io.anuke.arc.Core.audio."+loadMethod+"(io.anuke.arc.Core.files.internal(io.anuke.arc.Core.app.getType() != io.anuke.arc.Application.ApplicationType.iOS ? $S : $S))", load.addStatement(name + " = io.anuke.arc.Core.audio."+loadMethod+"(io.anuke.arc.Core.files.internal(io.anuke.arc.Core.app.getType() != io.anuke.arc.Application.ApplicationType.iOS ? $S : $S))",
path.substring(path.lastIndexOf("/") + 1) + "/" + fname, (path.substring(path.lastIndexOf("/") + 1) + "/" + fname).replace(".ogg", ".caf")); path.substring(path.lastIndexOf("/") + 1) + "/" + fname, (path.substring(path.lastIndexOf("/") + 1) + "/" + fname).replace(".ogg", ".mp3"));
dispose.addStatement(name + ".dispose()"); dispose.addStatement(name + ".dispose()");
dispose.addStatement(name + " = null"); dispose.addStatement(name + " = null");
type.addField(FieldSpec.builder(ClassName.bestGuess(rtype), name, Modifier.STATIC, Modifier.PUBLIC).initializer("new io.anuke.arc.audio.mock.Mock" + rtype.substring(rtype.lastIndexOf(".") + 1)+ "()").build()); type.addField(FieldSpec.builder(ClassName.bestGuess(rtype), name, Modifier.STATIC, Modifier.PUBLIC).initializer("new io.anuke.arc.audio.mock.Mock" + rtype.substring(rtype.lastIndexOf(".") + 1)+ "()").build());

View File

@@ -312,6 +312,5 @@ project(":net"){
dependencies{ dependencies{
compile project(":core") compile project(":core")
compile "org.lz4:lz4-java:1.4.1" compile "org.lz4:lz4-java:1.4.1"
compile 'com.github.Anuken:WaifUPnP:05eb46bc577fd7674596946ba288c96c0cedd893'
} }
} }

View File

@@ -75,6 +75,7 @@ server.kicked.nameEmpty = Your chosen name is invalid.
server.kicked.idInUse = You are already on this server! Connecting with two accounts is not permitted. server.kicked.idInUse = You are already on this server! Connecting with two accounts is not permitted.
server.kicked.customClient = This server does not support custom builds. Download an official version. server.kicked.customClient = This server does not support custom builds. Download an official version.
server.kicked.gameover = Game over! server.kicked.gameover = Game over!
server.versions = Your version:[accent] {0}[]\nServer version:[accent] {1}[]
host.info = The [accent]host[] button hosts a server on port [scarlet]6567[]. \nAnybody on the same [lightgray]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[lightgray]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. Note that public networks sometimes do not allow server discovery. host.info = The [accent]host[] button hosts a server on port [scarlet]6567[]. \nAnybody on the same [lightgray]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[lightgray]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. Note that public networks sometimes do not allow server discovery.
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[lightgray]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. 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[lightgray]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.
hostserver = Host Multiplayer Game hostserver = Host Multiplayer Game
@@ -124,7 +125,7 @@ save.new = New Save
save.overwrite = Are you sure you want to overwrite\nthis save slot? save.overwrite = Are you sure you want to overwrite\nthis save slot?
overwrite = Overwrite overwrite = Overwrite
save.none = No saves found! save.none = No saves found!
saveload = [accent]Saving... saveload = Saving...
savefail = Failed to save game! savefail = Failed to save game!
save.delete.confirm = Are you sure you want to delete this save? save.delete.confirm = Are you sure you want to delete this save?
save.delete = Delete save.delete = Delete
@@ -371,7 +372,7 @@ zone.crags.name = Crags
zone.fungalPass.name = Fungal Pass zone.fungalPass.name = Fungal Pass
zone.groundZero.description = The optimal location to begin once more. Low enemy threat. Few resources.\nGather as much lead and copper as possible.\nMove on. zone.groundZero.description = The optimal location to begin once more. Low enemy threat. Few resources.\nGather as much lead and copper as possible.\nMove on.
zone.frozenForest.description = Even here, closer to mountains, the spores have spread. The fridgid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders. zone.frozenForest.description = Even here, closer to mountains, the spores have spread. The frigid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders.
zone.desertWastes.description = These wastes are vast, unpredictable, and criss-crossed with derelict sector structures.\nCoal is present in the region. Burn it for power, or synthesize graphite.\n\n[lightgray]This landing location cannot be guaranteed. zone.desertWastes.description = These wastes are vast, unpredictable, and criss-crossed with derelict sector structures.\nCoal is present in the region. Burn it for power, or synthesize graphite.\n\n[lightgray]This landing location cannot be guaranteed.
zone.saltFlats.description = On the outskirts of the desert lie the Salt Flats. Few resources can be found in this location.\n\nThe enemy has erected a resource storage complex here. Eradicate their core. Leave nothing standing. zone.saltFlats.description = On the outskirts of the desert lie the Salt Flats. Few resources can be found in this location.\n\nThe enemy has erected a resource storage complex here. Eradicate their core. Leave nothing standing.
zone.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills. zone.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -188,7 +188,8 @@
up: button, up: button,
over: button-over, over: button-over,
imageDisabledColor: gray, imageDisabledColor: gray,
imageUpColor: white imageUpColor: white,
disabled: button-disabled
}, },
node: { node: {
up: button-over, up: button-over,

View File

@@ -119,7 +119,7 @@ public class BlockIndexer{
ObjectSet<Tile> set = damagedTiles[team.ordinal()]; ObjectSet<Tile> set = damagedTiles[team.ordinal()];
for(Tile tile : set){ for(Tile tile : set){
if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) && !(tile.block() instanceof BuildBlock)){ if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){
returnArray.add(tile); returnArray.add(tile);
} }
} }

View File

@@ -84,7 +84,7 @@ public class Control implements ApplicationListener{
}); });
Events.on(PlayEvent.class, event -> { Events.on(PlayEvent.class, event -> {
player.setTeam(defaultTeam); player.setTeam(state.rules.pvp ? netServer.assignTeam(player, playerGroup.all()) : defaultTeam);
player.setDead(true); player.setDead(true);
player.add(); player.add();
@@ -237,7 +237,7 @@ public class Control implements ApplicationListener{
public void playMap(Map map, Rules rules){ public void playMap(Map map, Rules rules){
ui.loadAnd(() -> { ui.loadAnd(() -> {
logic.reset(); logic.reset();
world.loadMap(map); world.loadMap(map, rules);
state.rules = rules; state.rules = rules;
logic.play(); logic.play();
}); });
@@ -350,35 +350,37 @@ public class Control implements ApplicationListener{
//display UI scale changed dialog //display UI scale changed dialog
if(Core.settings.getBool("uiscalechanged", false)){ if(Core.settings.getBool("uiscalechanged", false)){
FloatingDialog dialog = new FloatingDialog("$confirm"); Core.app.post(() -> Core.app.post(() -> {
FloatingDialog dialog = new FloatingDialog("$confirm");
dialog.setFillParent(true);
float[] countdown = {60 * 11}; float[] countdown = {60 * 11};
Runnable exit = () -> { Runnable exit = () -> {
Core.settings.put("uiscale", 100); Core.settings.put("uiscale", 100);
Core.settings.put("uiscalechanged", false); Core.settings.put("uiscalechanged", false);
settings.save(); settings.save();
dialog.hide(); dialog.hide();
Core.app.exit(); Core.app.exit();
}; };
dialog.setFillParent(false); dialog.cont.label(() -> {
dialog.cont.label(() -> { if(countdown[0] <= 0){
if(countdown[0] <= 0){ exit.run();
exit.run(); }
} return Core.bundle.format("uiscale.reset", (int)((countdown[0] -= Time.delta()) / 60f));
return Core.bundle.format("uiscale.reset", (int)((countdown[0] -= Time.delta()) / 60f)); }).pad(10f).expand().center();
}).pad(10f).expand().left();
dialog.buttons.defaults().size(200f, 60f); dialog.buttons.defaults().size(200f, 60f);
dialog.buttons.addButton("$uiscale.cancel", exit); dialog.buttons.addButton("$uiscale.cancel", exit);
dialog.buttons.addButton("$ok", () -> { dialog.buttons.addButton("$ok", () -> {
Core.settings.put("uiscalechanged", false); Core.settings.put("uiscalechanged", false);
settings.save(); settings.save();
dialog.hide(); dialog.hide();
}); });
Core.app.post(dialog::show); dialog.show();
}));
} }
} }

View File

@@ -40,7 +40,7 @@ import static io.anuke.mindustry.Vars.*;
public class NetServer implements ApplicationListener{ public class NetServer implements ApplicationListener{
public final static int maxSnapshotSize = 430; public final static int maxSnapshotSize = 430;
private final static float serverSyncTime = 15, kickDuration = 30 * 1000; private final static float serverSyncTime = 12, kickDuration = 30 * 1000;
private final static Vector2 vector = new Vector2(); private final static Vector2 vector = new Vector2();
private final static Rectangle viewport = new Rectangle(); private final static Rectangle viewport = new Rectangle();
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */ /** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
@@ -176,7 +176,7 @@ public class NetServer implements ApplicationListener{
//playing in pvp mode automatically assigns players to teams //playing in pvp mode automatically assigns players to teams
if(state.rules.pvp){ if(state.rules.pvp){
player.setTeam(assignTeam(playerGroup.all())); player.setTeam(assignTeam(player, playerGroup.all()));
Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam()); Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam());
} }
@@ -194,13 +194,13 @@ public class NetServer implements ApplicationListener{
}); });
} }
public Team assignTeam(Iterable<Player> players){ public Team assignTeam(Player current, Iterable<Player> players){
//find team with minimum amount of players and auto-assign player to that. //find team with minimum amount of players and auto-assign player to that.
return Structs.findMin(Team.all, team -> { return Structs.findMin(Team.all, team -> {
if(state.teams.isActive(team) && !state.teams.get(team).cores.isEmpty()){ if(state.teams.isActive(team) && !state.teams.get(team).cores.isEmpty()){
int count = 0; int count = 0;
for(Player other : players){ for(Player other : players){
if(other.getTeam() == team){ if(other.getTeam() == team && other != current){
count++; count++;
} }
} }

View File

@@ -220,6 +220,10 @@ public class World implements ApplicationListener{
} }
public void loadMap(Map map){ public void loadMap(Map map){
loadMap(map, new Rules());
}
public void loadMap(Map map, Rules checkRules){
try{ try{
SaveIO.load(map.file, new FilterContext(map)); SaveIO.load(map.file, new FilterContext(map));
}catch(Exception e){ }catch(Exception e){
@@ -238,20 +242,21 @@ public class World implements ApplicationListener{
invalidMap = false; invalidMap = false;
if(!headless){ if(!headless){
if(state.teams.get(defaultTeam).cores.size == 0){ if(state.teams.get(defaultTeam).cores.size == 0 && !checkRules.pvp){
ui.showError("$map.nospawn"); ui.showError("$map.nospawn");
invalidMap = true; invalidMap = true;
}else if(state.rules.pvp){ //pvp maps need two cores to be valid }else if(checkRules.pvp){ //pvp maps need two cores to be valid
invalidMap = true; int teams = 0;
for(Team team : Team.all){ for(Team team : Team.all){
if(state.teams.get(team).cores.size != 0 && team != defaultTeam){ if(state.teams.get(team).cores.size != 0){
invalidMap = false; teams ++;
} }
} }
if(invalidMap){ if(teams < 2){
invalidMap = true;
ui.showError("$map.nospawn.pvp"); ui.showError("$map.nospawn.pvp");
} }
}else if(state.rules.attackMode){ //pvp maps need two cores to be valid }else if(checkRules.attackMode){ //attack maps need two cores to be valid
invalidMap = state.teams.get(waveTeam).cores.isEmpty(); invalidMap = state.teams.get(waveTeam).cores.isEmpty();
if(invalidMap){ if(invalidMap){
ui.showError("$map.nospawn.attack"); ui.showError("$map.nospawn.attack");

View File

@@ -55,7 +55,7 @@ public class Predict{
* See {@link #intercept(float, float, float, float, float, float, float)}. * See {@link #intercept(float, float, float, float, float, float, float)}.
*/ */
public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v){ public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v){
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getTargetVelocityX() - src.getTargetVelocityX(), dst.getTargetVelocityY() - src.getTargetVelocityY(), v); return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getTargetVelocityX() - src.getTargetVelocityX()/2f, dst.getTargetVelocityY() - src.getTargetVelocityY()/2f, v);
} }
private static Vector2 quad(float a, float b, float c){ private static Vector2 quad(float a, float b, float c){

View File

@@ -1,33 +1,28 @@
package io.anuke.mindustry.entities.traits; package io.anuke.mindustry.entities.traits;
import io.anuke.annotations.Annotations.*; import io.anuke.annotations.Annotations.*;
import io.anuke.arc.Core; import io.anuke.arc.*;
import io.anuke.arc.Events;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.Queue; import io.anuke.arc.collection.Queue;
import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.Angles; import io.anuke.arc.math.*;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.geom.*;
import io.anuke.arc.math.geom.Vector2; import io.anuke.arc.util.*;
import io.anuke.arc.util.Time; import io.anuke.mindustry.*;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.content.*;
import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.entities.type.TileEntity; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.entities.type.Unit; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.game.EventType.BuildSelectEvent; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Pal;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.BuildBlock; import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity; import io.anuke.mindustry.world.blocks.BuildBlock.*;
import java.io.*; import java.io.*;
import java.util.Arrays; import java.util.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.entities.traits.BuilderTrait.BuildDataStatic.removal; import static io.anuke.mindustry.entities.traits.BuilderTrait.BuildDataStatic.*;
import static io.anuke.mindustry.entities.traits.BuilderTrait.BuildDataStatic.tmptr;
/** Interface for units that build things.*/ /** Interface for units that build things.*/
public interface BuilderTrait extends Entity, TeamTrait{ public interface BuilderTrait extends Entity, TeamTrait{
@@ -106,19 +101,14 @@ public interface BuilderTrait extends Entity, TeamTrait{
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f); unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f);
} }
//progress is synced, thus not updated clientside //deconstructing is 2x as fast
if(!Net.client()){ if(current.breaking){
//deconstructing is 2x as fast entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
if(current.breaking){
entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}else{
entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}
current.progress = entity.progress();
}else{ }else{
entity.progress = current.progress; entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
} }
current.progress = entity.progress;
} }
/** Returns the queue for storing build requests. */ /** Returns the queue for storing build requests. */
@@ -135,7 +125,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
default void writeBuilding(DataOutput output) throws IOException{ default void writeBuilding(DataOutput output) throws IOException{
BuildRequest request = buildRequest(); BuildRequest request = buildRequest();
if(request != null){ if(request != null && (request.block != null || request.breaking)){
output.writeByte(request.breaking ? 1 : 0); output.writeByte(request.breaking ? 1 : 0);
output.writeInt(Pos.get(request.x, request.y)); output.writeInt(Pos.get(request.x, request.y));
output.writeFloat(request.progress); output.writeFloat(request.progress);
@@ -174,7 +164,11 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(applyChanges){ if(applyChanges){
buildQueue().addLast(request); buildQueue().addLast(request);
}else if(isBuilding()){ }else if(isBuilding()){
buildRequest().progress = progress; BuildRequest last = buildRequest();
last.progress = progress;
if(last.tile() != null && last.tile().entity instanceof BuildEntity){
((BuildEntity)last.tile().entity).progress = progress;
}
} }
} }
} }
@@ -285,6 +279,10 @@ public interface BuilderTrait extends Entity, TeamTrait{
this.breaking = true; this.breaking = true;
} }
public Tile tile(){
return world.tile(x, y);
}
@Override @Override
public String toString(){ public String toString(){
return "BuildRequest{" + return "BuildRequest{" +

View File

@@ -70,7 +70,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
private Tile mining; private Tile mining;
private Vector2 movement = new Vector2(); private Vector2 movement = new Vector2();
private boolean moved; private boolean moved;
private SoundLoop buildSound = new SoundLoop(Sounds.build, 0.75f);
//endregion //endregion
@@ -131,11 +130,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
} }
} }
@Override
public void removed(){
buildSound.stop();
}
@Override @Override
public float drag(){ public float drag(){
return mech.drag; return mech.drag;
@@ -518,7 +512,9 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
} }
BuildRequest request = buildRequest(); BuildRequest request = buildRequest();
buildSound.update(request == null ? x : request.x * tilesize, request == null ? y : request.y * tilesize, isBuilding() && (Mathf.within(request.x * tilesize, request.y * tilesize, x, y, placeDistance) || state.isEditor())); if(isBuilding() && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){
loops.play(Sounds.build, request.tile(), 0.75f);
}
if(isDead()){ if(isDead()){
isBoosting = false; isBoosting = false;
@@ -531,7 +527,9 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
spawner = null; spawner = null;
} }
avoidOthers(); if(isLocal || Net.server()){
avoidOthers();
}
Tile tile = world.tileWorld(x, y); Tile tile = world.tileWorld(x, y);

View File

@@ -5,6 +5,7 @@ import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.entities.units.UnitState; import io.anuke.mindustry.entities.units.UnitState;
import io.anuke.mindustry.world.Pos; import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.*;
import java.io.*; import java.io.*;
@@ -23,6 +24,10 @@ public class RepairDrone extends BaseDrone{
target = Units.findDamagedTile(team, x, y); target = Units.findDamagedTile(team, x, y);
} }
if(target instanceof TileEntity && ((TileEntity)target).block instanceof BuildBlock){
target = null;
}
if(target != null){ if(target != null){
if(target.dst(RepairDrone.this) > type.range){ if(target.dst(RepairDrone.this) > type.range){
circle(type.range * 0.9f); circle(type.range * 0.9f);

View File

@@ -26,8 +26,10 @@ public class Stats{
public RankResult calculateRank(Zone zone, boolean launched){ public RankResult calculateRank(Zone zone, boolean launched){
float score = 0; float score = 0;
//each new launch period adds onto the rank 'points' if(launched && zone.getRules().attackMode){
if(wavesLasted >= zone.conditionWave){ score += 3f;
}else if(wavesLasted >= zone.conditionWave){
//each new launch period adds onto the rank 'points'
score += (float)((wavesLasted - zone.conditionWave) / zone.launchPeriod + 1) * 1.2f; score += (float)((wavesLasted - zone.conditionWave) / zone.launchPeriod + 1) * 1.2f;
} }

View File

@@ -131,7 +131,7 @@ public class DesktopInput extends InputHandler{
player.isShooting = false; player.isShooting = false;
} }
if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && !ui.chatfrag.chatOpen() && !(scene.getKeyboardFocus() instanceof TextField)){ if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && (scene.getKeyboardFocus() == ui.minimap || !scene.hasDialog()) && !ui.chatfrag.chatOpen() && !(scene.getKeyboardFocus() instanceof TextField)){
if(!ui.minimap.isShown()){ if(!ui.minimap.isShown()){
ui.minimap.show(); ui.minimap.show();
}else{ }else{

View File

@@ -214,7 +214,12 @@ public class Maps implements Disposable{
return filters; return filters;
}else{ }else{
return JsonIO.read(Array.class, str); try{
return JsonIO.read(Array.class, str);
}catch(Exception e){
e.printStackTrace();
return readFilters("");
}
} }
} }

View File

@@ -1,14 +1,15 @@
package io.anuke.mindustry.net; package io.anuke.mindustry.net;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.Vector2; import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.Time; import io.anuke.arc.util.*;
public class Interpolator{ public class Interpolator{
//used for movement //used for movement
public Vector2 target = new Vector2(); public Vector2 target = new Vector2();
public Vector2 last = new Vector2(); public Vector2 last = new Vector2();
public float[] targets = {}; public float[] targets = {};
public float[] lasts = {};
public long lastUpdated, updateSpacing; public long lastUpdated, updateSpacing;
//current state //current state
@@ -21,6 +22,12 @@ public class Interpolator{
lastUpdated = Time.millis(); lastUpdated = Time.millis();
targets = target1ds; targets = target1ds;
if(lasts.length != values.length){
lasts = new float[values.length];
}
for(int i = 0; i < values.length; i++){
lasts[i] = values[i];
}
last.set(cx, cy); last.set(cx, cy);
target.set(x, y); target.set(x, y);
} }
@@ -46,8 +53,12 @@ public class Interpolator{
values = new float[targets.length]; values = new float[targets.length];
} }
if(lasts.length != targets.length){
lasts = new float[targets.length];
}
for(int i = 0; i < values.length; i++){ for(int i = 0; i < values.length; i++){
values[i] = Mathf.slerp(values[i], targets[i], alpha); values[i] = Mathf.slerp(lasts[i], targets[i], alpha);
} }
}else{ }else{
pos.set(target); pos.set(target);

View File

@@ -162,8 +162,8 @@ public class Net{
/** /**
* Returns a list of all connections IDs. * Returns a list of all connections IDs.
*/ */
public static Array<NetConnection> getConnections(){ public static Iterable<NetConnection> getConnections(){
return (Array<NetConnection>)serverProvider.getConnections(); return (Iterable<NetConnection>)serverProvider.getConnections();
} }
/** /**
@@ -326,7 +326,7 @@ public class Net{
public static void dispose(){ public static void dispose(){
if(clientProvider != null) clientProvider.dispose(); if(clientProvider != null) clientProvider.dispose();
if(serverProvider != null) serverProvider.dispose(); if(serverProvider != null) serverProvider.close();
clientProvider = null; clientProvider = null;
serverProvider = null; serverProvider = null;
server = false; server = false;
@@ -377,16 +377,53 @@ public class Net{
void host(int port) throws IOException; void host(int port) throws IOException;
/** Sends a large stream of data to a specific client. */ /** Sends a large stream of data to a specific client. */
void sendStream(int id, Streamable stream); default void sendStream(int id, Streamable stream){
NetConnection connection = getByID(id);
if(connection == null) return;
try{
int cid;
StreamBegin begin = new StreamBegin();
begin.total = stream.stream.available();
begin.type = Registrator.getID(stream.getClass());
connection.send(begin, SendMode.tcp);
cid = begin.id;
/** Send an object to everyone connected. */ while(stream.stream.available() > 0){
void send(Object object, SendMode mode); byte[] bytes = new byte[Math.min(512, stream.stream.available())];
stream.stream.read(bytes);
/** Send an object to a specific client ID. */ StreamChunk chunk = new StreamChunk();
void sendTo(int id, Object object, SendMode mode); chunk.id = cid;
chunk.data = bytes;
connection.send(chunk, SendMode.tcp);
}
}catch(IOException e){
throw new RuntimeException(e);
}
}
/** Send an object to everyone <i>except</i> a client ID. */ default void send(Object object, SendMode mode){
void sendExcept(int id, Object object, SendMode mode); for(NetConnection con : getConnections()){
con.send(object, mode);
}
}
default void sendTo(int id, Object object, SendMode mode){
NetConnection conn = getByID(id);
if(conn == null){
Log.err("Failed to find connection with ID {0}.", id);
return;
}
conn.send(object, mode);
}
default void sendExcept(int id, Object object, SendMode mode){
for(NetConnection con : getConnections()){
if(con.id != id){
con.send(object, mode);
}
}
}
/** Close the server connection. */ /** Close the server connection. */
void close(); void close();
@@ -395,12 +432,9 @@ public class Net{
byte[] compressSnapshot(byte[] input); byte[] compressSnapshot(byte[] input);
/** Return all connected users. */ /** Return all connected users. */
Array<? extends NetConnection> getConnections(); Iterable<? extends NetConnection> getConnections();
/** Returns a connection by ID. */ /** Returns a connection by ID. */
NetConnection getByID(int id); NetConnection getByID(int id);
/** Close all connections. */
void dispose();
} }
} }

View File

@@ -3,6 +3,8 @@ package io.anuke.mindustry.net;
import io.anuke.mindustry.net.Net.SendMode; import io.anuke.mindustry.net.Net.SendMode;
public abstract class NetConnection{ public abstract class NetConnection{
private static int lastID;
public final int id; public final int id;
public final String address; public final String address;
@@ -18,8 +20,9 @@ public abstract class NetConnection{
public boolean hasBegunConnecting = false; public boolean hasBegunConnecting = false;
public float viewWidth, viewHeight, viewX, viewY; public float viewWidth, viewHeight, viewX, viewY;
public NetConnection(int id, String address){ /** Assigns this connection a unique ID. No two connections will ever have the same ID.*/
this.id = id; public NetConnection(String address){
this.id = lastID++;
this.address = address; this.address = address;
} }

View File

@@ -31,7 +31,6 @@ public class FileChooser extends FloatingDialog{
private Predicate<FileHandle> filter; private Predicate<FileHandle> filter;
private Consumer<FileHandle> selectListener; private Consumer<FileHandle> selectListener;
private boolean open; private boolean open;
private int lastWidth = Core.graphics.getWidth(), lastHeight = Core.graphics.getHeight();
public static final Predicate<String> pngFiles = str -> str.equals("png"); public static final Predicate<String> pngFiles = str -> str.equals("png");
public static final Predicate<String> anyMapFiles = str -> str.equals(oldMapExtension) || str.equals(mapExtension); public static final Predicate<String> anyMapFiles = str -> str.equals(oldMapExtension) || str.equals(mapExtension);
@@ -44,12 +43,14 @@ public class FileChooser extends FloatingDialog{
this.filter = filter; this.filter = filter;
this.selectListener = result; this.selectListener = result;
update(() -> { onResize(() -> {
if(Core.graphics.getWidth() != lastWidth || Core.graphics.getHeight() != lastHeight){ cont.clear();
updateFiles(false); setupWidgets();
lastHeight = Core.graphics.getHeight(); });
lastWidth = Core.graphics.getWidth();
} shown(() -> {
cont.clear();
setupWidgets();
}); });
} }
@@ -121,8 +122,9 @@ public class FileChooser extends FloatingDialog{
forward.resizeImage(isize); forward.resizeImage(isize);
forward.clicked(() -> stack.forward()); forward.clicked(() -> stack.forward());
back.clicked(() -> stack.back()); back.clicked(() -> stack.back());
forward.setDisabled(() -> !stack.canForward());
back.setDisabled(() -> !stack.canBack());
ImageButton home = new ImageButton("icon-home"); ImageButton home = new ImageButton("icon-home");
home.resizeImage(isize); home.resizeImage(isize);
@@ -206,7 +208,7 @@ public class FileChooser extends FloatingDialog{
//macs are confined to the Downloads/ directory //macs are confined to the Downloads/ directory
if(!OS.isMac){ if(!OS.isMac){
Image upimage = new Image("icon-folder-parent"); Image upimage = new Image("icon-folder-parent-small");
TextButton upbutton = new TextButton(".." + directory.toString(), "clear-toggle"); TextButton upbutton = new TextButton(".." + directory.toString(), "clear-toggle");
upbutton.clicked(() -> { upbutton.clicked(() -> {
directory = directory.parent(); directory = directory.parent();
@@ -214,7 +216,7 @@ public class FileChooser extends FloatingDialog{
updateFiles(true); updateFiles(true);
}); });
upbutton.left().add(upimage).padRight(4f).size(iconsize); upbutton.left().add(upimage).padRight(4f).size(iconsizesmall).padLeft(4);
upbutton.getLabel().setAlignment(Align.left); upbutton.getLabel().setAlignment(Align.left);
upbutton.getCells().reverse(); upbutton.getCells().reverse();
@@ -248,9 +250,9 @@ public class FileChooser extends FloatingDialog{
button.setChecked(filename.equals(filefield.getText())); button.setChecked(filename.equals(filefield.getText()));
}); });
Image image = new Image(file.isDirectory() ? "icon-folder" : "icon-file-text"); Image image = new Image(file.isDirectory() ? "icon-folder-small" : "icon-file-text-small");
button.add(image).padRight(4f).size(iconsize); button.add(image).padRight(4f).padLeft(4).size(iconsizesmall);
button.getCells().reverse(); button.getCells().reverse();
files.top().left().add(button).align(Align.topLeft).fillX().expandX() files.top().left().add(button).align(Align.topLeft).fillX().expandX()
.height(50).pad(2).padTop(0).padBottom(0).colspan(2); .height(50).pad(2).padTop(0).padBottom(0).colspan(2);
@@ -273,17 +275,6 @@ public class FileChooser extends FloatingDialog{
} }
} }
@Override
public Dialog show(){
Time.runTask(2f, () -> {
cont.clear();
setupWidgets();
super.show();
Core.scene.setScrollFocus(pane);
});
return this;
}
public class FileHistory{ public class FileHistory{
private Array<FileHandle> history = new Array<>(); private Array<FileHandle> history = new Array<>();
private int index; private int index;

View File

@@ -39,18 +39,6 @@ public class FloatingDialog extends Dialog{
state.set(State.paused); state.set(State.paused);
} }
}); });
boolean[] done = {false};
shown(() -> Core.app.post(() ->
forEach(child -> {
if(done[0]) return;
if(child instanceof ScrollPane){
Core.scene.setScrollFocus(child);
done[0] = true;
}
})));
} }
public FloatingDialog(String title){ public FloatingDialog(String title){
@@ -59,8 +47,9 @@ public class FloatingDialog extends Dialog{
protected void onResize(Runnable run){ protected void onResize(Runnable run){
Events.on(ResizeEvent.class, event -> { Events.on(ResizeEvent.class, event -> {
if(isShown()){ if(isShown() && Core.scene.getDialog() == this){
run.run(); run.run();
updateScrollFocus();
} }
}); });
} }

View File

@@ -1,11 +1,11 @@
package io.anuke.mindustry.ui.dialogs; package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core; import io.anuke.arc.*;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.game.Stats.RankResult; import io.anuke.mindustry.game.Stats.*;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.type.Item.Icon; import io.anuke.mindustry.type.Item.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;

View File

@@ -1,21 +1,20 @@
package io.anuke.mindustry.ui.dialogs; package io.anuke.mindustry.ui.dialogs;
import io.anuke.annotations.Annotations.Serialize; import io.anuke.annotations.Annotations.*;
import io.anuke.arc.Core; import io.anuke.arc.*;
import io.anuke.arc.collection.Array; import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.*;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.*;
import io.anuke.arc.scene.style.Drawable; import io.anuke.arc.scene.style.*;
import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.Cell; import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.scene.ui.layout.Table; import io.anuke.arc.util.*;
import io.anuke.arc.util.Strings; import io.anuke.mindustry.*;
import io.anuke.arc.util.Time; import io.anuke.mindustry.core.*;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.net.Host;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.net.Packets.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -97,9 +96,14 @@ public class JoinDialog extends FloatingDialog{
TextButton button = buttons[0] = remote.addButton("[accent]" + server.displayIP(), "clear", () -> { TextButton button = buttons[0] = remote.addButton("[accent]" + server.displayIP(), "clear", () -> {
if(!buttons[0].childrenPressed()){ if(!buttons[0].childrenPressed()){
connect(server.ip, server.port); if(server.lastHost != null && server.lastHost.version != Version.build && Version.build != -1 && server.lastHost.version != -1){
ui.showInfo("[scarlet]" + (server.lastHost.version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated).toString() + "\n[]" +
Core.bundle.format("server.versions", Version.build, server.lastHost.version));
}else{
connect(server.ip, server.port);
}
} }
}).width(targetWidth()).height(130f).pad(4f).get(); }).width(targetWidth()).pad(4f).get();
button.getLabel().setWrap(true); button.getLabel().setWrap(true);

View File

@@ -106,7 +106,7 @@ public class PausedDialog extends FloatingDialog{
return; return;
} }
if(control.saves.getCurrent() == null || !control.saves.getCurrent().isAutosave() || state.rules.tutorial){ if(control.saves.getCurrent() == null || !control.saves.getCurrent().isAutosave() || state.rules.tutorial || Net.client()){
state.set(State.menu); state.set(State.menu);
logic.reset(); logic.reset();
return; return;

View File

@@ -113,9 +113,16 @@ public class ZoneInfoDialog extends FloatingDialog{
t.add("$zone.resources").padRight(6); t.add("$zone.resources").padRight(6);
if(zone.resources.length > 0){ if(zone.resources.length > 0){
for(Item item : zone.resources){ t.table(r -> {
t.addImage(item.icon(Item.Icon.medium)).size(8 * 3); t.left();
} int i = 0;
for(Item item : zone.resources){
r.addImage(item.icon(Item.Icon.medium)).size(8 * 3);
if(++i % 4 == 0){
r.row();
}
}
});
}else{ }else{
t.add("$none"); t.add("$none");
} }

View File

@@ -242,9 +242,9 @@ public class HudFragment extends Fragment{
IntFormat fps = new IntFormat("fps"); IntFormat fps = new IntFormat("fps");
IntFormat ping = new IntFormat("ping"); IntFormat ping = new IntFormat("ping");
info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left(); info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left().style("outline");
info.row(); info.row();
info.label(() -> ping.get(Net.getPing())).visible(Net::client).left(); info.label(() -> ping.get(Net.getPing())).visible(Net::client).left().style("outline");
}).top().left(); }).top().left();
}); });

View File

@@ -294,9 +294,7 @@ public class Block extends BlockStorage{
/** Called after the block is placed by this client. */ /** Called after the block is placed by this client. */
@CallSuper @CallSuper
public void playerPlaced(Tile tile){ public void playerPlaced(Tile tile){
if(outputsPower && !consumesPower){
PowerNode.lastPlaced = tile.pos();
}
} }
/** Called after the block is placed by anyone. */ /** Called after the block is placed by anyone. */

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.world.blocks.power;
import io.anuke.annotations.Annotations.*; import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.function.*; import io.anuke.arc.function.*;
import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
@@ -20,9 +21,7 @@ import io.anuke.mindustry.world.meta.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class PowerNode extends PowerBlock{ public class PowerNode extends PowerBlock{
//last distribution block placed protected ObjectSet<PowerGraph> graphs = new ObjectSet<>();
public static int lastPlaced = -1;
protected Vector2 t1 = new Vector2(), t2 = new Vector2(); protected Vector2 t1 = new Vector2(), t2 = new Vector2();
protected TextureRegion laser, laserEnd; protected TextureRegion laser, laserEnd;
@@ -99,23 +98,11 @@ public class PowerNode extends PowerBlock{
() -> Mathf.clamp(entity.power.graph.getPowerProduced() / entity.power.graph.getPowerNeeded()))); () -> Mathf.clamp(entity.power.graph.getPowerProduced() / entity.power.graph.getPowerNeeded())));
} }
@Override
public void playerPlaced(Tile tile){
Tile before = world.tile(lastPlaced);
if(linkValid(tile, before) && !before.entity.proximity().contains(tile)){
Call.linkPowerNodes(null, tile, before);
}
lastPlaced = tile.pos();
super.playerPlaced(tile);
}
@Override @Override
public void placed(Tile tile){ public void placed(Tile tile){
if(Net.client()) return; if(Net.client()) return;
Predicate<Tile> valid = other -> other != null && other != tile && ((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower)) && linkValid(tile, other) Predicate<Tile> valid = other -> other != null && other != tile && ((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower) || other.block() instanceof PowerNode) && linkValid(tile, other)
&& !other.entity.proximity().contains(tile) && other.entity.power.graph != tile.entity.power.graph; && !other.entity.proximity().contains(tile) && other.entity.power.graph != tile.entity.power.graph;
tempTiles.clear(); tempTiles.clear();
@@ -132,6 +119,28 @@ public class PowerNode extends PowerBlock{
super.placed(tile); super.placed(tile);
} }
private void getPotentialLinks(Tile tile, Consumer<Tile> others){
Predicate<Tile> valid = other -> other != null && other != tile && other.entity != null && other.entity.power != null &&
((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower) || other.block() instanceof PowerNode) &&
overlaps(tile.x * tilesize + offset(), tile.y *tilesize + offset(), other, laserRange * tilesize)
&& !other.entity.proximity().contains(tile) && !graphs.contains(other.entity.power.graph);
tempTiles.clear();
graphs.clear();
Geometry.circle(tile.x, tile.y, (int)(laserRange + 1), (x, y) -> {
Tile other = world.ltile(x, y);
if(valid.test(other)){
tempTiles.add(other);
}
});
tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile)));
tempTiles.each(valid, t -> {
graphs.add(t.entity.power.graph);
others.accept(t);
});
}
@Override @Override
public void setStats(){ public void setStats(){
super.setStats(); super.setStats();
@@ -213,6 +222,11 @@ public class PowerNode extends PowerBlock{
Draw.color(Pal.placing); Draw.color(Pal.placing);
Drawf.circles(x * tilesize + offset(), y * tilesize + offset(), laserRange * tilesize); Drawf.circles(x * tilesize + offset(), y * tilesize + offset(), laserRange * tilesize);
getPotentialLinks(tile, other -> {
Drawf.square(other.drawx(), other.drawy(), other.block().size * tilesize / 2f + 2f, Pal.place);
});
/*
for(int cx = (int)(x - laserRange - 1); cx <= x + laserRange + 1; cx++){ for(int cx = (int)(x - laserRange - 1); cx <= x + laserRange + 1; cx++){
for(int cy = (int)(y - laserRange - 1); cy <= y + laserRange + 1; cy++){ for(int cy = (int)(y - laserRange - 1); cy <= y + laserRange + 1; cy++){
Tile link = world.ltile(cx, cy); Tile link = world.ltile(cx, cy);
@@ -221,7 +235,7 @@ public class PowerNode extends PowerBlock{
Drawf.square(link.drawx(), link.drawy(), link.block().size * tilesize / 2f + 2f, link.pos() == lastPlaced ? Pal.place : Pal.accent); Drawf.square(link.drawx(), link.drawy(), link.block().size * tilesize / 2f + 2f, link.pos() == lastPlaced ? Pal.place : Pal.accent);
} }
} }
} }*/
Draw.reset(); Draw.reset();
} }

View File

@@ -12,6 +12,11 @@ public class LiquidConverter extends GenericCrafter{
hasLiquids = true; hasLiquids = true;
} }
@Override
public boolean outputsItems(){
return false;
}
@Override @Override
public void init(){ public void init(){
ConsumeLiquidBase cl = consumes.get(ConsumeType.liquid); ConsumeLiquidBase cl = consumes.get(ConsumeType.liquid);

View File

@@ -27,13 +27,25 @@
"com/sun/jndi", "com/sun/jndi",
"com/sun/xml", "com/sun/xml",
"com/sun/script", "com/sun/script",
"sum/awt", "sun/awt",
"sun/java2d", "sun/java2d",
"sun/font", "sun/font",
"sun/rmi", "sun/rmi",
"sun/swing", "sun/swing",
"java/util/stream", "java/util/stream",
"com/sun/media", "com/sun/media",
"sun/print",
"sun/awt",
"sun/instrument",
"sun/security/tools",
"sun/security/smartcardio",
"sun/audio",
"javax/xml",
"javax/sound",
"javax/script",
"java/beans",
"java/applet",
"java/rmi",
"com/sun/naming", "com/sun/naming",
"java/awt", "java/awt",
"com/sun/org/apache/xpath", "com/sun/org/apache/xpath",

View File

@@ -1,7 +1,15 @@
#!/usr/bin/bash #!/usr/bin/bash
#convert ogg to .caf files for iOS cd $1
for i in $1/*.ogg; do
#convert ogg to .mp3 files for iOS
for i in *.ogg; do
echo $i echo $i
ffmpeg -i "$i" "${i%.*}.caf" ffmpeg -i "$i" "OUT_${i%.*}.mp3"
done done
find . -type f ! -name "OUT_*" -delete
for file in OUT_*; do mv "$file" "${file#OUT_}"; done;
cd ../../

Binary file not shown.

Before

Width:  |  Height:  |  Size: 996 KiB

After

Width:  |  Height:  |  Size: 706 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 905 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 993 KiB

After

Width:  |  Height:  |  Size: 632 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 725 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 890 KiB

After

Width:  |  Height:  |  Size: 598 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 KiB

After

Width:  |  Height:  |  Size: 204 KiB

View File

@@ -40,7 +40,7 @@ public class IOSLauncher extends IOSApplication.Delegate{
@Override @Override
public void shareFile(FileHandle file){ public void shareFile(FileHandle file){
Log.info("Attempting to share file " + file); Log.info("Attempting to share file " + file);
FileHandle to = Core.files.absolute(getDocumentsDirectory()).child(file.name()/* + ".png"*/); FileHandle to = Core.files.absolute(getDocumentsDirectory()).child(file.name());
file.copyTo(to); file.copyTo(to);
NSURL url = new NSURL(to.file()); NSURL url = new NSURL(to.file());
@@ -53,7 +53,6 @@ public class IOSLauncher extends IOSApplication.Delegate{
@Override @Override
public void beginForceLandscape(){ public void beginForceLandscape(){
Log.info("begin force landscape");
forced = true; forced = true;
UINavigationController.attemptRotationToDeviceOrientation(); UINavigationController.attemptRotationToDeviceOrientation();
} }

View File

@@ -4,6 +4,7 @@ import io.anuke.arc.*;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.function.*; import io.anuke.arc.function.*;
import io.anuke.arc.net.*; import io.anuke.arc.net.*;
import io.anuke.arc.util.async.*;
import io.anuke.arc.util.pooling.*; import io.anuke.arc.util.pooling.*;
import io.anuke.mindustry.net.Net.*; import io.anuke.mindustry.net.Net.*;
import io.anuke.mindustry.net.Packets.*; import io.anuke.mindustry.net.Packets.*;
@@ -84,7 +85,7 @@ public class ArcNetClient implements ClientProvider{
@Override @Override
public void connect(String ip, int port, Runnable success){ public void connect(String ip, int port, Runnable success){
runAsync(() -> { Threads.daemon(() -> {
try{ try{
//just in case //just in case
client.stop(); client.stop();
@@ -99,7 +100,7 @@ public class ArcNetClient implements ClientProvider{
updateThread.setDaemon(true); updateThread.setDaemon(true);
updateThread.start(); updateThread.start();
client.connect(5000, ip, port, port); client.connect(5000, ip, port);
success.run(); success.run();
}catch(Exception e){ }catch(Exception e){
handleException(e); handleException(e);
@@ -115,11 +116,7 @@ public class ArcNetClient implements ClientProvider{
@Override @Override
public void send(Object object, SendMode mode){ public void send(Object object, SendMode mode){
try{ try{
if(mode == SendMode.tcp){ client.sendTCP(object);
client.sendTCP(object);
}else{
client.sendUDP(object);
}
//sending things can cause an under/overflow, catch it and disconnect instead of crashing //sending things can cause an under/overflow, catch it and disconnect instead of crashing
}catch(BufferOverflowException | BufferUnderflowException e){ }catch(BufferOverflowException | BufferUnderflowException e){
Net.showError(e); Net.showError(e);
@@ -140,7 +137,7 @@ public class ArcNetClient implements ClientProvider{
@Override @Override
public void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> invalid){ public void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> invalid){
runAsync(() -> { Threads.daemon(() -> {
try{ try{
DatagramSocket socket = new DatagramSocket(); DatagramSocket socket = new DatagramSocket();
socket.send(new DatagramPacket(new byte[]{-2, 1}, 2, InetAddress.getByName(address), port)); socket.send(new DatagramPacket(new byte[]{-2, 1}, 2, InetAddress.getByName(address), port));
@@ -189,12 +186,6 @@ public class ArcNetClient implements ClientProvider{
} }
} }
private void runAsync(Runnable run){
Thread thread = new Thread(run, "Client Async Run");
thread.setDaemon(true);
thread.start();
}
private void handleException(Exception e){ private void handleException(Exception e){
if(e instanceof ArcNetException){ if(e instanceof ArcNetException){
Core.app.post(() -> Net.showError(new IOException("mismatch"))); Core.app.post(() -> Net.showError(new IOException("mismatch")));

View File

@@ -1,11 +1,9 @@
package io.anuke.mindustry.net; package io.anuke.mindustry.net;
import com.dosse.upnp.*;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.net.*; import io.anuke.arc.net.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.*; import io.anuke.arc.util.async.*;
import io.anuke.mindustry.net.Net.*; import io.anuke.mindustry.net.Net.*;
import io.anuke.mindustry.net.Packets.*; import io.anuke.mindustry.net.Packets.*;
import net.jpountz.lz4.*; import net.jpountz.lz4.*;
@@ -19,14 +17,10 @@ import static io.anuke.mindustry.Vars.*;
public class ArcNetServer implements ServerProvider{ public class ArcNetServer implements ServerProvider{
final Server server; final Server server;
final CopyOnWriteArrayList<KryoConnection> connections = new CopyOnWriteArrayList<>(); final CopyOnWriteArrayList<ArcConnection> connections = new CopyOnWriteArrayList<>();
final CopyOnWriteArraySet<Integer> missing = new CopyOnWriteArraySet<>();
final Array<KryoConnection> array = new Array<>();
final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor(); final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
Thread serverThread; Thread serverThread;
int lastconnection = 0;
public ArcNetServer(){ public ArcNetServer(){
server = new Server(4096 * 2, 4096, new PacketSerializer()); server = new Server(4096 * 2, 4096, new PacketSerializer());
server.setMulticast(multicastGroup, multicastPort); server.setMulticast(multicastGroup, multicastPort);
@@ -42,7 +36,7 @@ public class ArcNetServer implements ServerProvider{
public void connected(Connection connection){ public void connected(Connection connection){
String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress(); String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress();
KryoConnection kn = new KryoConnection(lastconnection++, ip, connection); ArcConnection kn = new ArcConnection(ip, connection);
Connect c = new Connect(); Connect c = new Connect();
c.id = kn.id; c.id = kn.id;
@@ -56,7 +50,7 @@ public class ArcNetServer implements ServerProvider{
@Override @Override
public void disconnected(Connection connection){ public void disconnected(Connection connection){
KryoConnection k = getByKryoID(connection.getID()); ArcConnection k = getByKryoID(connection.getID());
if(k == null) return; if(k == null) return;
Disconnect c = new Disconnect(); Disconnect c = new Disconnect();
@@ -70,7 +64,7 @@ public class ArcNetServer implements ServerProvider{
@Override @Override
public void received(Connection connection, Object object){ public void received(Connection connection, Object object){
KryoConnection k = getByKryoID(connection.getID()); ArcConnection k = getByKryoID(connection.getID());
if(object instanceof FrameworkMessage || k == null) return; if(object instanceof FrameworkMessage || k == null) return;
Core.app.post(() -> { Core.app.post(() -> {
@@ -99,18 +93,14 @@ public class ArcNetServer implements ServerProvider{
} }
@Override @Override
public Array<KryoConnection> getConnections(){ public Iterable<ArcConnection> getConnections(){
array.clear(); return connections;
for(KryoConnection c : connections){
array.add(c);
}
return array;
} }
@Override @Override
public KryoConnection getByID(int id){ public ArcConnection getByID(int id){
for(int i = 0; i < connections.size(); i++){ for(int i = 0; i < connections.size(); i++){
KryoConnection con = connections.get(i); ArcConnection con = connections.get(i);
if(con.id == id){ if(con.id == id){
return con; return con;
} }
@@ -121,28 +111,14 @@ public class ArcNetServer implements ServerProvider{
@Override @Override
public void host(int port) throws IOException{ public void host(int port) throws IOException{
//attempt to open default ports if they're not already open
//this only opens the default port due to security concerns (?)
if(port == Vars.port){
async(() -> {
try{
if(!UPnP.isMappedTCP(port)) UPnP.openPortTCP(port);
if(!UPnP.isMappedUDP(port)) UPnP.openPortUDP(port);
}catch(Throwable ignored){
}
});
}
lastconnection = 0;
connections.clear(); connections.clear();
missing.clear(); server.bind(port);
server.bind(port, port);
serverThread = new Thread(() -> { serverThread = new Thread(() -> {
try{ try{
server.run(); server.run();
}catch(Throwable e){ }catch(Throwable e){
if(!(e instanceof ClosedSelectorException)) handleException(e); if(!(e instanceof ClosedSelectorException)) Threads.throwAppException(e);
} }
}, "Net Server"); }, "Net Server");
serverThread.setDaemon(true); serverThread.setDaemon(true);
@@ -152,102 +128,12 @@ public class ArcNetServer implements ServerProvider{
@Override @Override
public void close(){ public void close(){
connections.clear(); connections.clear();
lastconnection = 0; Threads.daemon(server::stop);
async(server::stop);
} }
@Override ArcConnection getByKryoID(int id){
public void sendStream(int id, Streamable stream){
KryoConnection connection = getByID(id);
if(connection == null) return;
try{
if(connection.connection != null){
connection.connection.addListener(new InputStreamSender(stream.stream, 512){
int id;
protected void start(){
//send an object so the receiving side knows how to handle the following chunks
StreamBegin begin = new StreamBegin();
begin.total = stream.stream.available();
begin.type = Registrator.getID(stream.getClass());
connection.connection.sendTCP(begin);
id = begin.id;
}
protected Object next(byte[] bytes){
StreamChunk chunk = new StreamChunk();
chunk.id = id;
chunk.data = bytes;
return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it.
}
});
}else{
int cid;
StreamBegin begin = new StreamBegin();
begin.total = stream.stream.available();
begin.type = Registrator.getID(stream.getClass());
connection.send(begin, SendMode.tcp);
cid = begin.id;
while(stream.stream.available() > 0){
byte[] bytes = new byte[Math.min(512, stream.stream.available())];
stream.stream.read(bytes);
StreamChunk chunk = new StreamChunk();
chunk.id = cid;
chunk.data = bytes;
connection.send(chunk, SendMode.tcp);
}
}
}catch(IOException e){
throw new RuntimeException(e);
}
}
@Override
public void send(Object object, SendMode mode){
for(int i = 0; i < connections.size(); i++){ for(int i = 0; i < connections.size(); i++){
connections.get(i).send(object, mode); ArcConnection con = connections.get(i);
}
}
@Override
public void sendTo(int id, Object object, SendMode mode){
NetConnection conn = getByID(id);
if(conn == null){
if(!missing.contains(id))
Log.err("Failed to find connection with ID {0}.", id);
missing.add(id);
return;
}
conn.send(object, mode);
}
@Override
public void sendExcept(int id, Object object, SendMode mode){
for(int i = 0; i < connections.size(); i++){
KryoConnection conn = connections.get(i);
if(conn.id != id) conn.send(object, mode);
}
}
@Override
public void dispose(){
close();
}
private void handleException(Throwable e){
Time.run(0f, () -> {
throw new RuntimeException(e);
});
}
KryoConnection getByKryoID(int id){
for(int i = 0; i < connections.size(); i++){
KryoConnection con = connections.get(i);
if(con.connection != null && con.connection.getID() == id){ if(con.connection != null && con.connection.getID() == id){
return con; return con;
} }
@@ -256,17 +142,11 @@ public class ArcNetServer implements ServerProvider{
return null; return null;
} }
void async(Runnable run){ class ArcConnection extends NetConnection{
Thread thread = new Thread(run);
thread.setDaemon(true);
thread.start();
}
class KryoConnection extends NetConnection{
public final Connection connection; public final Connection connection;
public KryoConnection(int id, String address, Connection connection){ public ArcConnection(String address, Connection connection){
super(id, address); super(address);
this.connection = connection; this.connection = connection;
} }
@@ -278,17 +158,13 @@ public class ArcNetServer implements ServerProvider{
@Override @Override
public void send(Object object, SendMode mode){ public void send(Object object, SendMode mode){
try{ try{
if(mode == SendMode.tcp){ connection.sendTCP(object);
connection.sendTCP(object);
}else{
connection.sendUDP(object);
}
}catch(Exception e){ }catch(Exception e){
Log.err(e); Log.err(e);
Log.info("Error sending packet. Disconnecting invalid client!"); Log.info("Error sending packet. Disconnecting invalid client!");
connection.close(); connection.close();
KryoConnection k = getByKryoID(connection.getID()); ArcConnection k = getByKryoID(connection.getID());
if(k != null) connections.remove(k); if(k != null) connections.remove(k);
} }
} }

View File

@@ -157,7 +157,7 @@ public class ServerControl implements ApplicationListener{
info("Selected next map to be {0}.", map.name()); info("Selected next map to be {0}.", map.name());
play(true, () -> world.loadMap(map)); play(true, () -> world.loadMap(map, map.applyRules(lastMode)));
} }
}else{ }else{
netServer.kickAll(KickReason.gameover); netServer.kickAll(KickReason.gameover);
@@ -231,7 +231,7 @@ public class ServerControl implements ApplicationListener{
logic.reset(); logic.reset();
lastMode = preset; lastMode = preset;
try{ try{
world.loadMap(result); world.loadMap(result, result.applyRules(lastMode));
state.rules = result.applyRules(preset); state.rules = result.applyRules(preset);
logic.play(); logic.play();
@@ -700,10 +700,11 @@ public class ServerControl implements ApplicationListener{
run.run(); run.run();
logic.play(); logic.play();
state.rules = world.getMap().applyRules(lastMode); state.rules = world.getMap().applyRules(lastMode);
for(Player p : players){ for(Player p : players){
p.reset(); p.reset();
if(state.rules.pvp){ if(state.rules.pvp){
p.setTeam(netServer.assignTeam(new ArrayIterable<>(players))); p.setTeam(netServer.assignTeam(p, new ArrayIterable<>(players)));
} }
netServer.sendWorldData(p, p.con.id); netServer.sendWorldData(p, p.con.id);
} }