Merge branch 'master' into healbullets-bullets
This commit is contained in:
@@ -43,9 +43,9 @@ public class LogicStatementProcessor extends BaseProcessor{
|
|||||||
String name = c.annotation(RegisterStatement.class).value();
|
String name = c.annotation(RegisterStatement.class).value();
|
||||||
|
|
||||||
if(beganWrite){
|
if(beganWrite){
|
||||||
writer.nextControlFlow("else if(obj instanceof $T)", c.mirror());
|
writer.nextControlFlow("else if(obj.getClass() == $T.class)", c.mirror());
|
||||||
}else{
|
}else{
|
||||||
writer.beginControlFlow("if(obj instanceof $T)", c.mirror());
|
writer.beginControlFlow("if(obj.getClass() == $T.class)", c.mirror());
|
||||||
beganWrite = true;
|
beganWrite = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,6 +53,7 @@ public class LogicStatementProcessor extends BaseProcessor{
|
|||||||
writer.addStatement("out.append($S)", name);
|
writer.addStatement("out.append($S)", name);
|
||||||
|
|
||||||
Seq<Svar> fields = c.fields();
|
Seq<Svar> fields = c.fields();
|
||||||
|
fields.addAll(c.superclass().fields());
|
||||||
|
|
||||||
String readSt = "if(tokens[0].equals($S))";
|
String readSt = "if(tokens[0].equals($S))";
|
||||||
if(beganRead){
|
if(beganRead){
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ mindustry.entities.comp.EffectStateComp=9
|
|||||||
mindustry.entities.comp.FireComp=10
|
mindustry.entities.comp.FireComp=10
|
||||||
mindustry.entities.comp.LaunchCoreComp=11
|
mindustry.entities.comp.LaunchCoreComp=11
|
||||||
mindustry.entities.comp.PlayerComp=12
|
mindustry.entities.comp.PlayerComp=12
|
||||||
|
mindustry.entities.comp.PosTeam=27
|
||||||
|
mindustry.entities.comp.PosTeamDef=28
|
||||||
mindustry.entities.comp.PuddleComp=13
|
mindustry.entities.comp.PuddleComp=13
|
||||||
mindustry.type.Weather.WeatherStateComp=14
|
mindustry.type.Weather.WeatherStateComp=14
|
||||||
mindustry.world.blocks.campaign.LaunchPad.LaunchPayloadComp=15
|
mindustry.world.blocks.campaign.LaunchPad.LaunchPayloadComp=15
|
||||||
|
|||||||
1
annotations/src/main/resources/revisions/PosTeam/0.json
Normal file
1
annotations/src/main/resources/revisions/PosTeam/0.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{fields:[{name:team,type:mindustry.game.Team},{name:x,type:float},{name:y,type:float}]}
|
||||||
@@ -638,6 +638,8 @@ bar.progress = Build Progress
|
|||||||
bar.input = Input
|
bar.input = Input
|
||||||
bar.output = Output
|
bar.output = Output
|
||||||
|
|
||||||
|
units.processorcontrol = [lightgray]Processor Controlled
|
||||||
|
|
||||||
bullet.damage = [stat]{0}[lightgray] damage
|
bullet.damage = [stat]{0}[lightgray] damage
|
||||||
bullet.splashdamage = [stat]{0}[lightgray] area dmg ~[stat] {1}[lightgray] tiles
|
bullet.splashdamage = [stat]{0}[lightgray] area dmg ~[stat] {1}[lightgray] tiles
|
||||||
bullet.incendiary = [stat]incendiary
|
bullet.incendiary = [stat]incendiary
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ public class Vars implements Loadable{
|
|||||||
public static final float buildingRange = 220f;
|
public static final float buildingRange = 220f;
|
||||||
/** range for moving items */
|
/** range for moving items */
|
||||||
public static final float itemTransferRange = 220f;
|
public static final float itemTransferRange = 220f;
|
||||||
|
/** range for moving items for logic units */
|
||||||
|
public static final float logicItemTransferRange = 45f;
|
||||||
/** duration of time between turns in ticks */
|
/** duration of time between turns in ticks */
|
||||||
public static final float turnDuration = 20 * Time.toMinutes;
|
public static final float turnDuration = 20 * Time.toMinutes;
|
||||||
/** turns needed to destroy a sector completely */
|
/** turns needed to destroy a sector completely */
|
||||||
@@ -188,7 +190,6 @@ public class Vars implements Loadable{
|
|||||||
public static Schematics schematics;
|
public static Schematics schematics;
|
||||||
public static BeControl becontrol;
|
public static BeControl becontrol;
|
||||||
public static AsyncCore asyncCore;
|
public static AsyncCore asyncCore;
|
||||||
public static TeamIndexProcess teamIndex;
|
|
||||||
public static BaseRegistry bases;
|
public static BaseRegistry bases;
|
||||||
|
|
||||||
public static Universe universe;
|
public static Universe universe;
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ public class BlockIndexer{
|
|||||||
|
|
||||||
if(other == null) continue;
|
if(other == null) continue;
|
||||||
|
|
||||||
if(other.team == team && pred.get(other) && intSet.add(other.pos())){
|
if((team == null || other.team == team) && pred.get(other) && intSet.add(other.pos())){
|
||||||
cons.get(other);
|
cons.get(other);
|
||||||
any = true;
|
any = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ public class GroundAI extends AIController{
|
|||||||
if(spawner != null && unit.within(spawner, state.rules.dropZoneRadius + 120f)) move = false;
|
if(spawner != null && unit.within(spawner, state.rules.dropZoneRadius + 120f)) move = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(move) moveTo(Pathfinder.fieldCore);
|
if(move) pathfind(Pathfinder.fieldCore);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(command() == UnitCommand.rally){
|
if(command() == UnitCommand.rally){
|
||||||
Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false);
|
Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false);
|
||||||
|
|
||||||
if(target != null && !unit.within(target, 70f)){
|
if(target != null && !unit.within(target, 70f)){
|
||||||
moveTo(Pathfinder.fieldRally);
|
pathfind(Pathfinder.fieldRally);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,16 +72,4 @@ public class GroundAI extends AIController{
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void moveTo(int pathTarget){
|
|
||||||
int costType = unit.pathType();
|
|
||||||
|
|
||||||
Tile tile = unit.tileOn();
|
|
||||||
if(tile == null) return;
|
|
||||||
Tile targetTile = pathfinder.getTargetTile(tile, pathfinder.getField(unit.team, costType, pathTarget));
|
|
||||||
|
|
||||||
if(tile == targetTile || (costType == Pathfinder.costWater && !targetTile.floor().isLiquid)) return;
|
|
||||||
|
|
||||||
unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type().speed));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
129
core/src/mindustry/ai/types/LogicAI.java
Normal file
129
core/src/mindustry/ai/types/LogicAI.java
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package mindustry.ai.types;
|
||||||
|
|
||||||
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import mindustry.ai.*;
|
||||||
|
import mindustry.entities.units.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
|
import mindustry.logic.LExecutor.*;
|
||||||
|
import mindustry.logic.*;
|
||||||
|
import mindustry.world.*;
|
||||||
|
import mindustry.world.meta.*;
|
||||||
|
|
||||||
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
|
public class LogicAI extends AIController{
|
||||||
|
/** Minimum delay between item transfers. */
|
||||||
|
public static final float transferDelay = 60f * 2f;
|
||||||
|
/** Time after which the unit resets its controlled and reverts to a normal unit. */
|
||||||
|
public static final float logicControlTimeout = 10f * 60f;
|
||||||
|
|
||||||
|
public LUnitControl control = LUnitControl.stop;
|
||||||
|
public float moveX, moveY, moveRad;
|
||||||
|
public float itemTimer, controlTimer = logicControlTimeout, targetTimer;
|
||||||
|
public Building controller;
|
||||||
|
|
||||||
|
//type of aiming to use
|
||||||
|
public LUnitControl aimControl = LUnitControl.stop;
|
||||||
|
|
||||||
|
//main target set for shootP
|
||||||
|
public Teamc mainTarget;
|
||||||
|
//whether to shoot at all
|
||||||
|
public boolean shoot;
|
||||||
|
//target shoot positions for manual aiming
|
||||||
|
public PosTeam posTarget = PosTeam.create();
|
||||||
|
|
||||||
|
private ObjectSet<RadarI> radars = new ObjectSet<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateMovement(){
|
||||||
|
if(itemTimer > 0){
|
||||||
|
itemTimer -= Time.delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(targetTimer > 0f){
|
||||||
|
targetTimer -= Time.delta;
|
||||||
|
}else{
|
||||||
|
radars.clear();
|
||||||
|
targetTimer = 30f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//timeout when not controlled by logic for a while
|
||||||
|
if(controlTimer > 0 && controller != null && controller.isValid()){
|
||||||
|
controlTimer -= Time.delta;
|
||||||
|
}else{
|
||||||
|
unit.resetController();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(control){
|
||||||
|
case move -> {
|
||||||
|
moveTo(Tmp.v1.set(moveX, moveY), 1f, 30f);
|
||||||
|
}
|
||||||
|
case approach -> {
|
||||||
|
moveTo(Tmp.v1.set(moveX, moveY), moveRad, 1f);
|
||||||
|
}
|
||||||
|
case pathfind -> {
|
||||||
|
Building core = unit.closestEnemyCore();
|
||||||
|
|
||||||
|
if((core == null || !unit.within(core, unit.range() * 0.5f)) && command() == UnitCommand.attack){
|
||||||
|
boolean move = true;
|
||||||
|
|
||||||
|
if(state.rules.waves && unit.team == state.rules.defaultTeam){
|
||||||
|
Tile spawner = getClosestSpawner();
|
||||||
|
if(spawner != null && unit.within(spawner, state.rules.dropZoneRadius + 120f)) move = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(move) pathfind(Pathfinder.fieldCore);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(command() == UnitCommand.rally){
|
||||||
|
Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false);
|
||||||
|
|
||||||
|
if(target != null && !unit.within(target, 70f)){
|
||||||
|
pathfind(Pathfinder.fieldRally);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//look where moving if there's nothing to aim at
|
||||||
|
if(!shoot){
|
||||||
|
if(unit.moving()){
|
||||||
|
unit.lookAt(unit.vel().angle());
|
||||||
|
}
|
||||||
|
}else if(unit.hasWeapons()){ //if there is, look at the object
|
||||||
|
unit.lookAt(unit.mounts[0].aimX, unit.mounts[0].aimY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkTargetTimer(RadarI radar){
|
||||||
|
return radars.add(radar);
|
||||||
|
}
|
||||||
|
|
||||||
|
//always retarget
|
||||||
|
@Override
|
||||||
|
protected boolean retarget(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean invalid(Teamc target){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldShoot(){
|
||||||
|
return shoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
//always aim for the main target
|
||||||
|
@Override
|
||||||
|
protected Teamc target(float x, float y, float range, boolean air, boolean ground){
|
||||||
|
return switch(aimControl){
|
||||||
|
case target -> posTarget;
|
||||||
|
case targetp -> mainTarget;
|
||||||
|
default -> null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -67,10 +67,10 @@ public class SuicideAI extends GroundAI{
|
|||||||
Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false);
|
Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false);
|
||||||
|
|
||||||
if(target != null && !unit.within(target, 70f)){
|
if(target != null && !unit.within(target, 70f)){
|
||||||
moveTo(Pathfinder.fieldRally);
|
pathfind(Pathfinder.fieldRally);
|
||||||
}
|
}
|
||||||
}else if(command() == UnitCommand.attack && core != null){
|
}else if(command() == UnitCommand.attack && core != null){
|
||||||
moveTo(Pathfinder.fieldCore);
|
pathfind(Pathfinder.fieldCore);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(unit.moving()) unit.lookAt(unit.vel().angle());
|
if(unit.moving()) unit.lookAt(unit.vel().angle());
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package mindustry.async;
|
|||||||
|
|
||||||
import arc.*;
|
import arc.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import mindustry.*;
|
|
||||||
import mindustry.game.EventType.*;
|
import mindustry.game.EventType.*;
|
||||||
|
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
@@ -12,8 +11,7 @@ import static mindustry.Vars.*;
|
|||||||
public class AsyncCore{
|
public class AsyncCore{
|
||||||
//all processes to be executed each frame
|
//all processes to be executed each frame
|
||||||
private final Seq<AsyncProcess> processes = Seq.with(
|
private final Seq<AsyncProcess> processes = Seq.with(
|
||||||
new PhysicsProcess(),
|
new PhysicsProcess()
|
||||||
Vars.teamIndex = new TeamIndexProcess()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
//futures to be awaited
|
//futures to be awaited
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
package mindustry.async;
|
|
||||||
|
|
||||||
import arc.math.geom.*;
|
|
||||||
import mindustry.*;
|
|
||||||
import mindustry.game.*;
|
|
||||||
import mindustry.gen.*;
|
|
||||||
import mindustry.type.*;
|
|
||||||
import mindustry.world.blocks.payloads.*;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/** Creates quadtrees per unit team. */
|
|
||||||
public class TeamIndexProcess implements AsyncProcess{
|
|
||||||
private QuadTree<Unit>[] trees = new QuadTree[Team.all.length];
|
|
||||||
private int[] counts = new int[Team.all.length];
|
|
||||||
private int[][] typeCounts = new int[Team.all.length][0];
|
|
||||||
|
|
||||||
public QuadTree<Unit> tree(Team team){
|
|
||||||
if(trees[team.id] == null) trees[team.id] = new QuadTree<>(Vars.world.getQuadBounds(new Rect()));
|
|
||||||
|
|
||||||
return trees[team.id];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int count(Team team){
|
|
||||||
return counts[team.id];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int countType(Team team, UnitType type){
|
|
||||||
return typeCounts[team.id].length <= type.id ? 0 : typeCounts[team.id][type.id];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateCount(Team team, UnitType type, int amount){
|
|
||||||
counts[team.id] = Math.max(amount + counts[team.id], 0);
|
|
||||||
if(typeCounts[team.id].length <= type.id){
|
|
||||||
typeCounts[team.id] = new int[Vars.content.units().size];
|
|
||||||
}
|
|
||||||
typeCounts[team.id][type.id] = Math.max(amount + typeCounts[team.id][type.id], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void count(Unit unit){
|
|
||||||
updateCount(unit.team, unit.type(), 1);
|
|
||||||
|
|
||||||
if(unit instanceof Payloadc){
|
|
||||||
((Payloadc)unit).payloads().each(p -> {
|
|
||||||
if(p instanceof UnitPayload){
|
|
||||||
count(((UnitPayload)p).unit);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset(){
|
|
||||||
counts = new int[Team.all.length];
|
|
||||||
trees = new QuadTree[Team.all.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin(){
|
|
||||||
|
|
||||||
for(Team team : Team.all){
|
|
||||||
if(trees[team.id] != null){
|
|
||||||
trees[team.id].clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
Arrays.fill(typeCounts[team.id], 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Arrays.fill(counts, 0);
|
|
||||||
|
|
||||||
for(Unit unit : Groups.unit){
|
|
||||||
tree(unit.team).insert(unit);
|
|
||||||
|
|
||||||
count(unit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean shouldProcess(){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -266,7 +266,6 @@ public class UnitTypes implements ContentList{
|
|||||||
//region ground support
|
//region ground support
|
||||||
|
|
||||||
nova = new UnitType("nova"){{
|
nova = new UnitType("nova"){{
|
||||||
itemCapacity = 60;
|
|
||||||
canBoost = true;
|
canBoost = true;
|
||||||
boostMultiplier = 1.5f;
|
boostMultiplier = 1.5f;
|
||||||
speed = 0.55f;
|
speed = 0.55f;
|
||||||
@@ -293,7 +292,6 @@ public class UnitTypes implements ContentList{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
pulsar = new UnitType("pulsar"){{
|
pulsar = new UnitType("pulsar"){{
|
||||||
itemCapacity = 60;
|
|
||||||
canBoost = true;
|
canBoost = true;
|
||||||
boostMultiplier = 1.5f;
|
boostMultiplier = 1.5f;
|
||||||
speed = 0.65f;
|
speed = 0.65f;
|
||||||
@@ -340,7 +338,6 @@ public class UnitTypes implements ContentList{
|
|||||||
mineTier = 1;
|
mineTier = 1;
|
||||||
hitSize = 12f;
|
hitSize = 12f;
|
||||||
boostMultiplier = 2f;
|
boostMultiplier = 2f;
|
||||||
itemCapacity = 80;
|
|
||||||
health = 650f;
|
health = 650f;
|
||||||
buildSpeed = 1.7f;
|
buildSpeed = 1.7f;
|
||||||
canBoost = true;
|
canBoost = true;
|
||||||
@@ -397,7 +394,7 @@ public class UnitTypes implements ContentList{
|
|||||||
engineSize = 6f;
|
engineSize = 6f;
|
||||||
lowAltitude = true;
|
lowAltitude = true;
|
||||||
|
|
||||||
health = 6500f;
|
health = 7000f;
|
||||||
armor = 7f;
|
armor = 7f;
|
||||||
canBoost = true;
|
canBoost = true;
|
||||||
landShake = 4f;
|
landShake = 4f;
|
||||||
@@ -445,7 +442,6 @@ public class UnitTypes implements ContentList{
|
|||||||
corvus = new UnitType("corvus"){{
|
corvus = new UnitType("corvus"){{
|
||||||
mineTier = 1;
|
mineTier = 1;
|
||||||
hitSize = 29f;
|
hitSize = 29f;
|
||||||
itemCapacity = 80;
|
|
||||||
health = 18000f;
|
health = 18000f;
|
||||||
buildSpeed = 1.7f;
|
buildSpeed = 1.7f;
|
||||||
armor = 9f;
|
armor = 9f;
|
||||||
@@ -545,7 +541,6 @@ public class UnitTypes implements ContentList{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
atrax = new UnitType("atrax"){{
|
atrax = new UnitType("atrax"){{
|
||||||
itemCapacity = 80;
|
|
||||||
speed = 0.5f;
|
speed = 0.5f;
|
||||||
drag = 0.4f;
|
drag = 0.4f;
|
||||||
hitSize = 10f;
|
hitSize = 10f;
|
||||||
@@ -1134,7 +1129,6 @@ public class UnitTypes implements ContentList{
|
|||||||
health = 100;
|
health = 100;
|
||||||
engineSize = 1.8f;
|
engineSize = 1.8f;
|
||||||
engineOffset = 5.7f;
|
engineOffset = 5.7f;
|
||||||
itemCapacity = 30;
|
|
||||||
range = 50f;
|
range = 50f;
|
||||||
isCounted = false;
|
isCounted = false;
|
||||||
|
|
||||||
@@ -1153,7 +1147,6 @@ public class UnitTypes implements ContentList{
|
|||||||
rotateSpeed = 15f;
|
rotateSpeed = 15f;
|
||||||
accel = 0.1f;
|
accel = 0.1f;
|
||||||
range = 70f;
|
range = 70f;
|
||||||
itemCapacity = 70;
|
|
||||||
health = 400;
|
health = 400;
|
||||||
buildSpeed = 0.5f;
|
buildSpeed = 0.5f;
|
||||||
engineOffset = 6.5f;
|
engineOffset = 6.5f;
|
||||||
|
|||||||
@@ -283,6 +283,8 @@ public class Logic implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!state.isPaused()){
|
if(!state.isPaused()){
|
||||||
|
state.teams.updateTeamStats();
|
||||||
|
|
||||||
if(state.isCampaign()){
|
if(state.isCampaign()){
|
||||||
state.secinfo.update();
|
state.secinfo.update();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,9 @@ public class Renderer implements ApplicationListener{
|
|||||||
Color.white.set(1f, 1f, 1f, 1f);
|
Color.white.set(1f, 1f, 1f, 1f);
|
||||||
Gl.clear(Gl.stencilBufferBit);
|
Gl.clear(Gl.stencilBufferBit);
|
||||||
|
|
||||||
camerascale = Mathf.lerpDelta(camerascale, targetscale, 0.1f);
|
float dest = Mathf.round(targetscale, 0.5f);
|
||||||
|
camerascale = Mathf.lerpDelta(camerascale, dest, 0.1f);
|
||||||
|
if(Mathf.within(camerascale, dest, 0.001f)) camerascale = dest;
|
||||||
laserOpacity = Core.settings.getInt("lasersopacity") / 100f;
|
laserOpacity = Core.settings.getInt("lasersopacity") / 100f;
|
||||||
|
|
||||||
if(landTime > 0){
|
if(landTime > 0){
|
||||||
@@ -303,6 +305,10 @@ public class Renderer implements ApplicationListener{
|
|||||||
targetscale = Mathf.clamp(targetscale, minScale(), Math.round(s * 6));
|
targetscale = Mathf.clamp(targetscale, minScale(), Math.round(s * 6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getDisplayScale(){
|
||||||
|
return camerascale;
|
||||||
|
}
|
||||||
|
|
||||||
public float minScale(){
|
public float minScale(){
|
||||||
return Scl.scl(1.5f);
|
return Scl.scl(1.5f);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class Units{
|
|||||||
|
|
||||||
/** @return whether a new instance of a unit of this team can be created. */
|
/** @return whether a new instance of a unit of this team can be created. */
|
||||||
public static boolean canCreate(Team team, UnitType type){
|
public static boolean canCreate(Team team, UnitType type){
|
||||||
return teamIndex.countType(team, type) < getCap(team);
|
return team.data().countType(type) < getCap(team);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getCap(Team team){
|
public static int getCap(Team team){
|
||||||
@@ -284,7 +284,7 @@ public class Units{
|
|||||||
|
|
||||||
/** Iterates over all units in a rectangle. */
|
/** Iterates over all units in a rectangle. */
|
||||||
public static void nearby(Team team, float x, float y, float width, float height, Cons<Unit> cons){
|
public static void nearby(Team team, float x, float y, float width, float height, Cons<Unit> cons){
|
||||||
teamIndex.tree(team).intersect(x, y, width, height, cons);
|
team.data().tree().intersect(x, y, width, height, cons);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Iterates over all units in a circle around this position. */
|
/** Iterates over all units in a circle around this position. */
|
||||||
@@ -316,7 +316,7 @@ public class Units{
|
|||||||
//inactive teams have no cache, check everything
|
//inactive teams have no cache, check everything
|
||||||
//TODO cache all teams with units OR blocks
|
//TODO cache all teams with units OR blocks
|
||||||
for(Team other : Team.all){
|
for(Team other : Team.all){
|
||||||
if(other != team && teamIndex.count(other) > 0){
|
if(other != team && other.data().unitCount > 0){
|
||||||
nearby(other, x, y, width, height, cons);
|
nearby(other, x, y, width, height, cons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,6 +146,9 @@ public abstract class BulletType extends Content{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void hitTile(Bullet b, Building tile, float initialHealth){
|
public void hitTile(Bullet b, Building tile, float initialHealth){
|
||||||
|
if(status == StatusEffects.burning) {
|
||||||
|
Fires.create(tile.tile);
|
||||||
|
}
|
||||||
hit(b);
|
hit(b);
|
||||||
|
|
||||||
if(healPercent > 0f && tile.team == b.team && !(tile.block instanceof ConstructBlock)){
|
if(healPercent > 0f && tile.team == b.team && !(tile.block instanceof ConstructBlock)){
|
||||||
@@ -193,11 +196,16 @@ public abstract class BulletType extends Content{
|
|||||||
if(status != StatusEffects.none){
|
if(status != StatusEffects.none){
|
||||||
Damage.status(b.team, x, y, splashDamageRadius, status, statusDuration, collidesAir, collidesGround);
|
Damage.status(b.team, x, y, splashDamageRadius, status, statusDuration, collidesAir, collidesGround);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(healPercent > 0f) {
|
if(healPercent > 0f) {
|
||||||
indexer.eachBlock(b.team, x, y, splashDamageRadius, other -> other.damaged(), other -> {
|
indexer.eachBlock(b.team, x, y, splashDamageRadius, other -> other.damaged(), other -> {
|
||||||
Fx.healBlockFull.at(other.x, other.y, other.block.size, Pal.heal);
|
Fx.healBlockFull.at(other.x, other.y, other.block.size, Pal.heal);
|
||||||
other.heal(healPercent / 100f * other.maxHealth());
|
other.heal(healPercent / 100f * other.maxHealth());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status == StatusEffects.burning) {
|
||||||
|
indexer.eachBlock(null, x, y, splashDamageRadius, other -> other.team != b.team, other -> {
|
||||||
|
Fires.create(other.tile);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
|||||||
public void getCollisions(Cons<QuadTree> consumer){
|
public void getCollisions(Cons<QuadTree> consumer){
|
||||||
if(team.active()){
|
if(team.active()){
|
||||||
for(Team team : team.enemies()){
|
for(Team team : team.enemies()){
|
||||||
consumer.get(teamIndex.tree(team));
|
consumer.get(team.data().tree());
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
for(Team other : Team.all){
|
for(Team other : Team.all){
|
||||||
if(other != team && teamIndex.count(other) > 0){
|
if(other != team && team.data().unitCount > 0){
|
||||||
consumer.get(teamIndex.tree(other));
|
consumer.get(team.data().tree());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
core/src/mindustry/entities/comp/PosTeamDef.java
Normal file
9
core/src/mindustry/entities/comp/PosTeamDef.java
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package mindustry.entities.comp;
|
||||||
|
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
|
|
||||||
|
//dummy target definition
|
||||||
|
@EntityDef(value = Teamc.class, genio = false, isFinal = false)
|
||||||
|
public class PosTeamDef{
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@ import mindustry.world.blocks.environment.*;
|
|||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
@Component(base = true)
|
@Component(base = true)
|
||||||
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable, Senseable{
|
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable, Senseable, Ranged{
|
||||||
|
|
||||||
@Import boolean hovering, dead;
|
@Import boolean hovering, dead;
|
||||||
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo;
|
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo;
|
||||||
@@ -38,6 +38,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
private UnitType type;
|
private UnitType type;
|
||||||
boolean spawnedByCore;
|
boolean spawnedByCore;
|
||||||
|
|
||||||
|
//TODO mark as non-transient when done
|
||||||
|
transient double flag;
|
||||||
|
|
||||||
transient Seq<Ability> abilities = new Seq<>(0);
|
transient Seq<Ability> abilities = new Seq<>(0);
|
||||||
private transient float resupplyTime = Mathf.random(10f);
|
private transient float resupplyTime = Mathf.random(10f);
|
||||||
|
|
||||||
@@ -63,6 +66,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
return type.hasWeapons();
|
return type.hasWeapons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public float range(){
|
public float range(){
|
||||||
return type.range;
|
return type.range;
|
||||||
}
|
}
|
||||||
@@ -76,6 +80,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
public double sense(LAccess sensor){
|
public double sense(LAccess sensor){
|
||||||
return switch(sensor){
|
return switch(sensor){
|
||||||
case totalItems -> stack().amount;
|
case totalItems -> stack().amount;
|
||||||
|
case itemCapacity -> type.itemCapacity;
|
||||||
case rotation -> rotation;
|
case rotation -> rotation;
|
||||||
case health -> health;
|
case health -> health;
|
||||||
case maxHealth -> maxHealth;
|
case maxHealth -> maxHealth;
|
||||||
@@ -85,6 +90,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
case shooting -> isShooting() ? 1 : 0;
|
case shooting -> isShooting() ? 1 : 0;
|
||||||
case shootX -> aimX();
|
case shootX -> aimX();
|
||||||
case shootY -> aimY();
|
case shootY -> aimY();
|
||||||
|
case flag -> flag;
|
||||||
default -> 0;
|
default -> 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -93,6 +99,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
public Object senseObject(LAccess sensor){
|
public Object senseObject(LAccess sensor){
|
||||||
return switch(sensor){
|
return switch(sensor){
|
||||||
case type -> type;
|
case type -> type;
|
||||||
|
case name -> controller instanceof Player p ? p.name : null;
|
||||||
default -> noSensed;
|
default -> noSensed;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -182,7 +189,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int count(){
|
public int count(){
|
||||||
return teamIndex.countType(team, type);
|
return team.data().countType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int cap(){
|
public int cap(){
|
||||||
@@ -224,13 +231,13 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
//check if over unit cap
|
//check if over unit cap
|
||||||
if(count() > cap() && !spawnedByCore && !dead){
|
if(count() > cap() && !spawnedByCore && !dead){
|
||||||
Call.unitCapDeath(self());
|
Call.unitCapDeath(self());
|
||||||
teamIndex.updateCount(team, type, -1);
|
team.data().updateCount(type, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(){
|
public void remove(){
|
||||||
teamIndex.updateCount(team, type, -1);
|
team.data().updateCount(type, -1);
|
||||||
controller.removed(self());
|
controller.removed(self());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import arc.math.*;
|
|||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
|
import mindustry.ai.*;
|
||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.type.*;
|
import mindustry.type.*;
|
||||||
@@ -63,6 +64,23 @@ public class AIController implements UnitController{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean invalid(Teamc target){
|
||||||
|
return Units.invalidateTarget(target, unit.team, unit.x, unit.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void pathfind(int pathTarget){
|
||||||
|
int costType = unit.pathType();
|
||||||
|
|
||||||
|
Tile tile = unit.tileOn();
|
||||||
|
if(tile == null) return;
|
||||||
|
Tile targetTile = pathfinder.getTargetTile(tile, pathfinder.getField(unit.team, costType, pathTarget));
|
||||||
|
|
||||||
|
if(tile == targetTile || (costType == Pathfinder.costWater && !targetTile.floor().isLiquid)) return;
|
||||||
|
|
||||||
|
unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type().speed));
|
||||||
|
}
|
||||||
|
|
||||||
protected void updateWeapons(){
|
protected void updateWeapons(){
|
||||||
if(targets.length != unit.mounts.length) targets = new Teamc[unit.mounts.length];
|
if(targets.length != unit.mounts.length) targets = new Teamc[unit.mounts.length];
|
||||||
|
|
||||||
@@ -73,7 +91,7 @@ public class AIController implements UnitController{
|
|||||||
target = findTarget(unit.x, unit.y, unit.range(), unit.type().targetAir, unit.type().targetGround);
|
target = findTarget(unit.x, unit.y, unit.range(), unit.type().targetAir, unit.type().targetGround);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Units.invalidateTarget(target, unit.team, unit.x, unit.y)){
|
if(invalid(target)){
|
||||||
target = null;
|
target = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,13 +117,11 @@ public class AIController implements UnitController{
|
|||||||
boolean shoot = false;
|
boolean shoot = false;
|
||||||
|
|
||||||
if(targets[i] != null){
|
if(targets[i] != null){
|
||||||
shoot = targets[i].within(mountX, mountY, weapon.bullet.range());
|
shoot = targets[i].within(mountX, mountY, weapon.bullet.range()) && shouldShoot();
|
||||||
|
|
||||||
if(shoot){
|
Vec2 to = Predict.intercept(unit, targets[i], weapon.bullet.speed);
|
||||||
Vec2 to = Predict.intercept(unit, targets[i], weapon.bullet.speed);
|
mount.aimX = to.x;
|
||||||
mount.aimX = to.x;
|
mount.aimY = to.y;
|
||||||
mount.aimY = to.y;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mount.shoot = shoot;
|
mount.shoot = shoot;
|
||||||
@@ -113,6 +129,10 @@ public class AIController implements UnitController{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean shouldShoot(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected Teamc targetFlag(float x, float y, BlockFlag flag, boolean enemy){
|
protected Teamc targetFlag(float x, float y, BlockFlag flag, boolean enemy){
|
||||||
Tile target = Geometry.findClosest(x, y, enemy ? indexer.getEnemy(unit.team, flag) : indexer.getAllied(unit.team, flag));
|
Tile target = Geometry.findClosest(x, y, enemy ? indexer.getEnemy(unit.team, flag) : indexer.getAllied(unit.team, flag));
|
||||||
return target == null ? null : target.build;
|
return target == null ? null : target.build;
|
||||||
@@ -157,11 +177,15 @@ public class AIController implements UnitController{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void moveTo(Position target, float circleLength){
|
protected void moveTo(Position target, float circleLength){
|
||||||
|
moveTo(target, circleLength, 100f);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void moveTo(Position target, float circleLength, float smooth){
|
||||||
if(target == null) return;
|
if(target == null) return;
|
||||||
|
|
||||||
vec.set(target).sub(unit);
|
vec.set(target).sub(unit);
|
||||||
|
|
||||||
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / 100f, -1f, 1f);
|
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / smooth, -1f, 1f);
|
||||||
|
|
||||||
vec.setLength(unit.type().speed * length);
|
vec.setLength(unit.type().speed * length);
|
||||||
if(length < -0.5f){
|
if(length < -0.5f){
|
||||||
|
|||||||
@@ -2,15 +2,20 @@ package mindustry.game;
|
|||||||
|
|
||||||
import arc.func.*;
|
import arc.func.*;
|
||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
|
import arc.struct.Queue;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
|
import mindustry.*;
|
||||||
import mindustry.ai.*;
|
import mindustry.ai.*;
|
||||||
import mindustry.content.*;
|
import mindustry.content.*;
|
||||||
import mindustry.entities.units.*;
|
import mindustry.entities.units.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.type.*;
|
import mindustry.type.*;
|
||||||
|
import mindustry.world.blocks.payloads.*;
|
||||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
/** Class for various team-based utilities. */
|
/** Class for various team-based utilities. */
|
||||||
@@ -67,9 +72,7 @@ public class Teams{
|
|||||||
|
|
||||||
/** Returns team data by type. */
|
/** Returns team data by type. */
|
||||||
public TeamData get(Team team){
|
public TeamData get(Team team){
|
||||||
if(map[team.id] == null){
|
if(map[team.id] == null) map[team.id] = new TeamData(team);
|
||||||
map[team.id] = new TeamData(team);
|
|
||||||
}
|
|
||||||
return map[team.id];
|
return map[team.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +132,61 @@ public class Teams{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void count(Unit unit){
|
||||||
|
unit.team.data().updateCount(unit.type(), 1);
|
||||||
|
|
||||||
|
if(unit instanceof Payloadc){
|
||||||
|
((Payloadc)unit).payloads().each(p -> {
|
||||||
|
if(p instanceof UnitPayload){
|
||||||
|
count(((UnitPayload)p).unit);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateTeamStats(){
|
||||||
|
for(Team team : Team.all){
|
||||||
|
TeamData data = team.data();
|
||||||
|
|
||||||
|
data.unitCount = 0;
|
||||||
|
data.units.clear();
|
||||||
|
if(data.tree != null){
|
||||||
|
data.tree.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.typeCounts != null){
|
||||||
|
Arrays.fill(data.typeCounts, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//clear old unit records
|
||||||
|
if(data.unitsByType != null){
|
||||||
|
for(int i = 0; i < data.unitsByType.length; i++){
|
||||||
|
if(data.unitsByType[i] != null){
|
||||||
|
data.unitsByType[i].clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Unit unit : Groups.unit){
|
||||||
|
TeamData data = unit.team.data();
|
||||||
|
data.tree().insert(unit);
|
||||||
|
data.units.add(unit);
|
||||||
|
|
||||||
|
if(data.unitsByType == null || data.unitsByType.length <= unit.type().id){
|
||||||
|
data.unitsByType = new Seq[content.units().size];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.unitsByType[unit.type().id] == null){
|
||||||
|
data.unitsByType[unit.type().id] = new Seq<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
data.unitsByType[unit.type().id].add(unit);
|
||||||
|
|
||||||
|
count(unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateEnemies(){
|
private void updateEnemies(){
|
||||||
if(state.rules.waves && !active.contains(get(state.rules.waveTeam))){
|
if(state.rules.waves && !active.contains(get(state.rules.waveTeam))){
|
||||||
active.add(get(state.rules.waveTeam));
|
active.add(get(state.rules.waveTeam));
|
||||||
@@ -147,7 +205,7 @@ public class Teams{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TeamData{
|
public static class TeamData{
|
||||||
public final Seq<CoreBuild> cores = new Seq<>();
|
public final Seq<CoreBuild> cores = new Seq<>();
|
||||||
public final Team team;
|
public final Team team;
|
||||||
public final BaseAI ai;
|
public final BaseAI ai;
|
||||||
@@ -160,11 +218,48 @@ public class Teams{
|
|||||||
/** Target items to mine. */
|
/** Target items to mine. */
|
||||||
public Seq<Item> mineItems = Seq.with(Items.copper, Items.lead, Items.titanium, Items.thorium);
|
public Seq<Item> mineItems = Seq.with(Items.copper, Items.lead, Items.titanium, Items.thorium);
|
||||||
|
|
||||||
|
/** Total unit count. */
|
||||||
|
public int unitCount;
|
||||||
|
/** Counts for each type of unit. Do not access directly. */
|
||||||
|
@Nullable
|
||||||
|
public int[] typeCounts;
|
||||||
|
/** Quadtree for units of this type. Do not access directly. */
|
||||||
|
@Nullable
|
||||||
|
public QuadTree<Unit> tree;
|
||||||
|
/** Units of this team. Updated each frame. */
|
||||||
|
public Seq<Unit> units = new Seq<>();
|
||||||
|
/** Units of this team by type. Updated each frame. */
|
||||||
|
@Nullable
|
||||||
|
public Seq<Unit>[] unitsByType;
|
||||||
|
|
||||||
public TeamData(Team team){
|
public TeamData(Team team){
|
||||||
this.team = team;
|
this.team = team;
|
||||||
this.ai = new BaseAI(this);
|
this.ai = new BaseAI(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Seq<Unit> unitCache(UnitType type){
|
||||||
|
if(unitsByType == null || unitsByType.length <= type.id || unitsByType[type.id] == null) return null;
|
||||||
|
return unitsByType[type.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateCount(UnitType type, int amount){
|
||||||
|
unitCount = Math.max(amount + unitCount, 0);
|
||||||
|
if(typeCounts == null || typeCounts.length <= type.id){
|
||||||
|
typeCounts = new int[Vars.content.units().size];
|
||||||
|
}
|
||||||
|
typeCounts [type.id] = Math.max(amount + typeCounts [type.id], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QuadTree<Unit> tree(){
|
||||||
|
if(tree == null) tree = new QuadTree<>(Vars.world.getQuadBounds(new Rect()));
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countType(UnitType type){
|
||||||
|
return typeCounts == null || typeCounts.length <= type.id ? 0 : typeCounts[type.id];
|
||||||
|
}
|
||||||
|
|
||||||
public boolean active(){
|
public boolean active(){
|
||||||
return (team == state.rules.waveTeam && state.rules.waves) || cores.size > 0;
|
return (team == state.rules.waveTeam && state.rules.waves) || cores.size > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
public void buildUI(Group group){
|
public void buildUI(Group group){
|
||||||
|
|
||||||
group.fill(t -> {
|
group.fill(t -> {
|
||||||
t.visible(() -> Core.settings.getBool("hints") && ui.hudfrag.shown() && !player.dead() && !player.unit().spawnedByCore() && !(Core.settings.getBool("hints") && lastSchematic != null && !selectRequests.isEmpty()));
|
t.visible(() -> Core.settings.getBool("hints") && ui.hudfrag.shown && !player.dead() && !player.unit().spawnedByCore() && !(Core.settings.getBool("hints") && lastSchematic != null && !selectRequests.isEmpty()));
|
||||||
t.bottom();
|
t.bottom();
|
||||||
t.table(Styles.black6, b -> {
|
t.table(Styles.black6, b -> {
|
||||||
b.defaults().left();
|
b.defaults().left();
|
||||||
|
|||||||
@@ -77,6 +77,19 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
createItemTransfer(item, 1, x, y, to, null);
|
createItemTransfer(item, 1, x, y, to, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Remote(called = Loc.server, unreliable = true)
|
||||||
|
public static void takeItems(Building build, Item item, int amount, Unit to){
|
||||||
|
if(to == null || build == null) return;
|
||||||
|
|
||||||
|
int removed = build.removeStack(item, Math.min(player.unit().maxAccepted(item), amount));
|
||||||
|
if(removed == 0) return;
|
||||||
|
|
||||||
|
to.addItem(item, removed);
|
||||||
|
for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){
|
||||||
|
Time.run(j * 3f, () -> Call.transferItemEffect(item, build.x, build.y, to));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Remote(called = Loc.server, unreliable = true)
|
@Remote(called = Loc.server, unreliable = true)
|
||||||
public static void transferItemToUnit(Item item, float x, float y, Itemsc to){
|
public static void transferItemToUnit(Item item, float x, float y, Itemsc to){
|
||||||
if(to == null) return;
|
if(to == null) return;
|
||||||
@@ -92,6 +105,16 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
build.items.add(item, amount);
|
build.items.add(item, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Remote(called = Loc.server, unreliable = true)
|
||||||
|
public static void transferItemTo(Unit unit, Item item, int amount, float x, float y, Building build){
|
||||||
|
if(build == null || build.items == null) return;
|
||||||
|
unit.stack.amount = Math.max(unit.stack.amount - amount, 0);
|
||||||
|
for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){
|
||||||
|
Time.run(i * 3, () -> createItemTransfer(item, amount, x, y, build, () -> {}));
|
||||||
|
}
|
||||||
|
build.handleStack(item, amount, unit);
|
||||||
|
}
|
||||||
|
|
||||||
public static void createItemTransfer(Item item, int amount, float x, float y, Position to, Runnable done){
|
public static void createItemTransfer(Item item, int amount, float x, float y, Position to, Runnable done){
|
||||||
Fx.itemTransfer.at(x, y, amount, item.color, to);
|
Fx.itemTransfer.at(x, y, amount, item.color, to);
|
||||||
if(done != null){
|
if(done != null){
|
||||||
@@ -99,6 +122,29 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Remote(called = Loc.server, targets = Loc.both, forward = true)
|
||||||
|
public static void requestItem(Player player, Building tile, Item item, int amount){
|
||||||
|
if(player == null || tile == null || !tile.interactable(player.team()) || !player.within(tile, buildingRange)) return;
|
||||||
|
amount = Math.min(player.unit().maxAccepted(item), amount);
|
||||||
|
int fa = amount;
|
||||||
|
|
||||||
|
if(amount == 0) return;
|
||||||
|
|
||||||
|
if(net.server() && (!Units.canInteract(player, tile) ||
|
||||||
|
!netServer.admins.allowAction(player, ActionType.withdrawItem, tile.tile(), action -> {
|
||||||
|
action.item = item;
|
||||||
|
action.itemAmount = fa;
|
||||||
|
}))) throw new ValidateException(player, "Player cannot request items.");
|
||||||
|
|
||||||
|
int removed = tile.removeStack(item, amount);
|
||||||
|
|
||||||
|
player.unit().addItem(item, removed);
|
||||||
|
Events.fire(new WithdrawEvent(tile, player, item, amount));
|
||||||
|
for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){
|
||||||
|
Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.x, tile.y, player.unit()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Remote(variants = Variant.one)
|
@Remote(variants = Variant.one)
|
||||||
public static void removeQueueBlock(int x, int y, boolean breaking){
|
public static void removeQueueBlock(int x, int y, boolean breaking){
|
||||||
player.builder().removeBuild(x, y, breaking);
|
player.builder().removeBuild(x, y, breaking);
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ public enum LAccess{
|
|||||||
shooting,
|
shooting,
|
||||||
team,
|
team,
|
||||||
type,
|
type,
|
||||||
|
flag,
|
||||||
|
name,
|
||||||
|
|
||||||
//values with parameters are considered controllable
|
//values with parameters are considered controllable
|
||||||
enabled("to"), //"to" is standard for single parameter access
|
enabled("to"), //"to" is standard for single parameter access
|
||||||
@@ -34,21 +36,21 @@ public enum LAccess{
|
|||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
public final String[] parameters;
|
public final String[] params;
|
||||||
public final boolean isObj;
|
public final boolean isObj;
|
||||||
|
|
||||||
public static final LAccess[]
|
public static final LAccess[]
|
||||||
all = values(),
|
all = values(),
|
||||||
senseable = Seq.select(all, t -> t.parameters.length <= 1).toArray(LAccess.class),
|
senseable = Seq.select(all, t -> t.params.length <= 1).toArray(LAccess.class),
|
||||||
controls = Seq.select(all, t -> t.parameters.length > 0).toArray(LAccess.class);
|
controls = Seq.select(all, t -> t.params.length > 0).toArray(LAccess.class);
|
||||||
|
|
||||||
LAccess(String... parameters){
|
LAccess(String... params){
|
||||||
this.parameters = parameters;
|
this.params = params;
|
||||||
isObj = false;
|
isObj = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LAccess(boolean obj, String... parameters){
|
LAccess(boolean obj, String... params){
|
||||||
this.parameters = parameters;
|
this.params = params;
|
||||||
isObj = obj;
|
isObj = obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,14 @@ public class LAssembler{
|
|||||||
LInstruction[] instructions;
|
LInstruction[] instructions;
|
||||||
|
|
||||||
public LAssembler(){
|
public LAssembler(){
|
||||||
|
//instruction counter
|
||||||
putVar("@counter").value = 0;
|
putVar("@counter").value = 0;
|
||||||
|
//unix timestamp
|
||||||
putConst("@time", 0);
|
putConst("@time", 0);
|
||||||
|
//currently controlled unit
|
||||||
|
putConst("@unit", null);
|
||||||
|
//reference to self
|
||||||
|
putConst("@this", null);
|
||||||
|
|
||||||
//add default constants
|
//add default constants
|
||||||
putConst("false", 0);
|
putConst("false", 0);
|
||||||
@@ -45,6 +51,10 @@ public class LAssembler{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(UnitType type : Vars.content.units()){
|
||||||
|
putConst("@" + type.name, type);
|
||||||
|
}
|
||||||
|
|
||||||
//store sensor constants
|
//store sensor constants
|
||||||
|
|
||||||
for(LAccess sensor : LAccess.all){
|
for(LAccess sensor : LAccess.all){
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ public enum LCategory{
|
|||||||
blocks(Pal.accentBack),
|
blocks(Pal.accentBack),
|
||||||
control(Color.cyan.cpy().shiftSaturation(-0.6f).mul(0.7f)),
|
control(Color.cyan.cpy().shiftSaturation(-0.6f).mul(0.7f)),
|
||||||
operations(Pal.place.cpy().shiftSaturation(-0.5f).mul(0.7f)),
|
operations(Pal.place.cpy().shiftSaturation(-0.5f).mul(0.7f)),
|
||||||
io(Pal.remove.cpy().shiftSaturation(-0.5f).mul(0.7f));
|
io(Pal.remove.cpy().shiftSaturation(-0.5f).mul(0.7f)),
|
||||||
|
units(Pal.bulletYellowBack.cpy().shiftSaturation(-0.3f).mul(0.8f));
|
||||||
|
|
||||||
public final Color color;
|
public final Color color;
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ import arc.struct.*;
|
|||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
import arc.util.noise.*;
|
import arc.util.noise.*;
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
|
import mindustry.ai.types.*;
|
||||||
import mindustry.ctype.*;
|
import mindustry.ctype.*;
|
||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
import mindustry.game.*;
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
|
import mindustry.type.*;
|
||||||
|
import mindustry.world.*;
|
||||||
import mindustry.world.blocks.logic.LogicDisplay.*;
|
import mindustry.world.blocks.logic.LogicDisplay.*;
|
||||||
import mindustry.world.blocks.logic.MemoryBlock.*;
|
import mindustry.world.blocks.logic.MemoryBlock.*;
|
||||||
import mindustry.world.blocks.logic.MessageBlock.*;
|
import mindustry.world.blocks.logic.MessageBlock.*;
|
||||||
@@ -23,7 +26,9 @@ public class LExecutor{
|
|||||||
//special variables
|
//special variables
|
||||||
public static final int
|
public static final int
|
||||||
varCounter = 0,
|
varCounter = 0,
|
||||||
varTime = 1;
|
varTime = 1,
|
||||||
|
varUnit = 2,
|
||||||
|
varThis = 3;
|
||||||
|
|
||||||
public static final int
|
public static final int
|
||||||
maxGraphicsBuffer = 256,
|
maxGraphicsBuffer = 256,
|
||||||
@@ -36,6 +41,7 @@ public class LExecutor{
|
|||||||
public LongSeq graphicsBuffer = new LongSeq();
|
public LongSeq graphicsBuffer = new LongSeq();
|
||||||
public StringBuilder textBuffer = new StringBuilder();
|
public StringBuilder textBuffer = new StringBuilder();
|
||||||
public Building[] links = {};
|
public Building[] links = {};
|
||||||
|
public Team team = Team.derelict;
|
||||||
|
|
||||||
public boolean initialized(){
|
public boolean initialized(){
|
||||||
return instructions != null && vars != null && instructions.length > 0;
|
return instructions != null && vars != null && instructions.length > 0;
|
||||||
@@ -102,6 +108,11 @@ public class LExecutor{
|
|||||||
return v.isobj ? v.objval != null ? 1 : 0 : v.numval;
|
return v.isobj ? v.objval != null ? 1 : 0 : v.numval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float numf(int index){
|
||||||
|
Var v = vars[index];
|
||||||
|
return v.isobj ? v.objval != null ? 1 : 0 : (float)v.numval;
|
||||||
|
}
|
||||||
|
|
||||||
public int numi(int index){
|
public int numi(int index){
|
||||||
return (int)num(index);
|
return (int)num(index);
|
||||||
}
|
}
|
||||||
@@ -121,6 +132,12 @@ public class LExecutor{
|
|||||||
v.isobj = true;
|
v.isobj = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setconst(int index, Object value){
|
||||||
|
Var v = vars[index];
|
||||||
|
v.objval = value;
|
||||||
|
v.isobj = true;
|
||||||
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
public static class Var{
|
public static class Var{
|
||||||
@@ -142,6 +159,157 @@ public class LExecutor{
|
|||||||
void run(LExecutor exec);
|
void run(LExecutor exec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Binds the processor to a unit based on some filters. */
|
||||||
|
public static class UnitBindI implements LInstruction{
|
||||||
|
public int type;
|
||||||
|
|
||||||
|
//iteration index
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
public UnitBindI(int type){
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnitBindI(){
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(LExecutor exec){
|
||||||
|
Object typeObj = exec.obj(type);
|
||||||
|
UnitType type = typeObj instanceof UnitType t ? t : null;
|
||||||
|
|
||||||
|
Seq<Unit> seq = type == null ? exec.team.data().units : exec.team.data().unitCache(type);
|
||||||
|
|
||||||
|
if(seq != null && seq.any()){
|
||||||
|
index %= seq.size;
|
||||||
|
if(index < seq.size){
|
||||||
|
//bind to the next unit
|
||||||
|
exec.setconst(varUnit, seq.get(index));
|
||||||
|
}
|
||||||
|
index ++;
|
||||||
|
}else{
|
||||||
|
//no units of this type found
|
||||||
|
exec.setconst(varUnit, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Controls the unit based on some parameters. */
|
||||||
|
public static class UnitControlI implements LInstruction{
|
||||||
|
public LUnitControl type = LUnitControl.move;
|
||||||
|
public int p1, p2, p3, p4;
|
||||||
|
|
||||||
|
public UnitControlI(LUnitControl type, int p1, int p2, int p3, int p4){
|
||||||
|
this.type = type;
|
||||||
|
this.p1 = p1;
|
||||||
|
this.p2 = p2;
|
||||||
|
this.p3 = p3;
|
||||||
|
this.p4 = p4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnitControlI(){
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks is a unit is valid for logic AI control, and returns the controller. */
|
||||||
|
@Nullable
|
||||||
|
public static LogicAI checkLogicAI(LExecutor exec, Object unitObj){
|
||||||
|
if(unitObj instanceof Unit unit && exec.obj(varUnit) == unit && unit.team == exec.team && !unit.isPlayer() && !(unit.controller() instanceof FormationAI)){
|
||||||
|
if(!(unit.controller() instanceof LogicAI)){
|
||||||
|
unit.controller(new LogicAI());
|
||||||
|
((LogicAI)unit.controller()).controller = exec.building(varThis);
|
||||||
|
|
||||||
|
//clear old state
|
||||||
|
if(unit instanceof Minerc miner){
|
||||||
|
miner.mineTile(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(unit instanceof Builderc builder){
|
||||||
|
builder.clearBuilding();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (LogicAI)unit.controller();
|
||||||
|
}
|
||||||
|
return (LogicAI)unit.controller();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(LExecutor exec){
|
||||||
|
Object unitObj = exec.obj(varUnit);
|
||||||
|
LogicAI ai = checkLogicAI(exec, unitObj);
|
||||||
|
|
||||||
|
//only control standard AI units
|
||||||
|
if(unitObj instanceof Unit unit && ai != null){
|
||||||
|
ai.controlTimer = LogicAI.logicControlTimeout;
|
||||||
|
|
||||||
|
switch(type){
|
||||||
|
case move, stop, approach -> {
|
||||||
|
ai.control = type;
|
||||||
|
ai.moveX = exec.numf(p1);
|
||||||
|
ai.moveY = exec.numf(p2);
|
||||||
|
if(type == LUnitControl.approach){
|
||||||
|
ai.moveRad = exec.numf(p3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case pathfind -> {
|
||||||
|
ai.control = type;
|
||||||
|
}
|
||||||
|
case target -> {
|
||||||
|
ai.posTarget.set(exec.numf(p1), exec.numf(p2));
|
||||||
|
ai.aimControl = type;
|
||||||
|
ai.mainTarget = null;
|
||||||
|
ai.shoot = exec.bool(p3);
|
||||||
|
}
|
||||||
|
case targetp -> {
|
||||||
|
ai.aimControl = type;
|
||||||
|
ai.mainTarget = exec.obj(p1) instanceof Teamc t ? t : null;
|
||||||
|
ai.shoot = exec.bool(p2);
|
||||||
|
}
|
||||||
|
case flag -> {
|
||||||
|
unit.flag = exec.num(p1);
|
||||||
|
}
|
||||||
|
case mine -> {
|
||||||
|
Tile tile = world.tileWorld(exec.numf(p1), exec.numf(p2));
|
||||||
|
if(unit instanceof Minerc miner){
|
||||||
|
miner.mineTile(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case itemDrop -> {
|
||||||
|
if(ai.itemTimer > 0) return;
|
||||||
|
|
||||||
|
Building build = exec.building(p1);
|
||||||
|
int amount = exec.numi(p2);
|
||||||
|
int dropped = Math.min(unit.stack.amount, amount);
|
||||||
|
if(build != null && dropped > 0 && unit.within(build, logicItemTransferRange)){
|
||||||
|
int accepted = build.acceptStack(unit.item(), dropped, unit);
|
||||||
|
if(accepted > 0){
|
||||||
|
Call.transferItemTo(unit, unit.item(), accepted, unit.x, unit.y, build);
|
||||||
|
ai.itemTimer = LogicAI.transferDelay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case itemTake -> {
|
||||||
|
if(ai.itemTimer > 0) return;
|
||||||
|
|
||||||
|
Building build = exec.building(p1);
|
||||||
|
int amount = exec.numi(p3);
|
||||||
|
|
||||||
|
if(build != null && exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange)){
|
||||||
|
int taken = Math.min(build.items.get(item), Math.min(amount, unit.maxAccepted(item)));
|
||||||
|
|
||||||
|
if(taken > 0){
|
||||||
|
Call.takeItems(build, item, taken, unit);
|
||||||
|
ai.itemTimer = LogicAI.transferDelay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Controls a building's state. */
|
/** Controls a building's state. */
|
||||||
public static class ControlI implements LInstruction{
|
public static class ControlI implements LInstruction{
|
||||||
public int target;
|
public int target;
|
||||||
@@ -311,16 +479,20 @@ public class LExecutor{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(LExecutor exec){
|
public void run(LExecutor exec){
|
||||||
Building target = exec.building(radar);
|
Object base = exec.obj(radar);
|
||||||
|
|
||||||
int sortDir = exec.bool(sortOrder) ? 1 : -1;
|
int sortDir = exec.bool(sortOrder) ? 1 : -1;
|
||||||
|
LogicAI ai = null;
|
||||||
|
|
||||||
if(target instanceof Ranged){
|
if(base instanceof Ranged r && r.team() == exec.team &&
|
||||||
float range = ((Ranged)target).range();
|
(base instanceof Building || (ai = UnitControlI.checkLogicAI(exec, base)) != null)){ //must be a building or a controllable unit
|
||||||
|
float range = r.range();
|
||||||
|
|
||||||
Healthc targeted;
|
Healthc targeted;
|
||||||
|
|
||||||
if(timer.get(30f)){
|
//timers update on a fixed 30 tick interval
|
||||||
|
//units update on a special timer per controller instance
|
||||||
|
if((base instanceof Building && timer.get(30f)) || (ai != null && ai.checkTargetTimer(this))){
|
||||||
//if any of the targets involve enemies
|
//if any of the targets involve enemies
|
||||||
boolean enemies = target1 == RadarTarget.enemy || target2 == RadarTarget.enemy || target3 == RadarTarget.enemy;
|
boolean enemies = target1 == RadarTarget.enemy || target2 == RadarTarget.enemy || target3 == RadarTarget.enemy;
|
||||||
|
|
||||||
@@ -328,11 +500,11 @@ public class LExecutor{
|
|||||||
bestValue = 0;
|
bestValue = 0;
|
||||||
|
|
||||||
if(enemies){
|
if(enemies){
|
||||||
for(Team enemy : state.teams.enemiesOf(target.team)){
|
for(Team enemy : state.teams.enemiesOf(r.team())){
|
||||||
find(target, range, sortDir, enemy);
|
find(r, range, sortDir, enemy);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
find(target, range, sortDir, target.team);
|
find(r, range, sortDir, r.team());
|
||||||
}
|
}
|
||||||
|
|
||||||
lastTarget = targeted = best;
|
lastTarget = targeted = best;
|
||||||
@@ -346,14 +518,14 @@ public class LExecutor{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void find(Building b, float range, int sortDir, Team team){
|
void find(Ranged b, float range, int sortDir, Team team){
|
||||||
Units.nearby(team, b.x, b.y, range, u -> {
|
Units.nearby(team, b.x(), b.y(), range, u -> {
|
||||||
if(!u.within(b, range)) return;
|
if(!u.within(b, range)) return;
|
||||||
|
|
||||||
boolean valid =
|
boolean valid =
|
||||||
target1.func.get(b.team, u) &&
|
target1.func.get(b.team(), u) &&
|
||||||
target2.func.get(b.team, u) &&
|
target2.func.get(b.team(), u) &&
|
||||||
target3.func.get(b.team, u);
|
target3.func.get(b.team(), u);
|
||||||
|
|
||||||
if(!valid) return;
|
if(!valid) return;
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ public abstract class LStatement{
|
|||||||
return read.size == 0 ? null : read.first();
|
return read.size == 0 ? null : read.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hidden(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//protected methods are only for internal UI layout utilities
|
//protected methods are only for internal UI layout utilities
|
||||||
|
|
||||||
protected Cell<TextField> field(Table table, String value, Cons<String> setter){
|
protected Cell<TextField> field(Table table, String value, Cons<String> setter){
|
||||||
@@ -38,9 +42,9 @@ public abstract class LStatement{
|
|||||||
.size(144f, 40f).pad(2f).color(table.color).addInputDialog();
|
.size(144f, 40f).pad(2f).color(table.color).addInputDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void fields(Table table, String desc, String value, Cons<String> setter){
|
protected Cell<TextField> fields(Table table, String desc, String value, Cons<String> setter){
|
||||||
table.add(desc).padLeft(10).left();
|
table.add(desc).padLeft(10).left();
|
||||||
field(table, value, setter).width(85f).padRight(10).left();
|
return field(table, value, setter).width(85f).padRight(10).left();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void fields(Table table, String value, Cons<String> setter){
|
protected void fields(Table table, String value, Cons<String> setter){
|
||||||
|
|||||||
@@ -347,9 +347,9 @@ public class LStatements{
|
|||||||
//Q: why don't you just use arrays for this?
|
//Q: why don't you just use arrays for this?
|
||||||
//A: arrays aren't as easy to serialize so the code generator doesn't handle them
|
//A: arrays aren't as easy to serialize so the code generator doesn't handle them
|
||||||
int c = 0;
|
int c = 0;
|
||||||
for(int i = 0; i < type.parameters.length; i++){
|
for(int i = 0; i < type.params.length; i++){
|
||||||
|
|
||||||
fields(table, type.parameters[i], i == 0 ? p1 : i == 1 ? p2 : i == 2 ? p3 : p4, i == 0 ? v -> p1 = v : i == 1 ? v -> p2 = v : i == 2 ? v -> p3 = v : v -> p4 = v);
|
fields(table, type.params[i], i == 0 ? p1 : i == 1 ? p2 : i == 2 ? p3 : p4, i == 0 ? v -> p1 = v : i == 1 ? v -> p2 = v : i == 2 ? v -> p3 = v : v -> p4 = v);
|
||||||
|
|
||||||
if(++c % 2 == 0) row(table);
|
if(++c % 2 == 0) row(table);
|
||||||
}
|
}
|
||||||
@@ -376,11 +376,13 @@ public class LStatements{
|
|||||||
public void build(Table table){
|
public void build(Table table){
|
||||||
table.defaults().left();
|
table.defaults().left();
|
||||||
|
|
||||||
table.add(" from ");
|
if(buildFrom()){
|
||||||
|
table.add(" from ");
|
||||||
|
|
||||||
fields(table, radar, v -> radar = v);
|
fields(table, radar, v -> radar = v);
|
||||||
|
|
||||||
row(table);
|
row(table);
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < 3; i++){
|
for(int i = 0; i < 3; i++){
|
||||||
int fi = i;
|
int fi = i;
|
||||||
@@ -420,6 +422,10 @@ public class LStatements{
|
|||||||
fields(table, output, v -> output = v);
|
fields(table, output, v -> output = v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean buildFrom(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LCategory category(){
|
public LCategory category(){
|
||||||
return LCategory.blocks;
|
return LCategory.blocks;
|
||||||
@@ -694,4 +700,95 @@ public class LStatements{
|
|||||||
return LCategory.control;
|
return LCategory.control;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RegisterStatement("ubind")
|
||||||
|
public static class UnitBindStatement extends LStatement{
|
||||||
|
public String type = "@mono";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void build(Table table){
|
||||||
|
table.add(" type ");
|
||||||
|
|
||||||
|
field(table, type, str -> type = str);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LCategory category(){
|
||||||
|
return LCategory.units;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LInstruction build(LAssembler builder){
|
||||||
|
return new UnitBindI(builder.var(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RegisterStatement("ucontrol")
|
||||||
|
public static class UnitControlStatement extends LStatement{
|
||||||
|
public LUnitControl type = LUnitControl.move;
|
||||||
|
public String p1 = "0", p2 = "0", p3 = "0", p4 = "0";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void build(Table table){
|
||||||
|
rebuild(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rebuild(Table table){
|
||||||
|
table.clearChildren();
|
||||||
|
|
||||||
|
table.left();
|
||||||
|
|
||||||
|
table.add(" ");
|
||||||
|
|
||||||
|
table.button(b -> {
|
||||||
|
b.label(() -> type.name());
|
||||||
|
b.clicked(() -> showSelect(b, LUnitControl.all, type, t -> {
|
||||||
|
type = t;
|
||||||
|
rebuild(table);
|
||||||
|
}, 2, cell -> cell.size(120, 50)));
|
||||||
|
}, Styles.logict, () -> {}).size(120, 40).color(table.color).left().padLeft(2);
|
||||||
|
|
||||||
|
row(table);
|
||||||
|
|
||||||
|
//Q: why don't you just use arrays for this?
|
||||||
|
//A: arrays aren't as easy to serialize so the code generator doesn't handle them
|
||||||
|
int c = 0;
|
||||||
|
for(int i = 0; i < type.params.length; i++){
|
||||||
|
|
||||||
|
fields(table, type.params[i], i == 0 ? p1 : i == 1 ? p2 : i == 2 ? p3 : p4, i == 0 ? v -> p1 = v : i == 1 ? v -> p2 = v : i == 2 ? v -> p3 = v : v -> p4 = v).width(110f);
|
||||||
|
|
||||||
|
if(++c % 2 == 0) row(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LCategory category(){
|
||||||
|
return LCategory.units;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LInstruction build(LAssembler builder){
|
||||||
|
return new UnitControlI(type, builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RegisterStatement("uradar")
|
||||||
|
public static class UnitRadarStatement extends RadarStatement{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean buildFrom(){
|
||||||
|
//do not build the "from" section
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LCategory category(){
|
||||||
|
return LCategory.units;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LInstruction build(LAssembler builder){
|
||||||
|
return new RadarI(target1, target2, target3, sort, LExecutor.varUnit, builder.var(sortOrder), builder.var(output));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
core/src/mindustry/logic/LUnitControl.java
Normal file
21
core/src/mindustry/logic/LUnitControl.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package mindustry.logic;
|
||||||
|
|
||||||
|
public enum LUnitControl{
|
||||||
|
stop,
|
||||||
|
move("x", "y"),
|
||||||
|
approach("x", "y", "radius"),
|
||||||
|
pathfind(),
|
||||||
|
target("x", "y", "shoot"),
|
||||||
|
targetp("unit", "shoot"),
|
||||||
|
itemDrop("to", "amount"),
|
||||||
|
itemTake("from", "item", "amount"),
|
||||||
|
mine("x", "y"),
|
||||||
|
flag("value");
|
||||||
|
|
||||||
|
public final String[] params;
|
||||||
|
public static final LUnitControl[] all = values();
|
||||||
|
|
||||||
|
LUnitControl(String... params){
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,7 +60,7 @@ public class LogicDialog extends BaseDialog{
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
for(Prov<LStatement> prov : LogicIO.allStatements){
|
for(Prov<LStatement> prov : LogicIO.allStatements){
|
||||||
LStatement example = prov.get();
|
LStatement example = prov.get();
|
||||||
if(example instanceof InvalidStatement) continue;
|
if(example instanceof InvalidStatement || example.hidden()) continue;
|
||||||
|
|
||||||
TextButtonStyle style = new TextButtonStyle(Styles.cleart);
|
TextButtonStyle style = new TextButtonStyle(Styles.cleart);
|
||||||
style.fontColor = example.category().color;
|
style.fontColor = example.category().color;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package mindustry.logic;
|
package mindustry.logic;
|
||||||
|
|
||||||
import arc.math.*;
|
import arc.math.*;
|
||||||
|
import arc.util.*;
|
||||||
|
|
||||||
public enum LogicOp{
|
public enum LogicOp{
|
||||||
add("+", (a, b) -> a + b),
|
add("+", (a, b) -> a + b),
|
||||||
@@ -9,8 +10,8 @@ public enum LogicOp{
|
|||||||
div("/", (a, b) -> a / b),
|
div("/", (a, b) -> a / b),
|
||||||
idiv("//", (a, b) -> Math.floor(a / b)),
|
idiv("//", (a, b) -> Math.floor(a / b)),
|
||||||
mod("%", (a, b) -> a % b),
|
mod("%", (a, b) -> a % b),
|
||||||
equal("==", (a, b) -> Math.abs(a - b) < 0.000001 ? 1 : 0, (a, b) -> a == b ? 1 : 0),
|
equal("==", (a, b) -> Math.abs(a - b) < 0.000001 ? 1 : 0, (a, b) -> Structs.eq(a, b) ? 1 : 0),
|
||||||
notEqual("not", (a, b) -> Math.abs(a - b) < 0.000001 ? 0 : 1, (a, b) -> a != b ? 1 : 0),
|
notEqual("not", (a, b) -> Math.abs(a - b) < 0.000001 ? 0 : 1, (a, b) -> !Structs.eq(a, b) ? 1 : 0),
|
||||||
lessThan("<", (a, b) -> a < b ? 1 : 0),
|
lessThan("<", (a, b) -> a < b ? 1 : 0),
|
||||||
lessThanEq("<=", (a, b) -> a <= b ? 1 : 0),
|
lessThanEq("<=", (a, b) -> a <= b ? 1 : 0),
|
||||||
greaterThan(">", (a, b) -> a > b ? 1 : 0),
|
greaterThan(">", (a, b) -> a > b ? 1 : 0),
|
||||||
|
|||||||
@@ -163,6 +163,11 @@ public class UnitType extends UnlockableContent{
|
|||||||
bars.row();
|
bars.row();
|
||||||
}
|
}
|
||||||
}).growX();
|
}).growX();
|
||||||
|
|
||||||
|
if(unit.controller() instanceof LogicAI){
|
||||||
|
table.row();
|
||||||
|
table.add(Blocks.microProcessor.emoji() + " " + Core.bundle.get("units.processorcontrol")).growX().left();
|
||||||
|
}
|
||||||
|
|
||||||
table.row();
|
table.row();
|
||||||
}
|
}
|
||||||
@@ -206,7 +211,7 @@ public class UnitType extends UnlockableContent{
|
|||||||
singleTarget = weapons.size <= 1;
|
singleTarget = weapons.size <= 1;
|
||||||
|
|
||||||
if(itemCapacity < 0){
|
if(itemCapacity < 0){
|
||||||
itemCapacity = Math.max(Mathf.round(hitSize * 7, 20), 20);
|
itemCapacity = Math.max(Mathf.round(hitSize * 4, 10), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
//set up default range
|
//set up default range
|
||||||
|
|||||||
@@ -14,12 +14,8 @@ import arc.scene.ui.layout.Stack;
|
|||||||
import arc.scene.ui.layout.*;
|
import arc.scene.ui.layout.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
|
||||||
import mindustry.entities.*;
|
|
||||||
import mindustry.game.EventType.*;
|
import mindustry.game.EventType.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.net.Administration.*;
|
|
||||||
import mindustry.net.*;
|
|
||||||
import mindustry.type.*;
|
import mindustry.type.*;
|
||||||
import mindustry.ui.*;
|
import mindustry.ui.*;
|
||||||
|
|
||||||
@@ -42,29 +38,6 @@ public class BlockInventoryFragment extends Fragment{
|
|||||||
Events.on(WorldLoadEvent.class, e -> hide());
|
Events.on(WorldLoadEvent.class, e -> hide());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(called = Loc.server, targets = Loc.both, forward = true)
|
|
||||||
public static void requestItem(Player player, Building tile, Item item, int amount){
|
|
||||||
if(player == null || tile == null || !tile.interactable(player.team()) || !player.within(tile, buildingRange)) return;
|
|
||||||
amount = Math.min(player.unit().maxAccepted(item), amount);
|
|
||||||
int fa = amount;
|
|
||||||
|
|
||||||
if(amount == 0) return;
|
|
||||||
|
|
||||||
if(net.server() && (!Units.canInteract(player, tile) ||
|
|
||||||
!netServer.admins.allowAction(player, ActionType.withdrawItem, tile.tile(), action -> {
|
|
||||||
action.item = item;
|
|
||||||
action.itemAmount = fa;
|
|
||||||
}))) throw new ValidateException(player, "Player cannot request items.");
|
|
||||||
|
|
||||||
int removed = tile.removeStack(item, amount);
|
|
||||||
|
|
||||||
player.unit().addItem(item, removed);
|
|
||||||
Events.fire(new WithdrawEvent(tile, player, item, amount));
|
|
||||||
for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){
|
|
||||||
Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.x, tile.y, player.unit()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void build(Group parent){
|
public void build(Group parent){
|
||||||
table.name = "inventory";
|
table.name = "inventory";
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class ChatFragment extends Table{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return net.active() && ui.hudfrag.shown();
|
return net.active() && ui.hudfrag.shown;
|
||||||
});
|
});
|
||||||
|
|
||||||
update(() -> {
|
update(() -> {
|
||||||
|
|||||||
@@ -32,16 +32,16 @@ public class HudFragment extends Fragment{
|
|||||||
private static final float dsize = 65f;
|
private static final float dsize = 65f;
|
||||||
|
|
||||||
public final PlacementFragment blockfrag = new PlacementFragment();
|
public final PlacementFragment blockfrag = new PlacementFragment();
|
||||||
|
public boolean shown = true;
|
||||||
|
|
||||||
private ImageButton flip;
|
private ImageButton flip;
|
||||||
private Table lastUnlockTable;
|
|
||||||
private Table lastUnlockLayout;
|
|
||||||
private boolean shown = true;
|
|
||||||
private CoreItemsDisplay coreItems = new CoreItemsDisplay();
|
private CoreItemsDisplay coreItems = new CoreItemsDisplay();
|
||||||
|
|
||||||
private String hudText = "";
|
private String hudText = "";
|
||||||
private boolean showHudText;
|
private boolean showHudText;
|
||||||
|
|
||||||
|
private Table lastUnlockTable;
|
||||||
|
private Table lastUnlockLayout;
|
||||||
private long lastToast;
|
private long lastToast;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -420,10 +420,6 @@ public class HudFragment extends Fragment{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shown(){
|
|
||||||
return shown;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Show unlock notification for a new recipe. */
|
/** Show unlock notification for a new recipe. */
|
||||||
public void showUnlock(UnlockableContent content){
|
public void showUnlock(UnlockableContent content){
|
||||||
//some content may not have icons... yet
|
//some content may not have icons... yet
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ public class PlacementFragment extends Fragment{
|
|||||||
public void build(Group parent){
|
public void build(Group parent){
|
||||||
parent.fill(full -> {
|
parent.fill(full -> {
|
||||||
toggler = full;
|
toggler = full;
|
||||||
full.bottom().right().visible(() -> ui.hudfrag.shown());
|
full.bottom().right().visible(() -> ui.hudfrag.shown);
|
||||||
|
|
||||||
full.table(frame -> {
|
full.table(frame -> {
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class Router extends Block{
|
|||||||
@Override
|
@Override
|
||||||
public void updateTile(){
|
public void updateTile(){
|
||||||
if(lastItem == null && items.any()){
|
if(lastItem == null && items.any()){
|
||||||
items.clear();
|
lastItem = items.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lastItem != null){
|
if(lastItem != null){
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ public class LogicBlock extends Block{
|
|||||||
assemble.get(asm);
|
assemble.get(asm);
|
||||||
}
|
}
|
||||||
|
|
||||||
asm.putConst("@this", this);
|
asm.getVar("@this").value = this;
|
||||||
asm.putConst("@thisx", x);
|
asm.putConst("@thisx", x);
|
||||||
asm.putConst("@thisy", y);
|
asm.putConst("@thisy", y);
|
||||||
|
|
||||||
@@ -331,6 +331,7 @@ public class LogicBlock extends Block{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateTile(){
|
public void updateTile(){
|
||||||
|
executor.team = team;
|
||||||
|
|
||||||
//check for previously invalid links to add after configuration
|
//check for previously invalid links to add after configuration
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
|
|||||||
@@ -75,15 +75,15 @@ public class LogicDisplay extends Block{
|
|||||||
p1 = DisplayCmd.p1(c), p2 = DisplayCmd.p2(c), p3 = DisplayCmd.p3(c), p4 = DisplayCmd.p4(c);
|
p1 = DisplayCmd.p1(c), p2 = DisplayCmd.p2(c), p3 = DisplayCmd.p3(c), p4 = DisplayCmd.p4(c);
|
||||||
|
|
||||||
switch(type){
|
switch(type){
|
||||||
case commandClear: Core.graphics.clear(x/255f, y/255f, p1/255f, 1f); break;
|
case commandClear -> Core.graphics.clear(x / 255f, y / 255f, p1 / 255f, 1f);
|
||||||
case commandLine: Lines.line(x, y, p1, p2); break;
|
case commandLine -> Lines.line(x, y, p1, p2);
|
||||||
case commandRect: Fill.crect(x, y, p1, p2); break;
|
case commandRect -> Fill.crect(x, y, p1, p2);
|
||||||
case commandLineRect: Lines.rect(x, y, p1, p2); break;
|
case commandLineRect -> Lines.rect(x, y, p1, p2);
|
||||||
case commandPoly: Fill.poly(x, y, Math.min(p1, maxSides), p2, p3); break;
|
case commandPoly -> Fill.poly(x, y, Math.min(p1, maxSides), p2, p3);
|
||||||
case commandLinePoly: Lines.poly(x, y, Math.min(p1, maxSides), p2, p3); break;
|
case commandLinePoly -> Lines.poly(x, y, Math.min(p1, maxSides), p2, p3);
|
||||||
case commandTriangle: Fill.tri(x, y, p1, p2, p3, p4); break;
|
case commandTriangle -> Fill.tri(x, y, p1, p2, p3, p4);
|
||||||
case commandColor: this.color = Color.toFloatBits(x, y, p1, p2); Draw.color(this.color); break;
|
case commandColor -> Draw.color(this.color = Color.toFloatBits(x, y, p1, p2));
|
||||||
case commandStroke: this.stroke = x; Lines.stroke(x); break;
|
case commandStroke -> Lines.stroke(this.stroke = x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,11 +50,11 @@ public class Reconstructor extends UnitBlock{
|
|||||||
() -> e.unit() == null ? "[lightgray]" + Iconc.cancel :
|
() -> e.unit() == null ? "[lightgray]" + Iconc.cancel :
|
||||||
Core.bundle.format("bar.unitcap",
|
Core.bundle.format("bar.unitcap",
|
||||||
Fonts.getUnicodeStr(e.unit().name),
|
Fonts.getUnicodeStr(e.unit().name),
|
||||||
teamIndex.countType(e.team, e.unit()),
|
e.team.data().countType(e.unit()),
|
||||||
Units.getCap(e.team)
|
Units.getCap(e.team)
|
||||||
),
|
),
|
||||||
() -> Pal.power,
|
() -> Pal.power,
|
||||||
() -> e.unit() == null ? 0f : (float)teamIndex.countType(e.team, e.unit()) / Units.getCap(e.team)
|
() -> e.unit() == null ? 0f : (float)e.team.data().countType(e.unit()) / Units.getCap(e.team)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ import mindustry.world.blocks.payloads.*;
|
|||||||
import mindustry.world.consumers.*;
|
import mindustry.world.consumers.*;
|
||||||
import mindustry.world.meta.*;
|
import mindustry.world.meta.*;
|
||||||
|
|
||||||
import static mindustry.Vars.*;
|
|
||||||
|
|
||||||
public class UnitFactory extends UnitBlock{
|
public class UnitFactory extends UnitBlock{
|
||||||
public int[] capacities;
|
public int[] capacities;
|
||||||
|
|
||||||
@@ -71,11 +69,11 @@ public class UnitFactory extends UnitBlock{
|
|||||||
() -> e.unit() == null ? "[lightgray]" + Iconc.cancel :
|
() -> e.unit() == null ? "[lightgray]" + Iconc.cancel :
|
||||||
Core.bundle.format("bar.unitcap",
|
Core.bundle.format("bar.unitcap",
|
||||||
Fonts.getUnicodeStr(e.unit().name),
|
Fonts.getUnicodeStr(e.unit().name),
|
||||||
teamIndex.countType(e.team, e.unit()),
|
e.team.data().countType(e.unit()),
|
||||||
Units.getCap(e.team)
|
Units.getCap(e.team)
|
||||||
),
|
),
|
||||||
() -> Pal.power,
|
() -> Pal.power,
|
||||||
() -> e.unit() == null ? 0f : (float)teamIndex.countType(e.team, e.unit()) / Units.getCap(e.team)
|
() -> e.unit() == null ? 0f : (float)e.team.data().countType(e.unit()) / Units.getCap(e.team)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||||
archash=6fca97cecdf28a696b2c19097f70960485a62743
|
archash=86e6ad07a2bfc727f8772c3e9c5f9d2761580879
|
||||||
|
|||||||
Reference in New Issue
Block a user