Merge branch 'master' of https://github.com/Anuken/Mindustry into 7.0-features

 Conflicts:
	core/src/mindustry/type/UnitType.java
	gradle.properties
This commit is contained in:
Anuken
2021-11-04 19:39:16 -04:00
31 changed files with 285 additions and 94 deletions
+2 -2
View File
@@ -25,7 +25,7 @@ public class MinerAI extends AIController{
if(mining){
if(timer.get(timerTarget2, 60 * 4) || targetItem == null){
targetItem = unit.team.data().mineItems.min(i -> indexer.hasOre(i) && unit.canMine(i), i -> core.items.get(i));
targetItem = unit.type.mineItems.min(i -> indexer.hasOre(i) && unit.canMine(i), i -> core.items.get(i));
}
//core full of the target item, do nothing
@@ -75,4 +75,4 @@ public class MinerAI extends AIController{
circle(core, unit.type.range / 1.8f);
}
}
}
}
+3 -2
View File
@@ -5,6 +5,7 @@ import arc.math.*;
import arc.struct.*;
import mindustry.*;
import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.entities.bullet.*;
import mindustry.entities.effect.*;
import mindustry.gen.*;
@@ -2138,7 +2139,7 @@ public class Blocks implements ContentList{
size = 4;
shootCone = 2f;
shootSound = Sounds.railgun;
unitSort = (u, x, y) -> -u.maxHealth + Mathf.dst2(u.x, u.y, x, y) / 6400f;
unitSort = UnitSorts.strongest;
coolantMultiplier = 0.4f;
@@ -2638,4 +2639,4 @@ public class Blocks implements ContentList{
//endregion
}
}
}
+3 -26
View File
@@ -260,33 +260,10 @@ public class NetClient implements ApplicationListener{
//a command was sent, now get the output
if(response.type != ResponseType.valid){
String text;
//send usage
if(response.type == ResponseType.manyArguments){
text = "[scarlet]Too many arguments. Usage:[lightgray] " + response.command.text + "[gray] " + response.command.paramText;
}else if(response.type == ResponseType.fewArguments){
text = "[scarlet]Too few arguments. Usage:[lightgray] " + response.command.text + "[gray] " + response.command.paramText;
}else{ //unknown command
int minDst = 0;
Command closest = null;
for(Command command : netServer.clientCommands.getCommandList()){
int dst = Strings.levenshtein(command.text, response.runCommand);
if(dst < 3 && (closest == null || dst < minDst)){
minDst = dst;
closest = command;
}
}
if(closest != null){
text = "[scarlet]Unknown command. Did you mean \"[lightgray]" + closest.text + "[]\"?";
}else{
text = "[scarlet]Unknown command. Check [lightgray]/help[scarlet].";
}
String text = netServer.invalidHandler.handle(player, response);
if(text != null){
player.sendMessage(text);
}
player.sendMessage(text);
}
}
}
+30
View File
@@ -67,6 +67,32 @@ public class NetServer implements ApplicationListener{
/** Converts a message + NULLABLE player sender into a single string. Override for custom prefixes/suffixes. */
public ChatFormatter chatFormatter = (player, message) -> player == null ? message : "[coral][[" + player.coloredName() + "[coral]]:[white] " + message;
/** Handles an incorrect command response. Returns text that will be sent to player. Override for customisation. */
public InvalidCommandHandler invalidHandler = (player, response) -> {
if(response.type == ResponseType.manyArguments){
return "[scarlet]Too many arguments. Usage:[lightgray] " + response.command.text + "[gray] " + response.command.paramText;
}else if(response.type == ResponseType.fewArguments){
return "[scarlet]Too few arguments. Usage:[lightgray] " + response.command.text + "[gray] " + response.command.paramText;
}else{ //unknown command
int minDst = 0;
Command closest = null;
for(Command command : netServer.clientCommands.getCommandList()){
int dst = Strings.levenshtein(command.text, response.runCommand);
if(dst < 3 && (closest == null || dst < minDst)){
minDst = dst;
closest = command;
}
}
if(closest != null){
return "[scarlet]Unknown command. Did you mean \"[lightgray]" + closest.text + "[]\"?";
}else{
return "[scarlet]Unknown command. Check [lightgray]/help[scarlet].";
}
}
};
private boolean closing = false;
private Interval timer = new Interval();
@@ -994,4 +1020,8 @@ public class NetServer implements ApplicationListener{
/** @return text to be placed before player name */
String format(@Nullable Player player, String message);
}
public interface InvalidCommandHandler{
String handle(Player player, CommandResponse response);
}
}
+2 -1
View File
@@ -461,11 +461,12 @@ public class Damage{
}
private static void completeDamage(Team team, float x, float y, float radius, float damage){
int trad = (int)(radius / tilesize);
for(int dx = -trad; dx <= trad; dx++){
for(int dy = -trad; dy <= trad; dy++){
Tile tile = world.tile(Math.round(x / tilesize) + dx, Math.round(y / tilesize) + dy);
if(tile != null && tile.build != null && (team == null ||team.isEnemy(tile.team())) && dx*dx + dy*dy <= trad){
if(tile != null && tile.build != null && (team == null ||team.isEnemy(tile.team())) && dx*dx + dy*dy <= trad*trad){
tile.build.damage(team, damage);
}
}
@@ -14,4 +14,5 @@ class GroupDefs<G>{
@GroupDef(value = Firec.class) G fire;
@GroupDef(value = Puddlec.class) G puddle;
@GroupDef(value = WeatherStatec.class) G weather;
@GroupDef(value = WorldLabelc.class, mapping = true) G label;
}
@@ -0,0 +1,14 @@
package mindustry.entities;
import arc.math.*;
import mindustry.entities.Units.*;
import mindustry.gen.*;
public class UnitSorts{
public static Sortf
closest = Unit::dst2,
farthest = (u, x, y) -> -u.dst2(x, y),
strongest = (u, x, y) -> -u.maxHealth + Mathf.dst2(u.x, u.y, x, y) / 6400f,
weakest = (u, x, y) -> u.maxHealth + Mathf.dst2(u.x, u.y, x, y) / 6400f;
}
+6
View File
@@ -81,6 +81,12 @@ public class Units{
return Math.max(0, state.rules.unitCapVariable ? state.rules.unitCap + team.data().unitCap : state.rules.unitCap);
}
/** @return unit cap as a string, substituting the infinity symbol instead of MAX_VALUE */
public static String getStringCap(Team team){
int cap = getCap(team);
return cap >= Integer.MAX_VALUE - 1 ? "" : cap + "";
}
/** @return whether this player can interact with a specific tile. if either of these are null, returns true.*/
public static boolean canInteract(Player player, Building tile){
return player == null || tile == null || tile.interactable(player.team());
@@ -61,6 +61,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
transient boolean updateFlow;
transient byte cdump;
transient int rotation;
transient float payloadRotation;
transient boolean enabled = true;
transient float enabledControlTime;
transient String lastAccessed;
@@ -1293,16 +1294,18 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
return true;
}
/** Called right before this building is picked up. */
public void pickedUp(){
}
/** Called right after this building is picked up. */
public void afterPickedUp(){
if(power != null){
if(power.graph != null){
power.graph.removeList(self());
power.graph = new PowerGraph();
}
power.graph = new PowerGraph();
power.links.clear();
power.status = 0f;
}
}
public void removeFromProximity(){
@@ -93,6 +93,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
void pickup(Building tile){
tile.pickedUp();
tile.tile.remove();
tile.afterPickedUp();
addPayload(new BuildPayload(tile));
Fx.unitPickup.at(tile);
Events.fire(new PickupEvent(self(), tile));
@@ -0,0 +1,68 @@
package mindustry.entities.comp;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import arc.util.pooling.*;
import mindustry.annotations.Annotations.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.ui.*;
/** Component/entity for labels in world space. Useful for servers. Does not save in files - create only on world load. */
@EntityDef(value = {WorldLabelc.class}, serialize = false)
@Component(base = true)
public abstract class WorldLabelComp implements Posc, Drawc, Syncc{
@Import int id;
@Import float x, y;
public static final byte flagBackground = 1, flagOutline = 2;
public String text = "sample text";
public float fontSize = 1f, z = Layer.playerName + 1;
/** Flags are packed into a byte for sync efficiency; see the flag static values. */
public byte flags = flagBackground | flagOutline;
@Replace
public float clipSize(){
return text.length() * 10f * fontSize;
}
@Override
public void draw(){
Draw.z(z);
float z = Drawf.text();
Font font = (flags & flagOutline) != 0 ? Fonts.outline : Fonts.def;
GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
boolean ints = font.usesIntegerPositions();
font.setUseIntegerPositions(false);
font.getData().setScale(0.25f / Scl.scl(1f) * fontSize);
layout.setText(font, text);
if((flags & flagBackground) != 0){
Draw.color(0f, 0f, 0f, 0.3f);
Fill.rect(x, y - layout.height / 2, layout.width + 2, layout.height + 3);
Draw.color();
}
font.setColor(Color.white);
font.draw(text, x, y, 0, Align.center, false);
Draw.reset();
Pools.free(layout);
font.getData().setScale(1f);
font.setColor(Color.white);
font.setUseIntegerPositions(ints);
Draw.z(z);
}
/** This MUST be called instead of remove()! */
public void hide(){
remove();
Call.removeWorldLabel(id);
}
}
+1 -3
View File
@@ -234,8 +234,6 @@ public class Teams{
public Queue<BlockPlan> blocks = new Queue<>();
/** The current command for units to follow. */
public UnitCommand command = UnitCommand.attack;
/** Target items to mine. */
public Seq<Item> mineItems = Seq.with(Items.copper, Items.lead, Items.titanium, Items.thorium);
/** Quadtree for all buildings of this team. Null if not active. */
@Nullable
@@ -373,4 +371,4 @@ public class Teams{
'}';
}
}
}
}
+3 -1
View File
@@ -20,6 +20,7 @@ import mindustry.content.*;
import mindustry.content.TechTree.*;
import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.entities.Units.*;
import mindustry.entities.abilities.*;
import mindustry.entities.bullet.*;
import mindustry.entities.effect.*;
@@ -61,6 +62,7 @@ public class ContentParser{
readFields(result, data);
return result;
});
put(Sortf.class, (type, data) -> field(UnitSorts.class, data));
put(Interp.class, (type, data) -> field(Interp.class, data));
put(CacheLayer.class, (type, data) -> field(CacheLayer.class, data));
put(Attribute.class, (type, data) -> Attribute.get(data.asString()));
@@ -826,4 +828,4 @@ public class ContentParser{
void parsed(Class<?> type, JsonValue jsonData, Object result);
}
}
}
+3 -1
View File
@@ -89,6 +89,8 @@ public class UnitType extends UnlockableContent{
public BlockFlag[] targetFlags = {null};
/** targetFlags, as an override for "non-AI" teams. By default, units of this type will rush the core. */
public BlockFlag[] playerTargetFlags = {BlockFlag.core, null};
/** Target items to mine. Used in MinerAI */
public Seq<Item> mineItems = Seq.with(Items.copper, Items.lead, Items.titanium, Items.thorium);
public Color outlineColor = Pal.darkerMetal;
public int outlineRadius = 3;
@@ -1059,4 +1061,4 @@ public class UnitType extends UnlockableContent{
}
}
}
}
+10 -3
View File
@@ -94,9 +94,7 @@ public class Menus{
@Remote(variants = Variant.both)
public static void labelReliable(String message, float duration, float worldx, float worldy){
if(message == null) return;
ui.showLabel(message, duration, worldx, worldy);
label(message, duration, worldx, worldy);
}
@Remote(variants = Variant.both)
@@ -113,6 +111,15 @@ public class Menus{
ui.hudfrag.showToast(Fonts.getGlyph(Fonts.icon, (char)unicode), text);
}
//internal use only
@Remote
public static void removeWorldLabel(int id){
var label = Groups.label.getByID(id);
if(label != null){
label.remove();
}
}
public interface MenuListener{
void get(Player player, int option);
}
+1 -1
View File
@@ -86,7 +86,7 @@ public class Block extends UnlockableContent{
public boolean solid;
/** whether this block CAN be solid. */
public boolean solidifes;
/** whether this is rotateable */
/** whether this is rotatable */
public boolean rotate;
/** number of different variant regions to use */
public int variants = 0;
@@ -29,8 +29,7 @@ public class Thruster extends Wall{
@Override
public void draw(){
super.draw();
Draw.rect(block.region, x, y);
Draw.rect(topRegion, x, y, rotdeg());
}
}
@@ -76,7 +76,7 @@ public class Turret extends ReloadTurret{
public Effect chargeBeginEffect = Fx.none;
public Sound chargeSound = Sounds.none;
public Sortf unitSort = Unit::dst2;
public Sortf unitSort = UnitSorts.closest;
protected Vec2 tr = new Vec2();
protected Vec2 tr2 = new Vec2();
@@ -519,4 +519,4 @@ public class Turret extends ReloadTurret{
return 1;
}
}
}
}
@@ -95,7 +95,7 @@ public class PayloadConveyor extends Block{
public void onProximityUpdate(){
super.onProximityUpdate();
Building accept = nearby(Geometry.d4(rotation).x * size, Geometry.d4(rotation).y * size);
Building accept = nearby(Geometry.d4(rotation).x * (size/2+1), Geometry.d4(rotation).y * (size/2+1));
//next block must be aligned and of the same size
if(accept != null && (
//same size
@@ -153,6 +153,11 @@ public class StackConveyor extends Block implements Autotiler{
Draw.z(Layer.block - 0.15f);
super.drawCracks();
}
@Override
public void payloadDraw(){
Draw.rect(block.fullIcon, x, y);
}
@Override
public void onProximityUpdate(){
@@ -80,6 +80,7 @@ public class BuildPayload implements Payload{
@Override
public void set(float x, float y, float rotation){
build.set(x, y);
build.payloadRotation = rotation;
}
@Override
@@ -64,8 +64,11 @@ public class Unloader extends Block{
float loadFactor;
boolean canLoad;
boolean canUnload;
int index;
}
public int[] lastUsed;
@Override
public void updateTile(){
if(((unloadTimer += delta()) < speed) || (proximity.size < 2)) return;
@@ -80,14 +83,14 @@ public class Unloader extends Block{
for(int i = tmp; i < proximity.size; i++){
possibleBlocks.set(i, new ContainerStat());
}
lastUsed = new int[proximity.size];
}
if(sortItem != null){
item = sortItem;
for(int j = 0; j < proximity.size; j++){
int pos = (offset + j) % proximity.size;
var other = proximity.get(j);
for(int pos = 0; pos < proximity.size; pos++){
var other = proximity.get(pos);
boolean interactable = other.interactable(team);
//set the stats of all buildings in possibleBlocks
@@ -95,6 +98,7 @@ public class Unloader extends Block{
pb.building = other;
pb.canUnload = interactable && other.canUnload() && other.items != null && other.items.has(sortItem);
pb.canLoad = interactable && !(other.block instanceof StorageBlock) && other.acceptItem(this, sortItem);
pb.index = pos;
}
}else{
//select the next item for nulloaders
@@ -106,9 +110,8 @@ public class Unloader extends Block{
boolean isDistinct = false;
Item possibleItem = content.item(total);
for(int j = 0; j < proximity.size; j++){
int pos = (offset + j) % proximity.size;
var other = proximity.get(j);
for(int pos = 0; pos < proximity.size; pos++){
var other = proximity.get(pos);
boolean interactable = other.interactable(team);
//set the stats of all buildings in possibleBlocks while we are at it
@@ -116,6 +119,7 @@ public class Unloader extends Block{
pb.building = other;
pb.canUnload = interactable && other.canUnload() && other.items != null && other.items.has(possibleItem);
pb.canLoad = interactable && !(other.block instanceof StorageBlock) && other.acceptItem(this, possibleItem);
pb.index = pos;
//the part handling framerate issues and slow conveyor belts, to avoid skipping items
if(hasProvider && pb.canLoad) isDistinct = true;
@@ -138,11 +142,13 @@ public class Unloader extends Block{
pb.loadFactor = (other.getMaximumAccepted(item) == 0) || (other.items == null) ? 0 : other.items.get(item) / (float)other.getMaximumAccepted(item);
}
//sort so it gives full priority to blocks that can give but not receive (stackConveyors and Storage), and then by load
//sort so it gives full priority to blocks that can give but not receive (stackConveyors and Storage), and then by load, and then by last use
possibleBlocks.sort(Structs.comps(
Structs.comparingBool(e -> e.building.block.highUnloadPriority),
Structs.comparingFloat(e -> e.loadFactor)
));
Structs.comps(
Structs.comparingFloat(e -> e.loadFactor),
Structs.comparingInt(e -> -lastUsed[e.index])
)));
ContainerStat dumpingFrom = null;
ContainerStat dumpingTo = null;
@@ -163,10 +169,17 @@ public class Unloader extends Block{
}
}
//increment the priority if not used
for(int i = 0; i < possibleBlocks.size; i++){
lastUsed[i] = (lastUsed[i] + 1 ) % 2147483647;
}
//trade the items
if(dumpingFrom != null && dumpingTo != null && (dumpingFrom.loadFactor != dumpingTo.loadFactor || dumpingFrom.building.block.highUnloadPriority)){
dumpingTo.building.handleItem(this, item);
dumpingFrom.building.removeStack(item, 1);
lastUsed[dumpingFrom.index] = 0;
lastUsed[dumpingTo.index] = 0;
any = true;
}
@@ -78,7 +78,7 @@ public class UnitFactory extends UnitBlock{
Core.bundle.format("bar.unitcap",
Fonts.getUnicodeStr(e.unit().name),
e.team.data().countType(e.unit()),
Units.getCap(e.team)
Units.getStringCap(e.team)
),
() -> Pal.power,
() -> e.unit() == null ? 0f : (float)e.team.data().countType(e.unit()) / Units.getCap(e.team)