Extra mod field parsing (untested)

This commit is contained in:
Anuken
2020-10-07 11:00:02 -04:00
parent d4513fab19
commit be66a15287
10 changed files with 215 additions and 134 deletions

View File

@@ -3,6 +3,7 @@ package mindustry.content;
import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.struct.*;
import mindustry.ctype.*;
import mindustry.entities.bullet.*;
import mindustry.gen.*;
@@ -1801,30 +1802,30 @@ public class Blocks implements ContentList{
groundFactory = new UnitFactory("ground-factory"){{
requirements(Category.units, with(Items.copper, 50, Items.lead, 120, Items.silicon, 80));
plans = new UnitPlan[]{
plans = Seq.with(
new UnitPlan(UnitTypes.dagger, 60f * 15, with(Items.silicon, 10, Items.lead, 10)),
new UnitPlan(UnitTypes.crawler, 60f * 12, with(Items.silicon, 10, Items.coal, 20)),
new UnitPlan(UnitTypes.nova, 60f * 40, with(Items.silicon, 30, Items.lead, 20, Items.titanium, 20)),
};
new UnitPlan(UnitTypes.nova, 60f * 40, with(Items.silicon, 30, Items.lead, 20, Items.titanium, 20))
);
size = 3;
consumes.power(1.2f);
}};
airFactory = new UnitFactory("air-factory"){{
requirements(Category.units, with(Items.copper, 60, Items.lead, 70));
plans = new UnitPlan[]{
plans = Seq.with(
new UnitPlan(UnitTypes.flare, 60f * 15, with(Items.silicon, 15)),
new UnitPlan(UnitTypes.mono, 60f * 35, with(Items.silicon, 30, Items.lead, 15)),
};
new UnitPlan(UnitTypes.mono, 60f * 35, with(Items.silicon, 30, Items.lead, 15))
);
size = 3;
consumes.power(1.2f);
}};
navalFactory = new UnitFactory("naval-factory"){{
requirements(Category.units, with(Items.copper, 150, Items.lead, 130, Items.metaglass, 120));
plans = new UnitPlan[]{
new UnitPlan(UnitTypes.risso, 60f * 45f, with(Items.silicon, 20, Items.metaglass, 35)),
};
plans = Seq.with(
new UnitPlan(UnitTypes.risso, 60f * 45f, with(Items.silicon, 20, Items.metaglass, 35))
);
size = 3;
consumes.power(1.2f);
floating = true;
@@ -1839,14 +1840,14 @@ public class Blocks implements ContentList{
constructTime = 60f * 10f;
upgrades = new UnitType[][]{
{UnitTypes.nova, UnitTypes.pulsar},
{UnitTypes.dagger, UnitTypes.mace},
{UnitTypes.crawler, UnitTypes.atrax},
{UnitTypes.flare, UnitTypes.horizon},
{UnitTypes.mono, UnitTypes.poly},
{UnitTypes.risso, UnitTypes.minke},
};
upgrades.addAll(
new UnitType[]{UnitTypes.nova, UnitTypes.pulsar},
new UnitType[]{UnitTypes.dagger, UnitTypes.mace},
new UnitType[]{UnitTypes.crawler, UnitTypes.atrax},
new UnitType[]{UnitTypes.flare, UnitTypes.horizon},
new UnitType[]{UnitTypes.mono, UnitTypes.poly},
new UnitType[]{UnitTypes.risso, UnitTypes.minke}
);
}};
multiplicativeReconstructor = new Reconstructor("multiplicative-reconstructor"){{
@@ -1858,14 +1859,14 @@ public class Blocks implements ContentList{
constructTime = 60f * 30f;
upgrades = new UnitType[][]{
{UnitTypes.horizon, UnitTypes.zenith},
{UnitTypes.mace, UnitTypes.fortress},
{UnitTypes.poly, UnitTypes.mega},
{UnitTypes.minke, UnitTypes.bryde},
{UnitTypes.pulsar, UnitTypes.quasar},
{UnitTypes.atrax, UnitTypes.spiroct},
};
upgrades.addAll(
new UnitType[]{UnitTypes.horizon, UnitTypes.zenith},
new UnitType[]{UnitTypes.mace, UnitTypes.fortress},
new UnitType[]{UnitTypes.poly, UnitTypes.mega},
new UnitType[]{UnitTypes.minke, UnitTypes.bryde},
new UnitType[]{UnitTypes.pulsar, UnitTypes.quasar},
new UnitType[]{UnitTypes.atrax, UnitTypes.spiroct}
);
}};
exponentialReconstructor = new Reconstructor("exponential-reconstructor"){{
@@ -1879,14 +1880,14 @@ public class Blocks implements ContentList{
constructTime = 60f * 60f * 1.5f;
liquidCapacity = 60f;
upgrades = new UnitType[][]{
{UnitTypes.zenith, UnitTypes.antumbra},
{UnitTypes.spiroct, UnitTypes.arkyid},
{UnitTypes.fortress, UnitTypes.scepter},
{UnitTypes.bryde, UnitTypes.sei},
{UnitTypes.mega, UnitTypes.quad},
{UnitTypes.quasar, UnitTypes.vela},
};
upgrades.addAll(
new UnitType[]{UnitTypes.zenith, UnitTypes.antumbra},
new UnitType[]{UnitTypes.spiroct, UnitTypes.arkyid},
new UnitType[]{UnitTypes.fortress, UnitTypes.scepter},
new UnitType[]{UnitTypes.bryde, UnitTypes.sei},
new UnitType[]{UnitTypes.mega, UnitTypes.quad},
new UnitType[]{UnitTypes.quasar, UnitTypes.vela}
);
}};
tetrativeReconstructor = new Reconstructor("tetrative-reconstructor"){{
@@ -1900,14 +1901,14 @@ public class Blocks implements ContentList{
constructTime = 60f * 60f * 4;
liquidCapacity = 180f;
upgrades = new UnitType[][]{
{UnitTypes.antumbra, UnitTypes.eclipse},
{UnitTypes.arkyid, UnitTypes.toxopid},
{UnitTypes.scepter, UnitTypes.reign},
{UnitTypes.sei, UnitTypes.omura},
{UnitTypes.quad, UnitTypes.oct},
{UnitTypes.vela, UnitTypes.corvus}
};
upgrades.addAll(
new UnitType[]{UnitTypes.antumbra, UnitTypes.eclipse},
new UnitType[]{UnitTypes.arkyid, UnitTypes.toxopid},
new UnitType[]{UnitTypes.scepter, UnitTypes.reign},
new UnitType[] {UnitTypes.sei, UnitTypes.omura},
new UnitType[]{UnitTypes.quad, UnitTypes.oct},
new UnitType[]{UnitTypes.vela, UnitTypes.corvus}
);
}};
repairPoint = new RepairPoint("repair-point"){{

View File

@@ -15,6 +15,7 @@ import static mindustry.type.ItemStack.*;
public class TechTree implements ContentList{
static ObjectMap<UnlockableContent, TechNode> map = new ObjectMap<>();
static TechNode context = null;
public static Seq<TechNode> all;
public static TechNode root;
@@ -543,36 +544,46 @@ public class TechTree implements ContentList{
}
public static void setup(){
TechNode.context = null;
context = null;
map = new ObjectMap<>();
all = new Seq<>();
}
public static TechNode node(UnlockableContent content, Runnable children){
//all the "node" methods are hidden, because they are for internal context-dependent use only
//for custom research, just use the TechNode constructor
static TechNode node(UnlockableContent content, Runnable children){
return node(content, content.researchRequirements(), children);
}
public static TechNode node(UnlockableContent content, ItemStack[] requirements, Runnable children){
return new TechNode(content, requirements, children);
static TechNode node(UnlockableContent content, ItemStack[] requirements, Runnable children){
return node(content, requirements, null, children);
}
public static TechNode node(UnlockableContent content, Seq<Objective> objectives, Runnable children){
TechNode node = new TechNode(content, content.researchRequirements(), children);
node.objectives = objectives;
static TechNode node(UnlockableContent content, ItemStack[] requirements, Seq<Objective> objectives, Runnable children){
TechNode node = new TechNode(context, content, requirements);
if(objectives != null){
node.objectives = objectives;
}
TechNode prev = context;
context = node;
children.run();
context = prev;
return node;
}
public static TechNode node(UnlockableContent block){
static TechNode node(UnlockableContent content, Seq<Objective> objectives, Runnable children){
return node(content, content.researchRequirements(), objectives, children);
}
static TechNode node(UnlockableContent block){
return node(block, () -> {});
}
public static TechNode create(UnlockableContent parent, UnlockableContent block){
TechNode.context = all.find(t -> t.content == parent);
return node(block, () -> {});
}
public static @Nullable
TechNode get(UnlockableContent content){
@Nullable
public static TechNode get(UnlockableContent content){
return map.get(content);
}
@@ -581,8 +592,6 @@ public class TechTree implements ContentList{
}
public static class TechNode{
static TechNode context;
/** Depth in tech tree. */
public int depth;
/** Requirement node. */
@@ -600,10 +609,10 @@ public class TechTree implements ContentList{
/** Nodes that depend on this node. */
public final Seq<TechNode> children = new Seq<>();
TechNode(@Nullable TechNode ccontext, UnlockableContent content, ItemStack[] requirements, Runnable children){
if(ccontext != null) ccontext.children.add(this);
public TechNode(@Nullable TechNode parent, UnlockableContent content, ItemStack[] requirements){
if(parent != null) parent.children.add(this);
this.parent = ccontext;
this.parent = parent;
this.content = content;
this.requirements = requirements;
this.depth = parent == null ? 0 : parent.depth + 1;
@@ -619,14 +628,15 @@ public class TechTree implements ContentList{
content.getDependencies(d -> objectives.add(new Research(d)));
map.put(content, this);
context = this;
children.run();
context = ccontext;
all.add(this);
}
TechNode(UnlockableContent content, ItemStack[] requirements, Runnable children){
this(context, content, requirements, children);
/** Removes this node from the tech tree. */
public void remove(){
all.remove(this);
if(parent != null){
parent.children.remove(this);
}
}
/** Flushes research progress to settings. */

View File

@@ -208,7 +208,7 @@ abstract class BuilderComp implements Unitc{
BuildPlan plan = buildPlan();
Tile tile = world.tile(plan.x, plan.y);
if(dst(tile) > buildingRange && !state.isEditor()){
if(!within(tile, buildingRange) && !state.isEditor()){
return;
}

View File

@@ -182,20 +182,23 @@ public class LExecutor{
@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);
//binding to `null` was previously possible, but was too powerful and exploitable
if(exec.obj(type) instanceof UnitType type){
Seq<Unit> seq = 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));
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);
}
index ++;
}else{
//no units of this type found
exec.setconst(varUnit, null);
}
}

View File

@@ -26,6 +26,8 @@ import mindustry.mod.Mods.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.units.*;
import mindustry.world.blocks.units.UnitFactory.*;
import mindustry.world.consumers.*;
import mindustry.world.draw.*;
import mindustry.world.meta.*;
@@ -170,11 +172,9 @@ public class ContentParser{
readBundle(ContentType.block, name, value);
Block block;
boolean exists;
if(locate(ContentType.block, name) != null){
block = locate(ContentType.block, name);
exists = true;
if(value.has("type")){
throw new IllegalArgumentException("When defining properties for an existing block, you must not re-declare its type. The original type will be used. Block: " + name);
@@ -182,7 +182,6 @@ public class ContentParser{
}else{
//TODO generate dynamically instead of doing.. this
Class<? extends Block> type;
exists = false;
try{
type = resolve(getType(value),
@@ -208,14 +207,6 @@ public class ContentParser{
currentContent = block;
String[] research = {null};
//add research tech node
if(value.has("research")){
research[0] = value.get("research").asString();
value.remove("research");
}
read(() -> {
if(value.has("consumes")){
for(JsonValue child : value.get("consumes")){
@@ -246,33 +237,6 @@ public class ContentParser{
throw new IllegalArgumentException("Blocks cannot be larger than " + ConstructBlock.maxSize);
}
//add research tech node
if(research[0] != null){
//TODO only works with blocks
Block parent = find(ContentType.block, research[0]);
TechNode baseNode = exists && TechTree.all.contains(t -> t.content == block) ? TechTree.all.find(t -> t.content == block) : TechTree.create(parent, block);
LoadedMod cur = currentMod;
postreads.add(() -> {
currentContent = block;
currentMod = cur;
if(baseNode.parent != null){
baseNode.parent.children.remove(baseNode);
}
TechNode parnode = TechTree.all.find(t -> t.content == parent);
if(parnode == null){
throw new IllegalArgumentException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched.");
}
if(!parnode.children.contains(baseNode)){
parnode.children.add(baseNode);
}
baseNode.parent = parnode;
});
}
//make block visible by default if there are requirements and no visibility set
if(value.has("requirements") && block.buildVisibility == BuildVisibility.hidden){
block.buildVisibility = BuildVisibility.shown;
@@ -293,7 +257,37 @@ public class ContentParser{
}
currentContent = unit;
read(() -> readFields(unit, value, true));
//TODO test this!
read(() -> {
//add reconstructor type
if(value.hasChild("requirements")){
JsonValue rec = value.remove("requirements");
//intermediate class for parsing
class UnitReq{
public Block block;
public ItemStack[] requirements = {};
@Nullable
public UnitType previous;
public float time = 60f * 10f;
}
UnitReq req = parser.readValue(UnitReq.class, rec);
if(req.block instanceof Reconstructor r){
if(req.previous != null){
r.upgrades.add(new UnitType[]{req.previous, unit});
}
}else if(req.block instanceof UnitFactory f){
f.plans.add(new UnitPlan(unit, req.time, req.requirements));
}else{
throw new IllegalArgumentException("Missing a valid 'block' in 'requirements'");
}
}
readFields(unit, value, true);
});
return unit;
},
@@ -559,6 +553,59 @@ public class ContentParser{
private void readFields(Object object, JsonValue jsonMap, boolean stripType){
if(stripType) jsonMap.remove("type");
if(object instanceof UnlockableContent unlock){
JsonValue research = jsonMap.getChild("research");
//add research tech node
if(research != null){
String researchName;
ItemStack[] customRequirements;
//research can be a single string or an object with parent and requirements
if(research.isString()){
researchName = research.asString();
customRequirements = null;
}else{
researchName = research.getString("parent");
customRequirements = research.hasChild("requirements") ? parser.readValue(ItemStack[].class, research.getChild("requirements")) : null;
}
//remove old node
TechNode lastNode = TechTree.all.find(t -> t.content == unlock);
if(lastNode != null){
lastNode.remove();
}
TechNode node = new TechNode(null, unlock, customRequirements == null ? unlock.researchRequirements() : customRequirements);
LoadedMod cur = currentMod;
postreads.add(() -> {
currentContent = unlock;
currentMod = cur;
//remove old node from parent
if(node.parent != null){
node.parent.children.remove(node);
}
//find parent node.
TechNode parent = TechTree.all.find(t -> t.content.name.equals(researchName) || t.content.name.equals(currentMod.name + "-" + researchName));
if(parent == null){
throw new IllegalArgumentException("Content '" + researchName + "' isn't in the tech tree, but '" + unlock.name + "' requires it to be researched.");
}
//add this node to the parent
if(!parent.children.contains(node)){
parent.children.add(node);
}
//reparent the node
node.parent = parent;
});
}
}
readFields(object, jsonMap);
}

View File

@@ -18,7 +18,6 @@ import mindustry.core.*;
import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.entities.abilities.*;
import mindustry.entities.bullet.*;
import mindustry.entities.units.*;
import mindustry.game.*;
import mindustry.gen.*;
@@ -297,14 +296,14 @@ public class UnitType extends UnlockableContent{
ItemStack[] stacks = null;
//calculate costs based on reconstructors or factories found
Block rec = content.blocks().find(b -> b instanceof Reconstructor && Structs.contains(((Reconstructor)b).upgrades, u -> u[1] == this));
Block rec = content.blocks().find(b -> b instanceof Reconstructor && ((Reconstructor)b).upgrades.contains(u -> u[1] == this));
if(rec != null && rec.consumes.has(ConsumeType.item) && rec.consumes.get(ConsumeType.item) instanceof ConsumeItems){
stacks = ((ConsumeItems)rec.consumes.get(ConsumeType.item)).items;
}else{
UnitFactory factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory && Structs.contains(((UnitFactory)u).plans, p -> p.unit == this));
UnitFactory factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory && ((UnitFactory)u).plans.contains(p -> p.unit == this));
if(factory != null){
stacks = Structs.find(factory.plans, p -> p.unit == this).requirements;
stacks = factory.plans.find(p -> p.unit == this).requirements;
}
}

View File

@@ -30,6 +30,7 @@ public class PlacementFragment extends Fragment{
final int rowWidth = 4;
public Category currentCategory = Category.distribution;
Seq<Block> returnArray = new Seq<>(), returnArray2 = new Seq<>();
Seq<Category> returnCatArray = new Seq<>();
boolean[] categoryEmpty = new boolean[Category.all.length];
@@ -80,6 +81,10 @@ public class PlacementFragment extends Fragment{
});
}
public Displayable hover(){
return hover;
}
void rebuild(){
currentCategory = Category.turret;
Group group = toggler.parent;

View File

@@ -1,6 +1,7 @@
package mindustry.world.blocks.logic;
import arc.func.*;
import arc.graphics.g2d.*;
import arc.math.geom.*;
import arc.scene.ui.layout.*;
import arc.struct.Bits;
@@ -8,6 +9,7 @@ import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.*;
import mindustry.ai.types.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.io.*;
@@ -432,6 +434,19 @@ public class LogicBlock extends Block{
}).size(40);
}
@Override
public void draw(){
super.draw();
if(ui.hudfrag.blockfrag.hover() instanceof Unit unit && unit.controller() instanceof LogicAI ai && ai.controller == this){
Draw.z(Layer.overlayUI);
Drawf.square(x, y, size * tilesize/2f + 2f);
if(!unit.within(this, unit.hitSize * 2f)){
Drawf.arrow(unit.x, unit.y, x, y, unit.hitSize *2f, 4f);
}
}
}
@Override
public boolean onConfigureTileTapped(Building other){
if(this == other){

View File

@@ -3,6 +3,7 @@ package mindustry.world.blocks.units;
import arc.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.*;
@@ -21,7 +22,7 @@ import static mindustry.Vars.*;
public class Reconstructor extends UnitBlock{
public float constructTime = 60 * 2;
public UnitType[][] upgrades = {};
public Seq<UnitType[]> upgrades = new Seq<>();
public int[] capacities;
public Reconstructor(String name){
@@ -181,7 +182,7 @@ public class Reconstructor extends UnitBlock{
}
public UnitType upgrade(UnitType type){
UnitType[] r = Structs.find(upgrades, arr -> arr[0] == type);
UnitType[] r = upgrades.find(u -> u[0] == type);
return r == null ? null : r[1];
}

View File

@@ -24,7 +24,7 @@ import mindustry.world.meta.*;
public class UnitFactory extends UnitBlock{
public int[] capacities;
public UnitPlan[] plans = new UnitPlan[0];
public Seq<UnitPlan> plans = new Seq<>(4);
public UnitFactory(String name){
super(name);
@@ -39,11 +39,11 @@ public class UnitFactory extends UnitBlock{
rotate = true;
config(Integer.class, (UnitFactoryBuild tile, Integer i) -> {
tile.currentPlan = i < 0 || i >= plans.length ? -1 : i;
tile.currentPlan = i < 0 || i >= plans.size ? -1 : i;
tile.progress = 0;
});
consumes.add(new ConsumeItemDynamic((UnitFactoryBuild e) -> e.currentPlan != -1 ? plans[e.currentPlan].requirements : ItemStack.empty));
consumes.add(new ConsumeItemDynamic((UnitFactoryBuild e) -> e.currentPlan != -1 ? plans.get(e.currentPlan).requirements : ItemStack.empty));
}
@Override
@@ -119,7 +119,7 @@ public class UnitFactory extends UnitBlock{
public int currentPlan = -1;
public float fraction(){
return currentPlan == -1 ? 0 : progress / plans[currentPlan].time;
return currentPlan == -1 ? 0 : progress / plans.get(currentPlan).time;
}
@Override
@@ -127,7 +127,7 @@ public class UnitFactory extends UnitBlock{
Seq<UnitType> units = Seq.with(plans).map(u -> u.unit).filter(u -> u.unlockedNow());
if(units.any()){
ItemSelection.buildTable(table, units, () -> currentPlan == -1 ? null : plans[currentPlan].unit, unit -> configure(Structs.indexOf(plans, u -> u.unit == unit)));
ItemSelection.buildTable(table, units, () -> currentPlan == -1 ? null : plans.get(currentPlan).unit, unit -> configure(plans.indexOf(u -> u.unit == unit)));
}else{
table.table(Styles.black3, t -> t.add("@none").color(Color.lightGray));
}
@@ -148,11 +148,11 @@ public class UnitFactory extends UnitBlock{
table.table(t -> {
t.left();
t.image().update(i -> {
i.setDrawable(currentPlan == -1 ? Icon.cancel : reg.set(plans[currentPlan].unit.icon(Cicon.medium)));
i.setDrawable(currentPlan == -1 ? Icon.cancel : reg.set(plans.get(currentPlan).unit.icon(Cicon.medium)));
i.setScaling(Scaling.fit);
i.setColor(currentPlan == -1 ? Color.lightGray : Color.white);
}).size(32).padBottom(-4).padRight(2);
t.label(() -> currentPlan == -1 ? "@none" : plans[currentPlan].unit.localizedName).color(Color.lightGray);
t.label(() -> currentPlan == -1 ? "@none" : plans.get(currentPlan).unit.localizedName).color(Color.lightGray);
}).left();
}
@@ -167,7 +167,7 @@ public class UnitFactory extends UnitBlock{
Draw.rect(outRegion, x, y, rotdeg());
if(currentPlan != -1){
UnitPlan plan = plans[currentPlan];
UnitPlan plan = plans.get(currentPlan);
Draw.draw(Layer.blockOver, () -> Drawf.construct(this, plan.unit, rotdeg() - 90f, progress / plan.time, speedScl, time));
}
@@ -183,7 +183,7 @@ public class UnitFactory extends UnitBlock{
@Override
public void updateTile(){
if(currentPlan < 0 || currentPlan >= plans.length){
if(currentPlan < 0 || currentPlan >= plans.size){
currentPlan = -1;
}
@@ -198,7 +198,7 @@ public class UnitFactory extends UnitBlock{
moveOutPayload();
if(currentPlan != -1 && payload == null){
UnitPlan plan = plans[currentPlan];
UnitPlan plan = plans.get(currentPlan);
if(progress >= plan.time && consValid()){
progress = 0f;
@@ -228,11 +228,11 @@ public class UnitFactory extends UnitBlock{
@Override
public boolean acceptItem(Building source, Item item){
return currentPlan != -1 && items.get(item) < getMaximumAccepted(item) &&
Structs.contains(plans[currentPlan].requirements, stack -> stack.item == item);
Structs.contains(plans.get(currentPlan).requirements, stack -> stack.item == item);
}
public @Nullable UnitType unit(){
return currentPlan == - 1 ? null : plans[currentPlan].unit;
return currentPlan == - 1 ? null : plans.get(currentPlan).unit;
}
@Override