From f46be924b9628c35cc0c805ebd10249647c19a01 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 8 Feb 2020 13:14:23 -0500 Subject: [PATCH] Effects, collisions, method overrides --- .../mindustry/annotations/Annotations.java | 7 +++ .../annotations/impl/EntityProcess.java | 63 ++++++++++++++++--- .../src/main/resources/classids.properties | 15 ++--- core/src/mindustry/content/Fx.java | 2 +- core/src/mindustry/content/StatusEffects.java | 2 + core/src/mindustry/core/Renderer.java | 1 + .../entities/{def => }/AllEntities.java | 7 ++- core/src/mindustry/entities/Effects.java | 4 +- .../mindustry/entities/EntityCollisions.java | 32 +++++++--- .../src/mindustry/entities/def/DecalComp.java | 4 +- core/src/mindustry/entities/def/DrawComp.java | 5 -- .../mindustry/entities/def/EffectComp.java | 7 +-- .../entities/def/ElevationMoveComp.java | 22 +++++++ .../mindustry/entities/def/FlyingComp.java | 14 ++++- .../entities/def/GroundEffectComp.java | 13 ++++ core/src/mindustry/entities/def/LegsComp.java | 2 +- .../entities/def/StandardEffectComp.java | 13 ++++ .../mindustry/entities/def/StatusComp.java | 15 +++-- core/src/mindustry/entities/def/VelComp.java | 9 ++- .../mindustry/entities/def/WaterMoveComp.java | 33 ++++++++++ 20 files changed, 217 insertions(+), 53 deletions(-) rename core/src/mindustry/entities/{def => }/AllEntities.java (78%) create mode 100644 core/src/mindustry/entities/def/ElevationMoveComp.java create mode 100644 core/src/mindustry/entities/def/GroundEffectComp.java create mode 100644 core/src/mindustry/entities/def/StandardEffectComp.java create mode 100644 core/src/mindustry/entities/def/WaterMoveComp.java diff --git a/annotations/src/main/java/mindustry/annotations/Annotations.java b/annotations/src/main/java/mindustry/annotations/Annotations.java index 7d044e6416..0c9ddc7c4e 100644 --- a/annotations/src/main/java/mindustry/annotations/Annotations.java +++ b/annotations/src/main/java/mindustry/annotations/Annotations.java @@ -7,6 +7,7 @@ public class Annotations{ public enum DrawLayer{ floor, + floorOver, groundShadows, groundUnder, ground, @@ -17,6 +18,12 @@ public class Annotations{ names, } + /** Indicates that a method overrides other methods. */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.SOURCE) + public @interface Replace{ + } + /** Indicates that a component field is read-only. */ @Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) diff --git a/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java b/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java index b5fe7472c5..bb6e1b8257 100644 --- a/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java +++ b/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java @@ -6,6 +6,7 @@ import arc.struct.*; import arc.util.*; import arc.util.io.*; import arc.util.pooling.*; +import arc.util.pooling.Pool.*; import com.squareup.javapoet.*; import com.squareup.javapoet.TypeSpec.*; import com.sun.source.tree.*; @@ -216,6 +217,7 @@ public class EntityProcess extends BaseProcessor{ Array components = allComponents(type); Array groups = groupDefs.select(g -> (!g.components.isEmpty() && !g.components.contains(s -> !components.contains(s))) || g.manualInclusions.contains(type)); ObjectMap> methods = new ObjectMap<>(); + ObjectMap specVariables = new ObjectMap<>(); //add all components for(Stype comp : components){ @@ -237,6 +239,7 @@ public class EntityProcess extends BaseProcessor{ if(!isFinal) fbuilder.addModifiers(Modifier.PROTECTED); fbuilder.addAnnotations(f.annotations().map(AnnotationSpec::get)); builder.addField(fbuilder.build()); + specVariables.put(builder.fieldSpecs.get(builder.fieldSpecs.size() - 1), f); } //get all utility methods from components @@ -245,8 +248,30 @@ public class EntityProcess extends BaseProcessor{ } } + //override toString method + builder.addMethod(MethodSpec.methodBuilder("toString") + .addAnnotation(Override.class) + .returns(String.class) + .addModifiers(Modifier.PUBLIC) + .addStatement("return $S + $L", name + "#", "id").build()); + //add all methods from components for(ObjectMap.Entry> entry : methods){ + if(entry.value.contains(m -> m.has(Replace.class))){ + //check replacements + if(entry.value.count(m -> m.has(Replace.class)) > 1){ + err("Type " + type + " has multiple components replacing method " + entry.key + "."); + } + Smethod base = entry.value.find(m -> m.has(Replace.class)); + entry.value.clear(); + entry.value.add(base); + } + + //check multi return + if(entry.value.count(m -> !m.isAny(Modifier.NATIVE, Modifier.ABSTRACT) && !m.isVoid()) > 1){ + err("Type " + type + " has multiple components implementing non-void method " + entry.key + "."); + } + entry.value.sort(m -> m.has(MethodPriority.class) ? m.annotation(MethodPriority.class).value() : 0); //representative method @@ -275,6 +300,14 @@ public class EntityProcess extends BaseProcessor{ err(entry.value.first().up().getSimpleName() + "#" + entry.value.first() + " is an abstract method and must be implemented in some component", type); } + //SPECIAL CASE: inject group add/remove code + if(first.name().equals("add") || first.name().equals("remove")){ + for(GroupDefinition def : groups){ + //remove/add from each group, assume imported + mbuilder.addStatement("Groups.$L.$L(this)", def.name, first.name()); + } + } + for(Smethod elem : entry.value){ if(elem.is(Modifier.ABSTRACT) || elem.is(Modifier.NATIVE) || !methodBlocks.containsKey(elem)) continue; @@ -298,14 +331,6 @@ public class EntityProcess extends BaseProcessor{ //trim block str = str.substring(2, str.length() - 1); - //SPECIAL CASE: inject group add/remove code - if(elem.name().equals("add") || elem.name().equals("remove")){ - for(GroupDefinition def : groups){ - //remove/add from each group, assume imported - mbuilder.addStatement("Groups.$L.$L(this)", def.name, elem.name()); - } - } - //make sure to remove braces here mbuilder.addCode(str); @@ -313,6 +338,7 @@ public class EntityProcess extends BaseProcessor{ if(writeBlock) mbuilder.addCode("}\n"); } + //add free code to remove methods if(first.name().equals("remove") && ann.pooled()){ mbuilder.addStatement("$T.free(this)", Pools.class); } @@ -320,6 +346,27 @@ public class EntityProcess extends BaseProcessor{ builder.addMethod(mbuilder.build()); } + //add pool reset method and implment Poolable + if(ann.pooled()){ + builder.addSuperinterface(Poolable.class); + //implement reset() + MethodSpec.Builder resetBuilder = MethodSpec.methodBuilder("reset").addModifiers(Modifier.PUBLIC); + for(FieldSpec spec : builder.fieldSpecs){ + Svar variable = specVariables.get(spec); + if(spec.type.isPrimitive()){ + //set to primitive default + resetBuilder.addStatement("$L = $L", spec.name, varInitializers.containsKey(variable) ? varInitializers.get(variable) : getDefault(spec.type.toString())); + }else{ + //set to default null + if(!varInitializers.containsKey(variable)){ + resetBuilder.addStatement("$L = null", spec.name); + } //else... TODO reset if poolable + } + } + + builder.addMethod(resetBuilder.build()); + } + //make constructor private builder.addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PROTECTED).build()); diff --git a/annotations/src/main/resources/classids.properties b/annotations/src/main/resources/classids.properties index 75104b58c3..ae501a61b5 100644 --- a/annotations/src/main/resources/classids.properties +++ b/annotations/src/main/resources/classids.properties @@ -1,11 +1,12 @@ #Maps entity names to IDs. Autogenerated. dagger=7 -mindustry.entities.def.AllEntities.GenericBuilderDef=6 -mindustry.entities.def.AllEntities.BulletDef=0 -mindustry.entities.def.AllEntities.PlayerDef=4 +mindustry.entities.AllEntities.GenericBuilderDef=6 +mindustry.entities.AllEntities.BulletDef=0 +mindustry.entities.AllEntities.PlayerDef=4 +mindustry.entities.AllEntities.GroundEffectDef=9 +mindustry.entities.AllEntities.EffectDef=2 +mindustry.entities.AllEntities.GenericUnitDef=5 +mindustry.entities.AllEntities.TileDef=3 dagger2=8 -mindustry.entities.def.AllEntities.GenericUnitDef=5 -mindustry.entities.def.AllEntities.EffectDef=2 -mindustry.entities.def.AllEntities.DecalDef=1 -mindustry.entities.def.AllEntities.TileDef=3 \ No newline at end of file +mindustry.entities.AllEntities.DecalDef=1 \ No newline at end of file diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 02574f085e..22436c5154 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -1082,7 +1082,7 @@ public class Fx{ //TODO fix false in constructor ripple = new Effect(30, e -> { - color(Tmp.c1.set(e.color).mul(1.2f)); + color(Tmp.c1.set(e.color).mul(1.5f)); stroke(e.fout() + 0.4f); Lines.circle(e.x, e.y, 2f + e.fin() * 4f); }).ground(), diff --git a/core/src/mindustry/content/StatusEffects.java b/core/src/mindustry/content/StatusEffects.java index f0cb039a01..a925a77be4 100644 --- a/core/src/mindustry/content/StatusEffects.java +++ b/core/src/mindustry/content/StatusEffects.java @@ -1,6 +1,7 @@ package mindustry.content; import arc.*; +import arc.graphics.*; import arc.math.Mathf; import mindustry.ctype.ContentList; import mindustry.game.EventType.*; @@ -40,6 +41,7 @@ public class StatusEffects implements ContentList{ }}; wet = new StatusEffect("wet"){{ + color = Color.royal; speedMultiplier = 0.9f; effect = Fx.wet; diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 1d1f1abb80..20c8d8607a 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -188,6 +188,7 @@ public class Renderer implements ApplicationListener{ blocks.floor.drawFloor(); Groups.drawFloor(); + Groups.drawFloorOver(); blocks.processBlocks(); blocks.drawShadows(); diff --git a/core/src/mindustry/entities/def/AllEntities.java b/core/src/mindustry/entities/AllEntities.java similarity index 78% rename from core/src/mindustry/entities/def/AllEntities.java rename to core/src/mindustry/entities/AllEntities.java index 8f7d99ab25..26e645d589 100644 --- a/core/src/mindustry/entities/def/AllEntities.java +++ b/core/src/mindustry/entities/AllEntities.java @@ -1,4 +1,4 @@ -package mindustry.entities.def; +package mindustry.entities; import mindustry.annotations.Annotations.*; import mindustry.gen.*; @@ -11,9 +11,12 @@ class AllEntities{ @EntityDef(value = {Tilec.class}, isFinal = false) class TileDef{} - @EntityDef(value = {Effectc.class, Childc.class}, pooled = true) + @EntityDef(value = {StandardEffectc.class, Childc.class}, pooled = true) class EffectDef{} + @EntityDef(value = {GroundEffectc.class, Childc.class}, pooled = true) + class GroundEffectDef{} + @EntityDef({Decalc.class}) class DecalDef{} diff --git a/core/src/mindustry/entities/Effects.java b/core/src/mindustry/entities/Effects.java index 9b4c281eea..3d7f94a456 100644 --- a/core/src/mindustry/entities/Effects.java +++ b/core/src/mindustry/entities/Effects.java @@ -39,11 +39,11 @@ public class Effects{ Rect pos = Tmp.r2.setSize(effect.size).setCenter(x, y); if(view.overlaps(pos)){ - EffectEntity entity = EffectEntity.create(); + Effectc entity = effect.ground ? GroundEffectEntity.create() : EffectEntity.create(); entity.effect(effect); entity.rotation(rotation); entity.data(data); - entity.id(EntityGroup.nextId()); + entity.lifetime(effect.lifetime); entity.set(x, y); entity.color().set(color); if(data instanceof Posc) entity.parent((Posc)data); diff --git a/core/src/mindustry/entities/EntityCollisions.java b/core/src/mindustry/entities/EntityCollisions.java index f2a0d270b3..29be64cd5d 100644 --- a/core/src/mindustry/entities/EntityCollisions.java +++ b/core/src/mindustry/entities/EntityCollisions.java @@ -1,13 +1,12 @@ package mindustry.entities; -import arc.struct.Array; -import arc.math.Mathf; +import arc.math.*; import arc.math.geom.*; +import arc.struct.*; import mindustry.gen.*; -import mindustry.world.Tile; +import mindustry.world.*; -import static mindustry.Vars.tilesize; -import static mindustry.Vars.world; +import static mindustry.Vars.*; public class EntityCollisions{ //range for tile collision scanning @@ -26,12 +25,16 @@ public class EntityCollisions{ private Array arrOut = new Array<>(); public void move(Hitboxc entity, float deltax, float deltay){ + move(entity, deltax, deltay, EntityCollisions::solid); + } + + public void move(Hitboxc entity, float deltax, float deltay, SolidPred solidCheck){ boolean movedx = false; while(Math.abs(deltax) > 0 || !movedx){ movedx = true; - moveDelta(entity, Math.min(Math.abs(deltax), seg) * Mathf.sign(deltax), 0, true); + moveDelta(entity, Math.min(Math.abs(deltax), seg) * Mathf.sign(deltax), 0, true, solidCheck); if(Math.abs(deltax) >= seg){ deltax -= seg * Mathf.sign(deltax); @@ -44,7 +47,7 @@ public class EntityCollisions{ while(Math.abs(deltay) > 0 || !movedy){ movedy = true; - moveDelta(entity, 0, Math.min(Math.abs(deltay), seg) * Mathf.sign(deltay), false); + moveDelta(entity, 0, Math.min(Math.abs(deltay), seg) * Mathf.sign(deltay), false, solidCheck); if(Math.abs(deltay) >= seg){ deltay -= seg * Mathf.sign(deltay); @@ -54,7 +57,7 @@ public class EntityCollisions{ } } - public void moveDelta(Hitboxc entity, float deltax, float deltay, boolean x){ + public void moveDelta(Hitboxc entity, float deltax, float deltay, boolean x, SolidPred solidCheck){ Rect rect = r1; entity.hitboxTile(rect); entity.hitboxTile(r2); @@ -66,7 +69,7 @@ public class EntityCollisions{ for(int dx = -r; dx <= r; dx++){ for(int dy = -r; dy <= r; dy++){ int wx = dx + tilex, wy = dy + tiley; - if(solid(wx, wy)){ + if(solidCheck.solid(wx, wy)){ tmp.setSize(tilesize).setCenter(wx * tilesize, wy * tilesize); if(tmp.overlaps(rect)){ @@ -118,7 +121,12 @@ public class EntityCollisions{ }); } - private static boolean solid(int x, int y){ + public static boolean waterSolid(int x, int y){ + Tile tile = world.tile(x, y); + return tile != null && (tile.solid() || !tile.floor().isLiquid); + } + + public static boolean solid(int x, int y){ Tile tile = world.tile(x, y); return tile != null && tile.solid(); } @@ -221,4 +229,8 @@ public class EntityCollisions{ } }); } + + public interface SolidPred{ + boolean solid(int x, int y); + } } diff --git a/core/src/mindustry/entities/def/DecalComp.java b/core/src/mindustry/entities/def/DecalComp.java index 7b7d32a6ed..c9a208366c 100644 --- a/core/src/mindustry/entities/def/DecalComp.java +++ b/core/src/mindustry/entities/def/DecalComp.java @@ -6,12 +6,12 @@ import mindustry.annotations.Annotations.*; import mindustry.gen.*; @Component -abstract class DecalComp implements Drawc, Timedc, Rotc, Posc{ +abstract class DecalComp implements Drawc, Timedc, Rotc, Posc, DrawLayerFloorc{ Color color = new Color(1, 1, 1, 1); TextureRegion region; @Override - public void draw(){ + public void drawFloor(){ Draw.color(color); Draw.rect(region, x(), y(), rotation()); Draw.color(); diff --git a/core/src/mindustry/entities/def/DrawComp.java b/core/src/mindustry/entities/def/DrawComp.java index fa5e06285b..123c6a14ed 100644 --- a/core/src/mindustry/entities/def/DrawComp.java +++ b/core/src/mindustry/entities/def/DrawComp.java @@ -5,10 +5,5 @@ import mindustry.gen.*; @Component abstract class DrawComp implements Posc{ - abstract float clipSize(); - - void draw(){ - - } } diff --git a/core/src/mindustry/entities/def/EffectComp.java b/core/src/mindustry/entities/def/EffectComp.java index 2c9c1eb80c..b090a256f2 100644 --- a/core/src/mindustry/entities/def/EffectComp.java +++ b/core/src/mindustry/entities/def/EffectComp.java @@ -6,13 +6,12 @@ import mindustry.entities.*; import mindustry.gen.*; @Component -abstract class EffectComp implements Posc, Drawc, Timedc, Rotc{ - Effect effect; +abstract class EffectComp implements Posc, Drawc, Timedc, Rotc, Childc{ Color color = new Color(Color.white); + Effect effect; Object data; - @Override - public void draw(){ + void draw(){ effect.render(id(), color, time(), rotation(), x(), y(), data); } diff --git a/core/src/mindustry/entities/def/ElevationMoveComp.java b/core/src/mindustry/entities/def/ElevationMoveComp.java new file mode 100644 index 0000000000..079a32e9bc --- /dev/null +++ b/core/src/mindustry/entities/def/ElevationMoveComp.java @@ -0,0 +1,22 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +import static mindustry.Vars.collisions; + +@Component +abstract class ElevationMoveComp implements Velc, Posc, Flyingc, Hitboxc{ + transient float x, y; + + @Replace + @Override + public void move(float cx, float cy){ + if(isFlying()){ + x += cx; + y += cy; + }else{ + collisions.move(this, cx, cy); + } + } +} diff --git a/core/src/mindustry/entities/def/FlyingComp.java b/core/src/mindustry/entities/def/FlyingComp.java index f5783b245e..8a9f48fd0b 100644 --- a/core/src/mindustry/entities/def/FlyingComp.java +++ b/core/src/mindustry/entities/def/FlyingComp.java @@ -16,6 +16,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc{ float elevation; float drownTime; + float splashTimer; boolean isGrounded(){ return elevation < 0.001f; @@ -25,15 +26,22 @@ abstract class FlyingComp implements Posc, Velc, Healthc{ return elevation >= 0.001f; } + boolean canDrown(){ + return isGrounded(); + } + @Override public void update(){ Floor floor = floorOn(); - if(isGrounded() && floor.isLiquid && vel.len2() > 0.4f*0.4f && Mathf.chance((vel.len2() * floor.speedMultiplier) * 0.03f * Time.delta())){ - floor.walkEffect.at(x, y, 0, floor.color); + if(isGrounded() && floor.isLiquid && !vel.isZero(0.01f)){ + if((splashTimer += vel.len()) >= 7f){ + floor.walkEffect.at(x, y, 0, floor.color); + splashTimer = 0f; + } } - if(isGrounded() && floor.isLiquid && floor.drownTime > 0){ + if(canDrown() && floor.isLiquid && floor.drownTime > 0){ drownTime += Time.delta() * 1f / floor.drownTime; drownTime = Mathf.clamp(drownTime); if(Mathf.chance(Time.delta() * 0.05f)){ diff --git a/core/src/mindustry/entities/def/GroundEffectComp.java b/core/src/mindustry/entities/def/GroundEffectComp.java new file mode 100644 index 0000000000..c1a10fc11d --- /dev/null +++ b/core/src/mindustry/entities/def/GroundEffectComp.java @@ -0,0 +1,13 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class GroundEffectComp implements Effectc, DrawLayerFloorOverc{ + + @Override + public void drawFloorOver(){ + draw(); + } +} diff --git a/core/src/mindustry/entities/def/LegsComp.java b/core/src/mindustry/entities/def/LegsComp.java index 542d4d783c..7134aa980f 100644 --- a/core/src/mindustry/entities/def/LegsComp.java +++ b/core/src/mindustry/entities/def/LegsComp.java @@ -6,7 +6,7 @@ import mindustry.annotations.Annotations.*; import mindustry.gen.*; @Component -abstract class LegsComp implements Posc, Flyingc, Hitboxc, DrawLayerGroundUnderc, Unitc, Legsc{ +abstract class LegsComp implements Posc, Flyingc, Hitboxc, DrawLayerGroundUnderc, Unitc, Legsc, ElevationMovec{ transient float x, y; float baseRotation, walkTime; diff --git a/core/src/mindustry/entities/def/StandardEffectComp.java b/core/src/mindustry/entities/def/StandardEffectComp.java new file mode 100644 index 0000000000..4de2986f3d --- /dev/null +++ b/core/src/mindustry/entities/def/StandardEffectComp.java @@ -0,0 +1,13 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class StandardEffectComp implements Effectc, DrawLayerEffectsc{ + + @Override + public void drawEffects(){ + draw(); + } +} diff --git a/core/src/mindustry/entities/def/StatusComp.java b/core/src/mindustry/entities/def/StatusComp.java index cebe79045c..f504f6c4f0 100644 --- a/core/src/mindustry/entities/def/StatusComp.java +++ b/core/src/mindustry/entities/def/StatusComp.java @@ -73,13 +73,16 @@ abstract class StatusComp implements Posc, Flyingc{ return Tmp.c1.set(Color.white); } - float r = 0f, g = 0f, b = 0f; + float r = 1f, g = 1f, b = 1f, total = 0f; for(StatusEntry entry : statuses){ - r += entry.effect.color.r; - g += entry.effect.color.g; - b += entry.effect.color.b; + float intensity = entry.time < 10f ? entry.time/10f : 1f; + r += entry.effect.color.r * intensity; + g += entry.effect.color.g * intensity; + b += entry.effect.color.b * intensity; + total += intensity; } - return Tmp.c1.set(r / statuses.size, g / statuses.size, b / statuses.size, 1f); + float count = statuses.size + total; + return Tmp.c1.set(r / count, g / count, b / count, 1f); } @Override @@ -118,6 +121,8 @@ abstract class StatusComp implements Posc, Flyingc{ return applied.get(effect.id); } + //TODO autogen io code + void writeSave(DataOutput stream) throws IOException{ stream.writeByte(statuses.size); for(StatusEntry entry : statuses){ diff --git a/core/src/mindustry/entities/def/VelComp.java b/core/src/mindustry/entities/def/VelComp.java index d47e5f1ba4..512777a7f6 100644 --- a/core/src/mindustry/entities/def/VelComp.java +++ b/core/src/mindustry/entities/def/VelComp.java @@ -14,9 +14,12 @@ abstract class VelComp implements Posc{ @Override public void update(){ - //TODO handle solidity - x += vel.x; - y += vel.y; + move(vel.x, vel.y); vel.scl(1f - drag * Time.delta()); } + + void move(float cx, float cy){ + x += cx; + y += cy; + } } diff --git a/core/src/mindustry/entities/def/WaterMoveComp.java b/core/src/mindustry/entities/def/WaterMoveComp.java new file mode 100644 index 0000000000..ddef3d2acb --- /dev/null +++ b/core/src/mindustry/entities/def/WaterMoveComp.java @@ -0,0 +1,33 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.entities.*; +import mindustry.gen.*; + +import static mindustry.Vars.collisions; + +//just a proof of concept +@Component +abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc{ + transient float x, y; + + @Replace + @Override + public void move(float cx, float cy){ + if(isGrounded()){ + if(!EntityCollisions.waterSolid(tileX(), tileY())){ + collisions.move(this, cx, cy, EntityCollisions::waterSolid); + } + }else{ + x += cx; + y += cy; + } + } + + @Replace + @Override + public boolean canDrown(){ + return false; + } +} +