Merge branch 'master' of github.com:Anuken/Mindustry
This commit is contained in:
@@ -17,12 +17,12 @@ import io.anuke.mindustry.game.Version;
|
||||
import io.anuke.mindustry.gen.Serialization;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.world.blocks.defense.ForceProjector.ShieldEntity;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.entities.Entities;
|
||||
import io.anuke.ucore.entities.EntityGroup;
|
||||
import io.anuke.ucore.entities.impl.EffectEntity;
|
||||
import io.anuke.ucore.entities.trait.DrawTrait;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.OS;
|
||||
import io.anuke.ucore.util.Translator;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -170,7 +170,7 @@ public class Vars{
|
||||
ios = Gdx.app.getType() == ApplicationType.iOS;
|
||||
android = Gdx.app.getType() == ApplicationType.Android;
|
||||
|
||||
dataDirectory = OS.getAppDataDirectory(appName);
|
||||
dataDirectory = Settings.getDataDirectory(appName);
|
||||
customMapDirectory = dataDirectory.child("maps/");
|
||||
saveDirectory = dataDirectory.child("saves/");
|
||||
baseCameraScale = Math.round(Unit.dp.scl(4));
|
||||
|
||||
@@ -247,7 +247,7 @@ public class BlockIndexer{
|
||||
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){
|
||||
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){
|
||||
Tile result = world.tile(x, y);
|
||||
if(result.block().drops == null || !scanOres.contains(result.block().drops.item)) continue;
|
||||
if( result == null || result.block().drops == null || !scanOres.contains(result.block().drops.item)) continue;
|
||||
|
||||
itemSet.add(result.block().drops.item);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ public class Recipes implements ContentList{
|
||||
new Recipe(power, PowerBlocks.thoriumReactor, new ItemStack(Items.lead, 600), new ItemStack(Items.silicon, 400), new ItemStack(Items.densealloy, 300), new ItemStack(Items.thorium, 300));
|
||||
new Recipe(power, PowerBlocks.rtgGenerator, new ItemStack(Items.lead, 200), new ItemStack(Items.silicon, 150), new ItemStack(Items.phasefabric, 50), new ItemStack(Items.plastanium, 150), new ItemStack(Items.thorium, 100));
|
||||
|
||||
new Recipe(distribution, StorageBlocks.unloader, new ItemStack(Items.densealloy, 40), new ItemStack(Items.silicon, 50));
|
||||
new Recipe(distribution, StorageBlocks.unloader, new ItemStack(Items.densealloy, 50), new ItemStack(Items.silicon, 60));
|
||||
new Recipe(distribution, StorageBlocks.container, new ItemStack(Items.densealloy, 200));
|
||||
new Recipe(distribution, StorageBlocks.vault, new ItemStack(Items.densealloy, 500), new ItemStack(Items.thorium, 250));
|
||||
//core disabled due to being broken
|
||||
|
||||
@@ -45,6 +45,8 @@ public class Blocks extends BlockList implements ContentList{
|
||||
}
|
||||
};
|
||||
|
||||
//Registers build blocks from size 1-6
|
||||
//no reference is needed here since they can be looked up by name later
|
||||
for(int i = 1; i <= 6; i++){
|
||||
new BuildBlock("build" + i);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ import io.anuke.mindustry.content.Liquids;
|
||||
import io.anuke.mindustry.content.fx.BlockFx;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.distribution.WarpGate;
|
||||
import io.anuke.mindustry.world.blocks.power.*;
|
||||
|
||||
public class PowerBlocks extends BlockList implements ContentList{
|
||||
public static Block combustionGenerator, thermalGenerator, turbineGenerator, rtgGenerator, solarPanel, largeSolarPanel,
|
||||
thoriumReactor, fusionReactor, battery, batteryLarge, powerNode, powerNodeLarge, warpGate;
|
||||
thoriumReactor, fusionReactor, battery, batteryLarge, powerNode, powerNodeLarge;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
@@ -85,7 +84,5 @@ public class PowerBlocks extends BlockList implements ContentList{
|
||||
shadow = "shadow-round-2";
|
||||
}};
|
||||
|
||||
warpGate = new WarpGate("warp-gate");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,16 +17,16 @@ public class StorageBlocks extends BlockList implements ContentList{
|
||||
|
||||
vault = new Vault("vault"){{
|
||||
size = 3;
|
||||
itemCapacity = 1000;
|
||||
itemCapacity = 900;
|
||||
}};
|
||||
|
||||
container = new Vault("container"){{
|
||||
size = 2;
|
||||
itemCapacity = 250;
|
||||
itemCapacity = 200;
|
||||
}};
|
||||
|
||||
unloader = new SortedUnloader("unloader"){{
|
||||
speed = 5;
|
||||
speed = 12f;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ import io.anuke.mindustry.game.Teams;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.core.Events;
|
||||
|
||||
import static io.anuke.mindustry.Vars.unitGroups;
|
||||
import static io.anuke.mindustry.Vars.waveTeam;
|
||||
|
||||
public class GameState{
|
||||
public int wave = 1;
|
||||
public float wavetime;
|
||||
@@ -16,8 +19,13 @@ public class GameState{
|
||||
public Difficulty difficulty = Difficulty.normal;
|
||||
public WaveSpawner spawner = new WaveSpawner();
|
||||
public Teams teams = new Teams();
|
||||
public int enemies;
|
||||
private State state = State.menu;
|
||||
|
||||
public int enemies(){
|
||||
return Net.client() ? enemies : unitGroups[waveTeam.ordinal()].size();
|
||||
}
|
||||
|
||||
public void set(State astate){
|
||||
Events.fire(new StateChangeEvent(state, astate));
|
||||
state = astate;
|
||||
|
||||
@@ -34,7 +34,6 @@ import static io.anuke.mindustry.Vars.*;
|
||||
* This class should <i>not</i> call any outside methods to change state of modules, but instead fire events.
|
||||
*/
|
||||
public class Logic extends Module{
|
||||
public boolean doUpdate = true;
|
||||
|
||||
public Logic(){
|
||||
Events.on(TileChangeEvent.class, event -> {
|
||||
@@ -125,7 +124,7 @@ public class Logic extends Module{
|
||||
}
|
||||
|
||||
private void updateSectors(){
|
||||
if(world.getSector() == null) return;
|
||||
if(world.getSector() == null || state.gameOver) return;
|
||||
|
||||
world.getSector().currentMission().update();
|
||||
|
||||
@@ -172,7 +171,6 @@ public class Logic extends Module{
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
if(threads.isEnabled() && !threads.isOnThread()) return;
|
||||
|
||||
if(Vars.control != null){
|
||||
control.runUpdateLogic();
|
||||
@@ -219,12 +217,6 @@ public class Logic extends Module{
|
||||
if(group.isEmpty()) continue;
|
||||
|
||||
EntityQuery.collideGroups(bulletGroup, group);
|
||||
EntityQuery.collideGroups(group, playerGroup);
|
||||
|
||||
for(EntityGroup other : unitGroups){
|
||||
if(other.isEmpty()) continue;
|
||||
EntityQuery.collideGroups(group, other);
|
||||
}
|
||||
}
|
||||
|
||||
EntityQuery.collideGroups(bulletGroup, playerGroup);
|
||||
@@ -238,9 +230,5 @@ public class Logic extends Module{
|
||||
checkGameOver();
|
||||
}
|
||||
}
|
||||
|
||||
if(threads.isEnabled()){
|
||||
netServer.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ import static io.anuke.mindustry.Vars.*;
|
||||
public class NetClient extends Module{
|
||||
private final static float dataTimeout = 60 * 18;
|
||||
private final static float playerSyncTime = 2;
|
||||
private final static float viewScale = 1.75f;
|
||||
public final static float viewScale = 2f;
|
||||
|
||||
private Timer timer = new Timer(5);
|
||||
/**Whether the client is currently connecting.*/
|
||||
@@ -284,6 +284,7 @@ public class NetClient extends Module{
|
||||
//read wave info
|
||||
state.wavetime = input.readFloat();
|
||||
state.wave = input.readInt();
|
||||
state.enemies = input.readInt();
|
||||
|
||||
byte cores = input.readByte();
|
||||
for(int i = 0; i < cores; i++){
|
||||
@@ -399,11 +400,11 @@ public class NetClient extends Module{
|
||||
quiet = true;
|
||||
}
|
||||
|
||||
public synchronized void addRemovedEntity(int id){
|
||||
public void addRemovedEntity(int id){
|
||||
removed.add(id);
|
||||
}
|
||||
|
||||
public synchronized boolean isEntityUsed(int id){
|
||||
public boolean isEntityUsed(int id){
|
||||
return removed.contains(id);
|
||||
}
|
||||
|
||||
@@ -414,11 +415,9 @@ public class NetClient extends Module{
|
||||
|
||||
BuildRequest[] requests;
|
||||
|
||||
synchronized(player.getPlaceQueue()){
|
||||
requests = new BuildRequest[player.getPlaceQueue().size];
|
||||
for(int i = 0; i < requests.length; i++){
|
||||
requests[i] = player.getPlaceQueue().get(i);
|
||||
}
|
||||
requests = new BuildRequest[player.getPlaceQueue().size];
|
||||
for(int i = 0; i < requests.length; i++){
|
||||
requests[i] = player.getPlaceQueue().get(i);
|
||||
}
|
||||
|
||||
Call.onClientShapshot(lastSent++, TimeUtils.millis(), player.x, player.y,
|
||||
|
||||
@@ -412,11 +412,19 @@ public class NetServer extends Module{
|
||||
}
|
||||
|
||||
public boolean isWaitingForPlayers(){
|
||||
return state.mode.isPvp && playerGroup.size() < 2;
|
||||
if(state.mode.isPvp){
|
||||
int used = 0;
|
||||
for(Team t : Team.all){
|
||||
if(playerGroup.count(p -> p.getTeam() == t) > 0){
|
||||
used ++;
|
||||
}
|
||||
}
|
||||
return used < 2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
if(threads.isEnabled() && !threads.isOnThread()) return;
|
||||
|
||||
if(!headless && !closing && Net.server() && state.is(State.menu)){
|
||||
closing = true;
|
||||
@@ -469,6 +477,7 @@ public class NetServer extends Module{
|
||||
//write wave datas
|
||||
dataStream.writeFloat(state.wavetime);
|
||||
dataStream.writeInt(state.wave);
|
||||
dataStream.writeInt(state.enemies());
|
||||
|
||||
ObjectSet<Tile> cores = state.teams.get(player.getTeam()).cores;
|
||||
|
||||
@@ -495,7 +504,7 @@ public class NetServer extends Module{
|
||||
//check for syncable groups
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
if(group.isEmpty() || !(group.all().get(0) instanceof SyncTrait)) continue;
|
||||
//clipping is done by represntatives
|
||||
//clipping is done by representatives
|
||||
SyncTrait represent = (SyncTrait) group.all().get(0);
|
||||
|
||||
//make sure mapping is enabled for this group
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
package io.anuke.mindustry.core;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Base64Coder;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.scene.ui.Dialog;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
import io.anuke.ucore.util.Log;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import static io.anuke.mindustry.Vars.mobile;
|
||||
|
||||
public abstract class Platform {
|
||||
/**Each separate game platform should set this instance to their own implementation.*/
|
||||
public static Platform instance = new Platform() {};
|
||||
@@ -17,7 +25,34 @@ public abstract class Platform {
|
||||
addDialog(field, 16);
|
||||
}
|
||||
/**See addDialog().*/
|
||||
public void addDialog(TextField field, int maxLength){}
|
||||
public void addDialog(TextField field, int maxLength){
|
||||
if(!mobile) return; //this is mobile only, desktop doesn't need dialogs
|
||||
|
||||
field.tapped(() -> {
|
||||
Log.info("yappd");
|
||||
Dialog dialog = new Dialog("", "dialog");
|
||||
dialog.setFillParent(true);
|
||||
dialog.content().top();
|
||||
dialog.content().defaults().height(65f);
|
||||
TextField to = dialog.content().addField(field.getText(), t-> {}).pad(15).width(250f).get();
|
||||
to.setMaxLength(maxLength);
|
||||
to.keyDown(Keys.ENTER, () -> dialog.content().find("okb").fireClick());
|
||||
dialog.content().addButton("$text.ok", () -> {
|
||||
field.clearText();
|
||||
field.appendText(to.getText());
|
||||
field.change();
|
||||
dialog.hide();
|
||||
Gdx.input.setOnscreenKeyboardVisible(false);
|
||||
}).width(90f).name("okb");
|
||||
|
||||
dialog.show();
|
||||
Timers.runTask(1f, () -> {
|
||||
to.setCursorPosition(to.getText().length());
|
||||
Core.scene.setKeyboardFocus(to);
|
||||
Gdx.input.setOnscreenKeyboardVisible(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
/**Update discord RPC.*/
|
||||
public void updateRPC(){}
|
||||
/**Called when the game is exited.*/
|
||||
|
||||
@@ -1,80 +1,34 @@
|
||||
package io.anuke.mindustry.core;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.utils.Queue;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.util.Log;
|
||||
import io.anuke.ucore.util.Threads;
|
||||
import io.anuke.ucore.util.Threads.ThreadInfoProvider;
|
||||
|
||||
import static io.anuke.mindustry.Vars.control;
|
||||
import static io.anuke.mindustry.Vars.logic;
|
||||
|
||||
public class ThreadHandler implements ThreadInfoProvider{
|
||||
private final Queue<Runnable> toRun = new Queue<>();
|
||||
private Thread thread, graphicsThread;
|
||||
private final Object updateLock = new Object();
|
||||
private float delta = 1f;
|
||||
private float smoothDelta = 1f;
|
||||
private long frame = 0, lastDeltaUpdate;
|
||||
private float framesSinceUpdate;
|
||||
private boolean enabled;
|
||||
private boolean rendered = true;
|
||||
public class ThreadHandler{
|
||||
private long lastFrameTime;
|
||||
|
||||
public ThreadHandler(){
|
||||
Threads.setThreadInfoProvider(this);
|
||||
graphicsThread = Thread.currentThread();
|
||||
|
||||
Timers.setDeltaProvider(() -> {
|
||||
float result = isOnThread() ? delta : Gdx.graphics.getDeltaTime() * 60f;
|
||||
return Math.min(Float.isNaN(result) ? 1f : result, 15f);
|
||||
float result = Gdx.graphics.getDeltaTime() * 60f;
|
||||
return Float.isNaN(result) || Float.isInfinite(result) ? 1f : Math.min(result, 60f / 10f);
|
||||
});
|
||||
}
|
||||
|
||||
public void run(Runnable r){
|
||||
if(enabled){
|
||||
synchronized(toRun){
|
||||
toRun.addLast(r);
|
||||
}
|
||||
}else{
|
||||
r.run();
|
||||
}
|
||||
r.run();
|
||||
}
|
||||
|
||||
public void runGraphics(Runnable r){
|
||||
if(enabled){
|
||||
Gdx.app.postRunnable(r);
|
||||
}else{
|
||||
r.run();
|
||||
}
|
||||
r.run();
|
||||
}
|
||||
|
||||
public void runDelay(Runnable r){
|
||||
if(enabled){
|
||||
synchronized(toRun){
|
||||
toRun.addLast(r);
|
||||
}
|
||||
}else{
|
||||
Gdx.app.postRunnable(r);
|
||||
}
|
||||
}
|
||||
|
||||
public int getTPS(){
|
||||
if(smoothDelta == 0f){
|
||||
return 60;
|
||||
}
|
||||
return (int) (60 / smoothDelta);
|
||||
Gdx.app.postRunnable(r);
|
||||
}
|
||||
|
||||
public long getFrameID(){
|
||||
return enabled ? frame : Gdx.graphics.getFrameId();
|
||||
}
|
||||
|
||||
public float getFramesSinceUpdate(){
|
||||
return framesSinceUpdate;
|
||||
return Gdx.graphics.getFrameId();
|
||||
}
|
||||
|
||||
public void handleBeginRender(){
|
||||
@@ -95,119 +49,6 @@ public class ThreadHandler implements ThreadInfoProvider{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!enabled) return;
|
||||
|
||||
framesSinceUpdate += Timers.delta();
|
||||
|
||||
synchronized(updateLock){
|
||||
rendered = true;
|
||||
updateLock.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled(){
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled){
|
||||
if(enabled){
|
||||
logic.doUpdate = false;
|
||||
Timers.runTask(2f, () -> {
|
||||
if(thread != null){
|
||||
thread.interrupt();
|
||||
thread = null;
|
||||
}
|
||||
|
||||
thread = new Thread(this::runLogic);
|
||||
thread.setDaemon(true);
|
||||
thread.setName("Update Thread");
|
||||
thread.start();
|
||||
Log.info("Starting logic thread.");
|
||||
|
||||
this.enabled = true;
|
||||
});
|
||||
}else{
|
||||
this.enabled = false;
|
||||
if(thread != null){
|
||||
thread.interrupt();
|
||||
thread = null;
|
||||
}
|
||||
Timers.runTask(2f, () -> {
|
||||
logic.doUpdate = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public boolean doInterpolate(){
|
||||
return enabled && Gdx.graphics.getFramesPerSecond() - getTPS() > 20 && getTPS() < 30;
|
||||
}
|
||||
|
||||
public boolean isOnThread(){
|
||||
return Thread.currentThread() == thread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnLogicThread() {
|
||||
return !enabled || Thread.currentThread() == thread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnGraphicsThread() {
|
||||
return !enabled || Thread.currentThread() == graphicsThread;
|
||||
}
|
||||
|
||||
private void runLogic(){
|
||||
try{
|
||||
while(true){
|
||||
long time = TimeUtils.nanoTime();
|
||||
|
||||
while(true){
|
||||
Runnable r;
|
||||
synchronized(toRun){
|
||||
if(toRun.size > 0){
|
||||
r = toRun.removeFirst();
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
r.run();
|
||||
}
|
||||
|
||||
logic.doUpdate = true;
|
||||
logic.update();
|
||||
logic.doUpdate = false;
|
||||
|
||||
long elapsed = TimeUtils.nanosToMillis(TimeUtils.timeSinceNanos(time));
|
||||
long target = (long) ((1000) / 60f);
|
||||
|
||||
if(elapsed < target){
|
||||
Thread.sleep(target - elapsed);
|
||||
}
|
||||
|
||||
synchronized(updateLock){
|
||||
while(!rendered){
|
||||
updateLock.wait();
|
||||
}
|
||||
rendered = false;
|
||||
}
|
||||
|
||||
long actuallyElapsed = TimeUtils.nanosToMillis(TimeUtils.timeSinceNanos(time));
|
||||
delta = Math.max(actuallyElapsed, target) / 1000f * 60f;
|
||||
|
||||
if(TimeUtils.timeSinceMillis(lastDeltaUpdate) > 1000){
|
||||
lastDeltaUpdate = TimeUtils.millis();
|
||||
smoothDelta = delta;
|
||||
}
|
||||
|
||||
frame++;
|
||||
framesSinceUpdate = 0;
|
||||
}
|
||||
}catch(InterruptedException ex){
|
||||
Log.info("Stopping logic thread.");
|
||||
}catch(Throwable ex){
|
||||
control.setError(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import io.anuke.ucore.scene.ui.TextField.TextFieldFilter;
|
||||
import io.anuke.ucore.scene.ui.TooltipManager;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.Threads;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
import static io.anuke.ucore.scene.actions.Actions.*;
|
||||
@@ -155,6 +154,7 @@ public class UI extends SceneModule{
|
||||
load = new LoadDialog();
|
||||
levels = new CustomGameDialog();
|
||||
language = new LanguageDialog();
|
||||
unlocks = new UnlocksDialog();
|
||||
settings = new SettingsMenuDialog();
|
||||
host = new HostDialog();
|
||||
paused = new PausedDialog();
|
||||
@@ -165,7 +165,6 @@ public class UI extends SceneModule{
|
||||
traces = new TraceDialog();
|
||||
maps = new MapsDialog();
|
||||
localplayers = new LocalPlayerDialog();
|
||||
unlocks = new UnlocksDialog();
|
||||
content = new ContentInfoDialog();
|
||||
sectors = new SectorsDialog();
|
||||
missions = new MissionDialog();
|
||||
@@ -240,8 +239,6 @@ public class UI extends SceneModule{
|
||||
}
|
||||
|
||||
public void showInfoFade(String info){
|
||||
Threads.assertGraphics();
|
||||
|
||||
Table table = new Table();
|
||||
table.setFillParent(true);
|
||||
table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.removeActor());
|
||||
@@ -250,9 +247,7 @@ public class UI extends SceneModule{
|
||||
}
|
||||
|
||||
public void showInfo(String info){
|
||||
Threads.assertGraphics();
|
||||
|
||||
new Dialog("$text.info.title", "dialog"){{
|
||||
new Dialog("", "dialog"){{
|
||||
getCell(content()).growX();
|
||||
content().margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center);
|
||||
buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4);
|
||||
@@ -260,9 +255,7 @@ public class UI extends SceneModule{
|
||||
}
|
||||
|
||||
public void showInfo(String info, Runnable clicked){
|
||||
Threads.assertGraphics();
|
||||
|
||||
new Dialog("$text.info.title", "dialog"){{
|
||||
new Dialog("", "dialog"){{
|
||||
getCell(content()).growX();
|
||||
content().margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center);
|
||||
buttons().addButton("$text.ok", () -> {
|
||||
|
||||
@@ -16,6 +16,7 @@ import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Trail;
|
||||
import io.anuke.mindustry.io.TypeIO;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.NetConnection;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
@@ -70,7 +71,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
public TargetTrait moveTarget;
|
||||
|
||||
private float walktime;
|
||||
private Queue<BuildRequest> placeQueue = new ThreadQueue<>();
|
||||
private Queue<BuildRequest> placeQueue = new Queue<>();
|
||||
private Tile mining;
|
||||
private CarriableTrait carrying;
|
||||
private Trail trail = new Trail(12);
|
||||
@@ -292,7 +293,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
float x = snappedX(), y = snappedY();
|
||||
|
||||
if(!movement.isZero() && moved && !state.isPaused()){
|
||||
walktime += Timers.delta() * movement.len() / 0.7f * getFloorOn().speedMultiplier;
|
||||
walktime += movement.len() / 0.7f * getFloorOn().speedMultiplier;
|
||||
baseRotation = Mathf.slerpDelta(baseRotation, movement.angle(), 0.13f);
|
||||
}
|
||||
|
||||
@@ -421,55 +422,53 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
/**Draw all current build requests. Does not draw the beam effect, only the positions.*/
|
||||
public void drawBuildRequests(){
|
||||
synchronized(getPlaceQueue()){
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(getCurrentRequest() == request) continue;
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(getCurrentRequest() == request) continue;
|
||||
|
||||
if(request.breaking){
|
||||
Block block = world.tile(request.x, request.y).target().block();
|
||||
if(request.breaking){
|
||||
Block block = world.tile(request.x, request.y).target().block();
|
||||
|
||||
//draw removal request
|
||||
Lines.stroke(2f);
|
||||
//draw removal request
|
||||
Lines.stroke(2f);
|
||||
|
||||
Draw.color(Palette.removeBack);
|
||||
Draw.color(Palette.removeBack);
|
||||
|
||||
float rad = Mathf.absin(Timers.time(), 7f, 1f) + block.size * tilesize / 2f - 1;
|
||||
float rad = Mathf.absin(Timers.time(), 7f, 1f) + block.size * tilesize / 2f - 1;
|
||||
|
||||
Lines.square(
|
||||
request.x * tilesize + block.offset(),
|
||||
request.y * tilesize + block.offset() - 1,
|
||||
rad);
|
||||
Lines.square(
|
||||
request.x * tilesize + block.offset(),
|
||||
request.y * tilesize + block.offset() - 1,
|
||||
rad);
|
||||
|
||||
Draw.color(Palette.remove);
|
||||
Draw.color(Palette.remove);
|
||||
|
||||
Lines.square(
|
||||
request.x * tilesize + block.offset(),
|
||||
request.y * tilesize + block.offset(),
|
||||
rad);
|
||||
}else{
|
||||
//draw place request
|
||||
Lines.stroke(2f);
|
||||
Lines.square(
|
||||
request.x * tilesize + block.offset(),
|
||||
request.y * tilesize + block.offset(),
|
||||
rad);
|
||||
}else{
|
||||
//draw place request
|
||||
Lines.stroke(2f);
|
||||
|
||||
Draw.color(Palette.accentBack);
|
||||
Draw.color(Palette.accentBack);
|
||||
|
||||
float rad = Mathf.absin(Timers.time(), 7f, 1f) - 2f + request.recipe.result.size * tilesize / 2f;
|
||||
float rad = Mathf.absin(Timers.time(), 7f, 1f) - 2f + request.recipe.result.size * tilesize / 2f;
|
||||
|
||||
Lines.square(
|
||||
request.x * tilesize + request.recipe.result.offset(),
|
||||
request.y * tilesize + request.recipe.result.offset() - 1,
|
||||
rad);
|
||||
Lines.square(
|
||||
request.x * tilesize + request.recipe.result.offset(),
|
||||
request.y * tilesize + request.recipe.result.offset() - 1,
|
||||
rad);
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
Draw.color(Palette.accent);
|
||||
|
||||
Lines.square(
|
||||
request.x * tilesize + request.recipe.result.offset(),
|
||||
request.y * tilesize + request.recipe.result.offset(),
|
||||
rad);
|
||||
}
|
||||
Lines.square(
|
||||
request.x * tilesize + request.recipe.result.offset(),
|
||||
request.y * tilesize + request.recipe.result.offset(),
|
||||
rad);
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -551,8 +550,8 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
updateBuilding(this);
|
||||
|
||||
x = Mathf.clamp(x, 0, world.width() * tilesize);
|
||||
y = Mathf.clamp(y, 0, world.height() * tilesize);
|
||||
x = Mathf.clamp(x, tilesize, world.width() * tilesize - tilesize);
|
||||
y = Mathf.clamp(y, tilesize, world.height() * tilesize - tilesize);
|
||||
}
|
||||
|
||||
protected void updateMech(){
|
||||
@@ -609,11 +608,11 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
pointerY = vec.y;
|
||||
updateShooting();
|
||||
|
||||
movement.limit(speed * Timers.delta());
|
||||
movement.limit(speed).scl(Timers.delta());
|
||||
|
||||
if(getCarrier() == null){
|
||||
if(!ui.chatfrag.chatOpen()){
|
||||
velocity.add(movement);
|
||||
velocity.add(movement.x, movement.y);
|
||||
}
|
||||
float prex = x, prey = y;
|
||||
updateVelocityStatus();
|
||||
@@ -810,6 +809,12 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
//region read and write methods
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isClipped(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
stream.writeBoolean(isLocal);
|
||||
@@ -849,7 +854,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
@Override
|
||||
public void write(DataOutput buffer) throws IOException{
|
||||
super.writeSave(buffer, !isLocal);
|
||||
buffer.writeUTF(name); //TODO writing strings is very inefficient
|
||||
TypeIO.writeStringData(buffer, name); //TODO writing strings is very inefficient
|
||||
buffer.writeByte(Bits.toByte(isAdmin) | (Bits.toByte(dead) << 1) | (Bits.toByte(isBoosting) << 2));
|
||||
buffer.writeInt(Color.rgba8888(color));
|
||||
buffer.writeByte(mech.id);
|
||||
@@ -864,7 +869,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
public void read(DataInput buffer, long time) throws IOException{
|
||||
float lastx = x, lasty = y, lastrot = rotation;
|
||||
super.readSave(buffer);
|
||||
name = buffer.readUTF();
|
||||
name = TypeIO.readStringData(buffer);
|
||||
byte bools = buffer.readByte();
|
||||
isAdmin = (bools & 1) != 0;
|
||||
dead = (bools & 2) != 0;
|
||||
|
||||
@@ -259,27 +259,25 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
synchronized(Tile.tileSetLock){
|
||||
//TODO better smoke effect, this one is awful
|
||||
if(health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) &&
|
||||
Mathf.chance(0.009f * Timers.delta() * (1f - health / tile.block().health))){
|
||||
//TODO better smoke effect, this one is awful
|
||||
if(health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) &&
|
||||
Mathf.chance(0.009f * Timers.delta() * (1f - health / tile.block().health))){
|
||||
|
||||
Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4));
|
||||
}
|
||||
Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4));
|
||||
}
|
||||
|
||||
timeScaleDuration -= Timers.delta();
|
||||
if(timeScaleDuration <= 0f || !tile.block().canOverdrive){
|
||||
timeScale = 1f;
|
||||
}
|
||||
timeScaleDuration -= Timers.delta();
|
||||
if(timeScaleDuration <= 0f || !tile.block().canOverdrive){
|
||||
timeScale = 1f;
|
||||
}
|
||||
|
||||
if(health <= 0){
|
||||
onDeath();
|
||||
}
|
||||
Block previous = tile.block();
|
||||
tile.block().update(tile);
|
||||
if(tile.block() == previous && cons != null){
|
||||
cons.update(this);
|
||||
}
|
||||
if(health <= 0){
|
||||
onDeath();
|
||||
}
|
||||
Block previous = tile.block();
|
||||
tile.block().update(tile);
|
||||
if(tile.block() == previous && cons != null){
|
||||
cons.update(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
|
||||
status.update(this);
|
||||
|
||||
velocity.limit(getMaxVelocity()).scl(status.getSpeedMultiplier());
|
||||
velocity.limit(getMaxVelocity()).scl(1f + (status.getSpeedMultiplier()-1f) * Timers.delta());
|
||||
|
||||
if(isFlying()){
|
||||
x += velocity.x * Timers.delta();
|
||||
|
||||
@@ -13,7 +13,6 @@ import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.function.Predicate;
|
||||
import io.anuke.ucore.util.EnumSet;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Threads;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@@ -63,45 +62,20 @@ public class Units{
|
||||
|
||||
/**Can be called from any thread.*/
|
||||
public static boolean anyEntities(Rectangle rect){
|
||||
if(Threads.isLogic()){
|
||||
boolResult = false;
|
||||
boolResult = false;
|
||||
|
||||
Units.getNearby(rect, unit -> {
|
||||
if(boolResult) return;
|
||||
if(!unit.isFlying()){
|
||||
unit.getHitbox(hitrect);
|
||||
Units.getNearby(rect, unit -> {
|
||||
if(boolResult) return;
|
||||
if(!unit.isFlying()){
|
||||
unit.getHitbox(hitrect);
|
||||
|
||||
if(hitrect.overlaps(rect)){
|
||||
boolResult = true;
|
||||
}
|
||||
if(hitrect.overlaps(rect)){
|
||||
boolResult = true;
|
||||
}
|
||||
});
|
||||
|
||||
return boolResult;
|
||||
}else{
|
||||
boolResultGraphics = false;
|
||||
|
||||
for(EntityGroup<? extends BaseUnit> g : unitGroups){
|
||||
g.forEach(u -> {
|
||||
if(u.isFlying()) return;
|
||||
u.getHitbox(rectGraphics);
|
||||
if(rectGraphics.overlaps(rect)){
|
||||
boolResultGraphics = true;
|
||||
}
|
||||
});
|
||||
if(boolResultGraphics) return true;
|
||||
}
|
||||
});
|
||||
|
||||
playerGroup.forEach(u -> {
|
||||
if(u.isFlying()) return;
|
||||
u.getHitbox(rectGraphics);
|
||||
if(rectGraphics.overlaps(rect)){
|
||||
boolResultGraphics = true;
|
||||
}
|
||||
});
|
||||
|
||||
return boolResultGraphics;
|
||||
}
|
||||
return boolResult;
|
||||
}
|
||||
|
||||
/**Returns whether there are any entities on this tile, with the hitbox expanded.*/
|
||||
|
||||
@@ -84,30 +84,28 @@ public interface BuilderTrait extends Entity{
|
||||
}
|
||||
|
||||
default void readBuilding(DataInput input, boolean applyChanges) throws IOException{
|
||||
synchronized(getPlaceQueue()){
|
||||
if(applyChanges) getPlaceQueue().clear();
|
||||
if(applyChanges) getPlaceQueue().clear();
|
||||
|
||||
byte type = input.readByte();
|
||||
if(type != -1){
|
||||
int position = input.readInt();
|
||||
float progress = input.readFloat();
|
||||
BuildRequest request;
|
||||
byte type = input.readByte();
|
||||
if(type != -1){
|
||||
int position = input.readInt();
|
||||
float progress = input.readFloat();
|
||||
BuildRequest request;
|
||||
|
||||
if(type == 1){ //remove
|
||||
request = new BuildRequest(position % world.width(), position / world.width());
|
||||
}else{ //place
|
||||
byte recipe = input.readByte();
|
||||
byte rotation = input.readByte();
|
||||
request = new BuildRequest(position % world.width(), position / world.width(), rotation, content.recipe(recipe));
|
||||
}
|
||||
if(type == 1){ //remove
|
||||
request = new BuildRequest(position % world.width(), position / world.width());
|
||||
}else{ //place
|
||||
byte recipe = input.readByte();
|
||||
byte rotation = input.readByte();
|
||||
request = new BuildRequest(position % world.width(), position / world.width(), rotation, content.recipe(recipe));
|
||||
}
|
||||
|
||||
request.progress = progress;
|
||||
request.progress = progress;
|
||||
|
||||
if(applyChanges){
|
||||
getPlaceQueue().addLast(request);
|
||||
}else if(isBuilding()){
|
||||
getCurrentRequest().progress = progress;
|
||||
}
|
||||
if(applyChanges){
|
||||
getPlaceQueue().addLast(request);
|
||||
}else if(isBuilding()){
|
||||
getCurrentRequest().progress = progress;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,13 +120,11 @@ public interface BuilderTrait extends Entity{
|
||||
* Otherwise, a new place request is added to the queue.
|
||||
*/
|
||||
default void replaceBuilding(int x, int y, int rotation, Recipe recipe){
|
||||
synchronized(getPlaceQueue()){
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(request.x == x && request.y == y){
|
||||
clearBuilding();
|
||||
addBuildRequest(request);
|
||||
return;
|
||||
}
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(request.x == x && request.y == y){
|
||||
clearBuilding();
|
||||
addBuildRequest(request);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,18 +138,16 @@ public interface BuilderTrait extends Entity{
|
||||
|
||||
/**Add another build requests to the tail of the queue, if it doesn't exist there yet.*/
|
||||
default void addBuildRequest(BuildRequest place){
|
||||
synchronized(getPlaceQueue()){
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(request.x == place.x && request.y == place.y){
|
||||
return;
|
||||
}
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(request.x == place.x && request.y == place.y){
|
||||
return;
|
||||
}
|
||||
Tile tile = world.tile(place.x, place.y);
|
||||
if(tile != null && tile.entity instanceof BuildEntity){
|
||||
place.progress = tile.<BuildEntity>entity().progress;
|
||||
}
|
||||
getPlaceQueue().addLast(place);
|
||||
}
|
||||
Tile tile = world.tile(place.x, place.y);
|
||||
if(tile != null && tile.entity instanceof BuildEntity){
|
||||
place.progress = tile.<BuildEntity>entity().progress;
|
||||
}
|
||||
getPlaceQueue().addLast(place);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,9 +155,7 @@ public interface BuilderTrait extends Entity{
|
||||
* May return null.
|
||||
*/
|
||||
default BuildRequest getCurrentRequest(){
|
||||
synchronized(getPlaceQueue()){
|
||||
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
|
||||
}
|
||||
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -275,18 +267,15 @@ public interface BuilderTrait extends Entity{
|
||||
/**Draw placement effects for an entity. This includes mining*/
|
||||
default void drawBuilding(Unit unit){
|
||||
BuildRequest request;
|
||||
|
||||
synchronized(getPlaceQueue()){
|
||||
if(!isBuilding()){
|
||||
if(getMineTile() != null){
|
||||
drawMining(unit);
|
||||
}
|
||||
return;
|
||||
if(!isBuilding()){
|
||||
if(getMineTile() != null){
|
||||
drawMining(unit);
|
||||
}
|
||||
|
||||
request = getCurrentRequest();
|
||||
return;
|
||||
}
|
||||
|
||||
request = getCurrentRequest();
|
||||
|
||||
Tile tile = world.tile(request.x, request.y);
|
||||
|
||||
if(unit.distanceTo(tile) > placeDistance){
|
||||
@@ -311,10 +300,6 @@ public interface BuilderTrait extends Entity{
|
||||
|
||||
float x1 = tmptr[0].x, y1 = tmptr[0].y,
|
||||
x3 = tmptr[1].x, y3 = tmptr[1].y;
|
||||
Translator close = Geometry.findClosest(unit.x, unit.y, tmptr);
|
||||
float x2 = close.x, y2 = close.y;
|
||||
|
||||
Draw.alpha(0.3f + Mathf.absin(Timers.time(), 0.9f, 0.2f));
|
||||
|
||||
Draw.alpha(1f);
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.mindustry.core.NetClient;
|
||||
import io.anuke.mindustry.net.Interpolator;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.entities.trait.Entity;
|
||||
import io.anuke.ucore.util.Tmp;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
@@ -24,8 +27,21 @@ public interface SyncTrait extends Entity, TypeTrait{
|
||||
|
||||
/**Interpolate entity position only. Override if you need to interpolate rotations or other values.*/
|
||||
default void interpolate(){
|
||||
if(getInterpolator() == null)
|
||||
if(getInterpolator() == null){
|
||||
throw new RuntimeException("This entity must have an interpolator to interpolate()!");
|
||||
}
|
||||
|
||||
if(isClipped()){
|
||||
//move off screen when no longer in bounds
|
||||
Tmp.r1.setSize(Core.camera.viewportWidth * Core.camera.zoom * NetClient.viewScale,
|
||||
Core.camera.viewportHeight * Core.camera.zoom * NetClient.viewScale)
|
||||
.setCenter(Core.camera.position.x, Core.camera.position.y);
|
||||
|
||||
if(!Tmp.r1.contains(getX(), getY()) && !Tmp.r1.contains(getInterpolator().last.x, getInterpolator().last.y)){
|
||||
set(-99999f, -99999f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
getInterpolator().update();
|
||||
|
||||
|
||||
@@ -320,10 +320,8 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
|
||||
if(target != null) behavior();
|
||||
|
||||
if(!isWave && !isFlying()){
|
||||
x = Mathf.clamp(x, tilesize/2f, world.width() * tilesize - tilesize/2f);
|
||||
y = Mathf.clamp(y, tilesize/2f, world.height() * tilesize - tilesize/2f);
|
||||
}
|
||||
x = Mathf.clamp(x, tilesize, world.width() * tilesize - tilesize);
|
||||
y = Mathf.clamp(y, tilesize, world.height() * tilesize - tilesize);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -238,7 +238,7 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
}
|
||||
|
||||
protected void patrol(){
|
||||
vec.trns(baseRotation, type.speed);
|
||||
vec.trns(baseRotation, type.speed * Timers.delta());
|
||||
velocity.add(vec.x, vec.y);
|
||||
vec.trns(baseRotation, type.hitsizeTile);
|
||||
Tile tile = world.tileWorld(x + vec.x, y + vec.y);
|
||||
|
||||
@@ -40,12 +40,11 @@ import static io.anuke.mindustry.Vars.unitGroups;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Drone extends FlyingUnit implements BuilderTrait{
|
||||
protected static float discoverRange = 120f;
|
||||
protected static int timerRepairEffect = timerIndex++;
|
||||
|
||||
protected Item targetItem;
|
||||
protected Tile mineTile;
|
||||
protected Queue<BuildRequest> placeQueue = new ThreadQueue<>();
|
||||
protected Queue<BuildRequest> placeQueue = new Queue<>();
|
||||
protected boolean isBreaking;
|
||||
|
||||
public final UnitState
|
||||
@@ -250,14 +249,12 @@ public class Drone extends FlyingUnit implements BuilderTrait{
|
||||
for(BaseUnit unit : group.all()){
|
||||
if(unit instanceof Drone){
|
||||
Drone drone = (Drone)unit;
|
||||
synchronized(drone.getPlaceQueue()){
|
||||
if(drone.isBuilding()){
|
||||
//stop building if opposite building begins.
|
||||
BuildRequest req = drone.getCurrentRequest();
|
||||
if(req.breaking != event.breaking && req.x == event.tile.x && req.y == event.tile.y){
|
||||
drone.clearBuilding();
|
||||
drone.setState(drone.repair);
|
||||
}
|
||||
if(drone.isBuilding()){
|
||||
//stop building if opposite building begins.
|
||||
BuildRequest req = drone.getCurrentRequest();
|
||||
if(req.breaking != event.breaking && req.x == event.tile.x && req.y == event.tile.y){
|
||||
drone.clearBuilding();
|
||||
drone.setState(drone.repair);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,32 +106,29 @@ public class BlockRenderer{
|
||||
for(int x = minx; x <= maxx; x++){
|
||||
for(int y = miny; y <= maxy; y++){
|
||||
boolean expanded = (Math.abs(x - avgx) > rangex || Math.abs(y - avgy) > rangey);
|
||||
Tile tile = world.rawTile(x, y);
|
||||
|
||||
synchronized(Tile.tileSetLock){
|
||||
Tile tile = world.rawTile(x, y);
|
||||
if(tile != null){
|
||||
Block block = tile.block();
|
||||
Team team = tile.getTeam();
|
||||
|
||||
if(tile != null){
|
||||
Block block = tile.block();
|
||||
Team team = tile.getTeam();
|
||||
if(!expanded && block != Blocks.air && world.isAccessible(x, y)){
|
||||
tile.block().drawShadow(tile);
|
||||
}
|
||||
|
||||
if(!expanded && block != Blocks.air && world.isAccessible(x, y)){
|
||||
tile.block().drawShadow(tile);
|
||||
if(block != Blocks.air){
|
||||
if(!expanded){
|
||||
addRequest(tile, Layer.block);
|
||||
teamChecks.add(team.ordinal());
|
||||
}
|
||||
|
||||
if(block != Blocks.air){
|
||||
if(!expanded){
|
||||
addRequest(tile, Layer.block);
|
||||
teamChecks.add(team.ordinal());
|
||||
if(block.expanded || !expanded){
|
||||
if(block.layer != null && block.isLayer(tile)){
|
||||
addRequest(tile, block.layer);
|
||||
}
|
||||
|
||||
if(block.expanded || !expanded){
|
||||
if(block.layer != null && block.isLayer(tile)){
|
||||
addRequest(tile, block.layer);
|
||||
}
|
||||
|
||||
if(block.layer2 != null && block.isLayer2(tile)){
|
||||
addRequest(tile, block.layer2);
|
||||
}
|
||||
if(block.layer2 != null && block.isLayer2(tile)){
|
||||
addRequest(tile, block.layer2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,16 +168,14 @@ public class BlockRenderer{
|
||||
layerBegins(req.layer);
|
||||
}
|
||||
|
||||
synchronized(Tile.tileSetLock){
|
||||
Block block = req.tile.block();
|
||||
Block block = req.tile.block();
|
||||
|
||||
if(req.layer == Layer.block){
|
||||
block.draw(req.tile);
|
||||
}else if(req.layer == block.layer){
|
||||
block.drawLayer(req.tile);
|
||||
}else if(req.layer == block.layer2){
|
||||
block.drawLayer2(req.tile);
|
||||
}
|
||||
if(req.layer == Layer.block){
|
||||
block.draw(req.tile);
|
||||
}else if(req.layer == block.layer){
|
||||
block.drawLayer(req.tile);
|
||||
}else if(req.layer == block.layer2){
|
||||
block.drawLayer2(req.tile);
|
||||
}
|
||||
|
||||
lastLayer = req.layer;
|
||||
@@ -199,17 +194,16 @@ public class BlockRenderer{
|
||||
BlockRequest req = requests.get(index);
|
||||
if(req.tile.getTeam() != team) continue;
|
||||
|
||||
synchronized(Tile.tileSetLock){
|
||||
Block block = req.tile.block();
|
||||
Block block = req.tile.block();
|
||||
|
||||
if(req.layer == Layer.block){
|
||||
block.draw(req.tile);
|
||||
}else if(req.layer == block.layer){
|
||||
block.drawLayer(req.tile);
|
||||
}else if(req.layer == block.layer2){
|
||||
block.drawLayer2(req.tile);
|
||||
}
|
||||
if(req.layer == Layer.block){
|
||||
block.draw(req.tile);
|
||||
}else if(req.layer == block.layer){
|
||||
block.drawLayer(req.tile);
|
||||
}else if(req.layer == block.layer2){
|
||||
block.drawLayer2(req.tile);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,20 +74,18 @@ public class MinimapRenderer implements Disposable{
|
||||
dx = Mathf.clamp(dx, sz, world.width() - sz);
|
||||
dy = Mathf.clamp(dy, sz, world.height() - sz);
|
||||
|
||||
synchronized(units){
|
||||
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
|
||||
Graphics.beginClip(x, y, w, h);
|
||||
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
|
||||
Graphics.beginClip(x, y, w, h);
|
||||
|
||||
for(Unit unit : units){
|
||||
float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y) / rect.width * h;
|
||||
Draw.color(unit.getTeam().color);
|
||||
Draw.rect("white", x + rx, y + ry, w / (sz * 2), h / (sz * 2));
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
|
||||
Graphics.endClip();
|
||||
for(Unit unit : units){
|
||||
float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y) / rect.width * h;
|
||||
Draw.color(unit.getTeam().color);
|
||||
Draw.crect(Draw.getBlankRegion(), x + rx, y + ry, w / (sz * 2), h / (sz * 2));
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
|
||||
Graphics.endClip();
|
||||
}
|
||||
|
||||
public TextureRegion getRegion(){
|
||||
@@ -128,11 +126,9 @@ public class MinimapRenderer implements Disposable{
|
||||
dx = Mathf.clamp(dx, sz, world.width() - sz);
|
||||
dy = Mathf.clamp(dy, sz, world.height() - sz);
|
||||
|
||||
synchronized(units){
|
||||
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
|
||||
units.clear();
|
||||
Units.getNearby(rect, units::add);
|
||||
}
|
||||
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
|
||||
units.clear();
|
||||
Units.getNearby(rect, units::add);
|
||||
}
|
||||
|
||||
private int colorFor(Tile tile){
|
||||
|
||||
@@ -53,10 +53,7 @@ public class OverlayRenderer{
|
||||
//draw config selected block
|
||||
if(input.frag.config.isShown()){
|
||||
Tile tile = input.frag.config.getSelectedTile();
|
||||
|
||||
synchronized(Tile.tileSetLock){
|
||||
tile.block().drawConfigure(tile);
|
||||
}
|
||||
tile.block().drawConfigure(tile);
|
||||
}
|
||||
|
||||
input.drawTop();
|
||||
@@ -113,53 +110,52 @@ public class OverlayRenderer{
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
synchronized(Tile.tileSetLock){
|
||||
Block block = target.block();
|
||||
TileEntity entity = target.entity;
|
||||
Block block = target.block();
|
||||
TileEntity entity = target.entity;
|
||||
|
||||
if(entity != null){
|
||||
int[] values = {0, 0};
|
||||
boolean[] doDraw = {false};
|
||||
if(entity != null){
|
||||
int[] values = {0, 0};
|
||||
boolean[] doDraw = {false};
|
||||
|
||||
Runnable drawbars = () -> {
|
||||
for(BlockBar bar : block.bars.list()){
|
||||
float offset = Mathf.sign(bar.top) * (block.size / 2f * tilesize + 2f + (bar.top ? values[0] : values[1]));
|
||||
Runnable drawbars = () -> {
|
||||
for(BlockBar bar : block.bars.list()){
|
||||
float offset = Mathf.sign(bar.top) * (block.size / 2f * tilesize + 2f + (bar.top ? values[0] : values[1]));
|
||||
|
||||
float value = bar.value.get(target);
|
||||
float value = bar.value.get(target);
|
||||
|
||||
if(MathUtils.isEqual(value, -1f)) continue;
|
||||
if(MathUtils.isEqual(value, -1f)) continue;
|
||||
|
||||
if(doDraw[0]){
|
||||
drawBar(bar.type.color, target.drawx(), target.drawy() + offset, value);
|
||||
}
|
||||
|
||||
if(bar.top)
|
||||
values[0]++;
|
||||
else
|
||||
values[1]++;
|
||||
if(doDraw[0]){
|
||||
drawBar(bar.type.color, target.drawx(), target.drawy() + offset, value);
|
||||
}
|
||||
};
|
||||
|
||||
drawbars.run();
|
||||
|
||||
if(values[0] > 0){
|
||||
drawEncloser(target.drawx(), target.drawy() + block.size * tilesize / 2f + 2f, values[0]);
|
||||
if(bar.top)
|
||||
values[0]++;
|
||||
else
|
||||
values[1]++;
|
||||
}
|
||||
};
|
||||
|
||||
if(values[1] > 0){
|
||||
drawEncloser(target.drawx(), target.drawy() - block.size * tilesize / 2f - 2f - values[1], values[1]);
|
||||
}
|
||||
drawbars.run();
|
||||
|
||||
doDraw[0] = true;
|
||||
values[0] = 0;
|
||||
values[1] = 1;
|
||||
|
||||
drawbars.run();
|
||||
if(values[0] > 0){
|
||||
drawEncloser(target.drawx(), target.drawy() + block.size * tilesize / 2f + 2f, values[0]);
|
||||
}
|
||||
|
||||
if(values[1] > 0){
|
||||
drawEncloser(target.drawx(), target.drawy() - block.size * tilesize / 2f - 2f - values[1], values[1]);
|
||||
}
|
||||
|
||||
target.block().drawSelect(target);
|
||||
doDraw[0] = true;
|
||||
values[0] = 0;
|
||||
values[1] = 1;
|
||||
|
||||
drawbars.run();
|
||||
}
|
||||
|
||||
|
||||
target.block().drawSelect(target);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public class Trail{
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public synchronized void update(float curx, float cury){
|
||||
public void update(float curx, float cury){
|
||||
if(Vector2.dst(curx, cury, lastX, lastY) >= maxJump){
|
||||
points.clear();
|
||||
}
|
||||
@@ -39,11 +39,11 @@ public class Trail{
|
||||
lastY = cury;
|
||||
}
|
||||
|
||||
public synchronized void clear(){
|
||||
public void clear(){
|
||||
points.clear();
|
||||
}
|
||||
|
||||
public synchronized void draw(Color color, float stroke){
|
||||
public void draw(Color color, float stroke){
|
||||
Draw.color(color);
|
||||
|
||||
for(int i = 0; i < points.size - 2; i += 2){
|
||||
|
||||
@@ -23,15 +23,18 @@ import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Effects.Effect;
|
||||
import io.anuke.ucore.entities.Entities;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
/** Class for specifying read/write methods for code generation.*/
|
||||
@SuppressWarnings("unused")
|
||||
public class TypeIO{
|
||||
private static final Charset charset = Charset.forName("UTF-8");
|
||||
|
||||
@WriteClass(Player.class)
|
||||
public static void writePlayer(ByteBuffer buffer, Player player){
|
||||
@@ -329,19 +332,29 @@ public class TypeIO{
|
||||
@WriteClass(String.class)
|
||||
public static void writeString(ByteBuffer buffer, String string){
|
||||
if(string != null){
|
||||
Charset charset = Charset.defaultCharset();
|
||||
byte[] nameBytes = charset.name().getBytes(StandardCharsets.UTF_8);
|
||||
buffer.put((byte)nameBytes.length);
|
||||
buffer.put(nameBytes);
|
||||
|
||||
byte[] bytes = string.getBytes(charset);
|
||||
buffer.putShort((short) bytes.length);
|
||||
buffer.put(bytes);
|
||||
}else{
|
||||
buffer.putShort((short) -1);
|
||||
buffer.put((byte) -1);
|
||||
}
|
||||
}
|
||||
|
||||
@ReadClass(String.class)
|
||||
public static String readString(ByteBuffer buffer){
|
||||
short length = buffer.getShort();
|
||||
byte length = buffer.get();
|
||||
if(length != -1){
|
||||
byte[] bytes = new byte[length];
|
||||
byte[] cbytes = new byte[length];
|
||||
buffer.get(cbytes);
|
||||
Charset charset = Charset.forName(new String(cbytes, StandardCharsets.UTF_8));
|
||||
|
||||
short slength = buffer.getShort();
|
||||
byte[] bytes = new byte[slength];
|
||||
buffer.get(bytes);
|
||||
return new String(bytes, charset);
|
||||
}else{
|
||||
@@ -362,4 +375,35 @@ public class TypeIO{
|
||||
buffer.get(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static void writeStringData(DataOutput buffer, String string) throws IOException{
|
||||
if(string != null){
|
||||
Charset charset = Charset.defaultCharset();
|
||||
byte[] nameBytes = charset.name().getBytes(StandardCharsets.UTF_8);
|
||||
buffer.writeByte((byte)nameBytes.length);
|
||||
buffer.write(nameBytes);
|
||||
|
||||
byte[] bytes = string.getBytes(charset);
|
||||
buffer.writeShort((short) bytes.length);
|
||||
buffer.write(bytes);
|
||||
}else{
|
||||
buffer.writeByte((byte) -1);
|
||||
}
|
||||
}
|
||||
|
||||
public static String readStringData(DataInput buffer) throws IOException{
|
||||
byte length = buffer.readByte();
|
||||
if(length != -1){
|
||||
byte[] cbytes = new byte[length];
|
||||
buffer.readFully(cbytes);
|
||||
Charset charset = Charset.forName(new String(cbytes, StandardCharsets.UTF_8));
|
||||
|
||||
short slength = buffer.readShort();
|
||||
byte[] bytes = new byte[slength];
|
||||
buffer.readFully(bytes);
|
||||
return new String(bytes, charset);
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,8 @@ public class SectorPresets{
|
||||
Missions.blockRecipe(ProductionBlocks.waterExtractor),
|
||||
new ContentMission(Items.biomatter),
|
||||
Missions.blockRecipe(CraftingBlocks.biomatterCompressor),
|
||||
new ContentMission(Liquids.oil)
|
||||
new ContentMission(Liquids.oil),
|
||||
new BattleMission()
|
||||
),
|
||||
Array.with(Items.copper, Items.lead, Items.coal, Items.titanium)));
|
||||
}
|
||||
@@ -69,6 +70,8 @@ public class SectorPresets{
|
||||
return presets.get(x, y);
|
||||
}
|
||||
|
||||
public GridMap<SectorPreset> getPresets() { return presets; }
|
||||
|
||||
private void add(SectorPreset preset){
|
||||
presets.put(preset.x, preset.y, preset);
|
||||
orePresets.put(preset.x, preset.y, preset.ores);
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
package io.anuke.mindustry.maps.generation.pathfinding;
|
||||
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Queue;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.function.Predicate;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
|
||||
public class FlowPathFinder extends TilePathfinder{
|
||||
protected float[][] weights;
|
||||
|
||||
public FlowPathFinder(Tile[][] tiles){
|
||||
super(tiles);
|
||||
this.weights = new float[tiles.length][tiles[0].length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void search(Tile start, Tile end, Array<Tile> out){
|
||||
|
||||
}
|
||||
|
||||
public void search(Tile start, Predicate<Tile> result, Array<Tile> out){
|
||||
Queue<Tile> queue = new Queue<>();
|
||||
|
||||
for(int i = 0; i < weights.length; i++){
|
||||
for(int j = 0; j < weights[0].length; j++){
|
||||
if(result.test(tiles[i][j])){
|
||||
weights[i][j] = 100000;
|
||||
queue.addLast(tiles[i][j]);
|
||||
}else{
|
||||
weights[i][j] = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while(queue.size > 0){
|
||||
Tile tile = queue.first();
|
||||
for(GridPoint2 point : Geometry.d4){
|
||||
int nx = tile.x + point.x, ny = tile.y + point.y;
|
||||
if(inBounds(nx, ny) && weights[nx][ny] < weights[tile.x][tile.y] - 1f && tiles[nx][ny].passable()){
|
||||
weights[nx][ny] = weights[tile.x][tile.y] - 1;
|
||||
queue.addLast(tiles[nx][ny]);
|
||||
if(result.test(tiles[nx][ny])){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out.add(start);
|
||||
while(true){
|
||||
Tile tile = out.peek();
|
||||
|
||||
Tile max = null;
|
||||
float maxf = weights[tile.x][tile.y];
|
||||
for(GridPoint2 point : Geometry.d4){
|
||||
int nx = tile.x + point.x, ny = tile.y + point.y;
|
||||
if(inBounds(nx, ny) && (weights[nx][ny] > maxf)){
|
||||
max = tiles[nx][ny];
|
||||
maxf = weights[nx][ny];
|
||||
|
||||
if(MathUtils.isEqual(maxf, 100000)){
|
||||
out.add(max);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(max == null){
|
||||
break;
|
||||
}
|
||||
out.add(max);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package io.anuke.mindustry.maps.generation.pathfinding;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.util.Structs;
|
||||
|
||||
public abstract class TilePathfinder{
|
||||
protected Tile[][] tiles;
|
||||
|
||||
public TilePathfinder(Tile[][] tiles){
|
||||
this.tiles = tiles;
|
||||
}
|
||||
|
||||
protected boolean inBounds(int x, int y){
|
||||
return Structs.inBounds(x, y, tiles);
|
||||
}
|
||||
|
||||
public abstract void search(Tile start, Tile end, Array<Tile> out);
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
package io.anuke.mindustry.maps.missions;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.game.GameMode;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.Waves;
|
||||
import io.anuke.mindustry.maps.Sector;
|
||||
import io.anuke.mindustry.maps.generation.Generation;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -62,9 +60,9 @@ public class WaveMission extends MissionWithStartingCore{
|
||||
public String displayString(){
|
||||
return state.wave > target ?
|
||||
Bundles.format(
|
||||
Vars.unitGroups[Vars.waveTeam.ordinal()].size() > 1 && !Net.client() ?
|
||||
state.enemies() > 1 ?
|
||||
"text.mission.wave.enemies" :
|
||||
"text.mission.wave.enemy", target, target, Vars.unitGroups[Vars.waveTeam.ordinal()].size()) :
|
||||
"text.mission.wave.enemy", target, target, state.enemies()) :
|
||||
Bundles.format("text.mission.wave", state.wave, target, (int)(state.wavetime/60));
|
||||
}
|
||||
|
||||
@@ -82,6 +80,6 @@ public class WaveMission extends MissionWithStartingCore{
|
||||
|
||||
@Override
|
||||
public boolean isComplete(){
|
||||
return state.wave > target && Vars.unitGroups[Vars.waveTeam.ordinal()].size() == 0;
|
||||
return state.wave > target && state.enemies() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Log;
|
||||
import io.anuke.ucore.util.Pooling;
|
||||
import io.anuke.ucore.util.Threads;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -51,7 +50,6 @@ public class Net{
|
||||
public static void showError(Throwable e){
|
||||
|
||||
if(!headless){
|
||||
Threads.assertGraphics();
|
||||
|
||||
Throwable t = e;
|
||||
while(t.getCause() != null){
|
||||
@@ -59,7 +57,7 @@ public class Net{
|
||||
}
|
||||
|
||||
String error = t.getMessage() == null ? "" : t.getMessage().toLowerCase();
|
||||
String type = error.getClass().toString().toLowerCase();
|
||||
String type = t.getClass().toString().toLowerCase();
|
||||
|
||||
if(error.equals("mismatch")){
|
||||
error = Bundles.get("text.error.mismatch");
|
||||
|
||||
@@ -145,9 +145,6 @@ public class NetworkIO{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether a custom map is expected, and thus whether the client should wait for additional data.
|
||||
*/
|
||||
public static void loadWorld(InputStream is){
|
||||
|
||||
Player player = players[0];
|
||||
@@ -165,6 +162,8 @@ public class NetworkIO{
|
||||
world.sectors.createSector(Bits.getLeftShort(sector), Bits.getRightShort(sector));
|
||||
world.setSector(world.sectors.get(sector));
|
||||
world.getSector().completedMissions = missions;
|
||||
}else{
|
||||
world.setSector(null);
|
||||
}
|
||||
|
||||
ObjectMap<String, String> tags = new ObjectMap<>();
|
||||
|
||||
@@ -18,7 +18,7 @@ public class Liquid extends UnlockableContent{
|
||||
public float flammability;
|
||||
/**temperature: 0.5 is 'room' temperature, 0 is very cold, 1 is molten hot*/
|
||||
public float temperature = 0.5f;
|
||||
/**how much heat this liquid can store. 0.75=water (high), anything lower is probably less dense and bad at cooling.*/
|
||||
/**how much heat this liquid can store. 0.4=water (decent), anything lower is probably less dense and bad at cooling.*/
|
||||
public float heatCapacity = 0.5f;
|
||||
/**how thick this liquid is. 0.5=water (relatively viscous), 1 would be something like tar (very slow)*/
|
||||
public float viscosity = 0.5f;
|
||||
|
||||
@@ -8,13 +8,13 @@ public class Links{
|
||||
|
||||
private static void createLinks(){
|
||||
links = new LinkEntry[]{
|
||||
new LinkEntry("discord", "https://discord.gg/BKADYds", Color.valueOf("7289da")),
|
||||
new LinkEntry("trello", "https://trello.com/b/aE2tcUwF", Color.valueOf("026aa7")),
|
||||
new LinkEntry("wiki", "http://mindustry.wikia.com/wiki/Mindustry_Wiki", Color.valueOf("0f142f")),
|
||||
new LinkEntry("itch.io", "https://anuke.itch.io/mindustry", Color.valueOf("fa5c5c")),
|
||||
new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Color.valueOf("689f38")),
|
||||
new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Color.valueOf("24292e")),
|
||||
new LinkEntry("dev-builds", "https://github.com/Anuken/Mindustry/wiki", Color.valueOf("fafbfc"))
|
||||
new LinkEntry("discord", "https://discord.gg/BKADYds", Color.valueOf("7289da")),
|
||||
new LinkEntry("trello", "https://trello.com/b/aE2tcUwF", Color.valueOf("026aa7")),
|
||||
new LinkEntry("wiki", "http://mindustry.wikia.com/wiki/Mindustry_Wiki", Color.valueOf("0f142f")),
|
||||
new LinkEntry("itch.io", "https://anuke.itch.io/mindustry", Color.valueOf("fa5c5c")),
|
||||
new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Color.valueOf("689f38")),
|
||||
new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Color.valueOf("24292e")),
|
||||
new LinkEntry("dev-builds", "https://jenkins.hellomouse.net/job/mindustry/", Color.valueOf("fafbfc"))
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
52
core/src/io/anuke/mindustry/ui/SelectionTable.java
Normal file
52
core/src/io/anuke/mindustry/ui/SelectionTable.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.scene.style.TextureRegionDrawable;
|
||||
import io.anuke.ucore.scene.ui.Image;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class SelectionTable extends Table{
|
||||
Tile lastTile;
|
||||
|
||||
public SelectionTable(){
|
||||
super("clear");
|
||||
|
||||
margin(5f);
|
||||
|
||||
update(() -> {
|
||||
Block result;
|
||||
Tile tile = world.tileWorld(Graphics.mouseWorld().x, Graphics.mouseWorld().y);
|
||||
if(tile != null){
|
||||
tile = tile.target();
|
||||
result = tile.block().synthetic() ? tile.block() : tile.floor() instanceof OreBlock ? tile.floor() : null;
|
||||
}else{
|
||||
result = null;
|
||||
}
|
||||
|
||||
if(result != null){
|
||||
lastTile = tile;
|
||||
}
|
||||
|
||||
getTranslation().y = Mathf.lerp(getTranslation().y, result == null ? -getHeight() : 0f, 0.2f);
|
||||
});
|
||||
|
||||
Image image = new Image(new TextureRegionDrawable(new TextureRegion(Draw.region("clear"))));
|
||||
image.update(() ->
|
||||
((TextureRegionDrawable)image.getDrawable()).setRegion(lastTile == null ? Draw.getBlankRegion() :
|
||||
(lastTile.block().synthetic() ? lastTile.block() : lastTile.floor()).getDisplayIcon(lastTile)));
|
||||
|
||||
add(image).size(8*5).padRight(4);
|
||||
label(() -> lastTile == null ? "" : (lastTile.block().synthetic() ? lastTile.block() : lastTile.floor()).getDisplayName(lastTile));
|
||||
|
||||
pack();
|
||||
getTranslation().y = - getHeight();
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import io.anuke.ucore.scene.ui.layout.Cell;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.scene.utils.UIUtils;
|
||||
import io.anuke.ucore.util.OS;
|
||||
import io.anuke.ucore.util.Strings;
|
||||
|
||||
import static io.anuke.mindustry.Vars.ios;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
@@ -55,7 +56,7 @@ public class AboutDialog extends FloatingDialog{
|
||||
}).size(h - 5, h);
|
||||
|
||||
table.table(inset -> {
|
||||
inset.add("[accent]" + link.name.replace("-", " ")).growX().left();
|
||||
inset.add("[accent]" + Strings.capitalize(link.name.replace("-", " "))).growX().left();
|
||||
inset.row();
|
||||
inset.labelWrap(link.description).width(w - 100f).color(Color.LIGHT_GRAY).growX();
|
||||
}).padLeft(8);
|
||||
@@ -93,7 +94,7 @@ public class AboutDialog extends FloatingDialog{
|
||||
public void showCredits(){
|
||||
FloatingDialog dialog = new FloatingDialog("$text.credits");
|
||||
dialog.addCloseButton();
|
||||
dialog.content().add("$text.credits.text");
|
||||
dialog.content().labelWrap("$text.credits.text").width(400f);
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,9 @@ public class PausedDialog extends FloatingDialog{
|
||||
hide();
|
||||
});
|
||||
|
||||
content().row();
|
||||
content().addButton("$text.unlocks", ui.unlocks::show);
|
||||
|
||||
content().row();
|
||||
content().addButton("$text.settings", ui.settings::show);
|
||||
|
||||
|
||||
@@ -190,11 +190,6 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
});
|
||||
|
||||
graphics.sliderPref("fpscap", 125, 5, 125, 5, s -> (s > 120 ? Bundles.get("setting.fpscap.none") : Bundles.format("setting.fpscap.text", s)));
|
||||
graphics.checkPref("multithread", mobile, threads::setEnabled);
|
||||
|
||||
if(Settings.getBool("multithread")){
|
||||
threads.setEnabled(true);
|
||||
}
|
||||
|
||||
if(!mobile){
|
||||
graphics.checkPref("vsync", true, b -> Gdx.graphics.setVSync(b));
|
||||
|
||||
@@ -36,7 +36,7 @@ public class BlockConsumeFragment extends Fragment{
|
||||
tile = tile.target();
|
||||
|
||||
if(tile != lastTile){
|
||||
if(tile.block().consumes.hasAny()){
|
||||
if(tile.getTeam() == players[0].getTeam() && tile.block().consumes.hasAny()){
|
||||
show(tile);
|
||||
}else if(visible){
|
||||
hide();
|
||||
|
||||
@@ -128,7 +128,7 @@ public class BlocksFragment extends Fragment{
|
||||
recipeTable.margin(4).top().left().marginRight(15);
|
||||
|
||||
//add a new row here when needed
|
||||
if(cati == secrows){
|
||||
if(cati % secrows == 0){
|
||||
catTable = new Table();
|
||||
selectTable.row();
|
||||
selectTable.add(catTable).colspan(secrows).padTop(-5).growX();
|
||||
|
||||
@@ -16,6 +16,7 @@ import io.anuke.mindustry.net.Packets.AdminAction;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.ui.IntFormat;
|
||||
import io.anuke.mindustry.ui.Minimap;
|
||||
import io.anuke.mindustry.ui.SelectionTable;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.ucore.core.*;
|
||||
import io.anuke.ucore.graphics.Hue;
|
||||
@@ -107,7 +108,7 @@ public class HudFragment extends Fragment{
|
||||
|
||||
Stack stack = new Stack();
|
||||
TextButton waves = new TextButton("");
|
||||
Table btable = new Table().margin(14);
|
||||
Table btable = new Table().margin(0);
|
||||
|
||||
stack.add(waves);
|
||||
stack.add(btable);
|
||||
@@ -126,7 +127,6 @@ public class HudFragment extends Fragment{
|
||||
IntFormat tps = new IntFormat("text.tps");
|
||||
IntFormat ping = new IntFormat("text.ping");
|
||||
t.label(() -> fps.get(Gdx.graphics.getFramesPerSecond())).padRight(10);
|
||||
t.label(() -> tps.get(threads.getTPS())).visible(() -> threads.isEnabled());
|
||||
t.row();
|
||||
if(Net.hasClient()){
|
||||
t.label(() -> ping.get(Net.getPing())).visible(Net::client).colspan(2);
|
||||
@@ -199,6 +199,12 @@ public class HudFragment extends Fragment{
|
||||
t.add("$text.saveload");
|
||||
});
|
||||
|
||||
//tapped block indicator
|
||||
parent.fill(t -> {
|
||||
t.bottom().visible(() -> !state.is(State.menu));
|
||||
t.add(new SelectionTable());
|
||||
});
|
||||
|
||||
blockfrag.build(Core.scene.getRoot());
|
||||
}
|
||||
|
||||
@@ -367,15 +373,15 @@ public class HudFragment extends Fragment{
|
||||
|
||||
table.labelWrap(() ->
|
||||
world.getSector() == null ?
|
||||
(unitGroups[waveTeam.ordinal()].size() > 0 && state.mode.disableWaveTimer ?
|
||||
wavef.get(state.wave) + "\n" + (unitGroups[waveTeam.ordinal()].size() == 1 ?
|
||||
enemyf.get(unitGroups[waveTeam.ordinal()].size()) :
|
||||
enemiesf.get(unitGroups[waveTeam.ordinal()].size())) :
|
||||
(state.enemies() > 0 && state.mode.disableWaveTimer ?
|
||||
wavef.get(state.wave) + "\n" + (state.enemies() == 1 ?
|
||||
enemyf.get(state.enemies()) :
|
||||
enemiesf.get(state.enemies())) :
|
||||
wavef.get(state.wave) + "\n" +
|
||||
(!state.mode.disableWaveTimer ?
|
||||
Bundles.format("text.wave.waiting", (int)(state.wavetime/60)) :
|
||||
Bundles.get("text.waiting"))) :
|
||||
Bundles.format("text.mission.display", world.getSector().currentMission().displayString())).growX();
|
||||
Bundles.format("text.mission.display", world.getSector().currentMission().displayString())).growX().pad(8f);
|
||||
|
||||
table.clicked(() -> {
|
||||
if(world.getSector() != null && world.getSector().currentMission().hasMessage()){
|
||||
|
||||
@@ -97,7 +97,7 @@ public class PlayerListFragment extends Fragment{
|
||||
button.labelWrap("[#" + player.color.toString().toUpperCase() + "]" + player.name).width(170f).pad(10);
|
||||
button.add().grow();
|
||||
|
||||
button.addImage("icon-admin").size(14 * 2).visible(() -> player.isAdmin && !(!player.isLocal && Net.server())).padRight(5);
|
||||
button.addImage("icon-admin").size(14 * 2).visible(() -> player.isAdmin && !(!player.isLocal && Net.server())).padRight(5).get().updateVisibility();
|
||||
|
||||
if((Net.server() || players[0].isAdmin) && !player.isLocal && (!player.isAdmin || Net.server())){
|
||||
button.add().growY();
|
||||
@@ -124,12 +124,13 @@ public class PlayerListFragment extends Fragment{
|
||||
}else{
|
||||
ui.showConfirm("$text.confirm", "$text.confirmadmin", () -> netServer.admins.adminPlayer(id, player.usid));
|
||||
}
|
||||
}).update(b -> {
|
||||
b.setChecked(player.isAdmin);
|
||||
b.setDisabled(Net.client());
|
||||
}).get().setTouchable(() -> Net.client() ? Touchable.disabled : Touchable.enabled);
|
||||
})
|
||||
.update(b -> b.setChecked(player.isAdmin))
|
||||
.disabled(b -> Net.client())
|
||||
.touchable(() -> Net.client() ? Touchable.disabled : Touchable.enabled)
|
||||
.checked(player.isAdmin);
|
||||
|
||||
t.addImageButton("icon-zoom-small", 14 * 2, () -> Call.onAdminRequest(player, AdminAction.trace));
|
||||
t.addImageButton("icon-zoom-small", 14 * 2, () -> ui.showError("Currently unimplemented.")/*Call.onAdminRequest(player, AdminAction.trace)*/);
|
||||
|
||||
}).padRight(12).padTop(-5).padLeft(0).padBottom(-10).size(bs + 10f, bs);
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ public abstract class BaseBlock extends MappableContent{
|
||||
|
||||
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
|
||||
return hasLiquids && tile.entity.liquids.get(liquid) + amount < liquidCapacity &&
|
||||
(!singleLiquid || (tile.entity.liquids.current() == liquid || tile.entity.liquids.get(tile.entity.liquids.current()) < 0.01f)) &&
|
||||
(!singleLiquid || (tile.entity.liquids.current() == liquid || tile.entity.liquids.get(tile.entity.liquids.current()) < 0.2f)) &&
|
||||
(!consumes.has(ConsumeLiquid.class) || consumes.liquid() == liquid);
|
||||
}
|
||||
|
||||
|
||||
@@ -452,6 +452,14 @@ public class Block extends BaseBlock {
|
||||
}
|
||||
}
|
||||
|
||||
public String getDisplayName(Tile tile){
|
||||
return formalName;
|
||||
}
|
||||
|
||||
public TextureRegion getDisplayIcon(Tile tile){
|
||||
return getEditorIcon();
|
||||
}
|
||||
|
||||
public TextureRegion getEditorIcon(){
|
||||
if(editorIcon == null){
|
||||
editorIcon = Draw.region("block-icon-" + name, Draw.region("clear"));
|
||||
|
||||
@@ -17,7 +17,6 @@ import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Build{
|
||||
private static final Rectangle rect = new Rectangle();
|
||||
private static final Rectangle hitrect = new Rectangle();
|
||||
|
||||
/**Returns block type that was broken, or null if unsuccesful.*/
|
||||
public static void beginBreak(Team team, int x, int y){
|
||||
|
||||
@@ -22,7 +22,6 @@ import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
|
||||
public class Tile implements PosTrait, TargetTrait{
|
||||
public static final Object tileSetLock = new Object();
|
||||
/**
|
||||
* The coordinates of the core tile this is linked to, in the form of two bytes packed into one.
|
||||
* This is relative to the block it is linked to; negate coords to find the link.
|
||||
@@ -147,33 +146,27 @@ public class Tile implements PosTrait, TargetTrait{
|
||||
}
|
||||
|
||||
public void setBlock(Block type, int rotation){
|
||||
synchronized(tileSetLock){
|
||||
preChanged();
|
||||
if(rotation < 0) rotation = (-rotation + 2);
|
||||
this.wall = type;
|
||||
this.link = 0;
|
||||
setRotation((byte) (rotation % 4));
|
||||
changed();
|
||||
}
|
||||
preChanged();
|
||||
if(rotation < 0) rotation = (-rotation + 2);
|
||||
this.wall = type;
|
||||
this.link = 0;
|
||||
setRotation((byte) (rotation % 4));
|
||||
changed();
|
||||
}
|
||||
|
||||
public void setBlock(Block type, Team team){
|
||||
synchronized(tileSetLock){
|
||||
preChanged();
|
||||
this.wall = type;
|
||||
this.team = (byte)team.ordinal();
|
||||
this.link = 0;
|
||||
changed();
|
||||
}
|
||||
preChanged();
|
||||
this.wall = type;
|
||||
this.team = (byte)team.ordinal();
|
||||
this.link = 0;
|
||||
changed();
|
||||
}
|
||||
|
||||
public void setBlock(Block type){
|
||||
synchronized(tileSetLock){
|
||||
preChanged();
|
||||
this.wall = type;
|
||||
this.link = 0;
|
||||
changed();
|
||||
}
|
||||
preChanged();
|
||||
this.wall = type;
|
||||
this.link = 0;
|
||||
changed();
|
||||
}
|
||||
|
||||
public void setFloor(Floor type){
|
||||
@@ -270,7 +263,7 @@ public class Tile implements PosTrait, TargetTrait{
|
||||
* Returns the list of all tiles linked to this multiblock, or an empty array if it's not a multiblock.
|
||||
* This array contains all linked tiles, including this tile itself.
|
||||
*/
|
||||
public synchronized Array<Tile> getLinkedTiles(Array<Tile> tmpArray){
|
||||
public Array<Tile> getLinkedTiles(Array<Tile> tmpArray){
|
||||
Block block = block();
|
||||
tmpArray.clear();
|
||||
if(block.isMultiblock()){
|
||||
@@ -292,7 +285,7 @@ public class Tile implements PosTrait, TargetTrait{
|
||||
* Returns the list of all tiles linked to this multiblock if it were this block, or an empty array if it's not a multiblock.
|
||||
* This array contains all linked tiles, including this tile itself.
|
||||
*/
|
||||
public synchronized Array<Tile> getLinkedTilesAs(Block block, Array<Tile> tmpArray){
|
||||
public Array<Tile> getLinkedTilesAs(Block block, Array<Tile> tmpArray){
|
||||
tmpArray.clear();
|
||||
if(block.isMultiblock()){
|
||||
int offsetx = -(block.size - 1) / 2;
|
||||
@@ -394,52 +387,47 @@ public class Tile implements PosTrait, TargetTrait{
|
||||
}
|
||||
|
||||
private void preChanged(){
|
||||
synchronized(tileSetLock){
|
||||
block().removed(this);
|
||||
if(entity != null){
|
||||
entity.removeFromProximity();
|
||||
}
|
||||
team = 0;
|
||||
block().removed(this);
|
||||
if(entity != null){
|
||||
entity.removeFromProximity();
|
||||
}
|
||||
team = 0;
|
||||
}
|
||||
|
||||
private void changed(){
|
||||
|
||||
synchronized(tileSetLock){
|
||||
if(entity != null){
|
||||
entity.remove();
|
||||
entity = null;
|
||||
}
|
||||
|
||||
Block block = block();
|
||||
|
||||
if(block.hasEntity()){
|
||||
entity = block.newEntity().init(this, block.update);
|
||||
entity.cons = new ConsumeModule();
|
||||
if(block.hasItems) entity.items = new ItemModule();
|
||||
if(block.hasLiquids) entity.liquids = new LiquidModule();
|
||||
if(block.hasPower){
|
||||
entity.power = new PowerModule();
|
||||
entity.power.graph.add(this);
|
||||
}
|
||||
|
||||
if(!world.isGenerating()){
|
||||
entity.updateProximity();
|
||||
}
|
||||
}else if(!(block instanceof BlockPart) && !world.isGenerating()){
|
||||
//since the entity won't update proximity for us, update proximity for all nearby tiles manually
|
||||
for(GridPoint2 p : Geometry.d4){
|
||||
Tile tile = world.tile(x + p.x, y + p.y);
|
||||
if(tile != null){
|
||||
tile = tile.target();
|
||||
tile.block().onProximityUpdate(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateOcclusion();
|
||||
if(entity != null){
|
||||
entity.remove();
|
||||
entity = null;
|
||||
}
|
||||
|
||||
Block block = block();
|
||||
|
||||
if(block.hasEntity()){
|
||||
entity = block.newEntity().init(this, block.update);
|
||||
entity.cons = new ConsumeModule();
|
||||
if(block.hasItems) entity.items = new ItemModule();
|
||||
if(block.hasLiquids) entity.liquids = new LiquidModule();
|
||||
if(block.hasPower){
|
||||
entity.power = new PowerModule();
|
||||
entity.power.graph.add(this);
|
||||
}
|
||||
|
||||
if(!world.isGenerating()){
|
||||
entity.updateProximity();
|
||||
}
|
||||
}else if(!(block instanceof BlockPart) && !world.isGenerating()){
|
||||
//since the entity won't update proximity for us, update proximity for all nearby tiles manually
|
||||
for(GridPoint2 p : Geometry.d4){
|
||||
Tile tile = world.tile(x + p.x, y + p.y);
|
||||
if(tile != null){
|
||||
tile = tile.target();
|
||||
tile.block().onProximityUpdate(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateOcclusion();
|
||||
|
||||
world.notifyChanged(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import io.anuke.mindustry.graphics.Layer;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.input.CursorType;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.world.BarType;
|
||||
@@ -26,6 +27,7 @@ import io.anuke.mindustry.world.modules.ItemModule;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import java.io.DataInput;
|
||||
@@ -68,6 +70,18 @@ public class BuildBlock extends Block{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName(Tile tile){
|
||||
BuildEntity entity = tile.entity();
|
||||
return Bundles.format("block.constructing", entity.recipe == null ? entity.previous.formalName : entity.recipe.result.formalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion getDisplayIcon(Tile tile){
|
||||
BuildEntity entity = tile.entity();
|
||||
return (entity.recipe == null ? entity.previous : entity.recipe.result).getEditorIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolidFor(Tile tile){
|
||||
BuildEntity entity = tile.entity();
|
||||
|
||||
@@ -24,6 +24,11 @@ public class OreBlock extends Floor{
|
||||
this.edge = base.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName(Tile tile){
|
||||
return drops.item.localizedName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion getEditorIcon(){
|
||||
if(editorIcon == null){
|
||||
|
||||
@@ -396,7 +396,7 @@ public class Conveyor extends Block{
|
||||
public void read(DataInput stream) throws IOException{
|
||||
convey.clear();
|
||||
int amount = stream.readInt();
|
||||
convey.ensureCapacity(amount);
|
||||
convey.ensureCapacity(Math.min(amount, 10));
|
||||
|
||||
for(int i = 0; i < amount; i++){
|
||||
convey.add(ItemPos.toLong(stream.readInt()));
|
||||
|
||||
@@ -1,363 +0,0 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.ObjectSet;
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.mindustry.content.Liquids;
|
||||
import io.anuke.mindustry.content.fx.BlockFx;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.PowerBlock;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Effects.Effect;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Fill;
|
||||
import io.anuke.ucore.graphics.Hue;
|
||||
import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.scene.ui.ButtonGroup;
|
||||
import io.anuke.ucore.scene.ui.ImageButton;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
//TODO implement
|
||||
public class WarpGate extends PowerBlock{
|
||||
public static final Color[] colorArray = {Color.ROYAL, Color.ORANGE, Color.SCARLET, Color.LIME,
|
||||
Color.PURPLE, Color.GOLD, Color.PINK, Color.LIGHT_GRAY};
|
||||
public static final int colors = colorArray.length;
|
||||
private static ObjectSet<Tile>[] teleporters = new ObjectSet[colors];
|
||||
private static Color color = new Color();
|
||||
private static byte lastColor = 0;
|
||||
|
||||
static{
|
||||
for(int i = 0; i < colors; i++){
|
||||
teleporters[i] = new ObjectSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
protected int timerTeleport = timers++;
|
||||
protected float warmupTime = 60f;
|
||||
//time between teleports
|
||||
protected float teleportMax = 400f;
|
||||
protected float teleportLiquidUse = 0.3f;
|
||||
protected Liquid inputLiquid = Liquids.cryofluid;
|
||||
protected Effect activateEffect = BlockFx.teleportActivate;
|
||||
protected Effect teleportEffect = BlockFx.teleport;
|
||||
protected Effect teleportOutEffect = BlockFx.teleportOut;
|
||||
private Array<Tile> removal = new Array<>();
|
||||
private Array<Tile> returns = new Array<>();
|
||||
|
||||
public WarpGate(String name){
|
||||
super(name);
|
||||
update = true;
|
||||
solid = true;
|
||||
health = 80;
|
||||
powerCapacity = 300f;
|
||||
size = 3;
|
||||
itemCapacity = 100;
|
||||
hasLiquids = true;
|
||||
hasItems = true;
|
||||
liquidCapacity = 100f;
|
||||
configurable = true;
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, forward = true)
|
||||
public static void setTeleporterColor(Player player, Tile tile, byte color){
|
||||
TeleporterEntity entity = tile.entity();
|
||||
entity.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerPlaced(Tile tile){
|
||||
Call.setTeleporterColor(null, tile, lastColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){
|
||||
super.draw(tile);
|
||||
|
||||
TeleporterEntity entity = tile.entity();
|
||||
float time = entity.time;
|
||||
float rad = entity.activeScl;
|
||||
|
||||
if(entity.liquidLackScl > 0.01f){
|
||||
Graphics.setAdditiveBlending();
|
||||
Draw.color(1f, 0.3f, 0.3f, 0.4f * entity.liquidLackScl);
|
||||
Fill.square(tile.drawx(), tile.drawy(), size * tilesize);
|
||||
Graphics.setNormalBlending();
|
||||
}
|
||||
|
||||
Draw.color(getColor(tile, 0));
|
||||
Draw.rect(name + "-top", tile.drawx(), tile.drawy());
|
||||
Draw.reset();
|
||||
|
||||
if(rad <= 0.0001f) return;
|
||||
|
||||
Draw.color(getColor(tile, 0));
|
||||
|
||||
Fill.circle(tile.drawx(), tile.drawy(), rad * (7f + Mathf.absin(time + 55, 8f, 1f)));
|
||||
|
||||
Draw.color(getColor(tile, -1));
|
||||
|
||||
Fill.circle(tile.drawx(), tile.drawy(), rad * (2f + Mathf.absin(time, 7f, 3f)));
|
||||
|
||||
for(int i = 0; i < 11; i++){
|
||||
Lines.swirl(tile.drawx(), tile.drawy(),
|
||||
rad * (2f + i / 3f + Mathf.sin(time - i * 75, 20f + i, 3f)),
|
||||
0.3f + Mathf.sin(time + i * 33, 10f + i, 0.1f),
|
||||
time * (1f + Mathf.randomSeedRange(i + 1, 1f)) + Mathf.randomSeedRange(i, 360f));
|
||||
}
|
||||
|
||||
Draw.color(getColor(tile, 1));
|
||||
|
||||
Lines.stroke(2f);
|
||||
Lines.circle(tile.drawx(), tile.drawy(), rad * (7f + Mathf.absin(time + 55, 8f, 1f)));
|
||||
Lines.stroke(1f);
|
||||
|
||||
for(int i = 0; i < 11; i++){
|
||||
Lines.swirl(tile.drawx(), tile.drawy(),
|
||||
rad * (3f + i / 3f + Mathf.sin(time + i * 93, 20f + i, 3f)),
|
||||
0.2f + Mathf.sin(time + i * 33, 10f + i, 0.1f),
|
||||
time * (1f + Mathf.randomSeedRange(i + 1, 1f)) + Mathf.randomSeedRange(i, 360f));
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
TeleporterEntity entity = tile.entity();
|
||||
|
||||
teleporters[entity.color].add(tile);
|
||||
|
||||
if(entity.items.total() > 0){
|
||||
tryDump(tile);
|
||||
}
|
||||
|
||||
if(!entity.active){
|
||||
entity.activeScl = Mathf.lerpDelta(entity.activeScl, 0f, 0.01f);
|
||||
|
||||
if(entity.power.amount >= powerCapacity){
|
||||
Color resultColor = new Color();
|
||||
resultColor.set(getColor(tile, 0));
|
||||
|
||||
entity.active = true;
|
||||
entity.power.amount = 0f;
|
||||
Effects.effect(activateEffect, resultColor, tile.drawx(), tile.drawy());
|
||||
}
|
||||
}else{
|
||||
entity.activeScl = Mathf.lerpDelta(entity.activeScl, 1f, 0.015f);
|
||||
/*
|
||||
|
||||
if (entity.power.amount >= powerUsed) {
|
||||
entity.power.amount -= powerUsed;
|
||||
entity.powerLackScl = Mathf.lerpDelta(entity.powerLackScl, 0f, 0.1f);
|
||||
}else{
|
||||
entity.power.amount = 0f;
|
||||
entity.powerLackScl = Mathf.lerpDelta(entity.powerLackScl, 1f, 0.1f);
|
||||
}
|
||||
|
||||
if(entity.powerLackScl >= 0.999f){
|
||||
catastrophicFailure(tile);
|
||||
}
|
||||
|
||||
if (entity.liquids.amount >= liquidUsed) {
|
||||
entity.liquids.amount -= liquidUsed;
|
||||
entity.liquidLackScl = Mathf.lerpDelta(entity.liquidLackScl, 0f, 0.1f);
|
||||
}else{
|
||||
entity.liquids.amount = 0f;
|
||||
entity.liquidLackScl = Mathf.lerpDelta(entity.liquidLackScl, 1f, 0.1f);
|
||||
}*/
|
||||
|
||||
if(entity.liquidLackScl >= 0.999f){
|
||||
catastrophicFailure(tile);
|
||||
}
|
||||
|
||||
//TODO draw warning info!
|
||||
|
||||
if(entity.teleporting){
|
||||
entity.speedScl = Mathf.lerpDelta(entity.speedScl, 2f, 0.01f);
|
||||
//liquidUsed = Math.min(liquidCapacity, teleportLiquidUse * Timers.delta());
|
||||
|
||||
//if (entity.liquids.amount >= liquidUsed) {
|
||||
// entity.liquids.amount -= liquidUsed;
|
||||
//} else {
|
||||
catastrophicFailure(tile);
|
||||
//}
|
||||
}else{
|
||||
entity.speedScl = Mathf.lerpDelta(entity.speedScl, 1f, 0.04f);
|
||||
}
|
||||
|
||||
entity.time += Timers.delta() * entity.speedScl;
|
||||
/*
|
||||
if (!entity.teleporting && entity.items.total() >= itemCapacity && entity.power.amount >= powerCapacity - 0.01f - powerUse &&
|
||||
entity.timer.get(timerTeleport, teleportMax)) {
|
||||
Array<Tile> testLinks = findLinks(tile);
|
||||
|
||||
if (testLinks.size == 0) return;
|
||||
|
||||
Color resultColor = new Color();
|
||||
resultColor.set(getColor(tile, 0));
|
||||
|
||||
entity.teleporting = true;
|
||||
|
||||
Effects.effect(teleportEffect, resultColor, tile.drawx(), tile.drawy());
|
||||
Timers.run(warmupTime, () -> {
|
||||
Array<Tile> links = findLinks(tile);
|
||||
|
||||
for (Tile other : links) {
|
||||
int canAccept = itemCapacity - other.entity.items.total();
|
||||
int total = entity.items.total();
|
||||
if (total == 0) break;
|
||||
Effects.effect(teleportOutEffect, resultColor, other.drawx(), other.drawy());
|
||||
for (int i = 0; i < canAccept && i < total; i++) {
|
||||
other.entity.items.add(entity.items.take(), 1);
|
||||
}
|
||||
}
|
||||
Effects.effect(teleportOutEffect, resultColor, tile.drawx(), tile.drawy());
|
||||
entity.power.amount = 0f;
|
||||
entity.teleporting = false;
|
||||
});
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildTable(Tile tile, Table table){
|
||||
TeleporterEntity entity = tile.entity();
|
||||
|
||||
//TODO call event for change
|
||||
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
Table cont = new Table();
|
||||
|
||||
for(int i = 0; i < colors; i++){
|
||||
final int f = i;
|
||||
ImageButton button = cont.addImageButton("white", "toggle", 24, () -> {
|
||||
lastColor = (byte) f;
|
||||
Call.setTeleporterColor(null, tile, (byte) f);
|
||||
}).size(34, 38).padBottom(-5.1f).group(group).get();
|
||||
button.getStyle().imageUpColor = colorArray[f];
|
||||
button.setChecked(entity.color == f);
|
||||
|
||||
if(i % 4 == 3){
|
||||
cont.row();
|
||||
}
|
||||
}
|
||||
|
||||
table.add(cont);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||
TeleporterEntity entity = tile.entity();
|
||||
return entity.items.total() < itemCapacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new TeleporterEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
|
||||
return super.acceptLiquid(tile, source, liquid, amount) && liquid == inputLiquid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyed(Tile tile){
|
||||
super.onDestroyed(tile);
|
||||
|
||||
TeleporterEntity entity = tile.entity();
|
||||
|
||||
if(entity.activeScl < 0.5f) return;
|
||||
|
||||
//TODO catastrophic failure
|
||||
}
|
||||
|
||||
private void catastrophicFailure(Tile tile){
|
||||
tile.entity.damage(tile.entity.health + 1);
|
||||
//TODO fail gloriously
|
||||
}
|
||||
|
||||
private Color getColor(Tile tile, int shift){
|
||||
TeleporterEntity entity = tile.entity();
|
||||
|
||||
Color target = colorArray[entity.color];
|
||||
float ss = 0.5f;
|
||||
float bs = 0.2f;
|
||||
|
||||
return Hue.shift(Hue.multiply(color.set(target), 1, ss), 2, shift * bs + (entity.speedScl - 1f) / 3f);
|
||||
}
|
||||
|
||||
private Array<Tile> findLinks(Tile tile){
|
||||
TeleporterEntity entity = tile.entity();
|
||||
|
||||
removal.clear();
|
||||
returns.clear();
|
||||
|
||||
for(Tile other : teleporters[entity.color]){
|
||||
if(other != tile){
|
||||
if(other.block() instanceof WarpGate){
|
||||
TeleporterEntity oe = other.entity();
|
||||
if(!oe.active) continue;
|
||||
if(oe.color != entity.color){
|
||||
removal.add(other);
|
||||
}else if(other.entity.items.total() == 0){
|
||||
returns.add(other);
|
||||
}
|
||||
}else{
|
||||
removal.add(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(Tile remove : removal){
|
||||
teleporters[entity.color].remove(remove);
|
||||
}
|
||||
|
||||
return returns;
|
||||
}
|
||||
|
||||
public static class TeleporterEntity extends TileEntity{
|
||||
public byte color = 0;
|
||||
public boolean teleporting;
|
||||
public boolean active;
|
||||
public float activeScl = 0f;
|
||||
public float speedScl = 1f;
|
||||
public float powerLackScl, liquidLackScl;
|
||||
public float time;
|
||||
|
||||
@Override
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
stream.writeByte(color);
|
||||
stream.writeBoolean(active);
|
||||
stream.writeFloat(activeScl);
|
||||
stream.writeFloat(speedScl);
|
||||
stream.writeFloat(powerLackScl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput stream) throws IOException{
|
||||
color = stream.readByte();
|
||||
active = stream.readBoolean();
|
||||
activeScl = stream.readFloat();
|
||||
speedScl = stream.readFloat();
|
||||
powerLackScl = stream.readFloat();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import com.badlogic.gdx.utils.IntSet;
|
||||
import com.badlogic.gdx.utils.ObjectSet;
|
||||
import com.badlogic.gdx.utils.Queue;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
|
||||
import static io.anuke.mindustry.Vars.threads;
|
||||
|
||||
@@ -100,7 +99,7 @@ public class PowerGraph{
|
||||
|
||||
public void clear(){
|
||||
for(Tile other : all){
|
||||
other.entity.power.graph = null;
|
||||
if(other.entity != null && other.entity.power != null) other.entity.power.graph = null;
|
||||
}
|
||||
all.clear();
|
||||
producers.clear();
|
||||
|
||||
@@ -25,7 +25,6 @@ import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.scene.ui.Image;
|
||||
import io.anuke.ucore.scene.ui.layout.Cell;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.Threads;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
public class Drill extends Block{
|
||||
@@ -221,7 +220,7 @@ public class Drill extends Block{
|
||||
@Override
|
||||
public boolean canPlaceOn(Tile tile){
|
||||
if(isMultiblock()){
|
||||
for(Tile other : tile.getLinkedTilesAs(this, Threads.isLogic() ? tempTiles : drawTiles)){
|
||||
for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){
|
||||
if(isValid(other)){
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@ import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
|
||||
public class SortedUnloader extends Unloader implements SelectionTrait{
|
||||
protected float speed = 1f;
|
||||
|
||||
public SortedUnloader(String name){
|
||||
super(name);
|
||||
@@ -35,13 +37,13 @@ public class SortedUnloader extends Unloader implements SelectionTrait{
|
||||
public void update(Tile tile){
|
||||
SortedUnloaderEntity entity = tile.entity();
|
||||
|
||||
if(entity.items.total() == 0 && entity.timer.get(timerUnload, speed)){
|
||||
tile.allNearby(other -> {
|
||||
if(tile.entity.timer.get(timerUnload, speed) && tile.entity.items.total() == 0){
|
||||
for(Tile other : tile.entity.proximity()){
|
||||
if(other.getTeam() == tile.getTeam() && other.block() instanceof StorageBlock && entity.items.total() == 0 &&
|
||||
((entity.sortItem == null && other.entity.items.total() > 0) || ((StorageBlock) other.block()).hasItem(other, entity.sortItem))){
|
||||
offloadNear(tile, ((StorageBlock) other.block()).removeItem(other, entity.sortItem));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(entity.items.total() > 0){
|
||||
|
||||
@@ -5,9 +5,8 @@ import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.meta.BlockGroup;
|
||||
|
||||
public class Unloader extends Block{
|
||||
public abstract class Unloader extends Block{
|
||||
protected final int timerUnload = timers++;
|
||||
protected int speed = 5;
|
||||
|
||||
public Unloader(String name){
|
||||
super(name);
|
||||
@@ -18,22 +17,6 @@ public class Unloader extends Block{
|
||||
hasItems = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
if(tile.entity.items.total() == 0 && tile.entity.timer.get(timerUnload, speed)){
|
||||
tile.allNearby(other -> {
|
||||
if(other.getTeam() == tile.getTeam() && other.block() instanceof StorageBlock && tile.entity.items.total() == 0 &&
|
||||
((StorageBlock) other.block()).hasItem(other, null)){
|
||||
offloadNear(tile, ((StorageBlock) other.block()).removeItem(other, null));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(tile.entity.items.total() > 0){
|
||||
tryDump(tile);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDump(Tile tile, Tile to, Item item){
|
||||
Block block = to.target().block();
|
||||
|
||||
@@ -51,7 +51,7 @@ public class UnitFactory extends Block{
|
||||
hasItems = true;
|
||||
solid = false;
|
||||
itemCapacity = 10;
|
||||
flags = EnumSet.of(BlockFlag.producer);
|
||||
flags = EnumSet.of(BlockFlag.producer, BlockFlag.target);
|
||||
|
||||
consumes.require(ConsumeItems.class);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class UnitFactory extends Block{
|
||||
if(!Net.client()){
|
||||
BaseUnit unit = factory.type.create(tile.getTeam());
|
||||
unit.setSpawner(tile);
|
||||
unit.set(tile.drawx(), tile.drawy());
|
||||
unit.set(tile.drawx() + Mathf.range(4), tile.drawy() + Mathf.range(4));
|
||||
unit.add();
|
||||
unit.getVelocity().y = factory.launchVelocity;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user