Autogeneration of some IO code

This commit is contained in:
Anuken 2020-02-13 13:30:30 -05:00
parent 47f075133f
commit ad248e2e20
40 changed files with 163 additions and 74 deletions

View file

@ -24,6 +24,12 @@ public class Annotations{
public @interface Replace{
}
/** Indicates that a component field is imported from other components. */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Import{
}
/** Indicates that a component field is read-only. */
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
@ -70,6 +76,7 @@ public class Annotations{
Class[] value();
boolean isFinal() default true;
boolean pooled() default false;
boolean serialize() default true;
}
/** Indicates an internal interface for entity components. */

View file

@ -0,0 +1,55 @@
package mindustry.annotations.entity;
import arc.util.*;
import com.squareup.javapoet.*;
import com.squareup.javapoet.MethodSpec.*;
import mindustry.annotations.*;
import javax.lang.model.element.*;
public class EntityIO{
final TypeElement contentElem = BaseProcessor.elementu.getTypeElement("mindustry.ctype.Content");
final MethodSpec.Builder builder;
final boolean write;
EntityIO(Builder builder, boolean write){
this.builder = builder;
this.write = write;
}
void io(TypeName type, String field) throws Exception{
TypeElement element = BaseProcessor.elementu.getTypeElement(type.toString());
if(type.isPrimitive()){
s(type.toString(), field);
}else if(type.toString().equals("java.lang.String")){
s("UTF", field);
}else if(element != null && BaseProcessor.typeu.isSubtype(element.asType(), contentElem.asType())){
if(write){
s("short", field + ".id");
}else{
st(field + " = mindustry.Vars.content.getByID(mindustry.ctype.ContentType.$L, input.readShort())", BaseProcessor.simpleName(type.toString()).toLowerCase().replace("type", ""));
}
}
}
private void cont(String text, Object... fmt){
builder.beginControlFlow(text, fmt);
}
private void cont(){
builder.endControlFlow();
}
private void st(String text, Object... args){
builder.addStatement(text, args);
}
private void s(String type, String field){
if(write){
builder.addStatement("output.write$L($L)", Strings.capitalize(type), field);
}else{
builder.addStatement("$L = input.read$L()", field, Strings.capitalize(type));
}
}
}

View file

@ -1,4 +1,4 @@
package mindustry.annotations.impl;
package mindustry.annotations.entity;
import arc.files.*;
import arc.func.*;
@ -118,7 +118,7 @@ public class EntityProcess extends BaseProcessor{
.build())).addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build());
}
for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.is(Modifier.TRANSIENT))){
for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.has(Import.class))){
String cname = field.name();
//getter
@ -221,19 +221,32 @@ public class EntityProcess extends BaseProcessor{
Array<GroupDefinition> groups = groupDefs.select(g -> (!g.components.isEmpty() && !g.components.contains(s -> !components.contains(s))) || g.manualInclusions.contains(type));
ObjectMap<String, Array<Smethod>> methods = new ObjectMap<>();
ObjectMap<FieldSpec, Svar> specVariables = new ObjectMap<>();
ObjectSet<String> usedFields = new ObjectSet<>();
//add serialize() boolean
builder.addMethod(MethodSpec.methodBuilder("serialize").addModifiers(Modifier.PUBLIC, Modifier.FINAL).returns(boolean.class).addStatement("return " + ann.serialize()).build());
//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));
Array<Svar> fields = comp.fields().select(f -> !f.has(Import.class));
for(Svar f : fields){
if(!usedFields.add(f.name())){
err("Field '" + f.name() + "' of component '" + comp.name() + "' re-defines a field in entity '" + type.name() + "'");
continue;
}
FieldSpec.Builder fbuilder = FieldSpec.builder(f.tname(), f.name());
//keep statics/finals
if(f.is(Modifier.STATIC)){
fbuilder.addModifiers(Modifier.STATIC);
if(f.is(Modifier.FINAL)) fbuilder.addModifiers(Modifier.FINAL);
}
//add transient modifier for serialization
if(f.is(Modifier.TRANSIENT)){
fbuilder.addModifiers(Modifier.TRANSIENT);
}
//add initializer if it exists
if(varInitializers.containsKey(f)){
fbuilder.initializer(varInitializers.get(f));
@ -312,6 +325,18 @@ public class EntityProcess extends BaseProcessor{
}
}
//SPECIAL CASE: I/O code
//note that serialization is generated even for non-serializing entities for manual usage
if(first.name().equals("read") || first.name().equals("write")){
EntityIO writer = new EntityIO(mbuilder, first.name().equals("write"));
//write or read each non-transient field
for(FieldSpec spec : builder.fieldSpecs){
if(!spec.hasModifier(Modifier.TRANSIENT) && !spec.hasModifier(Modifier.STATIC) && !spec.hasModifier(Modifier.FINAL)){
writer.io(spec.type, "this." + spec.name);
}
}
}
for(Smethod elem : entry.value){
if(elem.is(Modifier.ABSTRACT) || elem.is(Modifier.NATIVE) || !methodBlocks.containsKey(elem)) continue;

View file

@ -6,22 +6,22 @@ import mindustry.gen.*;
import mindustry.type.*;
public class UnitTypes implements ContentList{
public static UnitDef
public static UnitType
draug, spirit, phantom,
wraith, ghoul, revenant, lich, reaper,
crawler, titan, fortress, eruptor, chaosArray, eradicator;
public static @EntityDef({Unitc.class, Legsc.class}) UnitDef dagger;
public static @EntityDef({Unitc.class, WaterMovec.class}) UnitDef vanguard;
public static @EntityDef({Unitc.class, Legsc.class}) UnitType dagger;
public static @EntityDef({Unitc.class, WaterMovec.class}) UnitType vanguard;
public static UnitDef alpha, delta, tau, omega, dart, javelin, trident, glaive;
public static UnitDef starter;
public static UnitType alpha, delta, tau, omega, dart, javelin, trident, glaive;
public static UnitType starter;
@Override
public void load(){
dagger = new UnitDef("dagger"){{
dagger = new UnitType("dagger"){{
speed = 1f;
drag = 0.3f;
hitsize = 8f;
@ -36,7 +36,7 @@ public class UnitTypes implements ContentList{
}});
}};
vanguard = new UnitDef("vanguard"){{
vanguard = new UnitType("vanguard"){{
speed = 1.3f;
drag = 0.1f;
hitsize = 8f;

View file

@ -261,7 +261,7 @@ public class ContentLoader{
return getBy(ContentType.zone);
}
public Array<UnitDef> units(){
public Array<UnitType> units(){
return getBy(ContentType.unit);
}
}

View file

@ -30,7 +30,7 @@ public class WaveInfoDialog extends FloatingDialog{
private Table table, preview;
private int start = 0;
private UnitDef lastType = UnitTypes.dagger;
private UnitType lastType = UnitTypes.dagger;
private float updateTimer, updatePeriod = 1f;
public WaveInfoDialog(MapEditor editor){
@ -221,7 +221,7 @@ public class WaveInfoDialog extends FloatingDialog{
dialog.setFillParent(true);
dialog.cont.pane(p -> {
int i = 0;
for(UnitDef type : content.units()){
for(UnitType type : content.units()){
p.addButton(t -> {
t.left();
t.addImage(type.icon(mindustry.ui.Cicon.medium)).size(40f).padRight(2f);
@ -256,7 +256,7 @@ public class WaveInfoDialog extends FloatingDialog{
for(int j = 0; j < spawned.length; j++){
if(spawned[j] > 0){
UnitDef type = content.getByID(ContentType.unit, j);
UnitType type = content.getByID(ContentType.unit, j);
table.addImage(type.icon(Cicon.medium)).size(8f * 4f).padRight(4);
table.add(spawned[j] + "x").color(Color.lightGray).padRight(6);
table.row();

View file

@ -11,8 +11,8 @@ import static mindustry.Vars.*;
abstract class BoundedComp implements Velc, Posc, Healthc, Flyingc{
static final float warpDst = 180f;
transient float x, y;
transient Vec2 vel;
@Import float x, y;
@Import Vec2 vel;
@Override
public void update(){

View file

@ -4,10 +4,9 @@ import arc.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.struct.Queue;
import arc.util.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
@ -27,10 +26,10 @@ import static mindustry.Vars.*;
abstract class BuilderComp implements Unitc{
static final Vec2[] tmptr = new Vec2[]{new Vec2(), new Vec2(), new Vec2(), new Vec2()};
transient float x, y, rotation;
@Import float x, y, rotation;
Queue<BuildRequest> requests = new Queue<>();
float buildSpeed = 1f;
transient float buildSpeed = 1f;
//boolean building;
void updateBuilding(){

View file

@ -6,7 +6,7 @@ import mindustry.gen.*;
@Component
abstract class ChildComp implements Posc{
transient float x, y;
@Import float x, y;
@Nullable Posc parent;
float offsetX, offsetY;

View file

@ -9,7 +9,7 @@ import mindustry.gen.*;
@EntityDef(value = {Decalc.class}, pooled = true)
@Component
abstract class DecalComp implements Drawc, Timedc, Rotc, Posc, DrawLayerFloorc{
transient float x, y, rotation;
@Import float x, y, rotation;
Color color = new Color(1, 1, 1, 1);
TextureRegion region;

View file

@ -7,7 +7,7 @@ import static mindustry.Vars.collisions;
@Component
abstract class ElevationMoveComp implements Velc, Posc, Flyingc, Hitboxc{
transient float x, y;
@Import float x, y;
@Replace
@Override

View file

@ -12,8 +12,8 @@ import static mindustry.Vars.player;
@Component
@BaseComponent
abstract class EntityComp{
private boolean added;
int id = EntityGroup.nextId();
private transient boolean added;
transient int id = EntityGroup.nextId();
boolean isAdded(){
return added;
@ -49,6 +49,9 @@ abstract class EntityComp{
@InternalImpl
abstract int classId();
@InternalImpl
abstract boolean serialize();
void read(DataInput input) throws IOException{
//TODO dynamic io
}

View file

@ -18,7 +18,7 @@ import static mindustry.Vars.*;
abstract class FireComp implements Timedc, Posc, Firec{
private static final float spreadChance = 0.05f, fireballChance = 0.07f;
transient float time, lifetime, x, y;
@Import float time, lifetime, x, y;
Tile tile;
private Block block;

View file

@ -12,12 +12,12 @@ import static mindustry.Vars.net;
@Component
abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
transient float x, y;
transient Vec2 vel;
@Import float x, y;
@Import Vec2 vel;
float elevation;
float drownTime;
float splashTimer;
transient float splashTimer;
boolean isGrounded(){
return elevation < 0.001f;

View file

@ -9,7 +9,8 @@ import mindustry.gen.*;
abstract class HealthComp implements Entityc{
static final float hitDuration = 9f;
float health, maxHealth = 1f, hitTime;
transient float hitTime;
float health, maxHealth = 1f;
boolean dead;
boolean isValid(){

View file

@ -7,7 +7,7 @@ import mindustry.gen.*;
@Component
abstract class HitboxComp implements Posc, QuadTreeObject{
transient float x, y;
@Import float x, y;
float hitSize;
float lastX, lastY;

View file

@ -8,7 +8,7 @@ import mindustry.type.*;
@Component
abstract class ItemsComp implements Posc{
@ReadOnly ItemStack stack = new ItemStack();
float itemTime;
transient float itemTime;
abstract int itemCapacity();

View file

@ -7,9 +7,10 @@ import mindustry.gen.*;
@Component
abstract class LegsComp implements Posc, Flyingc, Hitboxc, DrawLayerGroundUnderc, Unitc, Legsc, ElevationMovec{
transient float x, y;
@Import float x, y;
float baseRotation, walkTime;
float baseRotation;
transient float walkTime;
@Override
public void update(){

View file

@ -18,9 +18,9 @@ import static mindustry.Vars.*;
@Component
abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc{
transient float x, y, rotation;
@Import float x, y, rotation;
float mineTimer;
transient float mineTimer;
@Nullable Tile mineTile;
abstract boolean canMine(Item item);

View file

@ -23,8 +23,7 @@ import static mindustry.Vars.*;
@EntityDef({Playerc.class})
@Component
abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc{
@NonNull
@ReadOnly Unitc unit = Nulls.unit;
@NonNull @ReadOnly Unitc unit = Nulls.unit;
@ReadOnly Team team = Team.sharded;
String name = "noname";
@ -33,7 +32,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc{
Color color = new Color();
float mouseX, mouseY;
@Nullable String lastText;
String lastText = "";
float textFadeTime;
public boolean isBuilder(){
@ -51,7 +50,6 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc{
public void reset(){
team = state.rules.defaultTeam;
admin = typing = false;
lastText = null;
textFadeTime = 0f;
if(!dead()){
unit.controller(unit.type().createController());

View file

@ -25,7 +25,7 @@ abstract class PuddleComp implements Posc, DrawLayerFloorOverc{
private static final Rect rect2 = new Rect();
private static int seeds;
transient float x, y;
@Import float x, y;
float amount, lastRipple, accepting, updateTime;
int generation;

View file

@ -7,7 +7,7 @@ import mindustry.net.*;
@Component
abstract class SyncComp implements Posc{
transient float x, y;
@Import float x, y;
Interpolator interpolator = new Interpolator();

View file

@ -9,7 +9,7 @@ import static mindustry.Vars.state;
@Component
abstract class TeamComp implements Posc{
transient float x, y;
@Import float x, y;
Team team = Team.sharded;

View file

@ -20,10 +20,10 @@ import static mindustry.Vars.*;
@Component
abstract class UnitComp implements Healthc, Velc, Statusc, Teamc, Itemsc, Hitboxc, Rotc, Massc, Unitc, Weaponsc, Drawc, Boundedc,
DrawLayerGroundc, DrawLayerFlyingc, DrawLayerGroundShadowsc, DrawLayerFlyingShadowsc{
transient float x, y, rotation;
@Import float x, y, rotation;
private UnitController controller;
private UnitDef type;
private UnitType type;
@Override
public float clipSize(){
@ -52,7 +52,7 @@ abstract class UnitComp implements Healthc, Velc, Statusc, Teamc, Itemsc, Hitbox
}
@Override
public void set(UnitDef def, UnitController controller){
public void set(UnitType def, UnitController controller){
type(type);
controller(controller);
}
@ -75,7 +75,7 @@ abstract class UnitComp implements Healthc, Velc, Statusc, Teamc, Itemsc, Hitbox
}
@Override
public void type(UnitDef type){
public void type(UnitType type){
this.type = type;
maxHealth(type.health);
heal();
@ -86,7 +86,7 @@ abstract class UnitComp implements Healthc, Velc, Statusc, Teamc, Itemsc, Hitbox
}
@Override
public UnitDef type(){
public UnitType type(){
return type;
}

View file

@ -7,7 +7,7 @@ import mindustry.gen.*;
@Component
abstract class VelComp implements Posc{
transient float x, y;
@Import float x, y;
final Vec2 vel = new Vec2();
float drag = 0f;

View file

@ -11,7 +11,7 @@ import static mindustry.Vars.collisions;
//just a proof of concept
@Component
abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc{
transient float x, y;
@Import float x, y;
@Replace
@Override

View file

@ -12,7 +12,7 @@ import mindustry.type.*;
@Component
abstract class WeaponsComp implements Teamc, Posc, Rotc{
transient float x, y, rotation;
@Import float x, y, rotation;
/** minimum cursor distance from player, fixes 'cross-eyed' shooting */
static final float minAimDst = 20f;
@ -22,7 +22,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{
/** weapon mount array, never null */
@ReadOnly WeaponMount[] mounts = {};
void setupWeapons(UnitDef def){
void setupWeapons(UnitType def){
mounts = new WeaponMount[def.weapons.size];
for(int i = 0; i < mounts.length; i++){
mounts[i] = new WeaponMount(def.weapons.get(i));

View file

@ -5,7 +5,6 @@ import mindustry.core.GameState.*;
import mindustry.ctype.*;
import mindustry.gen.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.*;
@ -328,9 +327,9 @@ public class EventType{
//TODO rename
public static class MechChangeEvent{
public final Playerc player;
public final UnitDef mech;
public final UnitType mech;
public MechChangeEvent(Playerc player, UnitDef mech){
public MechChangeEvent(Playerc player, UnitType mech){
this.player = player;
this.mech = mech;
}

View file

@ -19,7 +19,7 @@ public class SpawnGroup implements Serializable{
public static final int never = Integer.MAX_VALUE;
/** The unit type spawned */
public UnitDef type;
public UnitType type;
/** When this spawn should end */
public int end = never;
/** When this spawn should start */
@ -37,7 +37,7 @@ public class SpawnGroup implements Serializable{
/** Items this unit spawns with. Null to disable. */
public ItemStack items;
public SpawnGroup(UnitDef type){
public SpawnGroup(UnitType type){
this.type = type;
}

View file

@ -30,7 +30,7 @@ public class MenuRenderer implements Disposable{
private float time = 0f;
private float flyerRot = 45f;
private int flyers = Mathf.chance(0.2) ? Mathf.random(35) : Mathf.random(15);
private UnitDef flyerType = Structs.select(UnitTypes.wraith, UnitTypes.wraith, UnitTypes.ghoul, UnitTypes.phantom, UnitTypes.phantom, UnitTypes.revenant);
private UnitType flyerType = Structs.select(UnitTypes.wraith, UnitTypes.wraith, UnitTypes.ghoul, UnitTypes.phantom, UnitTypes.phantom, UnitTypes.revenant);
public MenuRenderer(){
Time.mark();

View file

@ -224,6 +224,8 @@ public abstract class SaveVersion extends SaveFileReader{
stream.writeInt(Groups.sync.size());
for(Syncc entity : Groups.sync){
if(!entity.serialize()) continue;
writeChunk(stream, true, out -> {
out.writeByte(entity.classId());
entity.write(out);

View file

@ -155,13 +155,13 @@ public class TypeIO{
return AdminAction.values()[buffer.get()];
}
@WriteClass(UnitDef.class)
public static void writeUnitDef(ByteBuffer buffer, UnitDef effect){
@WriteClass(UnitType.class)
public static void writeUnitDef(ByteBuffer buffer, UnitType effect){
buffer.putShort(effect.id);
}
@ReadClass(UnitDef.class)
public static UnitDef readUnitDef(ByteBuffer buffer){
@ReadClass(UnitType.class)
public static UnitType readUnitDef(ByteBuffer buffer){
return content.getByID(ContentType.unit, buffer.getShort());
}

View file

@ -274,14 +274,14 @@ public class ContentParser{
return block;
},
ContentType.unit, (TypeParser<UnitDef>)(mod, name, value) -> {
ContentType.unit, (TypeParser<UnitType>)(mod, name, value) -> {
readBundle(ContentType.unit, name, value);
//TODO fix
UnitDef unit;
UnitType unit;
if(locate(ContentType.unit, name) == null){
Class<Unitc> type = resolve(legacyUnitMap.get(Strings.capitalize(getType(value)), getType(value)), "mindustry.entities.type.base");
unit = new UnitDef(mod + "-" + name);
unit = new UnitType(mod + "-" + name);
}else{
unit = locate(ContentType.unit, name);
}

View file

@ -21,8 +21,7 @@ import mindustry.world.blocks.*;
import static mindustry.Vars.*;
//TODO change to UnitType or Shell or something
public class UnitDef extends UnlockableContent{
public class UnitType extends UnlockableContent{
static final float shadowTX = -12, shadowTY = -13, shadowColor = Color.toFloatBits(0, 0, 0, 0.22f);
public @NonNull Prov<? extends UnitController> defaultController = AIController::new;
@ -53,7 +52,7 @@ public class UnitDef extends UnlockableContent{
public Array<Weapon> weapons = new Array<>();
public TextureRegion baseRegion, legRegion, region, cellRegion, occlusionRegion;
public UnitDef(String name){
public UnitType(String name){
super(name);
if(EntityMapping.map(name) != null){

View file

@ -131,7 +131,7 @@ public class ContentDisplay{
table.row();
}
public static void displayUnit(Table table, UnitDef unit){
public static void displayUnit(Table table, UnitType unit){
table.table(title -> {
title.addImage(unit.icon(Cicon.xlarge)).size(8 * 6);
title.add("[accent]" + unit.localizedName).padLeft(5);

View file

@ -12,7 +12,7 @@ import static mindustry.Vars.net;
public class RespawnBlock{
public static void drawRespawn(Tile tile, float heat, float progress, float time, Playerc player, UnitDef to){
public static void drawRespawn(Tile tile, float heat, float progress, float time, Playerc player, UnitType to){
progress = Mathf.clamp(progress);
Draw.color(Pal.darkMetal);

View file

@ -20,7 +20,7 @@ import mindustry.world.modules.*;
import static mindustry.Vars.*;
public class CoreBlock extends StorageBlock{
public UnitDef mech = UnitTypes.starter;
public UnitType mech = UnitTypes.starter;
public CoreBlock(String name){
super(name);

View file

@ -20,7 +20,7 @@ import static mindustry.Vars.*;
//TODO remove
public class MechPad extends Block{
public @NonNull UnitDef mech;
public @NonNull UnitType mech;
public float buildTime = 60 * 5;
public MechPad(String name){

View file

@ -22,7 +22,7 @@ import java.io.*;
import static mindustry.Vars.net;
public class UnitFactory extends Block{
public UnitDef unitType;
public UnitType unitType;
public float produceTime = 1000f;
public float launchVelocity = 0f;
public TextureRegion topRegion;

View file

@ -1,3 +1,3 @@
org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=dccfeeeffbf4e66b815306306b55472dcd123f61
archash=d271474a36e1b68887bdb7520bf683c5aa832e79