diff --git a/annotations/src/main/java/mindustry/annotations/BaseProcessor.java b/annotations/src/main/java/mindustry/annotations/BaseProcessor.java index 17e4238e30..f299b4af76 100644 --- a/annotations/src/main/java/mindustry/annotations/BaseProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/BaseProcessor.java @@ -10,6 +10,8 @@ import javax.lang.model.*; import javax.lang.model.element.*; import javax.lang.model.util.*; import javax.tools.Diagnostic.*; +import javax.tools.*; +import java.io.*; import java.lang.annotation.*; import java.util.*; @@ -38,7 +40,33 @@ public abstract class BaseProcessor extends AbstractProcessor{ } public static void write(TypeSpec.Builder builder) throws Exception{ - JavaFile.builder(packageName, builder.build()).build().writeTo(BaseProcessor.filer); + write(builder, null); + } + + public static void write(TypeSpec.Builder builder, Array imports) throws Exception{ + JavaFile file = JavaFile.builder(packageName, builder.build()).skipJavaLangImports(true).build(); + + if(imports != null){ + String rawSource = file.toString(); + Array result = new Array<>(); + for (String s : rawSource.split("\n", -1)) { + result.add(s); + if (s.startsWith("package ")) { + result.add(""); + for (String i : imports) { + result.add(i); + } + } + } + + String out = result.toString("\n"); + JavaFileObject object = filer.createSourceFile(file.packageName + "." + file.typeSpec.name, file.typeSpec.originatingElements.toArray(new Element[0])); + OutputStream stream = object.openOutputStream(); + stream.write(out.getBytes()); + stream.close(); + }else{ + file.writeTo(filer); + } } public Array types(Class type){ diff --git a/annotations/src/main/java/mindustry/annotations/impl/CallSuperProcess.java b/annotations/src/main/java/mindustry/annotations/impl/CallSuperProcess.java index 0080c0887f..b43a2d3eef 100644 --- a/annotations/src/main/java/mindustry/annotations/impl/CallSuperProcess.java +++ b/annotations/src/main/java/mindustry/annotations/impl/CallSuperProcess.java @@ -122,6 +122,7 @@ public class CallSuperProcess extends AbstractProcessor{ } for(Symbol s : it){ + if(s instanceof MethodSymbol){ MethodSymbol ms = (MethodSymbol)s; diff --git a/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java b/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java index 664cf6a802..9a9b253b00 100644 --- a/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java +++ b/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java @@ -23,6 +23,7 @@ public class EntityProcess extends BaseProcessor{ Array baseComponents; ObjectMap> componentDependencies = new ObjectMap<>(); ObjectMap> defComponents = new ObjectMap<>(); + ObjectSet imports = new ObjectSet<>(); { rounds = 2; @@ -40,6 +41,7 @@ public class EntityProcess extends BaseProcessor{ //find all components used... for(Stype type : allDefs){ + imports.addAll(getImports(type.e)); allComponents.addAll(allComponents(type)); } @@ -70,6 +72,7 @@ public class EntityProcess extends BaseProcessor{ //add utility methods to interface for(Smethod method : component.methods()){ inter.addMethod(MethodSpec.methodBuilder(method.name()) + .addExceptions(method.thrownt()) .addTypeVariables(method.typeVariables().map(TypeVariableName::get)) .returns(method.ret().toString().equals("void") ? TypeName.VOID : method.retn()) .addParameters(method.params().map(v -> ParameterSpec.builder(v.tname(), v.name()) @@ -119,6 +122,7 @@ public class EntityProcess extends BaseProcessor{ MethodSpec.Builder mbuilder = MethodSpec.methodBuilder(first.name()).addModifiers(Modifier.PUBLIC, Modifier.FINAL); mbuilder.addTypeVariables(first.typeVariables().map(TypeVariableName::get)); mbuilder.returns(first.retn()); + mbuilder.addExceptions(first.thrownt()); for(Svar var : first.params()){ mbuilder.addParameter(var.tname(), var.name()); @@ -127,19 +131,25 @@ public class EntityProcess extends BaseProcessor{ boolean returns = !first.ret().toString().equals("void"); for(Smethod elem : entry.value){ - //wrap scope to prevent variable leakage - if(!returns) mbuilder.beginControlFlow(""); - //get all statements in the method, copy them over MethodTree methodTree = elem.tree(); BlockTree blockTree = methodTree.getBody(); - for(StatementTree st : blockTree.getStatements()){ - String state = st.toString(); - mbuilder.addStatement(state.substring(0, state.length() - 1)); + String str = blockTree.toString(); + String blockName = elem.up().getSimpleName().toString().toLowerCase().replace("comp", ""); + + //skip empty blocks + if(str.replace("{", "").replace("\n", "").replace("}", "").replace("\t", "").replace(" ", "").isEmpty()){ + continue; } + //wrap scope to prevent variable leakage + if(!returns) mbuilder.addCode(blockName + ": {\n"); + + //make sure to remove braces here + mbuilder.addCode(str.substring(2, str.length() - 1).replace("return;", "break " + blockName + ";")); + //end scope - if(!returns) mbuilder.endControlFlow(); + if(!returns) mbuilder.addCode("}\n"); } builder.addMethod(mbuilder.build()); @@ -167,6 +177,9 @@ public class EntityProcess extends BaseProcessor{ if(method.name().length() <= 3) continue; String var = Strings.camelize(method.name().substring(3)); + //make sure it's a real variable + if(!Array.with(def.builder.fieldSpecs).contains(f -> f.name.equals(var))) continue; + if(method.name().startsWith("get")){ def.builder.addMethod(MethodSpec.overriding(method.e).addStatement("return " + var).build()); }else if(method.name().startsWith("set")){ @@ -175,11 +188,16 @@ public class EntityProcess extends BaseProcessor{ } } - write(def.builder); + write(def.builder, imports.asArray()); } } } + Array getImports(Element elem){ + return Array.with(trees.getPath(elem).getCompilationUnit().getImports()).map(t -> t.toString()); + } + + /** @return interface for a component type */ String interfaceName(Stype comp){ String suffix = "Comp"; if(!comp.name().endsWith(suffix)){ diff --git a/annotations/src/main/java/mindustry/annotations/util/Selement.java b/annotations/src/main/java/mindustry/annotations/util/Selement.java index b9d8aa4e32..d7e458a20e 100644 --- a/annotations/src/main/java/mindustry/annotations/util/Selement.java +++ b/annotations/src/main/java/mindustry/annotations/util/Selement.java @@ -13,6 +13,10 @@ public class Selement{ this.e = e; } + public Element up(){ + return e.getEnclosingElement(); + } + public TypeMirror mirror(){ return e.asType(); } diff --git a/annotations/src/main/java/mindustry/annotations/util/Smethod.java b/annotations/src/main/java/mindustry/annotations/util/Smethod.java index 8b840c2977..ec4b77b207 100644 --- a/annotations/src/main/java/mindustry/annotations/util/Smethod.java +++ b/annotations/src/main/java/mindustry/annotations/util/Smethod.java @@ -14,6 +14,14 @@ public class Smethod extends Selement{ super(executableElement); } + public Array thrown(){ + return Array.with(e.getThrownTypes()).as(TypeMirror.class); + } + + public Array thrownt(){ + return Array.with(e.getThrownTypes()).map(TypeName::get); + } + public Array typeVariables(){ return Array.with(e.getTypeParameters()).as(TypeParameterElement.class); } diff --git a/core/src/mindustry/entities/def/EntityDefs.java b/core/src/mindustry/entities/def/EntityDefs.java index fc59694193..df262e216b 100644 --- a/core/src/mindustry/entities/def/EntityDefs.java +++ b/core/src/mindustry/entities/def/EntityDefs.java @@ -1,11 +1,23 @@ package mindustry.entities.def; +import arc.graphics.*; import arc.math.geom.*; +import arc.struct.Bits; +import arc.struct.*; +import arc.util.*; +import arc.util.pooling.*; import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.ctype.*; import mindustry.entities.bullet.*; import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.net.*; +import mindustry.type.*; + +import java.io.*; + +import static mindustry.Vars.content; class EntityDefs{ @@ -64,11 +76,117 @@ class EntityDefs{ } } + @Depends(PosComp.class) class StatusComp{ - final Statuses statuses = new Statuses(); + private Array statuses = new Array<>(); + private Bits applied = new Bits(content.getBy(ContentType.status).size); + + private float speedMultiplier; + private float damageMultiplier; + private float armorMultiplier; + + void apply(StatusEffect effect, float duration){ + if(effect == StatusEffects.none || effect == null || isImmune(effect)) return; //don't apply empty or immune effects + + if(statuses.size > 0){ + //check for opposite effects + for(StatusEntry entry : statuses){ + //extend effect + if(entry.effect == effect){ + entry.time = Math.max(entry.time, duration); + return; + }else if(entry.effect.reactsWith(effect)){ //find opposite + StatusEntry.tmp.effect = entry.effect; + //TODO unit cannot be null here + entry.effect.getTransition(null, effect, entry.time, duration, StatusEntry.tmp); + entry.time = StatusEntry.tmp.time; + + if(StatusEntry.tmp.effect != entry.effect){ + entry.effect = StatusEntry.tmp.effect; + } + + //stop looking when one is found + return; + } + } + } + + //otherwise, no opposites found, add direct effect + StatusEntry entry = Pools.obtain(StatusEntry.class, StatusEntry::new); + entry.set(effect, duration); + statuses.add(entry); + } + + boolean isImmune(StatusEffect effect){ + return false; + } + + Color getStatusColor(){ + if(statuses.size == 0){ + return Tmp.c1.set(Color.white); + } + + float r = 0f, g = 0f, b = 0f; + for(StatusEntry entry : statuses){ + r += entry.effect.color.r; + g += entry.effect.color.g; + b += entry.effect.color.b; + } + return Tmp.c1.set(r / statuses.size, g / statuses.size, b / statuses.size, 1f); + } void update(){ - statuses.update(null); + applied.clear(); + speedMultiplier = damageMultiplier = armorMultiplier = 1f; + + if(statuses.isEmpty()) return; + + statuses.eachFilter(entry -> { + entry.time = Math.max(entry.time - Time.delta(), 0); + applied.set(entry.effect.id); + + if(entry.time <= 0){ + Pools.free(entry); + return true; + }else{ + speedMultiplier *= entry.effect.speedMultiplier; + armorMultiplier *= entry.effect.armorMultiplier; + damageMultiplier *= entry.effect.damageMultiplier; + //TODO unit can't be null + entry.effect.update(null, entry.time); + } + + return false; + }); + } + + boolean hasEffect(StatusEffect effect){ + return applied.get(effect.id); + } + + void writeSave(DataOutput stream) throws IOException{ + stream.writeByte(statuses.size); + for(StatusEntry entry : statuses){ + stream.writeByte(entry.effect.id); + stream.writeFloat(entry.time); + } + } + + void readSave(DataInput stream, byte version) throws IOException{ + for(StatusEntry effect : statuses){ + Pools.free(effect); + } + + statuses.clear(); + + byte amount = stream.readByte(); + for(int i = 0; i < amount; i++){ + byte id = stream.readByte(); + float time = stream.readFloat(); + StatusEntry entry = Pools.obtain(StatusEntry.class, StatusEntry::new); + entry.set(content.getByID(ContentType.status, id), time); + statuses.add(entry); + } } } diff --git a/core/src/mindustry/entities/units/StatusEntry.java b/core/src/mindustry/entities/units/StatusEntry.java new file mode 100644 index 0000000000..1c1f07f9b7 --- /dev/null +++ b/core/src/mindustry/entities/units/StatusEntry.java @@ -0,0 +1,16 @@ +package mindustry.entities.units; + +import mindustry.type.*; + +public class StatusEntry{ + public static final StatusEntry tmp = new StatusEntry(); + + public StatusEffect effect; + public float time; + + public StatusEntry set(StatusEffect effect, float time){ + this.effect = effect; + this.time = time; + return this; + } +} diff --git a/core/src/mindustry/entities/units/Statuses.java b/core/src/mindustry/entities/units/Statuses.java index 637bbf1a55..7fd37abe5b 100644 --- a/core/src/mindustry/entities/units/Statuses.java +++ b/core/src/mindustry/entities/units/Statuses.java @@ -147,14 +147,4 @@ public class Statuses implements Saveable{ } } - public static class StatusEntry{ - public StatusEffect effect; - public float time; - - public StatusEntry set(StatusEffect effect, float time){ - this.effect = effect; - this.time = time; - return this; - } - } } diff --git a/core/src/mindustry/type/StatusEffect.java b/core/src/mindustry/type/StatusEffect.java index 1ade3af60f..ef86ae6176 100644 --- a/core/src/mindustry/type/StatusEffect.java +++ b/core/src/mindustry/type/StatusEffect.java @@ -10,7 +10,7 @@ import mindustry.ctype.ContentType; import mindustry.entities.*; import mindustry.entities.Effects.*; import mindustry.entities.type.*; -import mindustry.entities.units.Statuses.*; +import mindustry.entities.units.*; public class StatusEffect extends MappableContent{ /** Damage dealt by the unit with the effect. */ diff --git a/gradle.properties b/gradle.properties index 6f276830f8..02a2b77c2a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=8c7b7cbef40a0cc546cace77364c88f3f6ee5ed7 +archash=45ffc0ea35fa7c282538259daf247eabfc987acf