This commit is contained in:
Anuken
2020-01-19 11:10:14 -05:00
parent f7c4ea3e58
commit c0844304a6
259 changed files with 7166 additions and 7198 deletions

View File

@@ -11,13 +11,14 @@ import arc.scene.ui.layout.*;
import arc.util.*;
import arc.util.async.*;
import mindustry.core.*;
import mindustry.ctype.Content;
import mindustry.ctype.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.maps.*;
import mindustry.mod.*;
import mindustry.net.Net;
import mindustry.ui.*;
import static arc.Core.*;
import static mindustry.Vars.*;
@@ -33,6 +34,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
@Override
public void setup(){
Vars.loadLogger();
Vars.loadFileLogger();
Vars.platform = this;
beginTime = Time.millis();
@@ -54,14 +56,15 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
Vars.net = new Net(platform.getNet());
mods = new Mods();
UI.loadSystemCursors();
Fonts.loadSystemCursors();
assets.load(new Vars());
UI.loadDefaultFont();
Fonts.loadDefaultFont();
assets.load(new AssetDescriptor<>("sprites/sprites.atlas", TextureAtlas.class)).loaded = t -> {
atlas = (TextureAtlas)t;
Fonts.mergeFontAtlas(atlas);
};
assets.loadRun("maps", Map.class, () -> maps.loadPreviews());

View File

@@ -1,13 +1,14 @@
package mindustry;
import arc.*;
import arc.Application.*;
import arc.*;
import arc.assets.*;
import arc.struct.*;
import arc.files.*;
import arc.graphics.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import arc.util.Log.*;
import arc.util.io.*;
import mindustry.ai.*;
import mindustry.core.*;
@@ -21,10 +22,11 @@ import mindustry.gen.*;
import mindustry.input.*;
import mindustry.maps.*;
import mindustry.mod.*;
import mindustry.net.*;
import mindustry.net.Net;
import mindustry.net.*;
import mindustry.world.blocks.defense.ForceProjector.*;
import java.io.*;
import java.nio.charset.*;
import java.util.*;
@@ -35,7 +37,7 @@ public class Vars implements Loadable{
/** Whether to load locales.*/
public static boolean loadLocales = true;
/** Whether the logger is loaded. */
public static boolean loadedLogger = false;
public static boolean loadedLogger = false, loadedFileLogger = false;
/** Maximum schematic size.*/
public static final int maxSchematicSize = 32;
/** All schematic base64 starts with this string.*/
@@ -86,7 +88,7 @@ public class Vars implements Loadable{
public static final Color[] playerColors = {
Color.valueOf("82759a"),
Color.valueOf("c0c1c5"),
Color.valueOf("fff0e7"),
Color.valueOf("ffffff"),
Color.valueOf("7d2953"),
Color.valueOf("ff074e"),
Color.valueOf("ff072a"),
@@ -282,9 +284,10 @@ public class Vars implements Loadable{
String[] stags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""};
Array<String> logBuffer = new Array<>();
Log.setLogger((level, text, args) -> {
String result = Log.format(text, args);
System.out.println(Log.format(stags[level.ordinal()] + "&fr " + text, args));
Log.setLogger((level, text) -> {
String result = text;
String rawText = Log.format(stags[level.ordinal()] + "&fr " + text);
System.out.println(rawText);
result = tags[level.ordinal()] + " " + result;
@@ -300,6 +303,28 @@ public class Vars implements Loadable{
loadedLogger = true;
}
public static void loadFileLogger(){
if(loadedFileLogger) return;
Core.settings.setAppName(appName);
Writer writer = settings.getDataDirectory().child("last_log.txt").writer(false);
LogHandler log = Log.getLogger();
Log.setLogger(((level, text) -> {
log.log(level, text);
try{
writer.write("[" + Character.toUpperCase(level.name().charAt(0)) +"] " + Log.removeCodes(text) + "\n");
writer.flush();
}catch(IOException e){
e.printStackTrace();
//ignore it
}
}));
loadedFileLogger = true;
}
public static void loadSettings(){
Core.settings.setAppName(appName);

View File

@@ -242,6 +242,7 @@ public class BlockIndexer{
public TileEntity findTile(Team team, float x, float y, float range, Boolf<Tile> pred, boolean usePriority){
TileEntity closest = null;
float dst = 0;
float range2 = range*range;
for(int rx = Math.max((int)((x - range) / tilesize / quadrantSize), 0); rx <= (int)((x + range) / tilesize / quadrantSize) && rx < quadWidth(); rx++){
for(int ry = Math.max((int)((y - range) / tilesize / quadrantSize), 0); ry <= (int)((y + range) / tilesize / quadrantSize) && ry < quadHeight(); ry++){
@@ -259,8 +260,12 @@ public class BlockIndexer{
TileEntity e = other.entity;
float ndst = Mathf.dst(x, y, e.x, e.y);
if(ndst < range && (closest == null || ndst < dst || (usePriority && closest.block.priority.ordinal() <= e.block.priority.ordinal()))){
float ndst = Mathf.dst2(x, y, e.x, e.y);
if(ndst < range2 && (closest == null ||
//this one is closer, and it is at least of equal priority
(ndst < dst && (!usePriority || closest.block.priority.ordinal() <= e.block.priority.ordinal())) ||
//priority is used, and new block has higher priority regardless of range
(usePriority && closest.block.priority.ordinal() < e.block.priority.ordinal()))){
dst = ndst;
closest = e;
}

View File

@@ -622,10 +622,6 @@ public class Blocks implements ContentList{
);
hasPower = true;
craftTime = 35f;
spinnerLength = 1.5f;
spinnerRadius = 3.5f;
spinnerThickness = 1.5f;
spinnerSpeed = 3f;
size = 2;
consumes.power(1f);
@@ -881,18 +877,21 @@ public class Blocks implements ContentList{
requirements(Category.distribution, ItemStack.with(Items.copper, 1), true);
health = 45;
speed = 0.03f;
displayedSpeed = 4.2f;
}};
titaniumConveyor = new Conveyor("titanium-conveyor"){{
requirements(Category.distribution, ItemStack.with(Items.copper, 1, Items.lead, 1, Items.titanium, 1));
health = 65;
speed = 0.08f;
displayedSpeed = 10f;
}};
armoredConveyor = new ArmoredConveyor("armored-conveyor"){{
requirements(Category.distribution, ItemStack.with(Items.plastanium, 1, Items.thorium, 1, Items.metaglass, 1));
health = 180;
speed = 0.08f;
displayedSpeed = 10f;
}};
junction = new Junction("junction"){{

View File

@@ -1,10 +1,8 @@
package mindustry.content;
import arc.struct.*;
import mindustry.ctype.ContentList;
import mindustry.ctype.*;
import mindustry.entities.bullet.*;
import mindustry.entities.type.*;
import mindustry.entities.type.Bullet;
import mindustry.entities.type.base.*;
import mindustry.gen.*;
import mindustry.type.*;
@@ -100,23 +98,14 @@ public class UnitTypes implements ContentList{
reload = 12f;
ejectEffect = Fx.none;
shootSound = Sounds.explosion;
bullet = new BombBulletType(2f, 3f, "clear"){
{
hitEffect = Fx.pulverize;
lifetime = 30f;
speed = 1.1f;
splashDamageRadius = 55f;
splashDamage = 30f;
}
@Override
public void init(Bullet b){
if(b.getOwner() instanceof Unit){
((Unit)b.getOwner()).kill();
}
b.time(b.lifetime());
}
};
bullet = new BombBulletType(2f, 3f, "clear"){{
hitEffect = Fx.pulverize;
lifetime = 2f;
speed = 1.1f;
splashDamageRadius = 55f;
splashDamage = 30f;
killShooter = true;
}};
}};
}};

View File

@@ -133,9 +133,9 @@ public class NetClient implements ApplicationListener{
}
//called on all clients
@Remote(called = Loc.server, targets = Loc.server, variants = Variant.both)
@Remote(targets = Loc.server, variants = Variant.both)
public static void sendMessage(String message, String sender, Player playersender){
if(Vars.ui != null && !(playersender != null && net.server() && sender.startsWith("[#" + player.getTeam().color.toString() + "]<T>"))){
if(Vars.ui != null){
Vars.ui.chatfrag.addMessage(message, sender);
}
@@ -171,6 +171,11 @@ public class NetClient implements ApplicationListener{
return;
}
//special case; graphical server needs to see its message
if(!headless && player == Vars.player){
Vars.ui.chatfrag.addMessage(message, colorizeName(player.id, player.name));
}
//server console logging
Log.info("&y{0}: &lb{1}", player.name, message);
@@ -272,7 +277,6 @@ public class NetClient implements ApplicationListener{
netClient.removed.clear();
logic.reset();
ui.chatfrag.clearMessages();
net.setClientLoaded(false);
ui.loadfrag.show("$connecting.data");
@@ -513,7 +517,7 @@ public class NetClient implements ApplicationListener{
return Core.settings.getString("usid-" + ip, null);
}else{
byte[] bytes = new byte[8];
new RandomXS128().nextBytes(bytes);
new Rand().nextBytes(bytes);
String result = new String(Base64Coder.encode(bytes));
Core.settings.put("usid-" + ip, result);
Core.settings.save();

View File

@@ -230,7 +230,11 @@ public class NetServer implements ApplicationListener{
net.handleServer(InvokePacket.class, (con, packet) -> {
if(con.player == null) return;
RemoteReadServer.readPacket(packet.writeBuffer, packet.type, con.player);
try{
RemoteReadServer.readPacket(packet.writeBuffer, packet.type, con.player);
}catch(ValidateException e){
Log.debug("Validation failed for '{0}': {1}", e.player, e.getMessage());
}
});
registerCommands();
@@ -506,6 +510,7 @@ public class NetServer implements ApplicationListener{
player.isShooting = shooting;
player.isBuilding = building;
player.buildQueue().clear();
for(BuildRequest req : requests){
if(req == null) continue;
Tile tile = world.tile(req.x, req.y);
@@ -515,10 +520,23 @@ public class NetServer implements ApplicationListener{
continue;
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || tile.rotation() == req.rotation)){
continue;
}else if(connection.rejectedRequests.contains(r -> r.breaking == req.breaking && r.x == req.x && r.y == req.y)){ //check if request was recently rejected, and skip it if so
continue;
}else if(!netServer.admins.allowAction(player, req.breaking ? ActionType.breakBlock : ActionType.placeBlock, tile, action -> { //make sure request is allowed by the server
action.block = req.block;
action.rotation = req.rotation;
action.config = req.config;
})){
//force the player to remove this request if that's not the case
Call.removeQueueBlock(player.con, req.x, req.y, req.breaking);
connection.rejectedRequests.add(req);
continue;
}
player.buildQueue().addLast(req);
}
connection.rejectedRequests.clear();
vector.set(x - player.getInterpolator().target.x, y - player.getInterpolator().target.y);
vector.limit(maxMove);

View File

@@ -90,7 +90,7 @@ public interface Platform{
String uuid = Core.settings.getString("uuid", "");
if(uuid.isEmpty()){
byte[] result = new byte[8];
new RandomXS128().nextBytes(result);
new Rand().nextBytes(result);
uuid = new String(Base64Coder.encode(result));
Core.settings.put("uuid", uuid);
Core.settings.save();

View File

@@ -2,29 +2,22 @@ package mindustry.core;
import arc.*;
import arc.Graphics.*;
import arc.Graphics.Cursor.*;
import arc.Input.*;
import arc.assets.*;
import arc.assets.loaders.*;
import arc.assets.loaders.resolvers.*;
import arc.struct.*;
import arc.files.*;
import arc.freetype.*;
import arc.freetype.FreeTypeFontGenerator.*;
import arc.freetype.FreetypeFontLoader.*;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.Texture.*;
import arc.graphics.g2d.*;
import arc.input.*;
import arc.math.*;
import arc.scene.*;
import arc.scene.actions.*;
import arc.scene.event.*;
import arc.scene.style.*;
import arc.scene.ui.*;
import arc.scene.ui.TextField.*;
import arc.scene.ui.Tooltip.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import mindustry.core.GameState.*;
import mindustry.editor.*;
@@ -39,6 +32,8 @@ import static arc.scene.actions.Actions.*;
import static mindustry.Vars.*;
public class UI implements ApplicationListener, Loadable{
public static PixmapPacker packer;
public MenuFragment menufrag;
public HudFragment hudfrag;
public ChatFragment chatfrag;
@@ -77,7 +72,7 @@ public class UI implements ApplicationListener, Loadable{
public Cursor drillCursor, unloadCursor;
public UI(){
setupFonts();
Fonts.loadFonts();
}
@Override
@@ -99,6 +94,7 @@ public class UI implements ApplicationListener, Loadable{
Icon.load();
Styles.load();
Tex.loadStyles();
Fonts.loadContentIcons();
Dialog.setShowAction(() -> sequence(alpha(0f), fadeIn(0.1f)));
Dialog.setHideAction(() -> sequence(fadeOut(0.1f)));
@@ -116,7 +112,9 @@ public class UI implements ApplicationListener, Loadable{
Colors.put("unlaunched", Color.valueOf("8982ed"));
Colors.put("highlight", Pal.accent.cpy().lerp(Color.white, 0.3f));
Colors.put("stat", Pal.stat);
loadExtraCursors();
drillCursor = Core.graphics.newCursor("drill");
unloadCursor = Core.graphics.newCursor("unload");
}
@Override
@@ -124,64 +122,6 @@ public class UI implements ApplicationListener, Loadable{
return Array.with(new AssetDescriptor<>(Control.class), new AssetDescriptor<>("outline", BitmapFont.class), new AssetDescriptor<>("default", BitmapFont.class), new AssetDescriptor<>("chat", BitmapFont.class));
}
/** Called from a static context to make the cursor appear immediately upon startup.*/
public static void loadSystemCursors(){
SystemCursor.arrow.set(Core.graphics.newCursor("cursor"));
SystemCursor.hand.set(Core.graphics.newCursor("hand"));
SystemCursor.ibeam.set(Core.graphics.newCursor("ibeam"));
Core.graphics.restoreCursor();
}
/** Called from a static context for use in the loading screen.*/
public static void loadDefaultFont(){
FileHandleResolver resolver = new InternalFileHandleResolver();
Core.assets.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver));
Core.assets.setLoader(BitmapFont.class, null, new FreetypeFontLoader(resolver){
@Override
public BitmapFont loadSync(AssetManager manager, String fileName, Fi file, FreeTypeFontLoaderParameter parameter){
if(fileName.equals("outline")){
parameter.fontParameters.borderWidth = Scl.scl(2f);
parameter.fontParameters.spaceX -= parameter.fontParameters.borderWidth;
}
parameter.fontParameters.magFilter = TextureFilter.Linear;
parameter.fontParameters.minFilter = TextureFilter.Linear;
parameter.fontParameters.size = fontParameter().size;
return super.loadSync(manager, fileName, file, parameter);
}
});
FreeTypeFontParameter param = new FreeTypeFontParameter(){{
borderColor = Color.darkGray;
incremental = true;
}};
Core.assets.load("outline", BitmapFont.class, new FreeTypeFontLoaderParameter("fonts/font.ttf", param)).loaded = t -> Fonts.outline = (BitmapFont)t;
}
void loadExtraCursors(){
drillCursor = Core.graphics.newCursor("drill");
unloadCursor = Core.graphics.newCursor("unload");
}
public void setupFonts(){
String fontName = "fonts/font.ttf";
FreeTypeFontParameter param = fontParameter();
Core.assets.load("default", BitmapFont.class, new FreeTypeFontLoaderParameter(fontName, param)).loaded = f -> Fonts.def = (BitmapFont)f;
Core.assets.load("chat", BitmapFont.class, new FreeTypeFontLoaderParameter(fontName, param)).loaded = f -> Fonts.chat = (BitmapFont)f;
}
static FreeTypeFontParameter fontParameter(){
return new FreeTypeFontParameter(){{
size = (int)(Scl.scl(18f));
shadowColor = Color.darkGray;
shadowOffsetY = 2;
incremental = true;
}};
}
@Override
public void update(){
if(disableUI || Core.scene == null) return;
@@ -271,7 +211,17 @@ public class UI implements ApplicationListener, Loadable{
@Override
public void dispose(){
//generator.dispose();
if(packer != null){
packer.dispose();
packer = null;
}
}
public TextureRegionDrawable getIcon(String name){
if(Icon.icons.containsKey(name)){
return Icon.icons.get(name);
}
return Core.atlas.getDrawable("error");
}
public void loadAnd(Runnable call){

View File

@@ -66,30 +66,30 @@ public class MapEditorDialog extends Dialog implements Disposable{
menu.cont.table(t -> {
t.defaults().size(swidth, 60f).padBottom(5).padRight(5).padLeft(5);
t.addImageTextButton("$editor.savemap", Icon.floppy16Small, this::save);
t.addImageTextButton("$editor.savemap", Icon.save, this::save);
t.addImageTextButton("$editor.mapinfo", Icon.pencilSmall, () -> {
t.addImageTextButton("$editor.mapinfo", Icon.pencil, () -> {
infoDialog.show();
menu.hide();
});
t.row();
t.addImageTextButton("$editor.generate", Icon.editorSmall, () -> {
t.addImageTextButton("$editor.generate", Icon.terrain, () -> {
generateDialog.show(generateDialog::applyToEditor);
menu.hide();
});
t.addImageTextButton("$editor.resize", Icon.resizeSmall, () -> {
t.addImageTextButton("$editor.resize", Icon.resize, () -> {
resizeDialog.show();
menu.hide();
});
t.row();
t.addImageTextButton("$editor.import", Icon.loadMapSmall, () ->
t.addImageTextButton("$editor.import", Icon.download, () ->
createDialog("$editor.import",
"$editor.importmap", "$editor.importmap.description", Icon.loadMap, (Runnable)loadDialog::show,
"$editor.importmap", "$editor.importmap.description", Icon.download, (Runnable)loadDialog::show,
"$editor.importfile", "$editor.importfile.description", Icon.file, (Runnable)() ->
platform.showFileChooser(true, mapExtension, file -> ui.loadAnd(() -> {
maps.tryCatchMapError(() -> {
@@ -115,7 +115,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
})))
);
t.addImageTextButton("$editor.export", Icon.saveMapSmall, () -> {
t.addImageTextButton("$editor.export", Icon.upload, () -> {
if(!ios){
platform.showFileChooser(false, mapExtension, file -> {
ui.loadAnd(() -> {
@@ -148,7 +148,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
menu.cont.row();
if(steam){
menu.cont.addImageTextButton("$editor.publish.workshop", Icon.linkSmall, () -> {
menu.cont.addImageTextButton("$editor.publish.workshop", Icon.link, () -> {
Map builtin = maps.all().find(m -> m.name().equals(editor.getTags().get("name", "").trim()));
if(editor.getTags().containsKey("steamid") && builtin != null && !builtin.custom){
@@ -181,11 +181,11 @@ public class MapEditorDialog extends Dialog implements Disposable{
menu.cont.row();
}
menu.cont.addImageTextButton("$editor.ingame", Icon.arrowSmall, this::playtest).padTop(!steam ? -3 : 1).size(swidth * 2f + 10, 60f);
menu.cont.addImageTextButton("$editor.ingame", Icon.right, this::playtest).padTop(!steam ? -3 : 1).size(swidth * 2f + 10, 60f);
menu.cont.row();
menu.cont.addImageTextButton("$quit", Icon.backSmall, () -> {
menu.cont.addImageTextButton("$quit", Icon.exit, () -> {
tryExit();
menu.hide();
}).size(swidth * 2f + 10, 60f);
@@ -427,7 +427,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
Cons<EditorTool> addTool = tool -> {
ImageButton button = new ImageButton(Core.atlas.drawable("icon-" + tool.name() + "-small"), Styles.clearTogglei);
ImageButton button = new ImageButton(ui.getIcon(tool.name()), Styles.clearTogglei);
button.clicked(() -> {
view.setTool(tool);
if(lastTable[0] != null){
@@ -503,16 +503,16 @@ public class MapEditorDialog extends Dialog implements Disposable{
tools.defaults().size(size, size);
tools.addImageButton(Icon.menuLargeSmall, Styles.cleari, menu::show);
tools.addImageButton(Icon.menu, Styles.cleari, menu::show);
ImageButton grid = tools.addImageButton(Icon.gridSmall, Styles.clearTogglei, () -> view.setGrid(!view.isGrid())).get();
ImageButton grid = tools.addImageButton(Icon.grid, Styles.clearTogglei, () -> view.setGrid(!view.isGrid())).get();
addTool.get(EditorTool.zoom);
tools.row();
ImageButton undo = tools.addImageButton(Icon.undoSmall, Styles.cleari, editor::undo).get();
ImageButton redo = tools.addImageButton(Icon.redoSmall, Styles.cleari, editor::redo).get();
ImageButton undo = tools.addImageButton(Icon.undo, Styles.cleari, editor::undo).get();
ImageButton redo = tools.addImageButton(Icon.redo, Styles.cleari, editor::redo).get();
addTool.get(EditorTool.pick);
@@ -534,7 +534,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
addTool.get(EditorTool.fill);
addTool.get(EditorTool.spray);
ImageButton rotate = tools.addImageButton(Icon.arrow16Small, Styles.cleari, () -> editor.rotation = (editor.rotation + 1) % 4).get();
ImageButton rotate = tools.addImageButton(Icon.right, Styles.cleari, () -> editor.rotation = (editor.rotation + 1) % 4).get();
rotate.getImage().update(() -> {
rotate.getImage().setRotation(editor.rotation * 90);
rotate.getImage().setOrigin(Align.center);

View File

@@ -235,24 +235,24 @@ public class MapGenerateDialog extends FloatingDialog{
t.table(b -> {
ImageButtonStyle style = Styles.cleari;
b.defaults().size(50f);
b.addImageButton(Icon.refreshSmall, style, () -> {
b.addImageButton(Icon.refresh, style, () -> {
filter.randomize();
update();
});
b.addImageButton(Icon.arrowUpSmall, style, () -> {
b.addImageButton(Icon.upOpen, style, () -> {
int idx = filters.indexOf(filter);
filters.swap(idx, Math.max(0, idx - 1));
rebuildFilters();
update();
});
b.addImageButton(Icon.arrowDownSmall, style, () -> {
b.addImageButton(Icon.downOpen, style, () -> {
int idx = filters.indexOf(filter);
filters.swap(idx, Math.min(filters.size - 1, idx + 1));
rebuildFilters();
update();
});
b.addImageButton(Icon.trashSmall, style, () -> {
b.addImageButton(Icon.trash, style, () -> {
filters.remove(filter);
rebuildFilters();
update();

View File

@@ -189,7 +189,7 @@ public class MapView extends Element implements GestureListener{
lastTool = null;
}
if(ui.editor.hasPane()) return;
if(Core.scene.getScrollFocus() != this) return;
zoom += Core.input.axis(KeyCode.SCROLL) / 10f * zoom;
clampZoom();

View File

@@ -1,5 +1,6 @@
package mindustry.entities;
/** A higher ordinal means a higher priority. Higher priority blocks will always get targeted over those of lower priority, regardless of distance. */
public enum TargetPriority{
base,
turret

View File

@@ -39,6 +39,8 @@ public abstract class BulletType extends Content{
public float reloadMultiplier = 1f;
/** Recoil from shooter entities. */
public float recoil;
/** Whether to kill the shooter when this is shot. For suicide bombers. */
public boolean killShooter;
public float splashDamage = 0f;
/** Knockback in velocity. */
@@ -146,6 +148,9 @@ public abstract class BulletType extends Content{
}
public void init(Bullet b){
if(killShooter && b.getOwner() instanceof HealthTrait){
((HealthTrait)b.getOwner()).kill();
}
}
public void update(Bullet b){

View File

@@ -27,7 +27,7 @@ import static mindustry.Vars.*;
public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
public static final float lifetime = 10f;
private static final RandomXS128 random = new RandomXS128();
private static final Rand random = new Rand();
private static final Rect rect = new Rect();
private static final Array<Unit> entities = new Array<>();
private static final IntSet hit = new IntSet();

View File

@@ -67,9 +67,9 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(!(tile.block() instanceof BuildBlock)){
if(!current.initialized && canCreateBlocks() && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){
Call.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation);
Build.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation);
}else if(!current.initialized && canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){
Call.beginBreak(getTeam(), current.x, current.y);
Build.beginBreak(getTeam(), current.x, current.y);
}else{
buildQueue().removeFirst();
return;
@@ -118,6 +118,14 @@ public interface BuilderTrait extends Entity, TeamTrait{
return request.stuck && !core.items.has(request.block.requirements);
}
default void removeRequest(int x, int y, boolean breaking){
//remove matching request
int idx = player.buildQueue().indexOf(req -> req.breaking == breaking && req.x == x && req.y == y);
if(idx != -1){
player.buildQueue().removeIndex(idx);
}
}
/** Returns the queue for storing build requests. */
Queue<BuildRequest> buildQueue();

View File

@@ -14,6 +14,11 @@ public interface HealthTrait{
void setDead(boolean dead);
default void kill(){
health(-1);
damage(1);
}
default void onHit(SolidTrait entity){
}

View File

@@ -719,7 +719,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public void sendMessage(String text){
if(isLocal){
if(Vars.ui != null){
Log.info("add " + text);
Vars.ui.chatfrag.addMessage(text, null);
}
}else{

View File

@@ -224,11 +224,6 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
y = Mathf.clamp(y, 0, world.height() * tilesize - tilesize);
}
public void kill(){
health = -1;
damage(1);
}
public boolean isImmune(StatusEffect effect){
return type.immunities.contains(effect);
}
@@ -281,6 +276,10 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
return tile == null ? (Floor)Blocks.air : tile.floor();
}
public @Nullable Tile tileOn(){
return world.tileWorld(x, y);
}
public void onRespawn(Tile tile){
}

View File

@@ -85,9 +85,15 @@ public class GlobalData{
if(amount > 0){
unlockContent(item);
}
amount = Math.max(amount, 0);
modified = true;
items.getAndIncrement(item, 0, amount);
state.stats.itemsDelivered.getAndIncrement(item, 0, amount);
//clamp overflow
if(items.get(item, 0) < 0) items.put(item, Integer.MAX_VALUE);
if(state.stats.itemsDelivered.get(item, 0) < 0) state.stats.itemsDelivered.put(item, Integer.MAX_VALUE);
}
public boolean hasItems(Array<ItemStack> stacks){

View File

@@ -35,7 +35,7 @@ public class Team implements Comparable<Team>{
for(int i = 6; i < all.length; i++){
new Team(i, "team#" + i, Color.HSVtoRGB(360f * Mathf.random(), 100f * Mathf.random(0.6f, 1f), 100f * Mathf.random(0.8f, 1f), 1f));
}
Mathf.random.setSeed(new RandomXS128().nextLong());
Mathf.random.setSeed(new Rand().nextLong());
}
public static Team get(int id){

View File

@@ -201,7 +201,7 @@ public class FloorRenderer implements Disposable{
int chunksx = Mathf.ceil((float)(world.width()) / chunksize),
chunksy = Mathf.ceil((float)(world.height()) / chunksize);
cache = new Chunk[chunksx][chunksy];
cbatch = new MultiCacheBatch(chunksize * chunksize * 4);
cbatch = new MultiCacheBatch(chunksize * chunksize * 5);
Time.mark();

View File

@@ -46,9 +46,9 @@ public class IndexedRenderer implements Disposable{
private float[] tmpVerts = new float[vsize * 6];
private float[] vertices;
private Matrix3 projMatrix = new Matrix3();
private Matrix3 transMatrix = new Matrix3();
private Matrix3 combined = new Matrix3();
private Mat projMatrix = new Mat();
private Mat transMatrix = new Mat();
private Mat combined = new Mat();
private float color = Color.white.toFloatBits();
public IndexedRenderer(int sprites){
@@ -210,11 +210,11 @@ public class IndexedRenderer implements Disposable{
mesh.updateVertices(index * vsize * 6, vertices);
}
public Matrix3 getTransformMatrix(){
public Mat getTransformMatrix(){
return transMatrix;
}
public void setProjectionMatrix(Matrix3 matrix){
public void setProjectionMatrix(Mat matrix){
projMatrix = matrix;
}

View File

@@ -27,7 +27,7 @@ public class MenuRenderer implements Disposable{
private int cacheFloor, cacheWall;
private Camera camera = new Camera();
private Matrix3 mat = new Matrix3();
private Mat mat = new Mat();
private FrameBuffer shadows;
private CacheBatch batch;
private float time = 0f;

View File

@@ -64,7 +64,7 @@ public class OverlayRenderer{
for(Tile mechpad : indexer.getAllied(player.getTeam(), BlockFlag.mechPad)){
if(!(mechpad.block() instanceof MechPad)) continue;
if(!rect.setSize(Core.camera.width * 0.9f, Core.camera.height * 0.9f)
.setCenter(Core.camera.position.x, Core.camera.position.y).contains(mechpad.x, mechpad.y)){
.setCenter(Core.camera.position.x, Core.camera.position.y).contains(mechpad.drawx(), mechpad.drawy())){
Tmp.v1.set(mechpad.drawx(), mechpad.drawy()).sub(Core.camera.position.x, Core.camera.position.y).setLength(indicatorLength);

View File

@@ -67,7 +67,7 @@ public class DesktopInput extends InputHandler{
Core.keybinds.get(Binding.schematic_flip_y).key.toString())).style(Styles.outlineLabel);
b.row();
b.table(a -> {
a.addImageTextButton("$schematic.add", Icon.saveSmall, this::showSchematicSave).colspan(2).size(250f, 50f).disabled(f -> lastSchematic == null || lastSchematic.file != null);
a.addImageTextButton("$schematic.add", Icon.save, this::showSchematicSave).colspan(2).size(250f, 50f).disabled(f -> lastSchematic == null || lastSchematic.file != null);
});
}).margin(6f);
});
@@ -256,7 +256,7 @@ public class DesktopInput extends InputHandler{
table.row();
table.left().margin(0f).defaults().size(48f).left();
table.addImageButton(Icon.pasteSmall, Styles.clearPartiali, () -> {
table.addImageButton(Icon.paste, Styles.clearPartiali, () -> {
ui.schematics.show();
});
}

View File

@@ -1,8 +1,6 @@
package mindustry.input;
import arc.*;
import mindustry.annotations.Annotations.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
@@ -13,8 +11,10 @@ import arc.math.geom.*;
import arc.scene.*;
import arc.scene.event.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.effect.*;
@@ -27,12 +27,13 @@ import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.input.Placement.*;
import mindustry.net.*;
import mindustry.net.Administration.*;
import mindustry.type.*;
import mindustry.ui.fragments.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.BuildBlock.*;
import mindustry.world.blocks.power.PowerNode;
import mindustry.world.blocks.power.*;
import java.util.*;
@@ -66,6 +67,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
//methods to override
@Remote(variants = Variant.one)
public static void removeQueueBlock(int x, int y, boolean breaking){
player.removeRequest(x, y, breaking);
}
@Remote(targets = Loc.client, called = Loc.server)
public static void dropItem(Player player, float angle){
if(net.server() && player.item().amount <= 0){
@@ -78,8 +84,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
@Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true)
public static void rotateBlock(Player player, Tile tile, boolean direction){
if(net.server() && !Units.canInteract(player, tile)){
throw new ValidateException(player, "Player cannot drop an item.");
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.rotate, tile, action -> action.rotation = Mathf.mod(tile.rotation() + Mathf.sign(direction), 4)))){
throw new ValidateException(player, "Player cannot rotate a block.");
}
tile.rotation(Mathf.mod(tile.rotation() + Mathf.sign(direction), 4));
@@ -93,7 +100,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
@Remote(targets = Loc.both, forward = true, called = Loc.server)
public static void transferInventory(Player player, Tile tile){
if(player == null || player.timer == null) return;
if(net.server() && (player.item().amount <= 0 || player.isTransferring|| !Units.canInteract(player, tile))){
if(net.server() && (player.item().amount <= 0 || player.isTransferring|| !Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.depositItem, tile, action -> {
action.itemAmount = player.item().amount;
action.item = player.item().item;
}))){
throw new ValidateException(player, "Player cannot transfer an item.");
}
@@ -143,14 +154,18 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
@Remote(targets = Loc.both, called = Loc.server, forward = true)
public static void onTileTapped(Player player, Tile tile){
if(tile == null || player == null) return;
if(!Units.canInteract(player, tile)) return;
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.tapTile, tile, action -> {}))) throw new ValidateException(player, "Player cannot tap a tile.");
tile.block().tapped(tile, player);
Core.app.post(() -> Events.fire(new TapEvent(tile, player)));
}
@Remote(targets = Loc.both, called = Loc.both, forward = true)
public static void onTileConfig(Player player, Tile tile, int value){
if(tile == null || !Units.canInteract(player, tile)) return;
if(tile == null) return;
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.configure, tile, action -> action.config = value))) throw new ValidateException(player, "Player cannot configure a tile.");
tile.block().configured(tile, player, value);
Core.app.post(() -> Events.fire(new TapConfigEvent(tile, player, value)));
}

View File

@@ -179,19 +179,19 @@ public class MobileInput extends InputHandler implements GestureListener{
table.row();
table.left().margin(0f).defaults().size(48f);
table.addImageButton(Icon.breakSmall, Styles.clearTogglePartiali, () -> {
table.addImageButton(Icon.hammer, Styles.clearTogglePartiali, () -> {
mode = mode == breaking ? block == null ? none : placing : breaking;
lastBlock = block;
}).update(l -> l.setChecked(mode == breaking)).name("breakmode");
//diagonal swap button
table.addImageButton(Icon.diagonalSmall, Styles.clearTogglePartiali, () -> {
table.addImageButton(Icon.diagonal, Styles.clearTogglePartiali, () -> {
Core.settings.put("swapdiagonal", !Core.settings.getBool("swapdiagonal"));
Core.settings.save();
}).update(l -> l.setChecked(Core.settings.getBool("swapdiagonal")));
//rotate button
table.addImageButton(Icon.arrowSmall, Styles.clearTogglePartiali, () -> {
table.addImageButton(Icon.right, Styles.clearTogglePartiali, () -> {
if(block != null && block.rotate){
rotation = Mathf.mod(rotation + 1, 4);
}else{
@@ -205,12 +205,12 @@ public class MobileInput extends InputHandler implements GestureListener{
boolean arrow = block != null && block.rotate;
i.getImage().setRotationOrigin(!arrow ? 0 : rotation * 90, Align.center);
i.getStyle().imageUp = arrow ? Icon.arrowSmall : Icon.pasteSmall;
i.getStyle().imageUp = arrow ? Icon.right : Icon.paste;
i.setChecked(!arrow && schematicMode);
});
//confirm button
table.addImageButton(Icon.checkSmall, Styles.clearPartiali, () -> {
table.addImageButton(Icon.ok, Styles.clearPartiali, () -> {
for(BuildRequest request : selectRequests){
Tile tile = request.tile();
@@ -253,7 +253,7 @@ public class MobileInput extends InputHandler implements GestureListener{
group.fill(t -> {
t.bottom().left().visible(() -> (player.isBuilding() || block != null || mode == breaking || !selectRequests.isEmpty()) && !schem.get());
t.addImageTextButton("$cancel", Icon.cancelSmall, () -> {
t.addImageTextButton("$cancel", Icon.cancel, () -> {
player.clearBuilding();
selectRequests.clear();
mode = none;
@@ -269,15 +269,15 @@ public class MobileInput extends InputHandler implements GestureListener{
ImageButtonStyle style = Styles.clearPartiali;
b.addImageButton(Icon.floppySmall, style, this::showSchematicSave).disabled(f -> lastSchematic == null || lastSchematic.file != null);
b.addImageButton(Icon.cancelSmall, style, () -> {
b.addImageButton(Icon.save, style, this::showSchematicSave).disabled(f -> lastSchematic == null || lastSchematic.file != null);
b.addImageButton(Icon.cancel, style, () -> {
selectRequests.clear();
});
b.row();
b.addImageButton(Icon.flipSmall, style, () -> flipRequests(selectRequests, true));
b.addImageButton(Icon.flipSmall, style, () -> flipRequests(selectRequests, false)).update(i -> i.getImage().setRotationOrigin(90f, Align.center));
b.addImageButton(Icon.flipX, style, () -> flipRequests(selectRequests, true));
b.addImageButton(Icon.flipY, style, () -> flipRequests(selectRequests, false));
b.row();
b.addImageButton(Icon.rotateSmall, style, () -> rotateRequests(selectRequests, 1));
b.addImageButton(Icon.rotate, style, () -> rotateRequests(selectRequests, 1));
}).margin(4f);
});

View File

@@ -76,15 +76,15 @@ public abstract class FilterOption{
@Override
public void build(Table table){
table.addButton(b -> b.addImage(supplier.get().icon(mindustry.ui.Cicon.small)).update(i -> ((TextureRegionDrawable)i.getDrawable())
.setRegion(supplier.get() == Blocks.air ? Core.atlas.find("icon-none") : supplier.get().icon(mindustry.ui.Cicon.small))).size(8 * 3), () -> {
table.addButton(b -> b.addImage(supplier.get().icon(Cicon.small)).update(i -> ((TextureRegionDrawable)i.getDrawable())
.setRegion(supplier.get() == Blocks.air ? Core.atlas.find("Icon.none") : supplier.get().icon(Cicon.small))).size(8 * 3), () -> {
FloatingDialog dialog = new FloatingDialog("");
dialog.setFillParent(false);
int i = 0;
for(Block block : Vars.content.blocks()){
if(!filter.get(block)) continue;
dialog.cont.addImage(block == Blocks.air ? Core.atlas.find("icon-none-small") : block.icon(Cicon.medium)).size(8 * 4).pad(3).get().clicked(() -> {
dialog.cont.addImage(block == Blocks.air ? Core.atlas.find("Icon.none-") : block.icon(Cicon.medium)).size(8 * 4).pad(3).get().clicked(() -> {
consumer.get(block);
dialog.hide();
changed.run();

File diff suppressed because one or more lines are too long

View File

@@ -42,7 +42,7 @@ public class Mods implements Loadable{
private Array<LoadedMod> mods = new Array<>();
private ObjectMap<Class<?>, ModMeta> metas = new ObjectMap<>();
private boolean requiresReload;
private boolean requiresReload, createdAtlas;
public Mods(){
Events.on(ClientLoadEvent.class, e -> Core.app.post(this::checkWarnings));
@@ -112,13 +112,6 @@ public class Mods implements Loadable{
totalSprites += sprites.size + overrides.size;
});
for(AtlasRegion region : Core.atlas.getRegions()){
PageType type = getPage(region);
if(!packer.has(type, region.name)){
packer.add(type, region.name, Core.atlas.getPixmap(region));
}
}
Log.debug("Time to pack textures: {0}", Time.elapsed());
}
@@ -159,6 +152,16 @@ public class Mods implements Loadable{
//get textures packed
if(totalSprites > 0){
if(!createdAtlas) Core.atlas = new TextureAtlas(Core.files.internal("sprites/sprites.atlas"));
createdAtlas = true;
for(AtlasRegion region : Core.atlas.getRegions()){
PageType type = getPage(region);
if(!packer.has(type, region.name)){
packer.add(type, region.name, Core.atlas.getPixmap(region));
}
}
TextureFilter filter = Core.settings.getBool("linear") ? TextureFilter.Linear : TextureFilter.Nearest;
//flush so generators can use these sprites
@@ -389,12 +392,12 @@ public class Mods implements Loadable{
d.left().marginLeft(15f);
for(Content c : m.erroredContent){
d.add(c.minfo.sourceFile.nameWithoutExtension()).left().padRight(10);
d.addImageTextButton("$details", Icon.arrowDownSmall, Styles.transt, () -> {
d.addImageTextButton("$details", Icon.downOpen, Styles.transt, () -> {
new Dialog(""){{
setFillParent(true);
cont.pane(e -> e.add(c.minfo.error)).grow();
cont.row();
cont.addImageTextButton("$ok", Icon.backSmall, this::hide).size(240f, 60f);
cont.addImageTextButton("$ok", Icon.left, this::hide).size(240f, 60f);
}}.show();
}).size(190f, 50f).left().marginLeft(6);
d.row();
@@ -419,6 +422,7 @@ public class Mods implements Loadable{
//epic memory leak
//TODO make it less epic
Core.atlas = new TextureAtlas(Core.files.internal("sprites/sprites.atlas"));
createdAtlas = true;
mods.each(LoadedMod::dispose);
mods.clear();

View File

@@ -2,6 +2,7 @@ package mindustry.mod;
import arc.*;
import arc.files.*;
import arc.struct.*;
import arc.util.*;
import arc.util.Log.*;
import mindustry.*;
@@ -9,6 +10,9 @@ import mindustry.mod.Mods.*;
import org.mozilla.javascript.*;
public class Scripts implements Disposable{
private final Array<String> blacklist = Array.with("net", "files", "reflect", "javax", "rhino", "file", "channels", "jdk",
"runtime", "util.os", "rmi", "security", "org.", "sun.", "beans", "sql", "http", "exec", "compiler", "process", "system", ".awt", "socket");
private final Array<String> whitelist = Array.with("mindustry.net");
private final Context context;
private final String wrapper;
private Scriptable scope;
@@ -18,9 +22,7 @@ public class Scripts implements Disposable{
Time.mark();
context = Vars.platform.getScriptContext();
context.setClassShutter(type -> (ClassAccess.allowedClassNames.contains(type) || type.startsWith("$Proxy") ||
type.startsWith("adapter") || type.contains("PrintStream") ||
type.startsWith("mindustry")) && !type.equals("mindustry.mod.ClassAccess"));
context.setClassShutter(type -> !blacklist.contains(type.toLowerCase()::contains) || whitelist.contains(type.toLowerCase()::contains));
context.getWrapFactory().setJavaPrimitiveWrap(false);
scope = new ImporterTopLevel(context);

View File

@@ -325,7 +325,8 @@ public class Administration{
ObjectSet<PlayerInfo> result = new ObjectSet<>();
for(PlayerInfo info : playerInfo.values()){
if(info.lastName.toLowerCase().equals(name.toLowerCase()) || (info.names.contains(name, false))
if(info.lastName.equalsIgnoreCase(name) || (info.names.contains(name, false))
|| Strings.stripColors(Strings.stripColors(info.lastName)).equals(name)
|| info.ips.contains(name, false) || info.id.equals(name)){
result.add(info);
}
@@ -334,6 +335,19 @@ public class Administration{
return result;
}
/** Finds by name, using contains(). */
public ObjectSet<PlayerInfo> searchNames(String name){
ObjectSet<PlayerInfo> result = new ObjectSet<>();
for(PlayerInfo info : playerInfo.values()){
if(info.names.contains(n -> n.toLowerCase().contains(name.toLowerCase()) || Strings.stripColors(n).trim().toLowerCase().contains(name))){
result.add(info);
}
}
return result;
}
public Array<PlayerInfo> findByIPs(String ip){
Array<PlayerInfo> result = new Array<>();
@@ -397,6 +411,7 @@ public class Administration{
/** Server configuration definition. Each config value can be a string, boolean or number. */
public enum Config{
name("The server name as displayed on clients.", "Server", "servername"),
desc("The server description, displayed under the name. Max 100 characters.", "off"),
port("The port to host on.", Vars.port),
autoUpdate("Whether to auto-update and exit when a new bleeding-edge update arrives.", false),
showConnectMessages("Whether to display connect/disconnect messages.", true),
@@ -529,6 +544,10 @@ public class Administration{
public @NonNull ActionType type;
public @NonNull Tile tile;
/** valid for block placement events only */
public @Nullable Block block;
public int rotation;
/** valid for configure and rotation-type events only. */
public int config;
@@ -554,7 +573,7 @@ public class Administration{
}
public enum ActionType{
breakBlock, placeBlock, rotate, configure, withdrawItem, depositItem
breakBlock, placeBlock, rotate, configure, tapTile, withdrawItem, depositItem
}
}

View File

@@ -21,7 +21,7 @@ import static mindustry.Vars.*;
public class ArcNetProvider implements NetProvider{
final Client client;
final Prov<DatagramPacket> packetSupplier = () -> new DatagramPacket(new byte[256], 256);
final Prov<DatagramPacket> packetSupplier = () -> new DatagramPacket(new byte[512], 512);
final Server server;
final CopyOnWriteArrayList<ArcConnection> connections = new CopyOnWriteArrayList<>();
@@ -114,12 +114,7 @@ public class ArcNetProvider implements NetProvider{
try{
net.handleServerReceived(k, object);
}catch(RuntimeException e){
if(e.getCause() instanceof ValidateException){
ValidateException v = (ValidateException)e.getCause();
Log.err("Validation failed: {0} ({1})", v.player.name, v.getMessage());
}else{
e.printStackTrace();
}
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}

View File

@@ -105,7 +105,7 @@ public class BeControl{
});
dialog.cont.add(new Bar(() -> length[0] == 0 ? Core.bundle.get("be.updating") : (int)(progress[0] * length[0]) / 1024/ 1024 + "/" + length[0]/1024/1024 + " MB", () -> Pal.accent, () -> progress[0])).width(400f).height(70f);
dialog.buttons.addImageTextButton("$cancel", Icon.cancelSmall, () -> {
dialog.buttons.addImageTextButton("$cancel", Icon.cancel, () -> {
cancel[0] = true;
dialog.hide();
}).size(210f, 64f);

View File

@@ -21,6 +21,18 @@ import static mindustry.Vars.net;
public class CrashSender{
public static void log(Throwable exception){
try{
Core.settings.getDataDirectory().child("crashes").child("crash_" + System.currentTimeMillis() + ".txt").writeString(Strings.parseException(exception, true));
}catch(Throwable ignored){
}
if(exception instanceof RuntimeException){
throw (RuntimeException)exception;
}
throw new RuntimeException(exception);
}
public static void send(Throwable exception, Cons<File> writeListener){
try{

View File

@@ -6,7 +6,7 @@ import mindustry.game.*;
public class Host{
public final String name;
public final String address;
public final String mapname;
public final String mapname, description;
public final int wave;
public final int players, playerLimit;
public final int version;
@@ -14,7 +14,7 @@ public class Host{
public final Gamemode mode;
public int ping, port = Vars.port;
public Host(String name, String address, String mapname, int wave, int players, int version, String versionType, Gamemode mode, int playerLimit){
public Host(String name, String address, String mapname, int wave, int players, int version, String versionType, Gamemode mode, int playerLimit, String description){
this.name = name;
this.address = address;
this.players = players;
@@ -24,5 +24,6 @@ public class Host{
this.versionType = versionType;
this.playerLimit = playerLimit;
this.mode = mode;
this.description = description;
}
}

View File

@@ -1,7 +1,9 @@
package mindustry.net;
import arc.util.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.entities.traits.BuilderTrait.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.net.Administration.*;
@@ -21,6 +23,8 @@ public abstract class NetConnection{
public int lastRecievedClientSnapshot = -1;
/** Timestamp of last recieved snapshot. */
public long lastRecievedClientTime;
/** Build requests that have been recently rejected. This is cleared every snapshot. */
public Array<BuildRequest> rejectedRequests = new Array<>();
public boolean hasConnected, hasBegunConnecting, hasDisconnected;
public float viewWidth, viewHeight, viewX, viewY;

View File

@@ -63,9 +63,10 @@ public class NetworkIO{
public static ByteBuffer writeServerData(){
String name = (headless ? Config.name.string() : player.name);
String description = headless && !Config.desc.string().equals("off") ? Config.desc.string() : "";
String map = world.getMap() == null ? "None" : world.getMap().name();
ByteBuffer buffer = ByteBuffer.allocate(256);
ByteBuffer buffer = ByteBuffer.allocate(512);
writeString(buffer, name, 100);
writeString(buffer, map);
@@ -77,6 +78,8 @@ public class NetworkIO{
buffer.put((byte)Gamemode.bestFit(state.rules).ordinal());
buffer.putInt(netServer.admins.getPlayerLimit());
writeString(buffer, description, 100);
return buffer;
}
@@ -89,8 +92,9 @@ public class NetworkIO{
String vertype = readString(buffer);
Gamemode gamemode = Gamemode.all[buffer.get()];
int limit = buffer.getInt();
String description = readString(buffer);
return new Host(host, hostAddress, map, wave, players, version, vertype, gamemode, limit);
return new Host(host, hostAddress, map, wave, players, version, vertype, gamemode, limit, description);
}
private static void writeString(ByteBuffer buffer, String string, int maxlen){

View File

@@ -1,9 +1,195 @@
package mindustry.ui;
import arc.*;
import arc.Graphics.Cursor.*;
import arc.assets.*;
import arc.assets.loaders.*;
import arc.assets.loaders.resolvers.*;
import arc.files.*;
import arc.freetype.*;
import arc.freetype.FreeTypeFontGenerator.*;
import arc.freetype.FreetypeFontLoader.*;
import arc.graphics.*;
import arc.graphics.Pixmap.*;
import arc.graphics.Texture.*;
import arc.graphics.g2d.*;
import arc.graphics.g2d.BitmapFont.*;
import arc.graphics.g2d.PixmapPacker.*;
import arc.graphics.g2d.TextureAtlas.*;
import arc.math.geom.*;
import arc.scene.style.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import mindustry.core.*;
import java.util.*;
public class Fonts{
private static ObjectIntMap<String> unicodeIcons = new ObjectIntMap<>();
public static BitmapFont def;
public static BitmapFont outline;
public static BitmapFont chat;
public static BitmapFont icon;
public static int getUnicode(String content){
return unicodeIcons.get(content, 0);
}
/** Called from a static context to make the cursor appear immediately upon startup.*/
public static void loadSystemCursors(){
SystemCursor.arrow.set(Core.graphics.newCursor("cursor"));
SystemCursor.hand.set(Core.graphics.newCursor("hand"));
SystemCursor.ibeam.set(Core.graphics.newCursor("ibeam"));
Core.graphics.restoreCursor();
}
public static void loadFonts(){
String fontName = "fonts/font.ttf";
FreeTypeFontParameter param = fontParameter();
Core.assets.load("default", BitmapFont.class, new FreeTypeFontLoaderParameter(fontName, param)).loaded = f -> Fonts.def = (BitmapFont)f;
Core.assets.load("chat", BitmapFont.class, new FreeTypeFontLoaderParameter(fontName, param)).loaded = f -> Fonts.chat = (BitmapFont)f;
Core.assets.load("icon", BitmapFont.class, new FreeTypeFontLoaderParameter("fonts/icon.ttf", new FreeTypeFontParameter(){{
size = (int)(Scl.scl(30f));
incremental = true;
}})).loaded = f -> Fonts.icon = (BitmapFont)f;
}
public static void loadContentIcons(){
Array<BitmapFont> fonts = Array.with(Fonts.chat, Fonts.def, Fonts.outline);
Texture uitex = Core.atlas.find("logo").getTexture();
int size = (int)(Fonts.def.getData().lineHeight/Fonts.def.getData().scaleY);
try(Scanner scan = new Scanner(Core.files.internal("icons/icons.properties").read(512))){
while(scan.hasNextLine()){
String line = scan.nextLine();
String[] split = line.split("=");
String[] nametex = split[1].split("\\|");
String character = split[0], texture = nametex[1];
int ch = Integer.parseInt(character);
TextureRegion region = Core.atlas.find(texture);
if(region.getTexture() != uitex) throw new IllegalArgumentException("Font icon '" + texture + "' is not in the UI texture.");
unicodeIcons.put(nametex[0], ch);
Glyph glyph = new Glyph();
glyph.id = ch;
glyph.srcX = 0;
glyph.srcY = 0;
glyph.width = size;
glyph.height = size;
glyph.u = region.getU();
glyph.v = region.getV2();
glyph.u2 = region.getU2();
glyph.v2 = region.getV();
glyph.xoffset = 0;
glyph.yoffset = -size;
glyph.xadvance = size;
glyph.kerning = null;
glyph.fixedWidth = true;
glyph.page = 0;
fonts.each(f -> f.getData().setGlyph(ch, glyph));
}
}
}
/** Called from a static context for use in the loading screen.*/
public static void loadDefaultFont(){
UI.packer = new PixmapPacker(2048, 2048, Format.RGBA8888, 2, true);
FileHandleResolver resolver = new InternalFileHandleResolver();
Core.assets.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver));
Core.assets.setLoader(BitmapFont.class, null, new FreetypeFontLoader(resolver){
@Override
public BitmapFont loadSync(AssetManager manager, String fileName, Fi file, FreeTypeFontLoaderParameter parameter){
if(fileName.equals("outline")){
parameter.fontParameters.borderWidth = Scl.scl(2f);
parameter.fontParameters.spaceX -= parameter.fontParameters.borderWidth;
}
parameter.fontParameters.magFilter = TextureFilter.Linear;
parameter.fontParameters.minFilter = TextureFilter.Linear;
parameter.fontParameters.packer = UI.packer;
return super.loadSync(manager, fileName, file, parameter);
}
});
FreeTypeFontParameter param = new FreeTypeFontParameter(){{
borderColor = Color.darkGray;
size = (int)(Scl.scl(18f));
incremental = true;
}};
Core.assets.load("outline", BitmapFont.class, new FreeTypeFontLoaderParameter("fonts/font.ttf", param)).loaded = t -> Fonts.outline = (BitmapFont)t;
}
/** Merges the UI and font atlas together for better performance. */
public static void mergeFontAtlas(TextureAtlas atlas){
//grab all textures from the ui page, remove all the regions assigned to it, then copy them over to Fonts.packer and replace the texture in this atlas.
//grab old UI texture and regions...
Texture texture = atlas.find("logo").getTexture();
Page page = UI.packer.getPages().first();
Array<AtlasRegion> regions = atlas.getRegions().select(t -> t.getTexture() == texture);
for(AtlasRegion region : regions){
//get new pack rect
page.setDirty(false);
Rect rect = UI.packer.pack(region.name + (region.splits != null ? ".9" : ""), atlas.getPixmap(region));
//set new texture
region.setTexture(UI.packer.getPages().first().getTexture());
//set its new position
region.set((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
//add old texture
atlas.getTextures().add(region.getTexture());
}
//remove old texture, it will no longer be used
atlas.getTextures().remove(texture);
texture.dispose();
atlas.disposePixmap(texture);
page.setDirty(true);
page.updateTexture(TextureFilter.Linear, TextureFilter.Linear, false);
}
public static TextureRegionDrawable getGlyph(BitmapFont font, char glyph){
Glyph g = font.getData().getGlyph(glyph);
if(g == null) throw new IllegalArgumentException("No glyph: " + glyph + " (" + (int)glyph + ")");
float size = Math.max(g.width, g.height);
float aspect = (float)g.height / g.width;
TextureRegionDrawable draw = new TextureRegionDrawable(new TextureRegion(font.getRegion().getTexture(), g.u, g.v2, g.u2, g.v)){
@Override
public void draw(float x, float y, float width, float height){
Draw.color(Tmp.c1.set(tint).mul(Draw.getColor()).toFloatBits());
float cx = x + width/2f - g.width/2f, cy = y + height/2f - g.height/2f;
cx = (int)cx;
cy = (int)cy;
Draw.rect(region, cx + g.width/2f, cy + g.height/2f, g.width, g.height);
}
@Override
public float imageSize(){
return size;
}
};
draw.setMinWidth(size);
draw.setMinHeight(size);
return draw;
}
static FreeTypeFontParameter fontParameter(){
return new FreeTypeFontParameter(){{
size = (int)(Scl.scl(18f));
shadowColor = Color.darkGray;
shadowOffsetY = 2;
incremental = true;
}};
}
}

View File

@@ -27,7 +27,7 @@ public class ItemImage extends Stack{
if(stack.amount != 0){
Table t = new Table().left().bottom();
t.add(stack.amount + "").name("item-label");
t.add(stack.amount + "").name("item-label").style(Styles.outlineLabel);
add(t);
}
}

View File

@@ -1,8 +1,10 @@
package mindustry.ui;
import arc.Core;
import arc.scene.style.*;
import arc.util.Strings;
import arc.graphics.Color;
import mindustry.gen.*;
import mindustry.graphics.Pal;
public class Links{
@@ -10,17 +12,17 @@ public class Links{
private static void createLinks(){
links = new LinkEntry[]{
new LinkEntry("discord", "https://discord.gg/mindustry", Color.valueOf("7289da")),
new LinkEntry("changelog", "https://github.com/Anuken/Mindustry/releases", Pal.accent.cpy()),
new LinkEntry("trello", "https://trello.com/b/aE2tcUwF", Color.valueOf("026aa7")),
new LinkEntry("wiki", "https://mindustrygame.github.io/wiki/", Color.valueOf("0f142f")),
new LinkEntry("feathub", "https://feathub.com/Anuken/Mindustry/", Color.valueOf("ebebeb")),
new LinkEntry("reddit", "https://www.reddit.com/r/Mindustry/", Color.valueOf("ee593b")),
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("f-droid", "https://f-droid.org/packages/io.anuke.mindustry/", Color.valueOf("026aa7")),
new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Color.valueOf("24292e")),
new LinkEntry("dev-builds", "https://github.com/Anuken/MindustryBuilds", Color.valueOf("fafbfc"))
new LinkEntry("discord", "https://discord.gg/mindustry", Icon.discord, Color.valueOf("7289da")),
new LinkEntry("changelog", "https://github.com/Anuken/Mindustry/releases", Icon.list, Pal.accent.cpy()),
new LinkEntry("trello", "https://trello.com/b/aE2tcUwF", Icon.trello, Color.valueOf("026aa7")),
new LinkEntry("wiki", "https://mindustrygame.github.io/wiki/", Icon.book, Color.valueOf("0f142f")),
new LinkEntry("feathub", "https://feathub.com/Anuken/Mindustry/", Icon.add, Color.valueOf("ebebeb")),
new LinkEntry("reddit", "https://www.reddit.com/r/Mindustry/", Icon.redditAlien, Color.valueOf("ee593b")),
new LinkEntry("itch.io", "https://anuke.itch.io/mindustry", Icon.itchio, Color.valueOf("fa5c5c")),
new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Icon.googleplay, Color.valueOf("689f38")),
new LinkEntry("f-droid", "https://f-droid.org/packages/io.anuke.mindustry/", Icon.android, Color.valueOf("026aa7")),
new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Icon.github, Color.valueOf("24292e")),
new LinkEntry("dev-builds", "https://github.com/Anuken/MindustryBuilds", Icon.githubSquare, Color.valueOf("fafbfc"))
};
}
@@ -35,12 +37,14 @@ public class Links{
public static class LinkEntry{
public final String name, title, description, link;
public final Color color;
public final Drawable icon;
public LinkEntry(String name, String link, Color color){
public LinkEntry(String name, String link, Drawable icon, Color color){
this.name = name;
this.color = color;
this.description = Core.bundle.getNotNull("link." + name + ".description");
this.link = link;
this.icon = icon;
String title = Core.bundle.getOrNull("link." + name + ".title");
this.title = title != null ? title : Strings.capitalize(name.replace("-", " "));

View File

@@ -24,13 +24,13 @@ public class LiquidDisplay extends Table{
if(amount != 0){
Table t = new Table().left().bottom();
t.add(Strings.autoFixed(amount, 1));
t.add(Strings.autoFixed(amount, 1)).style(Styles.outlineLabel);
add(t);
}
}}).size(8 * 4).padRight(3 + (amount != 0 && Strings.autoFixed(amount, 1).length() > 2 ? 8 : 0));
if(perSecond){
add(StatUnit.perSecond.localized()).padLeft(2).padRight(5).color(Color.lightGray);
add(StatUnit.perSecond.localized()).padLeft(2).padRight(5).color(Color.lightGray).style(Styles.outlineLabel);
}
add(liquid.localizedName);

View File

@@ -55,7 +55,7 @@ public class AboutDialog extends FloatingDialog{
table.table(i -> {
i.background(Tex.buttonEdge3);
i.addImage(Core.atlas.drawable("icon-" + link.name));
i.addImage(link.icon);
}).size(h - 5, h);
table.table(inset -> {

View File

@@ -55,7 +55,7 @@ public class ColorPicker extends FloatingDialog{
buttons.clear();
addCloseButton();
buttons.addImageTextButton("$ok", Icon.checkSmall, () -> {
buttons.addImageTextButton("$ok", Icon.ok, () -> {
cons.get(current);
hide();
});

View File

@@ -17,7 +17,7 @@ public class ControlsDialog extends KeybindDialog{
@Override
public void addCloseButton(){
buttons.addImageTextButton("$back", Icon.arrowLeftSmall, this::hide).size(230f, 64f);
buttons.addImageTextButton("$back", Icon.left, this::hide).size(230f, 64f);
keyDown(key -> {
if(key == KeyCode.ESCAPE || key == KeyCode.BACK)

View File

@@ -35,12 +35,12 @@ public class CustomRulesDialog extends FloatingDialog{
banDialog.addCloseButton();
banDialog.shown(this::rebuildBanned);
banDialog.buttons.addImageTextButton("$addall", Icon.arrow16Small, () -> {
banDialog.buttons.addImageTextButton("$addall", Icon.add, () -> {
rules.bannedBlocks.addAll(content.blocks().select(Block::isBuildable));
rebuildBanned();
}).size(180, 64f);
banDialog.buttons.addImageTextButton("$clear", Icon.trash16Small, () -> {
banDialog.buttons.addImageTextButton("$clear", Icon.trash, () -> {
rules.bannedBlocks.clear();
rebuildBanned();
}).size(180, 64f);
@@ -72,7 +72,7 @@ public class CustomRulesDialog extends FloatingDialog{
b.addImage(block.icon(Cicon.medium)).size(Cicon.medium.size).padRight(3);
b.add(block.localizedName).color(Color.lightGray).padLeft(3).growX().left().wrap();
b.addImageButton(Icon.cancelSmall, Styles.clearPartiali, () -> {
b.addImageButton(Icon.cancel, Styles.clearPartiali, () -> {
rules.bannedBlocks.remove(block);
rebuildBanned();
}).size(70f).pad(-4f).padLeft(0f);
@@ -84,7 +84,7 @@ public class CustomRulesDialog extends FloatingDialog{
}
}).get().setScrollYForce(previousScroll);
banDialog.cont.row();
banDialog.cont.addImageTextButton("$add", Icon.addSmall, () -> {
banDialog.cont.addImageTextButton("$add", Icon.add, () -> {
FloatingDialog dialog = new FloatingDialog("$add");
dialog.cont.pane(t -> {
t.left().margin(14f);

View File

@@ -1,6 +1,7 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.input.*;
import arc.struct.*;
import arc.graphics.*;
import arc.scene.event.*;
@@ -15,6 +16,8 @@ import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.ui.*;
import static mindustry.Vars.ui;
public class DatabaseDialog extends FloatingDialog{
public DatabaseDialog(){
@@ -55,7 +58,7 @@ public class DatabaseDialog extends FloatingDialog{
for(int i = 0; i < array.size; i++){
UnlockableContent unlock = (UnlockableContent)array.get(i);
Image image = unlocked(unlock) ? new Image(unlock.icon(Cicon.medium)) : new Image(Icon.lockedSmall, Pal.gray);
Image image = unlocked(unlock) ? new Image(unlock.icon(Cicon.medium)) : new Image(Icon.lockOpen, Pal.gray);
list.add(image).size(8*4).pad(3);
ClickListener listener = new ClickListener();
image.addListener(listener);
@@ -65,7 +68,14 @@ public class DatabaseDialog extends FloatingDialog{
}
if(unlocked(unlock)){
image.clicked(() -> Vars.ui.content.show(unlock));
image.clicked(() -> {
if(Core.input.keyDown(KeyCode.SHIFT_LEFT) && Fonts.getUnicode(unlock.name) != 0){
Core.app.setClipboardText((char)Fonts.getUnicode(unlock.name) + "");
ui.showInfoFade("$copied");
}else{
Vars.ui.content.show(unlock);
}
});
image.addListener(new Tooltip(t -> t.background(Tex.button).add(unlock.localizedName)));
}

View File

@@ -122,7 +122,7 @@ public class DeployDialog extends FloatingDialog{
setFilter(TextureFilter.Linear);
}}){{
float[] time = {0};
setColor(Color.fromGray(0.3f));
setColor(Color.gray(0.3f));
setScale(1.5f);
update(() -> {
setOrigin(Align.center);
@@ -140,7 +140,7 @@ public class DeployDialog extends FloatingDialog{
Stack sub = new Stack();
if(slot.getZone() != null){
sub.add(new Table(f -> f.margin(4f).add(new Image()).color(Color.fromGray(0.1f)).grow()));
sub.add(new Table(f -> f.margin(4f).add(new Image()).color(Color.gray(0.1f)).grow()));
sub.add(new Table(f -> f.margin(4f).add(new Image(slot.getZone().preview).setScaling(Scaling.fit)).update(img -> {
TextureRegionDrawable draw = (TextureRegionDrawable)img.getDrawable();
@@ -235,7 +235,7 @@ public class DeployDialog extends FloatingDialog{
button.labelWrap(zone.localizedName).style(Styles.outlineLabel).width(140).growX().get().setAlignment(Align.center);
}else{
Cons<Element> flasher = zone.canUnlock() && !hidden(zone) ? e -> e.update(() -> e.getColor().set(Color.white).lerp(Pal.accent, Mathf.absin(3f, 1f))) : e -> {};
flasher.get(button.addImage(Icon.locked).get());
flasher.get(button.addImage(Icon.lock).get());
button.row();
flasher.get(button.add("$locked").get());
}
@@ -254,7 +254,7 @@ public class DeployDialog extends FloatingDialog{
}
stack.setSize(Tmp.v1.x, Tmp.v1.y);
stack.add(new Table(t -> t.margin(4f).add(new Image(node.zone.preview).setScaling(Scaling.stretch)).color(node.zone.unlocked() ? Color.darkGray : Color.fromGray(0.2f)).grow()));
stack.add(new Table(t -> t.margin(4f).add(new Image(node.zone.preview).setScaling(Scaling.stretch)).color(node.zone.unlocked() ? Color.darkGray : Color.gray(0.2f)).grow()));
stack.update(() -> stack.setPosition(node.x + panX + width / 2f, node.y + panY + height / 2f, Align.center));
Button button = new Button(Styles.squaret);

View File

@@ -92,15 +92,15 @@ public class FileChooser extends FloatingDialog{
Table icontable = new Table();
ImageButton up = new ImageButton(Icon.folderParent);
ImageButton up = new ImageButton(Icon.upOpen);
up.clicked(() -> {
directory = directory.parent();
updateFiles(true);
});
ImageButton back = new ImageButton(Icon.arrowLeft);
ImageButton forward = new ImageButton(Icon.arrowRight);
ImageButton back = new ImageButton(Icon.left);
ImageButton forward = new ImageButton(Icon.right);
forward.clicked(() -> stack.forward());
back.clicked(() -> stack.back());
@@ -185,7 +185,7 @@ public class FileChooser extends FloatingDialog{
files.top().left();
Fi[] names = getFileNames();
Image upimage = new Image(Icon.folderParentSmall);
Image upimage = new Image(Icon.upOpen);
TextButton upbutton = new TextButton(".." + directory.toString(), Styles.clearTogglet);
upbutton.clicked(() -> {
directory = directory.parent();
@@ -229,7 +229,7 @@ public class FileChooser extends FloatingDialog{
button.setChecked(filename.equals(filefield.getText()));
});
Image image = new Image(file.isDirectory() ? Icon.folderSmall : Icon.fileTextSmall);
Image image = new Image(file.isDirectory() ? Icon.folder : Icon.fileText);
button.add(image).padRight(4f).padLeft(4);
button.getCells().reverse();

View File

@@ -56,7 +56,7 @@ public class FloatingDialog extends Dialog{
@Override
public void addCloseButton(){
buttons.defaults().size(210f, 64f);
buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f);
buttons.addImageTextButton("$back", Icon.left, this::hide).size(210f, 64f);
keyDown(key -> {
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){

View File

@@ -122,7 +122,7 @@ public class JoinDialog extends FloatingDialog{
inner.add(button.getLabel()).growX();
inner.addImageButton(Icon.arrowUpSmall, Styles.emptyi, () -> {
inner.addImageButton(Icon.upOpen, Styles.emptyi, () -> {
int index = servers.indexOf(server);
if(index > 0){
servers.remove(index);
@@ -139,25 +139,25 @@ public class JoinDialog extends FloatingDialog{
}
}
}).margin(3f).padTop(6f).top().right();
}).margin(3f).pad(2).padTop(6f).top().right();
inner.addImageButton(Icon.loadingSmall, Styles.emptyi, () -> {
inner.addImageButton(Icon.refresh, Styles.emptyi, () -> {
refreshServer(server);
}).margin(3f).padTop(6f).top().right();
}).margin(3f).pad(2).padTop(6f).top().right();
inner.addImageButton(Icon.pencilSmall, Styles.emptyi, () -> {
inner.addImageButton(Icon.pencil, Styles.emptyi, () -> {
renaming = server;
add.show();
}).margin(3f).padTop(6f).top().right();
}).margin(3f).pad(2).padTop(6f).top().right();
inner.addImageButton(Icon.trash16Small, Styles.emptyi, () -> {
inner.addImageButton(Icon.trash, Styles.emptyi, () -> {
ui.showConfirm("$confirm", "$server.delete", () -> {
servers.removeValue(server, true);
saveServers();
setupRemote();
refreshRemote();
});
}).margin(3f).pad(6).top().right();
}).margin(3f).pad(2).pad(6).top().right();
button.row();
@@ -179,7 +179,7 @@ public class JoinDialog extends FloatingDialog{
net.pingHost(server.ip, server.port, host -> setupServer(server, host), e -> {
server.content.clear();
server.content.add("$host.invalid");
server.content.add("$host.invalid").padBottom(4);
});
}
@@ -212,6 +212,10 @@ public class JoinDialog extends FloatingDialog{
content.table(t -> {
t.add("[lightgray]" + host.name + " " + versionString).width(targetWidth() - 10f).left().get().setEllipsis(true);
t.row();
if(!host.description.isEmpty()){
t.add("[gray]" + host.description).width(targetWidth() - 10f).left().wrap();
t.row();
}
t.add("[lightgray]" + (Core.bundle.format("players" + (host.players == 1 && host.playerLimit <= 0 ? ".single" : ""), (host.players == 0 ? "[lightgray]" : "[accent]") + host.players + (host.playerLimit > 0 ? "[lightgray]/[accent]" + host.playerLimit : "")+ "[lightgray]"))).left();
t.row();
t.add("[lightgray]" + Core.bundle.format("save.map", host.mapname) + "[lightgray] / " + host.mode.toString()).width(targetWidth() - 10f).left().get().setEllipsis(true);
@@ -303,7 +307,7 @@ public class JoinDialog extends FloatingDialog{
local.background(Tex.button);
local.add("$hosts.none").pad(10f);
local.add().growX();
local.addImageButton(Icon.loading, this::refreshLocal).pad(-12f).padLeft(0).size(70f);
local.addImageButton(Icon.refresh, this::refreshLocal).pad(-12f).padLeft(0).size(70f);
}else{
local.background(null);
}

View File

@@ -71,7 +71,7 @@ public class LoadDialog extends FloatingDialog{
title.table(t -> {
t.right();
t.addImageButton(Icon.floppy, Styles.emptytogglei, () -> {
t.addImageButton(Icon.save, Styles.emptytogglei, () -> {
slot.setAutosave(!slot.isAutosave());
}).checked(slot.isAutosave()).right();

View File

@@ -42,9 +42,9 @@ public class LoadoutDialog extends FloatingDialog{
}
});
buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f);
buttons.addImageTextButton("$back", Icon.left, this::hide).size(210f, 64f);
buttons.addImageTextButton("$settings.reset", Icon.refreshSmall, () -> {
buttons.addImageTextButton("$settings.reset", Icon.refresh, () -> {
resetter.run();
reseed();
updater.run();
@@ -83,7 +83,7 @@ public class LoadoutDialog extends FloatingDialog{
updater.run();
}).size(bsize);
t.addImageButton(Icon.pencilSmaller, Styles.cleari, () -> ui.showTextInput("$configure", stack.item.localizedName, 10, stack.amount + "", true, str -> {
t.addImageButton(Icon.pencil, Styles.cleari, () -> ui.showTextInput("$configure", stack.item.localizedName, 10, stack.amount + "", true, str -> {
if(Strings.canParsePostiveInt(str)){
int amount = Strings.parseInt(str);
if(amount >= 0 && amount <= capacity){

View File

@@ -68,7 +68,7 @@ public class MapPlayDialog extends FloatingDialog{
cont.add(selmode);
cont.row();
cont.addImageTextButton("$customize", Icon.toolsSmall, () -> dialog.show(rules, () -> rules = map.applyRules(selectedGamemode))).width(230);
cont.addImageTextButton("$customize", Icon.settings, () -> dialog.show(rules, () -> rules = map.applyRules(selectedGamemode))).width(230);
cont.row();
cont.add(new BorderImage(map.safeTexture(), 3f)).size(mobile && !Core.graphics.isPortrait() ? 150f : 250f).get().setScaling(Scaling.fit);
//only maps with survival are valid for high scores

View File

@@ -44,10 +44,10 @@ public class MapsDialog extends FloatingDialog{
buttons.clearChildren();
if(Core.graphics.isPortrait()){
buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f*2f, 64f).colspan(2);
buttons.addImageTextButton("$back", Icon.left, this::hide).size(210f*2f, 64f).colspan(2);
buttons.row();
}else{
buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f);
buttons.addImageTextButton("$back", Icon.left, this::hide).size(210f, 64f);
}
buttons.addImageTextButton("$editor.newmap", Icon.add, () -> {
@@ -67,7 +67,7 @@ public class MapsDialog extends FloatingDialog{
});
}).size(210f, 64f);
buttons.addImageTextButton("$editor.importmap", Icon.load, () -> {
buttons.addImageTextButton("$editor.importmap", Icon.upload, () -> {
platform.showFileChooser(true, mapExtension, file -> {
ui.loadAnd(() -> {
maps.tryCatchMapError(() -> {
@@ -192,7 +192,7 @@ public class MapsDialog extends FloatingDialog{
table.row();
table.addImageTextButton("$editor.openin", Icon.loadMapSmall, () -> {
table.addImageTextButton("$editor.openin", Icon.export, () -> {
try{
Vars.ui.editor.beginEditMap(map.file);
dialog.hide();
@@ -203,7 +203,7 @@ public class MapsDialog extends FloatingDialog{
}
}).fillX().height(54f).marginLeft(10);
table.addImageTextButton(map.workshop && steam ? "$view.workshop" : "$delete", map.workshop && steam ? Icon.linkSmall : Icon.trash16Small, () -> {
table.addImageTextButton(map.workshop && steam ? "$view.workshop" : "$delete", map.workshop && steam ? Icon.link : Icon.trash, () -> {
if(map.workshop && steam){
platform.viewListing(map);
}else{

View File

@@ -20,15 +20,8 @@ public class ModsDialog extends FloatingDialog{
super("$mods");
addCloseButton();
buttons.addImageTextButton(mobile ? "$mods.report" : "$mods.openfolder", Icon.link,
() -> {
if(mobile){
Core.net.openURI(reportIssueURL);
}else{
Core.net.openFolder(modDirectory.absolutePath());
}
})
.size(250f, 64f);
buttons.addImageTextButton("$mods.openfolder", Icon.link,
() -> Core.app.openFolder(modDirectory.absolutePath())).size(250f, 64f);
buttons.row();
@@ -127,18 +120,18 @@ public class ModsDialog extends FloatingDialog{
title.add("[accent]" + mod.meta.displayName() + "[lightgray] v" + mod.meta.version + (mod.enabled() ? "" : "\n" + Core.bundle.get("mod.disabled") + "")).width(200f).wrap();
title.add().growX();
title.addImageTextButton(mod.enabled() ? "$mod.disable" : "$mod.enable", mod.enabled() ? Icon.arrowDownSmall : Icon.arrowUpSmall, Styles.cleart, () -> {
title.addImageTextButton(mod.enabled() ? "$mod.disable" : "$mod.enable", mod.enabled() ? Icon.downOpen : Icon.upOpen, Styles.cleart, () -> {
mods.setEnabled(mod, !mod.enabled());
setup();
}).height(50f).margin(8f).width(130f).disabled(!mod.isSupported());
if(steam && !mod.hasSteamID()){
title.addImageButton(Icon.loadMapSmall, Styles.cleari, () -> {
title.addImageButton(Icon.download, Styles.cleari, () -> {
platform.publish(mod);
}).size(50f);
}
title.addImageButton(mod.hasSteamID() ? Icon.linkSmall : Icon.trash16Small, Styles.cleari, () -> {
title.addImageButton(mod.hasSteamID() ? Icon.link : Icon.trash, Styles.cleari, () -> {
if(!mod.hasSteamID()){
ui.showConfirm("$confirm", "$mod.remove.confirm", () -> {
mods.removeMod(mod);

View File

@@ -35,29 +35,29 @@ public class PausedDialog extends FloatingDialog{
});
if(!mobile){
float dw = 210f;
cont.defaults().width(dw).height(50).pad(5f);
float dw = 220f;
cont.defaults().width(dw).height(55).pad(5f);
cont.addButton("$back", this::hide).colspan(2).width(dw * 2 + 20f);
cont.addImageTextButton("$back", Icon.left, this::hide).colspan(2).width(dw * 2 + 20f);
cont.row();
if(world.isZone()){
cont.addButton("$techtree", ui.tech::show);
cont.addImageTextButton("$techtree", Icon.tree, ui.tech::show);
}else{
cont.addButton("$database", ui.database::show);
cont.addImageTextButton("$database", Icon.book, ui.database::show);
}
cont.addButton("$settings", ui.settings::show);
cont.addImageTextButton("$settings", Icon.settings, ui.settings::show);
if(!state.rules.tutorial){
if(!world.isZone() && !state.isEditor()){
cont.row();
cont.addButton("$savegame", save::show);
cont.addButton("$loadgame", load::show).disabled(b -> net.active());
cont.addImageTextButton("$savegame", Icon.save, save::show);
cont.addImageTextButton("$loadgame", Icon.upload, load::show).disabled(b -> net.active());
}
cont.row();
cont.addButton("$hostserver", () -> {
cont.addImageTextButton("$hostserver", Icon.host, () -> {
if(net.server() && steam){
platform.inviteFriends();
}else{
@@ -72,26 +72,29 @@ public class PausedDialog extends FloatingDialog{
cont.row();
cont.addButton("$quit", this::showQuitConfirm).colspan(2).width(dw + 10f).update(s -> s.setText(control.saves.getCurrent() != null && control.saves.getCurrent().isAutosave() ? "$save.quit" : "$quit"));
cont.addImageTextButton("$quit", Icon.exit, this::showQuitConfirm).colspan(2).width(dw + 20f).update(s -> s.setText(control.saves.getCurrent() != null && control.saves.getCurrent().isAutosave() ? "$save.quit" : "$quit"));
}else{
cont.defaults().size(130f).pad(5);
cont.addRowImageTextButton("$back", Icon.play2, this::hide);
cont.addRowImageTextButton("$settings", Icon.tools, ui.settings::show);
cont.addRowImageTextButton("$back", Icon.play, this::hide);
cont.addRowImageTextButton("$settings", Icon.settings, ui.settings::show);
if(!world.isZone() && !state.isEditor()){
cont.addRowImageTextButton("$save", Icon.save, save::show);
cont.row();
cont.addRowImageTextButton("$load", Icon.load, load::show).disabled(b -> net.active());
cont.addRowImageTextButton("$load", Icon.download, load::show).disabled(b -> net.active());
}else{
cont.row();
}
cont.addRowImageTextButton("$hostserver.mobile", Icon.host, ui.host::show).disabled(b -> net.active());
cont.addRowImageTextButton("$quit", Icon.quit, this::showQuitConfirm).update(s -> s.setText(control.saves.getCurrent() != null && control.saves.getCurrent().isAutosave() ? "$save.quit" : "$quit"));
cont.addRowImageTextButton("$quit", Icon.exit, this::showQuitConfirm).update(s -> {
s.setText(control.saves.getCurrent() != null && control.saves.getCurrent().isAutosave() ? "$save.quit" : "$quit");
s.getLabelCell().growX().wrap();
});
}
}

View File

@@ -32,7 +32,7 @@ public class SchematicsDialog extends FloatingDialog{
shouldPause = true;
addCloseButton();
buttons.addImageTextButton("$schematic.import", Icon.loadMapSmall, this::showImport);
buttons.addImageTextButton("$schematic.import", Icon.download, this::showImport);
shown(this::setup);
onResize(this::setup);
}
@@ -79,15 +79,15 @@ public class SchematicsDialog extends FloatingDialog{
ImageButtonStyle style = Styles.clearPartiali;
buttons.addImageButton(Icon.infoSmall, style, () -> {
buttons.addImageButton(Icon.info, style, () -> {
showInfo(s);
});
buttons.addImageButton(Icon.loadMapSmall, style, () -> {
buttons.addImageButton(Icon.download, style, () -> {
showExport(s);
});
buttons.addImageButton(Icon.pencilSmall, style, () -> {
buttons.addImageButton(Icon.pencil, style, () -> {
ui.showTextInput("$schematic.rename", "$name", s.name(), res -> {
s.tags.put("name", res);
s.save();
@@ -96,9 +96,9 @@ public class SchematicsDialog extends FloatingDialog{
});
if(s.hasSteamID()){
buttons.addImageButton(Icon.linkSmall, style, () -> platform.viewListing(s));
buttons.addImageButton(Icon.link, style, () -> platform.viewListing(s));
}else{
buttons.addImageButton(Icon.trash16Small, style, () -> {
buttons.addImageButton(Icon.trash, style, () -> {
if(s.mod != null){
ui.showInfo(Core.bundle.format("mod.item.remove", s.mod.meta.displayName()));
}else{
@@ -154,7 +154,7 @@ public class SchematicsDialog extends FloatingDialog{
TextButtonStyle style = Styles.cleart;
t.defaults().size(280f, 60f).left();
t.row();
t.addImageTextButton("$schematic.copy.import", Icon.copySmall, style, () -> {
t.addImageTextButton("$schematic.copy.import", Icon.copy, style, () -> {
dialog.hide();
try{
Schematic s = Schematics.readBase64(Core.app.getClipboardText());
@@ -168,7 +168,7 @@ public class SchematicsDialog extends FloatingDialog{
}
}).marginLeft(12f).disabled(b -> Core.app.getClipboardText() == null || !Core.app.getClipboardText().startsWith(schematicBaseStart));
t.row();
t.addImageTextButton("$schematic.importfile", Icon.saveMapSmall, style, () -> platform.showFileChooser(true, schematicExtension, file -> {
t.addImageTextButton("$schematic.importfile", Icon.download, style, () -> platform.showFileChooser(true, schematicExtension, file -> {
dialog.hide();
try{
@@ -183,7 +183,7 @@ public class SchematicsDialog extends FloatingDialog{
})).marginLeft(12f);
t.row();
if(steam){
t.addImageTextButton("$schematic.browseworkshop", Icon.wikiSmall, style, () -> {
t.addImageTextButton("$schematic.browseworkshop", Icon.book, style, () -> {
dialog.hide();
platform.openWorkshop();
}).marginLeft(12f);
@@ -203,18 +203,18 @@ public class SchematicsDialog extends FloatingDialog{
TextButtonStyle style = Styles.cleart;
t.defaults().size(280f, 60f).left();
if(steam && !s.hasSteamID()){
t.addImageTextButton("$schematic.shareworkshop", Icon.wikiSmall, style,
t.addImageTextButton("$schematic.shareworkshop", Icon.book, style,
() -> platform.publish(s)).marginLeft(12f);
t.row();
dialog.hide();
}
t.addImageTextButton("$schematic.copy", Icon.copySmall, style, () -> {
t.addImageTextButton("$schematic.copy", Icon.copy, style, () -> {
dialog.hide();
ui.showInfoFade("$copied");
Core.app.setClipboardText(schematics.writeBase64(s));
}).marginLeft(12f);
t.row();
t.addImageTextButton("$schematic.exportfile", Icon.saveMapSmall, style, () -> platform.showFileChooser(false, schematicExtension, file -> {
t.addImageTextButton("$schematic.exportfile", Icon.export, style, () -> platform.showFileChooser(false, schematicExtension, file -> {
dialog.hide();
try{
Schematics.write(s, file);
@@ -272,7 +272,7 @@ public class SchematicsDialog extends FloatingDialog{
if(wasSet){
super.draw();
}else{
Draw.rect(Icon.loading.getRegion(), x + width/2f, y + height/2f, width/4f, height/4f);
Draw.rect(Icon.refresh.getRegion(), x + width/2f, y + height/2f, width/4f, height/4f);
}
Draw.color(checked ? Pal.accent : borderColor);

View File

@@ -81,10 +81,10 @@ public class SettingsMenuDialog extends SettingsDialog{
dataDialog.addCloseButton();
dataDialog.cont.table(Tex.button, t -> {
t.defaults().size(240f, 60f).left();
t.defaults().size(270f, 60f).left();
TextButtonStyle style = Styles.cleart;
t.addButton("$settings.cleardata", style, () -> ui.showConfirm("$confirm", "$settings.clearall.confirm", () -> {
t.addImageTextButton("$settings.cleardata", Icon.trash, style, () -> ui.showConfirm("$confirm", "$settings.clearall.confirm", () -> {
ObjectMap<String, Object> map = new ObjectMap<>();
for(String value : Core.settings.keys()){
if(value.contains("usid") || value.contains("uuid")){
@@ -104,7 +104,7 @@ public class SettingsMenuDialog extends SettingsDialog{
t.row();
t.addButton("$data.export", style, () -> {
t.addImageTextButton("$data.export", Icon.download, style, () -> {
if(ios){
Fi file = Core.files.local("mindustry-data-export.zip");
try{
@@ -128,7 +128,7 @@ public class SettingsMenuDialog extends SettingsDialog{
t.row();
t.addButton("$data.import", style, () -> ui.showConfirm("$confirm", "$data.import.confirm", () -> platform.showFileChooser(true, "zip", file -> {
t.addImageTextButton("$data.import", Icon.download, style, () -> ui.showConfirm("$confirm", "$data.import.confirm", () -> platform.showFileChooser(true, "zip", file -> {
try{
data.importData(file);
Core.app.exit();
@@ -143,6 +143,11 @@ public class SettingsMenuDialog extends SettingsDialog{
}
}
})));
if(!ios){
t.row();
t.addImageTextButton("$data.openfolder", Icon.folder, style, () -> Core.app.openFolder(Core.settings.getDataDirectory().absolutePath()));
}
});
ScrollPane pane = new ScrollPane(prefs);
@@ -290,7 +295,7 @@ public class SettingsMenuDialog extends SettingsDialog{
if(Core.settings.getBool("borderlesswindow")){
Core.app.post(() -> Core.graphics.setUndecorated(true));
}
}else{
}else if(!ios){
graphics.checkPref("landscape", false, b -> {
if(b){
platform.beginForceLandscape();
@@ -357,7 +362,7 @@ public class SettingsMenuDialog extends SettingsDialog{
@Override
public void addCloseButton(){
buttons.addImageTextButton("$back", Icon.arrowLeftSmaller, () -> {
buttons.addImageTextButton("$back", Icon.leftOpen, () -> {
if(prefs.getChildren().first() != menu){
back();
}else{

View File

@@ -60,7 +60,7 @@ public class TechTreeDialog extends FloatingDialog{
addCloseButton();
buttons.addImageTextButton("$database", Icon.database, () -> {
buttons.addImageTextButton("$database", Icon.book, () -> {
hide();
ui.database.show();
}).size(210f, 64f);
@@ -324,7 +324,7 @@ public class TechTreeDialog extends FloatingDialog{
infoTable.table(b -> {
b.margin(0).left().defaults().left();
b.addImageButton(Icon.infoSmall, Styles.cleari, () -> ui.content.show(node.block)).growY().width(50f);
b.addImageButton(Icon.info, Styles.cleari, () -> ui.content.show(node.block)).growY().width(50f);
b.add().grow();
b.table(desc -> {
desc.left().defaults().left();
@@ -351,7 +351,7 @@ public class TechTreeDialog extends FloatingDialog{
if(mobile && locked(node)){
b.row();
b.addImageTextButton("$research", Icon.checkSmall, Styles.nodet, () -> unlock(node))
b.addImageTextButton("$research", Icon.ok, Styles.nodet, () -> unlock(node))
.disabled(i -> !data.hasItems(node.requirements)).growX().height(44f).colspan(3);
}
});

View File

@@ -45,7 +45,7 @@ public class ZoneInfoDialog extends FloatingDialog{
if(i++ % 2 == 0){
iteminfo.row();
}
iteminfo.addImage(stack.item.icon(mindustry.ui.Cicon.small)).size(8 * 3).padRight(1);
iteminfo.addImage(stack.item.icon(Cicon.small)).size(8 * 3).padRight(1);
iteminfo.add(stack.amount + "").color(Color.lightGray).padRight(5);
}
};
@@ -54,7 +54,7 @@ public class ZoneInfoDialog extends FloatingDialog{
cont.pane(cont -> {
if(zone.locked()){
cont.addImage(Icon.locked);
cont.addImage(Icon.lock);
cont.row();
cont.add("$locked").padBottom(6);
cont.row();
@@ -71,7 +71,7 @@ public class ZoneInfoDialog extends FloatingDialog{
for(Objective o : zones){
r.addImage(Icon.terrain).padRight(4);
r.add(o.display()).color(Color.lightGray);
r.addImage(o.complete() ? Icon.checkSmall : Icon.cancelSmall, o.complete() ? Color.lightGray : Color.scarlet).padLeft(3);
r.addImage(o.complete() ? Icon.ok : Icon.cancel, o.complete() ? Color.lightGray : Color.scarlet).padLeft(3);
r.row();
}
});
@@ -85,9 +85,9 @@ public class ZoneInfoDialog extends FloatingDialog{
r.add("$research.list").colspan(2).left();
r.row();
for(Unlock blocko : blocks){
r.addImage(blocko.block.icon(mindustry.ui.Cicon.small)).size(8 * 3).padRight(5);
r.addImage(blocko.block.icon(Cicon.small)).size(8 * 3).padRight(5);
r.add(blocko.block.localizedName).color(Color.lightGray).left();
r.addImage(blocko.block.unlocked() ? Icon.checkSmall : Icon.cancelSmall, blocko.block.unlocked() ? Color.lightGray : Color.scarlet).padLeft(3);
r.addImage(blocko.block.unlocked() ? Icon.ok : Icon.cancel, blocko.block.unlocked() ? Color.lightGray : Color.scarlet).padLeft(3);
r.row();
}

View File

@@ -1,8 +1,6 @@
package mindustry.ui.fragments;
import arc.*;
import mindustry.annotations.Annotations.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.g2d.*;
import arc.input.*;
@@ -13,14 +11,18 @@ import arc.scene.actions.*;
import arc.scene.event.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.core.GameState.*;
import mindustry.entities.*;
import mindustry.entities.type.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.net.Administration.*;
import mindustry.net.*;
import mindustry.type.*;
import mindustry.ui.Cicon;
import mindustry.ui.*;
import mindustry.world.*;
import static mindustry.Vars.*;
@@ -37,7 +39,14 @@ public class BlockInventoryFragment extends Fragment{
@Remote(called = Loc.server, targets = Loc.both, forward = true)
public static void requestItem(Player player, Tile tile, Item item, int amount){
if(player == null || tile == null || !tile.interactable(player.getTeam())) return;
if(!Units.canInteract(player, tile)) return;
amount = Mathf.clamp(amount, 0, player.getItemCapacity());
int fa = amount;
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.withdrawItem, tile, action -> {
action.item = item;
action.itemAmount = fa;
}))) throw new ValidateException(player, "Player cannot request items.");
int removed = tile.block().removeStack(tile, item, amount);

View File

@@ -62,12 +62,12 @@ public class HudFragment extends Fragment{
ImageButtonStyle style = Styles.clearTransi;
select.addImageButton(Icon.menuLargeSmall, style, ui.paused::show);
flip = select.addImageButton(Icon.arrowUpSmall, style, this::toggleMenus).get();
select.addImageButton(Icon.menu, style, ui.paused::show);
flip = select.addImageButton(Icon.upOpen, style, this::toggleMenus).get();
select.addImageButton(Icon.pasteSmall, style, ui.schematics::show);
select.addImageButton(Icon.paste, style, ui.schematics::show);
select.addImageButton(Icon.pauseSmall, style, () -> {
select.addImageButton(Icon.pause, style, () -> {
if(net.active()){
ui.listfrag.toggle();
}else{
@@ -75,14 +75,14 @@ public class HudFragment extends Fragment{
}
}).name("pause").update(i -> {
if(net.active()){
i.getStyle().imageUp = Icon.playersSmall;
i.getStyle().imageUp = Icon.user;
}else{
i.setDisabled(false);
i.getStyle().imageUp = state.is(State.paused) ? Icon.playSmall : Icon.pauseSmall;
i.getStyle().imageUp = state.is(State.paused) ? Icon.play : Icon.pause;
}
});
select.addImageButton(Icon.chatSmall, style,() -> {
select.addImageButton(Icon.chat, style,() -> {
if(net.active() && mobile){
if(ui.chatfrag.shown()){
ui.chatfrag.hide();
@@ -96,9 +96,9 @@ public class HudFragment extends Fragment{
}
}).update(i -> {
if(net.active() && mobile){
i.getStyle().imageUp = Icon.chatSmall;
i.getStyle().imageUp = Icon.chat;
}else{
i.getStyle().imageUp = Icon.databaseSmall;
i.getStyle().imageUp = Icon.book;
}
});
@@ -203,7 +203,7 @@ public class HudFragment extends Fragment{
float[] position = {0, 0};
t.row();
t.addImageTextButton("$editor.removeunit", Icon.quit, Styles.togglet, () -> {}).fillX().update(b -> {
t.addImageTextButton("$editor.removeunit", Icon.cancel, Styles.togglet, () -> {}).fillX().update(b -> {
boolean[] found = {false};
if(b.isChecked()){
Element e = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true);
@@ -319,7 +319,7 @@ public class HudFragment extends Fragment{
setDisabled(() -> !control.tutorial.canNext());
}},
new Table(f -> {
f.left().addImageButton(Icon.arrowLeftSmall, Styles.emptyi, () -> {
f.left().addImageButton(Icon.left, Styles.emptyi, () -> {
control.tutorial.prevSentence();
}).width(44f).growY().visible(() -> control.tutorial.canPrev());
}));
@@ -393,7 +393,7 @@ public class HudFragment extends Fragment{
}
});
table.margin(12);
table.addImage(Icon.check).pad(3);
table.addImage(Icon.ok).pad(3);
table.add(text).wrap().width(280f).get().setAlignment(Align.center, Align.center);
table.pack();
@@ -562,7 +562,7 @@ public class HudFragment extends Fragment{
private void toggleMenus(){
if(flip != null){
flip.getStyle().imageUp = shown ? Icon.arrowDownSmall : Icon.arrowUpSmall;
flip.getStyle().imageUp = shown ? Icon.downOpen : Icon.upOpen;
}
shown = !shown;
@@ -650,7 +650,7 @@ public class HudFragment extends Fragment{
}
private void addPlayButton(Table table){
table.right().addImageButton(Icon.playSmaller, Styles.righti, 30f, () -> {
table.right().addImageButton(Icon.play, Styles.righti, 30f, () -> {
if(net.client() && player.isAdmin){
Call.onAdminRequest(player, AdminAction.wave);
}else if(inLaunchWave()){

View File

@@ -60,7 +60,7 @@ public class MenuFragment extends Fragment{
parent.fill(c -> c.bottom().left().addButton("", Styles.infot, ui.about::show).size(84, 45));
parent.fill(c -> c.bottom().right().addButton("", Styles.discordt, ui.discord::show).size(84, 45));
}else if(becontrol.active()){
parent.fill(c -> c.bottom().right().addImageTextButton("$be.check", Icon.refreshSmall, () -> {
parent.fill(c -> c.bottom().right().addImageTextButton("$be.check", Icon.refresh, () -> {
ui.loadfrag.show();
becontrol.checkUpdate(result -> {
ui.loadfrag.hide();
@@ -100,13 +100,13 @@ public class MenuFragment extends Fragment{
container.defaults().size(size).pad(5).padTop(4f);
MobileButton
play = new MobileButton(Icon.play2, "$campaign", () -> checkPlay(ui.deploy::show)),
custom = new MobileButton(Icon.playCustom, "$customgame", () -> checkPlay(ui.custom::show)),
maps = new MobileButton(Icon.load, "$loadgame", () -> checkPlay(ui.load::show)),
play = new MobileButton(Icon.play, "$campaign", () -> checkPlay(ui.deploy::show)),
custom = new MobileButton(Icon.rightOpenOut, "$customgame", () -> checkPlay(ui.custom::show)),
maps = new MobileButton(Icon.download, "$loadgame", () -> checkPlay(ui.load::show)),
join = new MobileButton(Icon.add, "$joingame", () -> checkPlay(ui.join::show)),
editor = new MobileButton(Icon.editor, "$editor", () -> checkPlay(ui.maps::show)),
tools = new MobileButton(Icon.tools, "$settings", ui.settings::show),
mods = new MobileButton(Icon.wiki, "$mods", ui.mods::show),
editor = new MobileButton(Icon.terrain, "$editor", () -> checkPlay(ui.maps::show)),
tools = new MobileButton(Icon.settings, "$settings", ui.settings::show),
mods = new MobileButton(Icon.book, "$mods", ui.mods::show),
donate = new MobileButton(Icon.link, "$website", () -> Core.net.openURI("https://anuke.itch.io/mindustry")),
exit = new MobileButton(Icon.exit, "$quit", () -> Core.app.exit());
@@ -164,20 +164,20 @@ public class MenuFragment extends Fragment{
t.defaults().width(width).height(70f);
buttons(t,
new Buttoni("$play", Icon.play2Small,
new Buttoni("$campaign", Icon.play2Small, () -> checkPlay(ui.deploy::show)),
new Buttoni("$joingame", Icon.addSmall, () -> checkPlay(ui.join::show)),
new Buttoni("$customgame", Icon.editorSmall, () -> checkPlay(ui.custom::show)),
new Buttoni("$loadgame", Icon.loadSmall, () -> checkPlay(ui.load::show)),
new Buttoni("$tutorial", Icon.infoSmall, () -> checkPlay(control::playTutorial))
new Buttoni("$play", Icon.play,
new Buttoni("$campaign", Icon.play, () -> checkPlay(ui.deploy::show)),
new Buttoni("$joingame", Icon.add, () -> checkPlay(ui.join::show)),
new Buttoni("$customgame", Icon.terrain, () -> checkPlay(ui.custom::show)),
new Buttoni("$loadgame", Icon.download, () -> checkPlay(ui.load::show)),
new Buttoni("$tutorial", Icon.info, () -> checkPlay(control::playTutorial))
),
new Buttoni("$editor", Icon.editorSmall, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("$workshop", Icon.saveSmall, platform::openWorkshop) : null,
new Buttoni(Core.bundle.get("mods") + "\n" + Core.bundle.get("mods.alpha"), Icon.wikiSmall, ui.mods::show),
new Buttoni("$editor", Icon.terrain, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("$workshop", Icon.save, platform::openWorkshop) : null,
new Buttoni(Core.bundle.get("mods"), Icon.bookOpen, ui.mods::show),
//not enough space for this button
//new Buttoni("$schematics", Icon.pasteSmall, ui.schematics::show),
new Buttoni("$settings", Icon.toolsSmall, ui.settings::show),
new Buttoni("$about.button", Icon.infoSmall, ui.about::show),
new Buttoni("$quit", Icon.exitSmall, Core.app::exit)
//new Buttoni("$schematics", Icon.paste, ui.schematics::show),
new Buttoni("$settings", Icon.settings, ui.settings::show),
new Buttoni("$about.button", Icon.info, ui.about::show),
new Buttoni("$quit", Icon.exit, Core.app::exit)
);
}).width(width).growY();

View File

@@ -100,7 +100,7 @@ public class MinimapFragment extends Fragment{
t.row();
t.add().growY();
t.row();
t.addImageTextButton("$back", Icon.backSmall, () -> shown = false).size(220f, 60f).pad(10f);
t.addImageTextButton("$back", Icon.leftOpen, () -> shown = false).size(220f, 60f).pad(10f);
});
}

View File

@@ -1,14 +1,15 @@
package mindustry.ui.fragments;
import arc.*;
import arc.struct.*;
import arc.graphics.*;
import arc.input.*;
import arc.math.geom.*;
import arc.scene.*;
import arc.scene.event.*;
import arc.scene.style.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.traits.BuilderTrait.*;
@@ -19,7 +20,6 @@ import mindustry.graphics.*;
import mindustry.input.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.ui.Cicon;
import mindustry.world.*;
import static mindustry.Vars.*;
@@ -202,14 +202,18 @@ public class PlacementFragment extends Fragment{
blockTable.row();
}
ImageButton button = blockTable.addImageButton(Icon.lockedSmall, Styles.selecti, () -> {
ImageButton button = blockTable.addImageButton(new TextureRegionDrawable(block.icon(Cicon.medium)), Styles.selecti, () -> {
if(unlocked(block)){
control.input.block = control.input.block == block ? null : block;
selectedBlocks.put(currentCategory, control.input.block);
if(Core.input.keyDown(KeyCode.SHIFT_LEFT) && Fonts.getUnicode(block.name) != 0){
Core.app.setClipboardText((char)Fonts.getUnicode(block.name) + "");
ui.showInfoFade("$copied");
}else{
control.input.block = control.input.block == block ? null : block;
selectedBlocks.put(currentCategory, control.input.block);
}
}
}).size(46f).group(group).name("block-" + block.name).get();
button.getStyle().imageUp = new TextureRegionDrawable(block.icon(Cicon.medium));
button.resizeImage(Cicon.medium.size);
button.update(() -> { //color unplacable things gray
TileEntity core = player.getClosestCore();
@@ -311,7 +315,7 @@ public class PlacementFragment extends Fragment{
if(state.rules.bannedBlocks.contains(lastDisplay)){
topTable.row();
topTable.table(b -> {
b.addImage(Icon.cancelSmall).padRight(2).color(Color.scarlet);
b.addImage(Icon.cancel).padRight(2).color(Color.scarlet);
b.add("$banned");
b.left();
}).padTop(2).left();
@@ -378,7 +382,7 @@ public class PlacementFragment extends Fragment{
continue;
}
categories.addImageButton(Core.atlas.drawable("icon-" + cat.name() + "-smaller"), Styles.clearToggleTransi, () -> {
categories.addImageButton(ui.getIcon(cat.name()), Styles.clearToggleTransi, () -> {
currentCategory = cat;
if(control.input.block != null){
control.input.block = getSelectedBlock(currentCategory);

View File

@@ -104,14 +104,14 @@ public class PlayerListFragment extends Fragment{
button.table(t -> {
t.defaults().size(bs);
t.addImageButton(Icon.banSmall, Styles.clearPartiali,
t.addImageButton(Icon.hammer, Styles.clearPartiali,
() -> ui.showConfirm("$confirm", "$confirmban", () -> Call.onAdminRequest(user, AdminAction.ban)));
t.addImageButton(Icon.cancelSmall, Styles.clearPartiali,
t.addImageButton(Icon.cancel, Styles.clearPartiali,
() -> ui.showConfirm("$confirm", "$confirmkick", () -> Call.onAdminRequest(user, AdminAction.kick)));
t.row();
t.addImageButton(Icon.adminSmall, Styles.clearTogglePartiali, () -> {
t.addImageButton(Icon.admin, Styles.clearTogglePartiali, () -> {
if(net.client()) return;
String id = user.uuid;
@@ -127,13 +127,13 @@ public class PlayerListFragment extends Fragment{
.touchable(() -> net.client() ? Touchable.disabled : Touchable.enabled)
.checked(user.isAdmin);
t.addImageButton(Icon.zoomSmall, Styles.clearPartiali, () -> Call.onAdminRequest(user, AdminAction.trace));
t.addImageButton(Icon.zoom, Styles.clearPartiali, () -> Call.onAdminRequest(user, AdminAction.trace));
}).padRight(12).size(bs + 10f, bs);
}else if((!user.isLocal && !user.isAdmin) && net.client() && playerGroup.size() >= 3 && player.getTeam() != user.getTeam()){ //votekick
}else if(!user.isLocal && !user.isAdmin && net.client() && playerGroup.size() >= 3 && player.getTeam() == user.getTeam()){ //votekick
button.add().growY();
button.addImageButton(Icon.banSmall, Styles.clearPartiali,
button.addImageButton(Icon.hammer, Styles.clearPartiali,
() -> ui.showConfirm("$confirm", "$confirmvotekick", () -> Call.sendChatMessage("/votekick " + user.name))).size(h);
}

View File

@@ -53,7 +53,7 @@ public class ScriptConsoleFragment extends Table{
clearChatInput();
}
return shown && Vars.net.active();
return shown && !Vars.net.active();
});
update(() -> {

View File

@@ -1,17 +1,15 @@
package mindustry.world;
import mindustry.annotations.Annotations.Loc;
import mindustry.annotations.Annotations.Remote;
import arc.Core;
import arc.Events;
import arc.math.Mathf;
import arc.*;
import arc.math.*;
import arc.math.geom.*;
import mindustry.content.Blocks;
import mindustry.entities.Units;
import mindustry.game.EventType.BlockBuildBeginEvent;
import mindustry.game.Team;
import mindustry.world.blocks.BuildBlock;
import mindustry.world.blocks.BuildBlock.BuildEntity;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.BuildBlock.*;
import static mindustry.Vars.*;

View File

@@ -1,10 +1,11 @@
package mindustry.world;
import arc.struct.*;
import arc.func.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
@@ -215,6 +216,16 @@ public class Tile implements Position, TargetTrait{
}
}
/** remove()-s this tile, except it's synced across the network */
public void removeNet(){
Call.removeTile(this);
}
/** set()-s this tile, except it's synced across the network */
public void setNet(Block block, Team team, int rotation){
Call.setTile(this, block, team, rotation);
}
public byte rotation(){
return rotation;
}
@@ -506,4 +517,16 @@ public class Tile implements Position, TargetTrait{
public String toString(){
return floor.name + ":" + block.name + ":" + overlay + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass())) + ":" + getTeam();
}
//remote utility methods
@Remote(called = Loc.server)
public static void removeTile(Tile tile){
tile.remove();
}
@Remote(called = Loc.server)
public static void setTile(Tile tile, Block block, Team team, int rotation){
tile.set(block, team, rotation);
}
}

View File

@@ -33,6 +33,7 @@ public class Conveyor extends Block implements Autotiler{
private TextureRegion[][] regions = new TextureRegion[7][4];
public float speed = 0f;
public float displayedSpeed = 0f;
protected Conveyor(String name){
super(name);
@@ -59,7 +60,8 @@ public class Conveyor extends Block implements Autotiler{
@Override
public void setStats(){
super.setStats();
stats.add(BlockStat.itemsMoved, speed * 60 / itemSpace, StatUnit.itemsSecond);
//have to add a custom calculated speed, since the actual movement speed is apparently not linear
stats.add(BlockStat.itemsMoved, displayedSpeed, StatUnit.itemsSecond);
}
@Override

View File

@@ -3,8 +3,8 @@ package mindustry.world.blocks.distribution;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.entities.traits.BuilderTrait.*;
import mindustry.entities.type.*;
import mindustry.type.*;
@@ -85,7 +85,8 @@ public class Sorter extends Block{
}
boolean isSame(Tile tile, Tile other){
return other != null && other.block() instanceof Sorter;
//uncomment comment below to prevent sorter/gate chaining (hacky)
return other != null && (other.block() instanceof Sorter/* || other.block() instanceof OverflowGate */);
}
Tile getTileTarget(Item item, Tile dest, Tile source, boolean flip){

View File

@@ -1,11 +1,11 @@
package mindustry.world.blocks.liquid;
import arc.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.traits.BuilderTrait.*;
@@ -13,7 +13,6 @@ import mindustry.entities.type.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.modules.*;
public class Conduit extends LiquidBlock implements Autotiler{
public final int timerFlow = timers++;
@@ -92,13 +91,12 @@ public class Conduit extends LiquidBlock implements Autotiler{
@Override
public void draw(Tile tile){
ConduitEntity entity = tile.ent();
LiquidModule mod = tile.entity.liquids;
int rotation = tile.rotation() * 90;
Draw.colorl(0.34f);
Draw.rect(botRegions[entity.blendbits], tile.drawx(), tile.drawy(), rotation);
Draw.color(mod.current().color);
Draw.color(tile.entity.liquids.current().color);
Draw.alpha(entity.smoothLiquid);
Draw.rect(botRegions[entity.blendbits], tile.drawx(), tile.drawy(), rotation);
Draw.color();
@@ -109,7 +107,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
@Override
public void update(Tile tile){
ConduitEntity entity = tile.ent();
entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquids.total() / liquidCapacity, 0.05f);
entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquids.currentAmount() / liquidCapacity, 0.05f);
if(tile.entity.liquids.total() > 0.001f && tile.entity.timer.get(timerFlow, 1)){
tryMoveLiquid(tile, tile.getNearby(tile.rotation()), leakResistance, tile.entity.liquids.current());

View File

@@ -98,7 +98,7 @@ public class MessageBlock extends Block{
public void buildConfiguration(Tile tile, Table table){
MessageBlockEntity entity = tile.ent();
table.addImageButton(Icon.pencilSmall, () -> {
table.addImageButton(Icon.pencil, () -> {
if(mobile){
Core.input.getTextInput(new TextInput(){{
text = entity.message;

View File

@@ -52,7 +52,7 @@ public class LightBlock extends Block{
public void buildConfiguration(Tile tile, Table table){
LightEntity entity = tile.ent();
table.addImageButton(Icon.pencilSmall, () -> {
table.addImageButton(Icon.pencil, () -> {
ui.picker.show(Tmp.c1.set(entity.color).a(0.5f), false, res -> {
entity.color = res.rgba();
lastColor = entity.color;

View File

@@ -4,7 +4,7 @@ import arc.Core;
import arc.graphics.Color;
import arc.graphics.g2d.*;
import arc.math.Mathf;
import arc.math.RandomXS128;
import arc.math.Rand;
import arc.util.Time;
import mindustry.content.Fx;
import mindustry.entities.type.TileEntity;
@@ -21,7 +21,7 @@ public class Cultivator extends GenericCrafter{
public Color bottomColor = Color.valueOf("474747");
public TextureRegion middleRegion, topRegion;
public RandomXS128 random = new RandomXS128(0);
public Rand random = new Rand(0);
public float recurrence = 6f;
public Attribute attribute = Attribute.spores;

View File

@@ -1,6 +1,6 @@
package mindustry.world.blocks.production;
import arc.graphics.*;
import arc.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.util.ArcAnnotate.*;
@@ -15,15 +15,11 @@ import mindustry.world.meta.values.*;
* Extracts a random list of items from an input item and an input liquid.
*/
public class Separator extends Block{
protected @NonNull ItemStack[] results;
protected float craftTime;
protected float spinnerRadius = 2.5f;
protected float spinnerLength = 1f;
protected float spinnerThickness = 1f;
protected float spinnerSpeed = 2f;
public @NonNull ItemStack[] results;
public float craftTime;
protected Color color = Color.valueOf("858585");
protected int liquidRegion;
public int liquidRegion, spinnerRegion;
public float spinnerSpeed = 3f;
public Separator(String name){
super(name);
@@ -33,6 +29,7 @@ public class Separator extends Block{
hasLiquids = true;
liquidRegion = reg("-liquid");
spinnerRegion = reg("-spinner");
entityType = GenericCrafterEntity::new;
}
@@ -70,10 +67,10 @@ public class Separator extends Block{
Draw.alpha(tile.entity.liquids.total() / liquidCapacity);
Draw.rect(reg(liquidRegion), tile.drawx(), tile.drawy());
Draw.color(color);
Lines.stroke(spinnerThickness);
Lines.spikes(tile.drawx(), tile.drawy(), spinnerRadius, spinnerLength, 3, entity.totalProgress * spinnerSpeed);
Draw.reset();
if(Core.atlas.isFound(reg(spinnerRegion))){
Draw.rect(reg(spinnerRegion), tile.drawx(), tile.drawy(), entity.totalProgress * spinnerSpeed);
}
}
@Override

View File

@@ -66,7 +66,7 @@ public class CommandCenter extends Block{
super.load();
for(UnitCommand cmd : UnitCommand.all){
commandRegions[cmd.ordinal()] = Core.atlas.find("icon-command-" + cmd.name() + "-small");
commandRegions[cmd.ordinal()] = Core.atlas.find("Icon.command-" + cmd.name() + "-");
}
}
@@ -91,7 +91,7 @@ public class CommandCenter extends Block{
Table buttons = new Table();
for(UnitCommand cmd : UnitCommand.all){
buttons.addImageButton(Core.atlas.drawable("icon-command-" + cmd.name() + "-small"), Styles.clearToggleTransi, () -> tile.configure(cmd.ordinal()))
buttons.addImageButton(Core.atlas.drawable("Icon.command-" + cmd.name() + "-"), Styles.clearToggleTransi, () -> tile.configure(cmd.ordinal()))
.size(44).group(group).update(b -> b.setChecked(entity.command == cmd));
}
table.add(buttons);