mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-01-24 21:41:25 -08:00
Removed entity processor files
This commit is contained in:
parent
70c06b58ef
commit
e9f37ea68e
3 changed files with 0 additions and 538 deletions
|
|
@ -1,297 +0,0 @@
|
|||
package mindustry.annotations.impl;
|
||||
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import com.squareup.javapoet.*;
|
||||
import com.squareup.javapoet.TypeSpec.*;
|
||||
import com.sun.source.tree.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.annotations.*;
|
||||
import mindustry.annotations.util.*;
|
||||
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.type.*;
|
||||
|
||||
@SupportedAnnotationTypes({
|
||||
"mindustry.annotations.Annotations.EntityDef",
|
||||
"mindustry.annotations.Annotations.EntityInterface",
|
||||
"mindustry.annotations.Annotations.BaseComponent"
|
||||
})
|
||||
public class EntityProcess extends BaseProcessor{
|
||||
Array<Definition> definitions = new Array<>();
|
||||
Array<Stype> baseComponents;
|
||||
ObjectMap<Stype, Array<Stype>> componentDependencies = new ObjectMap<>();
|
||||
ObjectMap<Stype, Array<Stype>> defComponents = new ObjectMap<>();
|
||||
ObjectSet<String> imports = new ObjectSet<>();
|
||||
|
||||
{
|
||||
rounds = 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(RoundEnvironment env) throws Exception{
|
||||
|
||||
//round 1: get component classes and generate interfaces for them
|
||||
if(round == 1){
|
||||
baseComponents = types(BaseComponent.class);
|
||||
Array<Stype> allDefs = types(EntityDef.class);
|
||||
|
||||
ObjectSet<Stype> allComponents = new ObjectSet<>();
|
||||
|
||||
//find all components used...
|
||||
for(Stype type : allDefs){
|
||||
allComponents.addAll(allComponents(type));
|
||||
}
|
||||
|
||||
//add all components w/ dependencies
|
||||
allComponents.addAll(types(Depends.class).map(s -> Array.withArrays(getDependencies(s), s)).flatten());
|
||||
|
||||
//add component imports
|
||||
for(Stype comp : allComponents){
|
||||
imports.addAll(getImports(comp.e));
|
||||
}
|
||||
|
||||
//create component interfaces
|
||||
for(Stype component : allComponents){
|
||||
TypeSpec.Builder inter = TypeSpec.interfaceBuilder(interfaceName(component)).addModifiers(Modifier.PUBLIC).addAnnotation(EntityInterface.class);
|
||||
|
||||
//implement extra interfaces these components may have, e.g. position
|
||||
for(Stype extraInterface : component.interfaces()){
|
||||
inter.addSuperinterface(extraInterface.mirror());
|
||||
}
|
||||
|
||||
//implement super interfaces
|
||||
Array<Stype> depends = getDependencies(component);
|
||||
for(Stype type : depends){
|
||||
inter.addSuperinterface(ClassName.get(packageName, interfaceName(type)));
|
||||
}
|
||||
|
||||
for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.is(Modifier.TRANSIENT))){
|
||||
String cname = Strings.capitalize(field.name());
|
||||
//getter
|
||||
inter.addMethod(MethodSpec.methodBuilder("get" + cname).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC).returns(field.tname()).build());
|
||||
//setter
|
||||
if(!field.is(Modifier.FINAL)) inter.addMethod(MethodSpec.methodBuilder("set" + cname).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC).addParameter(field.tname(), field.name()).build());
|
||||
}
|
||||
|
||||
//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())
|
||||
.build())).addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build());
|
||||
}
|
||||
|
||||
write(inter);
|
||||
}
|
||||
|
||||
//look at each definition
|
||||
for(Stype type : allDefs){
|
||||
if(!type.name().endsWith("Def")){
|
||||
err("All entity def names must end with 'Def'", type.e);
|
||||
}
|
||||
String name = type.name().replace("Def", "Gen"); //TODO remove 'gen'
|
||||
TypeSpec.Builder builder = TypeSpec.classBuilder(name).addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||
|
||||
Array<Stype> components = allComponents(type);
|
||||
ObjectMap<String, Array<Smethod>> methods = new ObjectMap<>();
|
||||
|
||||
//add all components
|
||||
for(Stype comp : components){
|
||||
|
||||
//write fields to the class; ignoring transient ones
|
||||
Array<Svar> fields = comp.fields().select(f -> !f.is(Modifier.TRANSIENT));
|
||||
for(Svar f : fields){
|
||||
VariableTree tree = f.tree();
|
||||
FieldSpec.Builder fbuilder = FieldSpec.builder(f.tname(), f.name());
|
||||
//add initializer if it exists
|
||||
if(tree.getInitializer() != null){
|
||||
fbuilder.initializer(tree.getInitializer().toString());
|
||||
}
|
||||
builder.addField(fbuilder.build());
|
||||
}
|
||||
|
||||
//get all utility methods from components
|
||||
for(Smethod elem : comp.methods()){
|
||||
methods.getOr(elem.toString(), Array::new).add(elem);
|
||||
}
|
||||
}
|
||||
|
||||
//add all methods from components
|
||||
for(ObjectMap.Entry<String, Array<Smethod>> entry : methods){
|
||||
//representative method
|
||||
Smethod first = entry.value.first();
|
||||
//build method using same params/returns
|
||||
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());
|
||||
}
|
||||
|
||||
//only write the block if it's a void method with several entries
|
||||
boolean writeBlock = first.ret().toString().equals("void") && entry.value.size > 1;
|
||||
|
||||
if(entry.value.first().is(Modifier.ABSTRACT) && entry.value.size == 1){
|
||||
err(entry.value.first().up().getSimpleName() + " declares an abstract method. This method must be implemented in another component", entry.value.first());
|
||||
}
|
||||
|
||||
for(Smethod elem : entry.value){
|
||||
if(elem.is(Modifier.ABSTRACT)) continue;
|
||||
|
||||
//get all statements in the method, copy them over
|
||||
MethodTree methodTree = elem.tree();
|
||||
BlockTree blockTree = methodTree.getBody();
|
||||
String str = blockTree.toString();
|
||||
//name for code blocks in the methods
|
||||
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(writeBlock){
|
||||
//replace return; with block break
|
||||
str = str.replace("return;", "break " + blockName + ";");
|
||||
mbuilder.addCode(blockName + ": {\n");
|
||||
}
|
||||
|
||||
//trim block
|
||||
str = str.substring(2, str.length() - 1);
|
||||
|
||||
//make sure to remove braces here
|
||||
mbuilder.addCode(str);
|
||||
|
||||
//end scope
|
||||
if(writeBlock) mbuilder.addCode("}\n");
|
||||
}
|
||||
|
||||
builder.addMethod(mbuilder.build());
|
||||
}
|
||||
|
||||
definitions.add(new Definition(builder, type));
|
||||
|
||||
}
|
||||
}else{
|
||||
//round 2: generate actual classes and implement interfaces
|
||||
Array<Stype> interfaces = types(EntityInterface.class);
|
||||
|
||||
//implement each definition
|
||||
for(Definition def : definitions){
|
||||
Array<Stype> components = allComponents(def.base);
|
||||
|
||||
//get interface for each component
|
||||
for(Stype comp : components){
|
||||
//implement the interface
|
||||
Stype inter = interfaces.find(i -> i.name().equals(interfaceName(comp)));
|
||||
def.builder.addSuperinterface(inter.tname());
|
||||
|
||||
//generate getter/setter for each method
|
||||
for(Smethod method : inter.methods()){
|
||||
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")){
|
||||
def.builder.addMethod(MethodSpec.overriding(method.e).addStatement("this." + var + " = " + var).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write(def.builder, imports.asArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array<String> getImports(Element elem){
|
||||
return Array.with(trees.getPath(elem).getCompilationUnit().getImports()).map(Object::toString);
|
||||
}
|
||||
|
||||
/** @return interface for a component type */
|
||||
String interfaceName(Stype comp){
|
||||
String suffix = "Comp";
|
||||
if(!comp.name().endsWith(suffix)){
|
||||
err("All components must have names that end with 'Comp'.", comp.e);
|
||||
}
|
||||
return comp.name().substring(0, comp.name().length() - suffix.length()) + "c";
|
||||
}
|
||||
|
||||
/** @return all components that a entity def has */
|
||||
Array<Stype> allComponents(Stype type){
|
||||
if(!defComponents.containsKey(type)){
|
||||
//get base defs
|
||||
Array<Stype> components = Array.with(mirrors(type)).map(Stype::of);
|
||||
ObjectSet<Stype> out = new ObjectSet<>();
|
||||
for(Stype comp : components){
|
||||
//get dependencies for each def, add them
|
||||
out.add(comp);
|
||||
out.addAll(getDependencies(comp));
|
||||
}
|
||||
|
||||
defComponents.put(type, out.asArray());
|
||||
}
|
||||
|
||||
return defComponents.get(type);
|
||||
}
|
||||
|
||||
Array<Stype> getDependencies(Stype component){
|
||||
if(!componentDependencies.containsKey(component)){
|
||||
ObjectSet<Stype> out = new ObjectSet<>();
|
||||
out.addAll(component.superclasses());
|
||||
|
||||
//get dependency classes
|
||||
if(component.annotation(Depends.class) != null){
|
||||
try{
|
||||
component.annotation(Depends.class).value();
|
||||
}catch(MirroredTypesException e){
|
||||
out.addAll(Array.with(e.getTypeMirrors()).map(Stype::of));
|
||||
}
|
||||
}
|
||||
|
||||
//out now contains the base dependencies; finish constructing the tree
|
||||
ObjectSet<Stype> result = new ObjectSet<>();
|
||||
for(Stype type : out){
|
||||
result.add(type);
|
||||
result.addAll(getDependencies(type));
|
||||
}
|
||||
|
||||
if(component.annotation(BaseComponent.class) == null){
|
||||
result.addAll(baseComponents);
|
||||
}
|
||||
|
||||
componentDependencies.put(component, result.asArray());
|
||||
}
|
||||
|
||||
return componentDependencies.get(component);
|
||||
}
|
||||
|
||||
TypeMirror[] mirrors(Stype type){
|
||||
try{
|
||||
type.annotation(EntityDef.class).value();
|
||||
}catch(MirroredTypesException e){
|
||||
return e.getTypeMirrors().toArray(new TypeMirror[0]);
|
||||
}
|
||||
throw new IllegalArgumentException("Missing components: " + type);
|
||||
}
|
||||
|
||||
class Definition{
|
||||
final TypeSpec.Builder builder;
|
||||
final Stype base;
|
||||
|
||||
public Definition(Builder builder, Stype base){
|
||||
this.builder = builder;
|
||||
this.base = base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,231 +0,0 @@
|
|||
package mindustry.entities.def;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.math.*;
|
||||
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.type.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static mindustry.Vars.content;
|
||||
|
||||
public class EntityComps{
|
||||
|
||||
@Depends({HealthComp.class, VelComp.class, StatusComp.class})
|
||||
class UnitComp{
|
||||
|
||||
}
|
||||
|
||||
class OwnerComp{
|
||||
Entityc owner;
|
||||
}
|
||||
|
||||
@Depends({TimedComp.class})
|
||||
class BulletComp{
|
||||
BulletType bullet;
|
||||
|
||||
void init(){
|
||||
bullet.init();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TimedComp extends EntityComp implements Scaled{
|
||||
float time, lifetime;
|
||||
|
||||
void update(){
|
||||
time = Math.min(time + Time.delta(), lifetime);
|
||||
|
||||
if(time >= lifetime){
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float fin(){
|
||||
return time / lifetime;
|
||||
}
|
||||
}
|
||||
|
||||
class HealthComp{
|
||||
float health, maxHealth;
|
||||
boolean dead;
|
||||
|
||||
float healthf(){
|
||||
return health / maxHealth;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PosComp implements Position{
|
||||
float x, y;
|
||||
|
||||
void set(float x, float y){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
@Depends(PosComp.class)
|
||||
class VelComp{
|
||||
//transient fields act as imports from any other component clases; these are ignored by the generator
|
||||
transient float x, y;
|
||||
|
||||
final Vec2 vel = new Vec2();
|
||||
|
||||
void update(){
|
||||
x += vel.x;
|
||||
y += vel.y;
|
||||
vel.scl(0.9f);
|
||||
}
|
||||
}
|
||||
|
||||
@Depends(PosComp.class)
|
||||
class HitboxComp{
|
||||
transient float x, y;
|
||||
|
||||
float hitSize;
|
||||
|
||||
boolean collides(Hitboxc other){
|
||||
return Intersector.overlapsRect(x - hitSize/2f, y - hitSize/2f, hitSize, hitSize,
|
||||
other.getX() - other.getHitSize()/2f, other.getY() - other.getHitSize()/2f, other.getHitSize(), other.getHitSize());
|
||||
}
|
||||
}
|
||||
|
||||
@Depends(PosComp.class)
|
||||
class StatusComp{
|
||||
private Array<StatusEntry> 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(){
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@BaseComponent
|
||||
class EntityComp{
|
||||
int id;
|
||||
|
||||
void init(){}
|
||||
|
||||
void update(){}
|
||||
|
||||
void remove(){}
|
||||
|
||||
<T> T as(Class<T> type){
|
||||
return (T)this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package mindustry.entities.def;
|
||||
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.entities.def.EntityComps.*;
|
||||
|
||||
class EntityDefs{
|
||||
|
||||
@EntityDef({BulletComp.class, VelComp.class, TimedComp.class})
|
||||
class BulletDef{}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue