1
0
mirror of https://github.com/Anuken/Mindustry.git synced 2024-11-13 07:15:28 +03:00

Refactoring

This commit is contained in:
Anuken 2020-02-03 14:07:06 -05:00
parent f937cb30f0
commit 141cf518a2
56 changed files with 706 additions and 1418 deletions

View File

@ -10,7 +10,14 @@ public class Annotations{
@Retention(RetentionPolicy.SOURCE)
public @interface Component{
/** Dependencies. */
Class[] value() default {};
//Class[] value() default {};
}
/** Indicates priority of a method in an entity. Methods with higher priority are done last. */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface MethodPriority{
float value();
}
/** Indicates that a component def is present on all entities. */

View File

@ -21,6 +21,7 @@ import javax.lang.model.type.*;
public class EntityProcess extends BaseProcessor{
Array<Definition> definitions = new Array<>();
Array<Stype> baseComponents;
ObjectMap<String, Stype> componentNames = new ObjectMap<>();
ObjectMap<Stype, Array<Stype>> componentDependencies = new ObjectMap<>();
ObjectMap<Stype, Array<Stype>> defComponents = new ObjectMap<>();
ObjectSet<String> imports = new ObjectSet<>();
@ -36,17 +37,12 @@ public class EntityProcess extends BaseProcessor{
if(round == 1){
baseComponents = types(BaseComponent.class);
Array<Stype> allDefs = types(EntityDef.class);
Array<Stype> allComponents = types(Component.class);
ObjectSet<Stype> allComponents = new ObjectSet<>();
//find all components used...
for(Stype type : allDefs){
allComponents.addAll(allComponents(type));
for(Stype type : allComponents){
componentNames.put(type.name(), type);
}
//add all components w/ dependencies
allComponents.addAll(types(Component.class).map(s -> Array.withArrays(getDependencies(s), s)).flatten());
//add component imports
for(Stype comp : allComponents){
imports.addAll(getImports(comp.e));
@ -57,7 +53,7 @@ public class EntityProcess extends BaseProcessor{
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()){
for(Stype extraInterface : component.interfaces().select(i -> !isCompInterface(i))){
inter.addSuperinterface(extraInterface.mirror());
}
@ -130,6 +126,8 @@ public class EntityProcess extends BaseProcessor{
//add all methods from components
for(ObjectMap.Entry<String, Array<Smethod>> entry : methods){
entry.value.sort(m -> m.has(MethodPriority.class) ? m.annotation(MethodPriority.class).value() : 0);
//representative method
Smethod first = entry.value.first();
//build method using same params/returns
@ -261,18 +259,8 @@ public class EntityProcess extends BaseProcessor{
Array<Stype> getDependencies(Stype component){
if(!componentDependencies.containsKey(component)){
ObjectSet<Stype> out = new ObjectSet<>();
out.addAll(component.superclasses());
//TODO extreme confusion
//out.addAll(component.interfaces().select(this::isComponent));
//get dependency classes
if(component.annotation(Component.class) != null){
try{
component.annotation(Component.class).value();
}catch(MirroredTypesException e){
out.addAll(Array.with(e.getTypeMirrors()).map(Stype::of));
}
}
//add base component interfaces
out.addAll(component.interfaces().select(this::isCompInterface).map(this::interfaceToComp));
//out now contains the base dependencies; finish constructing the tree
ObjectSet<Stype> result = new ObjectSet<>();
@ -291,6 +279,15 @@ public class EntityProcess extends BaseProcessor{
return componentDependencies.get(component);
}
boolean isCompInterface(Stype type){
return interfaceToComp(type) != null;
}
Stype interfaceToComp(Stype type){
String name = type.name().substring(0, type.name().length() - 1) + "Comp";
return componentNames.get(name);
}
boolean isComponent(Stype type){
return type.annotation(Component.class) != null;
}

View File

@ -5,6 +5,7 @@ import mindustry.annotations.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import java.lang.annotation.*;
public class Selement<T extends Element>{
public final T e;
@ -13,6 +14,14 @@ public class Selement<T extends Element>{
this.e = e;
}
public <A extends Annotation> A annotation(Class<A> annotation){
return e.getAnnotation(annotation);
}
public <A extends Annotation> boolean has(Class<A> annotation){
return e.getAnnotation(annotation) != null;
}
public Element up(){
return e.getEnclosingElement();
}

View File

@ -5,7 +5,6 @@ import mindustry.annotations.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import java.lang.annotation.*;
public class Stype extends Selement<TypeElement>{
@ -35,10 +34,6 @@ public class Stype extends Selement<TypeElement>{
return new Stype((TypeElement)BaseProcessor.typeu.asElement(BaseProcessor.typeu.directSupertypes(mirror()).get(0)));
}
public <A extends Annotation> A annotation(Class<A> annotation){
return e.getAnnotation(annotation);
}
public Array<Svar> fields(){
return Array.with(e.getEnclosedElements()).select(e -> e instanceof VariableElement).map(e -> new Svar((VariableElement)e));
}

View File

@ -189,7 +189,7 @@ public class Vars implements Loadable{
public static EntityGroup<Fire> fireGroup;
public static EntityGroup<BaseUnit> unitGroup;
public static Player player;
public static Unitc player;
@Override
public void loadAsync(){

View File

@ -13,7 +13,6 @@ import mindustry.annotations.Annotations.*;
import mindustry.core.GameState.*;
import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
@ -365,8 +364,8 @@ public class NetClient implements ApplicationListener{
if(created && entity.getInterpolator() != null && entity.getInterpolator().target != null){
//set initial starting position
entity.setNet(entity.getInterpolator().target.x, entity.getInterpolator().target.y);
if(entity instanceof Unit && entity.getInterpolator().targets.length > 0){
((Unit)entity).rotation = entity.getInterpolator().targets[0];
if(entity instanceof Unitc && entity.getInterpolator().targets.length > 0){
((Unitc)entity).rotation = entity.getInterpolator().targets[0];
}
}

View File

@ -12,7 +12,6 @@ import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.core.GameState.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.game.EventType.*;
import mindustry.graphics.*;
@ -306,7 +305,7 @@ public class Renderer implements ApplicationListener{
Draw.color(0, 0, 0, 0.4f);
float rad = 1.6f;
Cons<Unit> draw = u -> {
Cons<Unitc> draw = u -> {
float size = Math.max(u.getIconRegion().getWidth(), u.getIconRegion().getHeight()) * Draw.scl;
Draw.rect("circle-shadow", u.x, u.y, size * rad, size * rad);
};
@ -331,14 +330,14 @@ public class Renderer implements ApplicationListener{
}
private void drawAllTeams(boolean flying){
unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder);
playerGroup.draw(p -> p.isFlying() == flying && !p.isDead(), Unit::drawUnder);
unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unitc::drawUnder);
playerGroup.draw(p -> p.isFlying() == flying && !p.isDead(), Unitc::drawUnder);
unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll);
playerGroup.draw(p -> p.isFlying() == flying, Unit::drawAll);
unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unitc::drawAll);
playerGroup.draw(p -> p.isFlying() == flying, Unitc::drawAll);
unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver);
playerGroup.draw(p -> p.isFlying() == flying, Unit::drawOver);
unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unitc::drawOver);
playerGroup.draw(p -> p.isFlying() == flying, Unitc::drawOver);
}
public void scaleCamera(float amount){

View File

@ -9,7 +9,6 @@ import arc.math.*;
import arc.math.geom.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.Effects.*;
import mindustry.entities.effect.*;
import mindustry.entities.type.*;
import mindustry.game.EventType.*;
@ -125,7 +124,7 @@ public class Damage{
rect.width += expand * 2;
rect.height += expand * 2;
Cons<Unit> cons = e -> {
Cons<Unitc> cons = e -> {
e.hitbox(hitrect);
Rect other = hitrect;
other.y -= expand;
@ -146,8 +145,8 @@ public class Damage{
}
/** Damages all entities and blocks in a radius that are enemies of the team. */
public static void damageUnits(Team team, float x, float y, float size, float damage, Boolf<Unit> predicate, Cons<Unit> acceptor){
Cons<Unit> cons = entity -> {
public static void damageUnits(Team team, float x, float y, float size, float damage, Boolf<Unitc> predicate, Cons<Unitc> acceptor){
Cons<Unitc> cons = entity -> {
if(!predicate.get(entity)) return;
entity.hitbox(hitrect);
@ -178,7 +177,7 @@ public class Damage{
/** Damages all entities and blocks in a radius that are enemies of the team. */
public static void damage(Team team, float x, float y, float radius, float damage, boolean complete){
Cons<Unit> cons = entity -> {
Cons<Unitc> cons = entity -> {
if(entity.getTeam() == team || entity.dst(x, y) > radius){
return;
}

View File

@ -0,0 +1,8 @@
package mindustry.entities;
/**
* Marks an entity as serializable.
*/
public interface SaveTrait extends Saveable{
byte version();
}

View File

@ -1,4 +1,4 @@
package mindustry.entities.traits;
package mindustry.entities;
import java.io.*;

View File

@ -3,7 +3,6 @@ package mindustry.entities;
import arc.func.*;
import arc.math.*;
import arc.math.geom.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.game.*;
import mindustry.world.*;
@ -13,7 +12,7 @@ import static mindustry.Vars.*;
/** Utility class for unit and team interactions.*/
public class Units{
private static Rect hitrect = new Rect();
private static Unit result;
private static Unitc result;
private static float cdist;
private static boolean boolResult;
@ -41,7 +40,7 @@ public class Units{
}
/** See {@link #invalidateTarget(TargetTrait, Team, float, float, float)} */
public static boolean invalidateTarget(TargetTrait target, Unit targeter){
public static boolean invalidateTarget(TargetTrait target, Unitc targeter){
return invalidateTarget(target, targeter.getTeam(), targeter.x, targeter.y, targeter.getWeapon().bullet.range());
}
@ -88,19 +87,19 @@ public class Units{
/** Returns the closest target enemy. First, units are checked, then tile entities. */
public static TargetTrait closestTarget(Team team, float x, float y, float range){
return closestTarget(team, x, y, range, Unit::isValid);
return closestTarget(team, x, y, range, Unitc::isValid);
}
/** Returns the closest target enemy. First, units are checked, then tile entities. */
public static TargetTrait closestTarget(Team team, float x, float y, float range, Boolf<Unit> unitPred){
public static TargetTrait closestTarget(Team team, float x, float y, float range, Boolf<Unitc> unitPred){
return closestTarget(team, x, y, range, unitPred, t -> true);
}
/** Returns the closest target enemy. First, units are checked, then tile entities. */
public static TargetTrait closestTarget(Team team, float x, float y, float range, Boolf<Unit> unitPred, Boolf<Tile> tilePred){
public static TargetTrait closestTarget(Team team, float x, float y, float range, Boolf<Unitc> unitPred, Boolf<Tile> tilePred){
if(team == Team.derelict) return null;
Unit unit = closestEnemy(team, x, y, range, unitPred);
Unitc unit = closestEnemy(team, x, y, range, unitPred);
if(unit != null){
return unit;
}else{
@ -109,7 +108,7 @@ public class Units{
}
/** Returns the closest enemy of this team. Filter by predicate. */
public static Unit closestEnemy(Team team, float x, float y, float range, Boolf<Unit> predicate){
public static Unitc closestEnemy(Team team, float x, float y, float range, Boolf<Unitc> predicate){
if(team == Team.derelict) return null;
result = null;
@ -129,7 +128,7 @@ public class Units{
}
/** Returns the closest ally of this team. Filter by predicate. */
public static Unit closest(Team team, float x, float y, float range, Boolf<Unit> predicate){
public static Unitc closest(Team team, float x, float y, float range, Boolf<Unitc> predicate){
result = null;
cdist = 0f;
@ -147,7 +146,7 @@ public class Units{
}
/** Iterates over all units in a rectangle. */
public static void nearby(Team team, float x, float y, float width, float height, Cons<Unit> cons){
public static void nearby(Team team, float x, float y, float width, float height, Cons<Unitc> cons){
unitGroup.intersect(x, y, width, height, u -> {
if(u.getTeam() == team){
cons.get(u);
@ -161,7 +160,7 @@ public class Units{
}
/** Iterates over all units in a circle around this position. */
public static void nearby(Team team, float x, float y, float radius, Cons<Unit> cons){
public static void nearby(Team team, float x, float y, float radius, Cons<Unitc> cons){
unitGroup.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> {
if(unit.getTeam() == team && unit.withinDst(x, y, radius)){
cons.get(unit);
@ -176,18 +175,18 @@ public class Units{
}
/** Iterates over all units in a rectangle. */
public static void nearby(float x, float y, float width, float height, Cons<Unit> cons){
public static void nearby(float x, float y, float width, float height, Cons<Unitc> cons){
unitGroup.intersect(x, y, width, height, cons);
playerGroup.intersect(x, y, width, height, cons);
}
/** Iterates over all units in a rectangle. */
public static void nearby(Rect rect, Cons<Unit> cons){
public static void nearby(Rect rect, Cons<Unitc> cons){
nearby(rect.x, rect.y, rect.width, rect.height, cons);
}
/** Iterates over all units that are enemies of this team. */
public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons<Unit> cons){
public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons<Unitc> cons){
unitGroup.intersect(x, y, width, height, u -> {
if(team.isEnemy(u.getTeam())){
cons.get(u);
@ -202,12 +201,12 @@ public class Units{
}
/** Iterates over all units that are enemies of this team. */
public static void nearbyEnemies(Team team, Rect rect, Cons<Unit> cons){
public static void nearbyEnemies(Team team, Rect rect, Cons<Unitc> cons){
nearbyEnemies(team, rect.x, rect.y, rect.width, rect.height, cons);
}
/** Iterates over all units. */
public static void all(Cons<Unit> cons){
public static void all(Cons<Unitc> cons){
unitGroup.all().each(cons);
playerGroup.all().each(cons);
}

View File

@ -1,13 +1,16 @@
package mindustry.entities.def;
import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.scene.ui.layout.*;
import arc.struct.Bits;
import arc.struct.Queue;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import arc.util.ArcAnnotate.*;
import arc.util.pooling.*;
import mindustry.*;
import mindustry.annotations.Annotations.*;
@ -15,64 +18,154 @@ import mindustry.content.*;
import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.entities.bullet.*;
import mindustry.entities.def.EntityComps.MinerComp.*;
import mindustry.entities.effect.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.net.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.BuildBlock.*;
import java.io.*;
import java.util.*;
import static arc.math.Mathf.dst;
import static mindustry.Vars.*;
import static mindustry.entities.traits.BuilderTrait.BuildDataStatic.tmptr;
@SuppressWarnings("unused")
public class EntityComps{
@Component({HealthComp.class, VelComp.class, StatusComp.class, TeamComp.class, ItemsComp.class})
class UnitComp{
@Component
abstract class UnitComp implements Healthc, Velc, Statusc, Teamc, Itemsc, Hitboxc, Rotc{
UnitDef type;
UnitController controller;
float getBounds(){
return getHitSize() * 2f;
}
public void update(){
//apply knockback based on spawns
//TODO move elsewhere
if(getTeam() != state.rules.waveTeam){
float relativeSize = state.rules.dropZoneRadius + getBounds()/2f + 1f;
for(Tile spawn : spawner.getGroundSpawns()){
if(withinDst(spawn.worldx(), spawn.worldy(), relativeSize)){
getVel().add(Tmp.v1.set(this).sub(spawn.worldx(), spawn.worldy()).setLength(0.1f + 1f - dst(spawn) / relativeSize).scl(0.45f * Time.delta()));
}
}
}
Tile tile = tileOn();
Floor floor = floorOn();
if(tile != null){
//unit block update
tile.block().unitOn(tile, (mindustry.gen.Unitc)this);
//apply damage
if(floor.damageTaken > 0f){
damageContinuous(floor.damageTaken);
}
}
}
public void drawLight(){
//TODO move
if(type.lightRadius > 0){
renderer.lights.add(getX(), getY(), type.lightRadius, type.lightColor, 0.6f);
}
}
public void draw(){
//draw power cell - TODO move
Draw.color(Color.black, getTeam().color, healthf() + Mathf.absin(Time.time(), Math.max(healthf() * 5f, 1f), 1f - healthf()));
Draw.rect(type.cellRegion, getX(), getY(), getRotation() - 90);
Draw.color();
}
public void killed(){
float explosiveness = 2f + item().explosiveness * getStack().amount;
float flammability = item().flammability * getStack().amount;
Damage.dynamicExplosion(getX(), getY(), flammability, explosiveness, 0f, getBounds() / 2f, Pal.darkFlame);
//TODO cleanup
ScorchDecal.create(getX(), getY());
Fx.explosion.at(this);
Effects.shake(2f, 2f, this);
Sounds.bang.at(this);
Events.fire(new UnitDestroyEvent((mindustry.gen.Unitc)this));
//TODO implement suicide bomb trigger
//if(explosiveness > 7f && this == player){
// Events.fire(Trigger.suicideBomb);
//}
}
}
@Component
class OwnerComp{
Entityc owner;
}
@Component({TimedComp.class, DamageComp.class, HitboxComp.class})
class BulletComp{
@Component
abstract class ChildComp implements Posc{
transient float x, y;
private @Nullable Posc parent;
private float offsetX, offsetY;
public void add(){
if(parent != null){
offsetX = x - parent.getX();
offsetY = y - parent.getY();
}
}
public void update(){
if(parent != null){
x = parent.getX() + offsetX;
y = parent.getY() + offsetY;
}
}
}
@Component
abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc{
BulletType bullet;
float getDamage(){
public float getDamage(){
return bullet.damage;
}
void init(){
public void init(){
//TODO
bullet.init(null);
}
void remove(){
public void remove(){
//TODO
bullet.despawned(null);
}
}
@Component
class DamageComp{
native float getDamage();
abstract class DamageComp{
abstract float getDamage();
}
@Component
abstract class TimedComp extends EntityComp implements Scaled{
abstract class TimedComp implements Entityc, Scaled{
float time, lifetime;
void update(){
public void update(){
time = Math.min(time + Time.delta(), lifetime);
if(time >= lifetime){
@ -87,16 +180,22 @@ public class EntityComps{
}
@Component
class HealthComp{
abstract class HealthComp implements Entityc{
static final float hitDuration = 9f;
float health, maxHealth, hitTime;
boolean dead;
boolean isValid(){
return !dead && isAdded();
}
float healthf(){
return health / maxHealth;
}
void update(){
hitTime -= Time.delta() / 9f;
public void update(){
hitTime -= Time.delta() / hitDuration;
}
void killed(){
@ -125,6 +224,20 @@ public class EntityComps{
}
}
void damage(float amount, boolean withEffect){
float pre = hitTime;
damage(amount);
if(!withEffect){
hitTime = pre;
}
}
void damageContinuous(float amount){
damage(amount * Time.delta(), hitTime <= -20 + hitDuration);
}
void clampHealth(){
health = Mathf.clamp(health, 0, maxHealth);
}
@ -136,23 +249,67 @@ public class EntityComps{
}
@Component
class FlyingComp{
boolean flying;
abstract class FlyingComp implements Posc, Velc, Healthc{
transient float x, y;
transient Vec2 vel;
float elevation;
float drownTime;
boolean isGrounded(){
return elevation < 0.001f;
}
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 && floor.drownTime > 0){
drownTime += Time.delta() * 1f / floor.drownTime;
drownTime = Mathf.clamp(drownTime);
if(Mathf.chance(Time.delta() * 0.05f)){
floor.drownUpdateEffect.at(getX(), getY(), 0f, floor.color);
}
//TODO is the netClient check necessary?
if(drownTime >= 0.999f && !net.client()){
kill();
//TODO drown event!
}
}else{
drownTime = Mathf.lerpDelta(drownTime, 0f, 0.03f);
}
}
}
@Component
class LegsComp{
abstract class LegsComp implements Posc, Flyingc{
float baseRotation;
float drownTime;
}
@Component
class RotComp{
float rotation;
void interpolate(){
Syncc sync = (Syncc)this;
if(sync.getInterpolator().values.length > 0){
rotation = sync.getInterpolator().values[0];
}
}
}
@Component
abstract class TileComp implements Posc, Teamc{
Tile tile;
}
@Component
abstract class TeamComp{
abstract class TeamComp implements Posc{
transient float x, y;
Team team = Team.sharded;
@ -162,8 +319,8 @@ public class EntityComps{
}
}
@Component({RotComp.class, PosComp.class})
abstract static class WeaponsComp implements Teamc{
@Component
abstract static class WeaponsComp implements Teamc, Posc, Rotc{
transient float x, y, rotation;
/** 1 */
@ -184,7 +341,7 @@ public class EntityComps{
}
/** Aim at something. This will make all mounts point at it. */
void aim(Unit unit, float x, float y){
void aim(Unitc unit, float x, float y){
Tmp.v1.set(x, y).sub(this.x, this.y);
if(Tmp.v1.len() < minAimDst) Tmp.v1.setLength(minAimDst);
@ -198,12 +355,12 @@ public class EntityComps{
}
/** Update shooting and rotation for this unit. */
void update(Unit unit){
public void update(){
for(WeaponMount mount : mounts){
Weapon weapon = mount.weapon;
mount.reload -= Time.delta();
float rotation = unit.rotation - 90;
float rotation = this.rotation - 90;
//rotate if applicable
if(weapon.rotate){
@ -294,39 +451,115 @@ public class EntityComps{
private void bullet(Weapon weapon, float x, float y, float angle){
Tmp.v1.trns(angle, 3f);
Bullet.create(weapon.bullet, this, getTeam(), x + Tmp.v1.x, y + Tmp.v1.y, angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd));
//TODO create the bullet
//Bullet.create(weapon.bullet, this, getTeam(), x + Tmp.v1.x, y + Tmp.v1.y, angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd));
}
}
@Component
class DrawComp{
//TODO ponder.
abstract static class DrawShadowComp implements Drawc, Rotc, Flyingc{
static final float shadowTX = -12, shadowTY = -13, shadowColor = Color.toFloatBits(0, 0, 0, 0.22f);
native float drawSize();
transient float x, y, rotation;
abstract TextureRegion getShadowRegion();
void drawShadow(){
if(!isGrounded()){
Draw.color(shadowColor);
Draw.rect(getShadowRegion(), x + shadowTX * getElevation(), y + shadowTY * getElevation(), rotation - 90);
Draw.color();
}
}
}
@Component
abstract class DrawItemsComp implements Drawc, Itemsc, Posc, Rotc{
transient float x, y, rotation;
float itemTime;
//drawn after base
@MethodPriority(3)
public void draw(){
boolean number = isLocal();
itemTime = Mathf.lerpDelta(itemTime, Mathf.num(hasItem()), 0.05f);
//draw back items
if(itemTime > 0.01f){
float backTrns = 5f;
float size = (itemSize + Mathf.absin(Time.time(), 5f, 1f)) * itemTime;
Draw.mixcol(Pal.accent, Mathf.absin(Time.time(), 5f, 0.5f));
Draw.rect(item().icon(Cicon.medium),
x + Angles.trnsx(rotation + 180f, backTrns),
y + Angles.trnsy(rotation + 180f, backTrns),
size, size, rotation);
Draw.mixcol();
Lines.stroke(1f, Pal.accent);
Lines.circle(
x + Angles.trnsx(rotation + 180f, backTrns),
y + Angles.trnsy(rotation + 180f, backTrns),
(3f + Mathf.absin(Time.time(), 5f, 1f)) * itemTime);
if(isLocal()){
Fonts.outline.draw(getStack().amount + "",
x + Angles.trnsx(rotation + 180f, backTrns),
y + Angles.trnsy(rotation + 180f, backTrns) - 3,
Pal.accent, 0.25f * itemTime / Scl.scl(1f), false, Align.center
);
}
Draw.reset();
}
}
}
@Component
abstract class DrawLightComp implements Drawc{
void drawLight(){}
}
@Component
abstract class DrawOverComp implements Drawc{
void drawOver(){}
}
@Component
abstract class DrawUnderComp implements Drawc{
void drawUnder(){}
}
@Component
abstract class DrawComp{
abstract float clipSize();
void draw(){
}
}
@Component(PosComp.class)
abstract class SyncComp extends PosComp{
@Component
abstract class SyncComp implements Posc{
transient float x, y;
Interpolator interpolator = new Interpolator();
void setNet(float x, float y){
set(x, y);
//TODO change interpolator API
if(interpolator != null){
interpolator.target.set(x, y);
interpolator.last.set(x, y);
interpolator.pos.set(0, 0);
interpolator.updateSpacing = 16;
interpolator.lastUpdated = 0;
}
interpolator.target.set(x, y);
interpolator.last.set(x, y);
interpolator.pos.set(0, 0);
interpolator.updateSpacing = 16;
interpolator.lastUpdated = 0;
}
void update(){
public void update(){
if(Vars.net.client() && !isLocal()){
interpolate();
}
@ -340,7 +573,35 @@ public class EntityComps{
}
@Component
abstract class PosComp extends EntityComp implements Position{
abstract class BoundedComp implements Velc, Posc, Healthc, Flyingc{
static final float warpDst = 180f;
transient float x, y;
transient Vec2 vel;
@Override
public void update(){
//repel unit out of bounds
if(x < 0) vel.x += (-x/warpDst);
if(y < 0) vel.y += (-y/warpDst);
if(x > world.unitWidth()) vel.x -= (x - world.unitWidth())/warpDst;
if(y > world.unitHeight()) vel.y -= (y - world.unitHeight())/warpDst;
//clamp position if not flying
if(isGrounded()){
x = Mathf.clamp(x, 0, world.width() * tilesize - tilesize);
y = Mathf.clamp(y, 0, world.height() * tilesize - tilesize);
}
//kill when out of bounds
if(x < -finalWorldBounds || y < -finalWorldBounds || x >= world.width() * tilesize + finalWorldBounds || y >= world.height() * tilesize + finalWorldBounds){
kill();
}
}
}
@Component
abstract class PosComp implements Position{
float x, y;
void set(float x, float y){
@ -359,19 +620,31 @@ public class EntityComps{
int tileY(){
return Vars.world.toTile(getY());
}
/** Returns air if this unit is on a non-air top block. */
public Floor floorOn(){
Tile tile = tileOn();
return tile == null || tile.block() != Blocks.air ? (Floor)Blocks.air : tile.floor();
}
public @Nullable Tile tileOn(){
return world.tileWorld(x, y);
}
}
@Component({ItemsComp.class, TeamComp.class, RotComp.class})
@Component
static abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc{
static float miningRange = 70f;
transient float x, y, rotation;
@Nullable Tile mineTile;
native boolean canMine(Item item);
abstract boolean canMine(Item item);
native float getMiningSpeed();
abstract float getMiningSpeed();
native boolean offloadImmediately();
abstract boolean offloadImmediately();
boolean isMining(){
return mineTile != null;
@ -381,7 +654,7 @@ public class EntityComps{
TileEntity core = getClosestCore();
if(core != null && mineTile != null && mineTile.drop() != null && !acceptsItem(mineTile.drop()) && dst(core) < mineTransferRange){
int accepted = core.tile.block().acceptStack(item(), getStack().amount, core.tile, unit);
int accepted = core.tile.block().acceptStack(item(), getStack().amount, core.tile, this);
if(accepted > 0){
Call.transferItemTo(item(), accepted,
mineTile.worldx() + Mathf.range(tilesize / 2f),
@ -399,7 +672,7 @@ public class EntityComps{
if(Mathf.chance(Time.delta() * (0.06 - item.hardness * 0.01) * getMiningSpeed())){
if(dst(core) < mineTransferRange && core.tile.block().acceptStack(item, 1, core.tile, unit) == 1 && offloadImmediately()){
if(dst(core) < mineTransferRange && core.tile.block().acceptStack(item, 1, core.tile, this) == 1 && offloadImmediately()){
Call.transferItemTo(item, 1,
mineTile.worldx() + Mathf.range(tilesize / 2f),
mineTile.worldy() + Mathf.range(tilesize / 2f), core.tile);
@ -408,7 +681,7 @@ public class EntityComps{
ItemTransfer.transferItemToUnit(item,
mineTile.worldx() + Mathf.range(tilesize / 2f),
mineTile.worldy() + Mathf.range(tilesize / 2f),
unit);
this);
}
}
@ -417,19 +690,136 @@ public class EntityComps{
}
}
}
void drawOver(){
if(!isMining()) return;
float focusLen = 4f + Mathf.absin(Time.time(), 1.1f, 0.5f);
float swingScl = 12f, swingMag = tilesize / 8f;
float flashScl = 0.3f;
float px = x + Angles.trnsx(rotation, focusLen);
float py = y + Angles.trnsy(rotation, focusLen);
float ex = mineTile.worldx() + Mathf.sin(Time.time() + 48, swingScl, swingMag);
float ey = mineTile.worldy() + Mathf.sin(Time.time() + 48, swingScl + 2f, swingMag);
Draw.color(Color.lightGray, Color.white, 1f - flashScl + Mathf.absin(Time.time(), 0.5f, flashScl));
Drawf.laser(Core.atlas.find("minelaser"), Core.atlas.find("minelaser-end"), px, py, ex, ey, 0.75f);
//TODO hack?
if(isLocal()){
Lines.stroke(1f, Pal.accent);
Lines.poly(mineTile.worldx(), mineTile.worldy(), 4, tilesize / 2f * Mathf.sqrt2, Time.time());
}
Draw.color();
}
}
@Component
class BuilderComp{
abstract static class BuilderComp implements mindustry.gen.Unitc{
static final float placeDistance = 220f;
static final Vec2[] tmptr = new Vec2[]{new Vec2(), new Vec2(), new Vec2(), new Vec2()};
transient float x, y, rotation;
Queue<BuildRequest> requests = new Queue<>();
float buildSpeed = 1f;
//boolean building;
void updateBuilding(){
float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : placeDistance;
Iterator<BuildRequest> it = requests.iterator();
while(it.hasNext()){
BuildRequest req = it.next();
Tile tile = world.tile(req.x, req.y);
if(tile == null || (req.breaking && tile.block() == Blocks.air) || (!req.breaking && (tile.rotation() == req.rotation || !req.block.rotate) && tile.block() == req.block)){
it.remove();
}
}
TileEntity core = getClosestCore();
//nothing to build.
if(buildRequest() == null) return;
//find the next build request
if(requests.size > 1){
int total = 0;
BuildRequest req;
while((dst((req = buildRequest()).tile()) > finalPlaceDst || shouldSkip(req, core)) && total < requests.size){
requests.removeFirst();
requests.addLast(req);
total++;
}
}
BuildRequest current = buildRequest();
if(dst(current.tile()) > finalPlaceDst) return;
Tile tile = world.tile(current.x, current.y);
if(!(tile.block() instanceof BuildBlock)){
if(!current.initialized && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){
Build.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation);
}else if(!current.initialized && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){
Build.beginBreak(getTeam(), current.x, current.y);
}else{
requests.removeFirst();
return;
}
}
if(tile.entity instanceof BuildEntity && !current.initialized){
Core.app.post(() -> Events.fire(new BuildSelectEvent(tile, getTeam(), (Builderc)this, current.breaking)));
current.initialized = true;
}
//if there is no core to build with or no build entity, stop building!
if((core == null && !state.rules.infiniteResources) || !(tile.entity instanceof BuildEntity)){
return;
}
//otherwise, update it.
BuildEntity entity = tile.ent();
if(entity == null){
return;
}
if(dst(tile) <= finalPlaceDst){
rotation = Mathf.slerpDelta(rotation, angleTo(entity), 0.4f);
}
if(current.breaking){
entity.deconstruct(this, core, 1f / entity.buildCost * Time.delta() * buildSpeed * state.rules.buildSpeedMultiplier);
}else{
if(entity.construct(this, core, 1f / entity.buildCost * Time.delta() * buildSpeed * state.rules.buildSpeedMultiplier, current.hasConfig)){
if(current.hasConfig){
Call.onTileConfig(null, tile, current.config);
}
}
}
current.stuck = Mathf.equal(current.progress, entity.progress);
current.progress = entity.progress;
}
/** @return whether this request should be skipped, in favor of the next one. */
boolean shouldSkip(BuildRequest request, @Nullable TileEntity core){
//requests that you have at least *started* are considered
if(state.rules.infiniteResources || request.breaking || !request.initialized || core == null) return false;
return request.stuck && !core.items.has(request.block.requirements);
}
void removeBuild(int x, int y, boolean breaking){
//remove matching request
int idx = player.buildQueue().indexOf(req -> req.breaking == breaking && req.x == x && req.y == y);
int idx = requests.indexOf(req -> req.breaking == breaking && req.x == x && req.y == y);
if(idx != -1){
player.buildQueue().removeIndex(idx);
requests.removeIndex(idx);
}
}
@ -475,10 +865,47 @@ public class EntityComps{
@Nullable BuildRequest buildRequest(){
return requests.size == 0 ? null : requests.first();
}
void drawOver(){
if(!isBuilding()) return;
BuildRequest request = buildRequest();
Tile tile = world.tile(request.x, request.y);
if(dst(tile) > placeDistance && !state.isEditor()){
return;
}
Lines.stroke(1f, Pal.accent);
float focusLen = 3.8f + Mathf.absin(Time.time(), 1.1f, 0.6f);
float px = x + Angles.trnsx(rotation, focusLen);
float py = y + Angles.trnsy(rotation, focusLen);
float sz = Vars.tilesize * tile.block().size / 2f;
float ang = angleTo(tile);
tmptr[0].set(tile.drawx() - sz, tile.drawy() - sz);
tmptr[1].set(tile.drawx() + sz, tile.drawy() - sz);
tmptr[2].set(tile.drawx() - sz, tile.drawy() + sz);
tmptr[3].set(tile.drawx() + sz, tile.drawy() + sz);
Arrays.sort(tmptr, Structs.comparingFloat(vec -> Angles.angleDist(angleTo(vec), ang)));
float x1 = tmptr[0].x, y1 = tmptr[0].y,
x3 = tmptr[1].x, y3 = tmptr[1].y;
Draw.alpha(1f);
Lines.line(px, py, x1, y1);
Lines.line(px, py, x3, y3);
Fill.circle(px, py, 1.6f + Mathf.absin(Time.time(), 0.8f, 1.5f));
Draw.color();
}
}
@Component(DamageComp.class)
class ShielderComp{
@Component
abstract class ShielderComp implements Damagec{
void absorb(){
@ -486,12 +913,16 @@ public class EntityComps{
}
@Component
class ItemsComp{
abstract class ItemsComp{
ItemStack stack = new ItemStack();
native int getItemCapacity();
abstract int getItemCapacity();
public Item item(){
void update(){
stack.amount = Mathf.clamp(stack.amount, 0, getItemCapacity());
}
Item item(){
return stack.item;
}
@ -508,47 +939,50 @@ public class EntityComps{
}
}
@Component(VelComp.class)
class MassComp{
@Component
abstract class MassComp implements Velc{
float mass;
}
@Component({PosComp.class, DrawComp.class, TimedComp.class})
class EffectComp extends EntityComp{
@Component
abstract class EffectComp implements Posc, Drawc, Timedc{
Effect effect;
Color color = new Color(Color.white);
Object data;
float rotation = 0f;
void draw(){
public void draw(){
}
void update(){
public void update(){
//TODO fix effects, make everything poolable
}
}
@Component
abstract class VelComp extends PosComp{
abstract class VelComp implements Posc{
transient float x, y;
final Vec2 vel = new Vec2();
float drag = 0f;
void update(){
public void update(){
//TODO handle solidity
x += vel.x;
y += vel.y;
vel.scl(1f - drag * Time.delta());
}
}
@Component(PosComp.class)
class HitboxComp{
@Component
abstract class HitboxComp implements Posc{
transient float x, y;
float hitSize;
float lastX, lastY;
void update(){
public void update(){
}
@ -575,8 +1009,8 @@ public class EntityComps{
}
}
@Component(PosComp.class)
class StatusComp{
@Component
abstract class StatusComp implements Posc{
private Array<StatusEntry> statuses = new Array<>();
private Bits applied = new Bits(content.getBy(ContentType.status).size);
@ -584,6 +1018,11 @@ public class EntityComps{
private float damageMultiplier;
private float armorMultiplier;
/** @return damage taken based on status armor multipliers */
float getDamage(float amount){
return amount * Mathf.clamp(1f - armorMultiplier / 100f);
}
void apply(StatusEffect effect, float duration){
if(effect == StatusEffects.none || effect == null || isImmune(effect)) return; //don't apply empty or immune effects
@ -597,7 +1036,7 @@ public class EntityComps{
}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.effect.getTransition((mindustry.gen.Unitc)this, effect, entry.time, duration, StatusEntry.tmp);
entry.time = StatusEntry.tmp.time;
if(StatusEntry.tmp.effect != entry.effect){
@ -634,7 +1073,18 @@ public class EntityComps{
return Tmp.c1.set(r / statuses.size, g / statuses.size, b / statuses.size, 1f);
}
void update(){
public void update(){
Floor floor = floorOn();
Tile tile = tileOn();
boolean flying = false;
//TODO conditionally apply status effects on floor, if not flying
if(!flying && tile != null){
//apply effect
if(floor.status != null){
apply(floor.status, floor.statusDuration);
}
}
applied.clear();
speedMultiplier = damageMultiplier = armorMultiplier = 1f;
@ -651,8 +1101,8 @@ public class EntityComps{
speedMultiplier *= entry.effect.speedMultiplier;
armorMultiplier *= entry.effect.armorMultiplier;
damageMultiplier *= entry.effect.damageMultiplier;
//TODO unit can't be null
entry.effect.update(null, entry.time);
//TODO ugly casting
entry.effect.update((mindustry.gen.Unitc)this, entry.time);
}
return false;
@ -694,6 +1144,10 @@ public class EntityComps{
class EntityComp{
int id;
boolean isAdded(){
return true;
}
void init(){}
void update(){}
@ -707,8 +1161,7 @@ public class EntityComps{
}
boolean isLocal(){
//TODO fix
return this == (Object)Vars.player;
return this == Vars.player;
}
<T> T as(Class<T> type){

View File

@ -3,7 +3,6 @@ package mindustry.entities.effect;
import arc.graphics.g2d.Draw;
import arc.math.Mathf;
import mindustry.entities.EntityGroup;
import mindustry.entities.type.TimedEntity;
import mindustry.graphics.Pal;
import static mindustry.Vars.groundEffectGroup;

View File

@ -8,7 +8,6 @@ import arc.math.geom.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.game.EventType.*;
import mindustry.game.*;

View File

@ -6,7 +6,6 @@ import mindustry.Vars;
import mindustry.entities.Effects;
import mindustry.entities.Effects.Effect;
import mindustry.entities.Effects.EffectRenderer;
import mindustry.entities.type.EffectEntity;
import mindustry.world.Tile;
/**

View File

@ -1,22 +1,19 @@
package mindustry.entities.effect;
import mindustry.annotations.Annotations.Loc;
import mindustry.annotations.Annotations.Remote;
import arc.graphics.g2d.*;
import arc.math.Interpolation;
import arc.math.Mathf;
import arc.math.geom.Position;
import arc.math.geom.Vec2;
import arc.util.Time;
import arc.util.pooling.Pools;
import arc.math.*;
import arc.math.geom.*;
import arc.util.*;
import arc.util.pooling.*;
import mindustry.annotations.Annotations.*;
import mindustry.entities.*;
import mindustry.entities.type.TimedEntity;
import mindustry.entities.type.Unit;
import mindustry.graphics.Pal;
import mindustry.type.Item;
import mindustry.world.Tile;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.*;
import static mindustry.Vars.*;
import static mindustry.Vars.effectGroup;
public class ItemTransfer extends TimedEntity implements DrawTrait{
private Vec2 from = new Vec2();
@ -31,14 +28,14 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
}
@Remote(called = Loc.server, unreliable = true)
public static void transferItemEffect(Item item, float x, float y, Unit to){
public static void transferItemEffect(Item item, float x, float y, Itemsc to){
if(to == null) return;
create(item, x, y, to, () -> {
});
}
@Remote(called = Loc.server, unreliable = true)
public static void transferItemToUnit(Item item, float x, float y, Unit to){
public static void transferItemToUnit(Item item, float x, float y, Itemsc to){
if(to == null) return;
create(item, x, y, to, () -> to.addItem(item));
}

View File

@ -13,8 +13,6 @@ import mindustry.content.Bullets;
import mindustry.entities.EntityGroup;
import mindustry.entities.Units;
import mindustry.entities.type.Bullet;
import mindustry.entities.type.TimedEntity;
import mindustry.entities.type.Unit;
import mindustry.game.Team;
import mindustry.gen.Call;
import mindustry.graphics.Pal;
@ -27,7 +25,7 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
private static final Rand random = new Rand();
private static final Rect rect = new Rect();
private static final Array<Unit> entities = new Array<>();
private static final Array<Unitc> entities = new Array<>();
private static final IntSet hit = new IntSet();
private static final int maxChain = 8;
private static final float hitRange = 30f;
@ -98,7 +96,7 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
});
}
Unit furthest = Geometry.findFurthest(x, y, entities);
Unitc furthest = Geometry.findFurthest(x, y, entities);
if(furthest != null){
hit.add(furthest.getID());

View File

@ -11,8 +11,6 @@ import arc.util.pooling.Pool.*;
import arc.util.pooling.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.type.*;

View File

@ -1,285 +0,0 @@
package mindustry.entities.traits;
import arc.*;
import arc.struct.Queue;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.entities.type.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.BuildBlock.*;
import java.io.*;
import java.util.*;
import static mindustry.Vars.*;
import static mindustry.entities.traits.BuilderTrait.BuildDataStatic.*;
/** Interface for units that build things.*/
public interface BuilderTrait extends Entity, TeamTrait{
//these are not instance variables!
float placeDistance = 220f;
float mineDistance = 70f;
/** Updates building mechanism for this unit.*/
default void updateBuilding(){
float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : placeDistance;
Unit unit = (Unit)this;
Iterator<BuildRequest> it = buildQueue().iterator();
while(it.hasNext()){
BuildRequest req = it.next();
Tile tile = world.tile(req.x, req.y);
if(tile == null || (req.breaking && tile.block() == Blocks.air) || (!req.breaking && (tile.rotation() == req.rotation || !req.block.rotate) && tile.block() == req.block)){
it.remove();
}
}
TileEntity core = unit.getClosestCore();
//nothing to build.
if(buildRequest() == null) return;
//find the next build request
if(buildQueue().size > 1){
int total = 0;
BuildRequest req;
while((dst((req = buildRequest()).tile()) > finalPlaceDst || shouldSkip(req, core)) && total < buildQueue().size){
buildQueue().removeFirst();
buildQueue().addLast(req);
total++;
}
}
BuildRequest current = buildRequest();
if(dst(current.tile()) > finalPlaceDst) return;
Tile tile = world.tile(current.x, current.y);
if(!(tile.block() instanceof BuildBlock)){
if(!current.initialized && canCreateBlocks() && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){
Build.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation);
}else if(!current.initialized && canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){
Build.beginBreak(getTeam(), current.x, current.y);
}else{
buildQueue().removeFirst();
return;
}
}
if(tile.entity instanceof BuildEntity && !current.initialized){
Core.app.post(() -> Events.fire(new BuildSelectEvent(tile, unit.getTeam(), this, current.breaking)));
current.initialized = true;
}
//if there is no core to build with or no build entity, stop building!
if((core == null && !state.rules.infiniteResources) || !(tile.entity instanceof BuildEntity)){
return;
}
//otherwise, update it.
BuildEntity entity = tile.ent();
if(entity == null){
return;
}
if(unit.dst(tile) <= finalPlaceDst){
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f);
}
if(current.breaking){
entity.deconstruct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}else{
if(entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier, current.hasConfig)){
if(current.hasConfig){
Call.onTileConfig(null, tile, current.config);
}
}
}
current.stuck = Mathf.equal(current.progress, entity.progress);
current.progress = entity.progress;
}
/** @return whether this request should be skipped, in favor of the next one. */
default boolean shouldSkip(BuildRequest request, @Nullable TileEntity core){
//requests that you have at least *started* are considered
if(state.rules.infiniteResources || request.breaking || !request.initialized || core == null) return false;
return request.stuck && !core.items.has(request.block.requirements);
}
default void removeRequest(int x, int y, boolean breaking){
//remove matching request
int idx = player.buildQueue().indexOf(req -> req.breaking == breaking && req.x == x && req.y == y);
if(idx != -1){
player.buildQueue().removeIndex(idx);
}
}
/** Returns the queue for storing build requests. */
Queue<BuildRequest> buildQueue();
/** Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all. */
float getBuildPower(Tile tile);
/** Whether this type of builder can begin creating new blocks. */
default boolean canCreateBlocks(){
return true;
}
default void writeBuilding(DataOutput output) throws IOException{
BuildRequest request = buildRequest();
if(request != null && (request.block != null || request.breaking)){
output.writeByte(request.breaking ? 1 : 0);
output.writeInt(Pos.get(request.x, request.y));
output.writeFloat(request.progress);
if(!request.breaking){
output.writeShort(request.block.id);
output.writeByte(request.rotation);
}
}else{
output.writeByte(-1);
}
}
default void readBuilding(DataInput input) throws IOException{
readBuilding(input, true);
}
default void readBuilding(DataInput input, boolean applyChanges) throws IOException{
if(applyChanges) buildQueue().clear();
byte type = input.readByte();
if(type != -1){
int position = input.readInt();
float progress = input.readFloat();
BuildRequest request;
if(type == 1){ //remove
request = new BuildRequest(Pos.x(position), Pos.y(position));
}else{ //place
short block = input.readShort();
byte rotation = input.readByte();
request = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.block(block));
}
request.progress = progress;
if(applyChanges){
buildQueue().addLast(request);
}else if(isBuilding()){
BuildRequest last = buildRequest();
last.progress = progress;
if(last.tile() != null && last.tile().entity instanceof BuildEntity){
((BuildEntity)last.tile().entity).progress = progress;
}
}
}
}
/** Return whether this builder's place queue contains items. */
default boolean isBuilding(){
return buildQueue().size != 0;
}
/** Clears the placement queue. */
default void clearBuilding(){
buildQueue().clear();
}
/** Add another build requests to the tail of the queue, if it doesn't exist there yet. */
default void addBuildRequest(BuildRequest place){
addBuildRequest(place, true);
}
/** Add another build requests to the queue, if it doesn't exist there yet. */
default void addBuildRequest(BuildRequest place, boolean tail){
BuildRequest replace = null;
for(BuildRequest request : buildQueue()){
if(request.x == place.x && request.y == place.y){
replace = request;
break;
}
}
if(replace != null){
buildQueue().remove(replace);
}
Tile tile = world.tile(place.x, place.y);
if(tile != null && tile.entity instanceof BuildEntity){
place.progress = tile.<BuildEntity>ent().progress;
}
if(tail){
buildQueue().addLast(place);
}else{
buildQueue().addFirst(place);
}
}
/**
* Return the build requests currently active, or the one at the top of the queue.
* May return null.
*/
default @Nullable
BuildRequest buildRequest(){
return buildQueue().size == 0 ? null : buildQueue().first();
}
//due to iOS weirdness, this is apparently required
class BuildDataStatic{
static Vec2[] tmptr = new Vec2[]{new Vec2(), new Vec2(), new Vec2(), new Vec2()};
}
/** Draw placement effects for an entity. */
default void drawBuilding(){
if(!isBuilding()) return;
Unit unit = (Unit)this;
BuildRequest request = buildRequest();
Tile tile = world.tile(request.x, request.y);
if(dst(tile) > placeDistance && !state.isEditor()){
return;
}
Lines.stroke(1f, Pal.accent);
float focusLen = 3.8f + Mathf.absin(Time.time(), 1.1f, 0.6f);
float px = unit.x + Angles.trnsx(unit.rotation, focusLen);
float py = unit.y + Angles.trnsy(unit.rotation, focusLen);
float sz = Vars.tilesize * tile.block().size / 2f;
float ang = unit.angleTo(tile);
tmptr[0].set(tile.drawx() - sz, tile.drawy() - sz);
tmptr[1].set(tile.drawx() + sz, tile.drawy() - sz);
tmptr[2].set(tile.drawx() - sz, tile.drawy() + sz);
tmptr[3].set(tile.drawx() + sz, tile.drawy() + sz);
Arrays.sort(tmptr, (a, b) -> -Float.compare(Angles.angleDist(Angles.angle(unit.x, unit.y, a.x, a.y), ang),
Angles.angleDist(Angles.angle(unit.x, unit.y, b.x, b.y), ang)));
float x1 = tmptr[0].x, y1 = tmptr[0].y,
x3 = tmptr[1].x, y3 = tmptr[1].y;
Draw.alpha(1f);
Lines.line(px, py, x1, y1);
Lines.line(px, py, x3, y3);
Fill.circle(px, py, 1.6f + Mathf.absin(Time.time(), 0.8f, 1.5f));
Draw.color();
}
}

View File

@ -1,119 +0,0 @@
package mindustry.entities.traits;
import arc.Core;
import arc.graphics.Color;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.util.Time;
import mindustry.content.*;
import mindustry.entities.Effects;
import mindustry.entities.effect.*;
import mindustry.entities.type.*;
import mindustry.gen.Call;
import mindustry.graphics.*;
import mindustry.type.Item;
import mindustry.world.Tile;
import static mindustry.Vars.*;
public interface MinerTrait extends Entity{
/** Returns the range at which this miner can mine blocks.*/
default float getMiningRange(){
return 70f;
}
default boolean isMining(){
return getMineTile() != null;
}
/** Returns the tile this builder is currently mining. */
Tile getMineTile();
/** Sets the tile this builder is currently mining. */
void setMineTile(Tile tile);
/** Returns the mining speed of this miner. 1 = standard, 0.5 = half speed, 2 = double speed, etc. */
float getMinePower();
/** Returns whether or not this builder can mine a specific item type. */
boolean canMine(Item item);
/** @return whether to offload mined items immediately at the core. if false, items are collected and dropped in a burst. */
default boolean offloadImmediately(){
return false;
}
default void updateMining(){
Unit unit = (Unit)this;
Tile tile = getMineTile();
TileEntity core = unit.getClosestCore();
if(core != null && tile != null && tile.drop() != null && !unit.acceptsItem(tile.drop()) && unit.dst(core) < mineTransferRange){
int accepted = core.tile.block().acceptStack(unit.item().item, unit.item().amount, core.tile, unit);
if(accepted > 0){
Call.transferItemTo(unit.item().item, accepted,
tile.worldx() + Mathf.range(tilesize / 2f),
tile.worldy() + Mathf.range(tilesize / 2f), core.tile);
unit.clearItem();
}
}
if(tile == null || core == null || tile.block() != Blocks.air || dst(tile.worldx(), tile.worldy()) > getMiningRange()
|| tile.drop() == null || !unit.acceptsItem(tile.drop()) || !canMine(tile.drop())){
setMineTile(null);
}else{
Item item = tile.drop();
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(tile.worldx(), tile.worldy()), 0.4f);
if(Mathf.chance(Time.delta() * (0.06 - item.hardness * 0.01) * getMinePower())){
if(unit.dst(core) < mineTransferRange && core.tile.block().acceptStack(item, 1, core.tile, unit) == 1 && offloadImmediately()){
Call.transferItemTo(item, 1,
tile.worldx() + Mathf.range(tilesize / 2f),
tile.worldy() + Mathf.range(tilesize / 2f), core.tile);
}else if(unit.acceptsItem(item)){
//this is clientside, since items are synced anyway
ItemTransfer.transferItemToUnit(item,
tile.worldx() + Mathf.range(tilesize / 2f),
tile.worldy() + Mathf.range(tilesize / 2f),
unit);
}
}
if(Mathf.chance(0.06 * Time.delta())){
Effects.effect(Fx.pulverizeSmall,
tile.worldx() + Mathf.range(tilesize / 2f),
tile.worldy() + Mathf.range(tilesize / 2f), 0f, item.color);
}
}
}
default void drawMining(){
Unit unit = (Unit)this;
Tile tile = getMineTile();
if(tile == null) return;
float focusLen = 4f + Mathf.absin(Time.time(), 1.1f, 0.5f);
float swingScl = 12f, swingMag = tilesize / 8f;
float flashScl = 0.3f;
float px = unit.x + Angles.trnsx(unit.rotation, focusLen);
float py = unit.y + Angles.trnsy(unit.rotation, focusLen);
float ex = tile.worldx() + Mathf.sin(Time.time() + 48, swingScl, swingMag);
float ey = tile.worldy() + Mathf.sin(Time.time() + 48, swingScl + 2f, swingMag);
Draw.color(Color.lightGray, Color.white, 1f - flashScl + Mathf.absin(Time.time(), 0.5f, flashScl));
Drawf.laser(Core.atlas.find("minelaser"), Core.atlas.find("minelaser-end"), px, py, ex, ey, 0.75f);
if(unit instanceof Player && ((Player)unit).isLocal){
Lines.stroke(1f, Pal.accent);
Lines.poly(tile.worldx(), tile.worldy(), 4, tilesize / 2f * Mathf.sqrt2, Time.time());
}
Draw.color();
}
}

View File

@ -1,8 +0,0 @@
package mindustry.entities.traits;
/**
* Marks an entity as serializable.
*/
public interface SaveTrait extends Entity, TypeTrait, Saveable{
byte version();
}

View File

@ -1,18 +0,0 @@
package mindustry.entities.traits;
import arc.math.geom.Position;
import mindustry.entities.type.*;
import mindustry.world.Tile;
public interface SpawnerTrait extends TargetTrait, Position{
Tile getTile();
void updateSpawning(Player unit);
boolean hasUnit(Unit unit);
@Override
default boolean isValid(){
return getTile().entity instanceof SpawnerTrait;
}
}

View File

@ -1,65 +0,0 @@
package mindustry.entities.type;
import mindustry.entities.EntityGroup;
public abstract class BaseEntity implements Entity{
private static int lastid;
/** Do not modify. Used for network operations and mapping. */
public int id;
public float x, y;
protected transient EntityGroup group;
public BaseEntity(){
id = lastid++;
}
@Override
public int getID(){
return id;
}
@Override
public void resetID(int id){
this.id = id;
}
@Override
public EntityGroup getGroup(){
return group;
}
@Override
public void setGroup(EntityGroup group){
this.group = group;
}
@Override
public float getX(){
return x;
}
@Override
public void setX(float x){
this.x = x;
}
@Override
public float getY(){
return y;
}
@Override
public void setY(float y){
this.y = y;
}
@Override
public String toString(){
return getClass() + " " + id;
}
/** Increments this entity's ID. Used for pooled entities.*/
public void incrementID(){
id = lastid++;
}
}

View File

@ -11,7 +11,6 @@ import mindustry.*;
import mindustry.content.*;
import mindustry.ctype.ContentType;
import mindustry.entities.*;
import mindustry.entities.traits.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
@ -31,7 +30,7 @@ import java.io.*;
import static mindustry.Vars.*;
/** Base class for AI units. */
public abstract class BaseUnit extends Unit implements ShooterTrait{
public abstract class BaseUnit extends Unitc implements ShooterTrait{
protected static int timerIndex = 0;
protected static final int timerTarget = timerIndex++;
@ -151,7 +150,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
}
public void updateTargeting(){
if(target == null || (target instanceof Unit && (target.isDead() || target.getTeam() == team))
if(target == null || (target instanceof Unitc && (target.isDead() || target.getTeam() == team))
|| (target instanceof TileEntity && ((TileEntity)target).tile.entity == null)){
target = null;
}

View File

@ -9,7 +9,6 @@ import arc.util.pooling.*;
import mindustry.entities.*;
import mindustry.entities.bullet.*;
import mindustry.entities.effect.*;
import mindustry.entities.traits.*;
import mindustry.game.*;
import mindustry.graphics.*;
import mindustry.world.*;
@ -122,8 +121,8 @@ public class Bullet extends SolidEntity implements DamageTrait, Scaled, Poolable
}
public float damageMultiplier(){
if(owner instanceof Unit){
return ((Unit)owner).getDamageMultipler();
if(owner instanceof Unitc){
return ((Unitc)owner).getDamageMultipler();
}
return 1f;
}
@ -166,7 +165,7 @@ public class Bullet extends SolidEntity implements DamageTrait, Scaled, Poolable
@Override
public boolean collides(SolidTrait other){
return type.collides && (other != owner && !(other instanceof DamageTrait)) && !supressCollision && !(other instanceof Unit && ((Unit)other).isFlying() && !type.collidesAir);
return type.collides && (other != owner && !(other instanceof DamageTrait)) && !supressCollision && !(other instanceof Unitc && ((Unitc)other).isFlying() && !type.collidesAir);
}
@Override
@ -174,8 +173,8 @@ public class Bullet extends SolidEntity implements DamageTrait, Scaled, Poolable
if(!type.pierce) remove();
type.hit(this, x, y);
if(other instanceof Unit){
Unit unit = (Unit)other;
if(other instanceof Unitc){
Unitc unit = (Unitc)other;
unit.velocity().add(Tmp.v3.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.mass()));
unit.applyEffect(type.status, type.statusDuration);
}

View File

@ -1,79 +0,0 @@
package mindustry.entities.type;
import arc.graphics.*;
import arc.util.pooling.Pool.*;
import arc.util.pooling.*;
import mindustry.entities.*;
import mindustry.entities.Effects.*;
import mindustry.entities.traits.*;
import static mindustry.Vars.effectGroup;
public class EffectEntity extends TimedEntity implements Poolable, DrawTrait{
public Effect effect;
public Color color = new Color(Color.white);
public Object data;
public float rotation = 0f;
public Entity parent;
public float poffsetx, poffsety;
/** For pooling use only! */
public EffectEntity(){
}
public void setParent(Entity parent){
this.parent = parent;
this.poffsetx = x - parent.getX();
this.poffsety = y - parent.getY();
}
@Override
public EntityGroup targetGroup(){
//this should never actually be called
return effectGroup;
}
@Override
public float lifetime(){
return effect.lifetime;
}
@Override
public float drawSize(){
return effect.size;
}
@Override
public void update(){
if(effect == null){
remove();
return;
}
super.update();
if(parent != null){
x = parent.getX() + poffsetx;
y = parent.getY() + poffsety;
}
}
@Override
public void reset(){
effect = null;
color.set(Color.white);
rotation = time = poffsetx = poffsety = 0f;
parent = null;
data = null;
}
@Override
public void draw(){
Effects.renderEffect(id, effect, color, time, rotation, x, y, data);
}
@Override
public void removed(){
Pools.free(this);
}
}

View File

@ -34,7 +34,7 @@ import java.io.*;
import static mindustry.Vars.*;
public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public class Player extends Unitc implements BuilderMinerTrait, ShooterTrait{
public static final int timerSync = 2;
public static final int timerAbility = 3;
private static final float liftoffBoost = 0.2f;

View File

@ -21,7 +21,7 @@ import java.io.*;
import static mindustry.Vars.*;
public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
public class TileEntity{
public static final float timeToSleep = 60f * 1; //1 second to fall asleep
private static final ObjectSet<Tile> tmpTiles = new ObjectSet<>();
/** This value is only used for debugging. */
@ -112,10 +112,6 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
}
}
public boolean isSleeping(){
return sleeping;
}
public boolean isDead(){
return dead || tile.entity != this;
}
@ -256,26 +252,6 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
}
}
@Override
public void health(float health){
this.health = health;
}
@Override
public float health(){
return health;
}
@Override
public float maxHealth(){
return block.health;
}
@Override
public void setDead(boolean dead){
this.dead = dead;
}
@Override
public void onDeath(){
if(!dead){
@ -289,16 +265,6 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
}
}
@Override
public Team getTeam(){
return tile.getTeam();
}
@Override
public Vec2 velocity(){
return Vec2.ZERO;
}
@Override
public void update(){
timeScaleDuration -= Time.delta();
@ -339,11 +305,6 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
return !isDead() && tile.entity == this;
}
@Override
public EntityGroup targetGroup(){
return tileGroup;
}
@Override
public String toString(){
return "TileEntity{" +

View File

@ -1,33 +0,0 @@
package mindustry.entities.type;
import arc.util.pooling.Pool.*;
import mindustry.entities.traits.*;
public abstract class TimedEntity extends BaseEntity implements TimeTrait, Poolable{
public float time;
@Override
public void time(float time){
this.time = time;
}
@Override
public float time(){
return time;
}
@Override
public void update(){
updateTime();
}
@Override
public void reset(){
time = 0f;
}
@Override
public float fin(){
return time() / lifetime();
}
}

View File

@ -1,504 +0,0 @@
package mindustry.entities.type;
import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import arc.util.ArcAnnotate.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.effect.*;
import mindustry.entities.traits.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.net.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import java.io.*;
import static mindustry.Vars.*;
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, ShooterTrait{
/** Total duration of hit flash effect */
public static final float hitDuration = 9f;
/** Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks. */
public static final float velocityPercision = 8f;
/** Maximum absolute value of a velocity vector component. */
public static final float maxAbsVelocity = 127f / velocityPercision;
public static final int noSpawner = Pos.get(-1, 1);
private static final Vec2 moveVector = new Vec2();
public float rotation;
protected final Interpolator interpolator = new Interpolator();
/** status effects */
protected final Statuses status = new Statuses();
/** current item held */
protected final ItemStack item = new ItemStack(content.item(0), 0);
/** holds weapon aiming positions and angles */
protected final Weapons weapons = new Weapons();
/** team; can be changed at any time */
protected Team team = Team.sharded;
/** timers for drowning and getting hit */
protected float drownTime, hitTime;
/** this unit's type; do not change internally without calling setType(...) */
protected UnitDef type;
public void setType(UnitDef type){
this.type = type;
clampHealth();
weapons.init(this);
}
public UnitDef type(){
return type;
}
@Override
public boolean collidesGrid(int x, int y){
return !isFlying();
}
@Override
public Team getTeam(){
return team;
}
@Override
public Weapons getWeapons(){
return weapons;
}
@Override
public void interpolate(){
interpolator.update();
x = interpolator.pos.x;
y = interpolator.pos.y;
if(interpolator.values.length > 0){
rotation = interpolator.values[0];
}
}
@Override
public Interpolator getInterpolator(){
return interpolator;
}
@Override
public void damage(float amount){
if(!net.client()){
super.damage(calculateDamage(amount));
}
hitTime = hitDuration;
}
@Override
public boolean collides(SolidTrait other){
if(isDead()) return false;
if(other instanceof DamageTrait){
return other instanceof TeamTrait && (((TeamTrait)other).getTeam()).isEnemy(team);
}else{
return other instanceof Unit && ((Unit)other).isFlying() == isFlying();
}
}
@Override
public void onDeath(){
float explosiveness = 2f + item.item.explosiveness * item.amount;
float flammability = item.item.flammability * item.amount;
Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, getSize() / 2f, Pal.darkFlame);
ScorchDecal.create(x, y);
Fx.explosion.at(this);
Effects.shake(2f, 2f, this);
Sounds.bang.at(this);
item.amount = 0;
drownTime = 0f;
status.clear();
Events.fire(new UnitDestroyEvent(this));
if(explosiveness > 7f && this == player){
Events.fire(Trigger.suicideBomb);
}
}
@Override
public Vec2 velocity(){
return velocity;
}
@Override
public void move(float x, float y){
if(!isFlying()){
super.move(x, y);
}else{
moveBy(x, y);
}
}
@Override
public boolean isValid(){
return !isDead() && isAdded();
}
@Override
public void hitbox(Rect rect){
rect.setSize(type.hitsize).setCenter(x, y);
}
@Override
public void hitboxTile(Rect rect){
rect.setSize(type.hitsizeTile).setCenter(x, y);
}
@Override
public float drag(){
return type.drag;
}
@Override
public void writeSave(DataOutput stream) throws IOException{
writeSave(stream, false);
}
@Override
public void readSave(DataInput stream, byte version) throws IOException{
byte team = stream.readByte();
boolean dead = stream.readBoolean();
float x = stream.readFloat();
float y = stream.readFloat();
byte xv = stream.readByte();
byte yv = stream.readByte();
float rotation = stream.readShort() / 2f;
int health = stream.readShort();
byte itemID = stream.readByte();
short itemAmount = stream.readShort();
this.status.readSave(stream, version);
this.item.amount = itemAmount;
this.item.item = content.item(itemID);
this.dead = dead;
this.team = Team.get(team);
this.health = health;
this.x = x;
this.y = y;
this.velocity.set(xv / velocityPercision, yv / velocityPercision);
this.rotation = rotation;
}
public void writeSave(DataOutput stream, boolean net) throws IOException{
if(item.item == null) item.item = Items.copper;
stream.writeByte(team.id);
stream.writeBoolean(isDead());
stream.writeFloat(net ? interpolator.target.x : x);
stream.writeFloat(net ? interpolator.target.y : y);
stream.writeByte((byte)(Mathf.clamp(velocity.x, -maxAbsVelocity, maxAbsVelocity) * velocityPercision));
stream.writeByte((byte)(Mathf.clamp(velocity.y, -maxAbsVelocity, maxAbsVelocity) * velocityPercision));
stream.writeShort((short)(rotation * 2));
stream.writeShort((short)health);
stream.writeByte(item.item.id);
stream.writeShort((short)item.amount);
status.writeSave(stream);
}
protected void clampPosition(){
x = Mathf.clamp(x, 0, world.width() * tilesize - tilesize);
y = Mathf.clamp(y, 0, world.height() * tilesize - tilesize);
}
public boolean isImmune(StatusEffect effect){
return type.immunities.contains(effect);
}
public boolean isOutOfBounds(){
return x < -worldBounds || y < -worldBounds || x > world.width() * tilesize + worldBounds || y > world.height() * tilesize + worldBounds;
}
public float calculateDamage(float amount){
return amount * Mathf.clamp(1f - status.getArmorMultiplier() / 100f);
}
public float getDamageMultipler(){
return status.getDamageMultiplier();
}
public boolean hasEffect(StatusEffect effect){
return status.hasEffect(effect);
}
public void avoidOthers(){
float radScl = 1.5f;
float fsize = getSize() / radScl;
moveVector.setZero();
float cx = x - fsize/2f, cy = y - fsize/2f;
avoid(unitGroup.intersect(cx, cy, fsize, fsize));
if(!(this instanceof Player)){
avoid(playerGroup.intersect(cx, cy, fsize, fsize));
}
velocity.add(moveVector.x / mass() * Time.delta(), moveVector.y / mass() * Time.delta());
}
private void avoid(Array<? extends Unit> arr){
float radScl = 1.5f;
for(Unit en : arr){
if(en.isFlying() != isFlying() || (en instanceof Player && en.getTeam() != getTeam()) || (this instanceof Player && en.isFlying())) continue;
float dst = dst(en);
float scl = Mathf.clamp(1f - dst / (getSize()/(radScl*2f) + en.getSize()/(radScl*2f)));
moveVector.add(Tmp.v1.set((x - en.x) * scl, (y - en.y) * scl).limit(0.4f));
}
}
public @Nullable TileEntity getClosestCore(){
return state.teams.closestCore(x, y, team);
}
public Floor getFloorOn(){
Tile tile = world.tileWorld(x, y);
return tile == null ? (Floor)Blocks.air : tile.floor();
}
public @Nullable Tile tileOn(){
return world.tileWorld(x, y);
}
public void onRespawn(Tile tile){
}
/** Updates velocity and status effects. */
public void updateVelocityStatus(){
Floor floor = getFloorOn();
Tile tile = world.tileWorld(x, y);
status.update(this);
item.amount = Mathf.clamp(this.item.amount, 0, getItemCapacity());
//velocity.limit(maxVelocity()).scl(1f + (status.getSpeedMultiplier() - 1f) * Time.delta());
if(x < -finalWorldBounds || y < -finalWorldBounds || x >= world.width() * tilesize + finalWorldBounds || y >= world.height() * tilesize + finalWorldBounds){
kill();
}
//apply knockback based on spawns
if(getTeam() != state.rules.waveTeam){
float relativeSize = state.rules.dropZoneRadius + getSize()/2f + 1f;
for(Tile spawn : spawner.getGroundSpawns()){
if(withinDst(spawn.worldx(), spawn.worldy(), relativeSize)){
velocity.add(Tmp.v1.set(this).sub(spawn.worldx(), spawn.worldy()).setLength(0.1f + 1f - dst(spawn) / relativeSize).scl(0.45f * Time.delta()));
}
}
}
//repel player out of bounds
final float warpDst = 180f;
if(x < 0) velocity.x += (-x/warpDst);
if(y < 0) velocity.y += (-y/warpDst);
if(x > world.unitWidth()) velocity.x -= (x - world.unitWidth())/warpDst;
if(y > world.unitHeight()) velocity.y -= (y - world.unitHeight())/warpDst;
if(isFlying()){
drownTime = 0f;
move(velocity.x * Time.delta(), velocity.y * Time.delta());
}else{
boolean onLiquid = floor.isLiquid;
if(tile != null){
tile.block().unitOn(tile, this);
if(tile.block() != Blocks.air){
onLiquid = false;
}
}
if(onLiquid && velocity.len() > 0.4f && Mathf.chance((velocity.len() * floor.speedMultiplier) * 0.06f * Time.delta())){
floor.walkEffect.at(floor.color, x, y);
}
if(onLiquid){
status.handleApply(this, floor.status, floor.statusDuration);
if(floor.damageTaken > 0f){
damagePeriodic(floor.damageTaken);
}
}
if(onLiquid && floor.drownTime > 0){
drownTime += Time.delta() * 1f / floor.drownTime;
if(Mathf.chance(Time.delta() * 0.05f)){
floor.drownUpdateEffect.at(floor.color, x, y);
}
}else{
drownTime = Mathf.lerpDelta(drownTime, 0f, 0.03f);
}
drownTime = Mathf.clamp(drownTime);
if(drownTime >= 0.999f && !net.client()){
damage(health + 1);
if(this == player){
Events.fire(Trigger.drown);
}
}
float px = x, py = y;
move(velocity.x * floor.speedMultiplier * Time.delta(), velocity.y * floor.speedMultiplier * Time.delta());
if(Math.abs(px - x) <= 0.0001f) velocity.x = 0f;
if(Math.abs(py - y) <= 0.0001f) velocity.y = 0f;
}
//velocity.scl(Mathf.clamp(1f - drag() * (isFlying() ? 1f : floor.dragMultiplier) * Time.delta()));
}
public boolean acceptsItem(Item item){
return this.item.amount <= 0 || (this.item.item == item && this.item.amount <= getItemCapacity());
}
public void addItem(Item item){
addItem(item, 1);
}
public void addItem(Item item, int amount){
this.item.amount = this.item.item == item ? this.item.amount + amount : amount;
this.item.item = item;
this.item.amount = Mathf.clamp(this.item.amount, 0, getItemCapacity());
}
public void clearItem(){
item.amount = 0;
}
public ItemStack item(){
return item;
}
public int maxAccepted(Item item){
return this.item.item != item && this.item.amount > 0 ? 0 : getItemCapacity() - this.item.amount;
}
public void applyEffect(StatusEffect effect, float duration){
if(dead || net.client()) return; //effects are synced and thus not applied through clients
status.handleApply(this, effect, duration);
}
public void damagePeriodic(float amount){
damage(amount * Time.delta(), hitTime <= -20 + hitDuration);
}
public void damage(float amount, boolean withEffect){
float pre = hitTime;
damage(amount);
if(!withEffect){
hitTime = pre;
}
}
public void drawUnder(){
}
public void drawOver(){
}
public void drawStats(){
Draw.color(Color.black, team.color, healthf() + Mathf.absin(Time.time(), Math.max(healthf() * 5f, 1f), 1f - healthf()));
Draw.rect(getPowerCellRegion(), x, y, rotation - 90);
Draw.color();
drawBackItems(item.amount > 0 ? 1f : 0f, false);
drawLight();
}
public void drawLight(){
if(type.lightRadius > 0){
renderer.lights.add(x, y, type.lightRadius, type.lightColor, 0.6f);
}
}
public void drawBackItems(float itemtime, boolean number){
//draw back items
if(itemtime > 0.01f && item.item != null){
float backTrns = 5f;
float size = (itemSize + Mathf.absin(Time.time(), 5f, 1f)) * itemtime;
Draw.mixcol(Pal.accent, Mathf.absin(Time.time(), 5f, 0.5f));
Draw.rect(item.item.icon(Cicon.medium),
x + Angles.trnsx(rotation + 180f, backTrns),
y + Angles.trnsy(rotation + 180f, backTrns),
size, size, rotation);
Draw.mixcol();
Lines.stroke(1f, Pal.accent);
Lines.circle(
x + Angles.trnsx(rotation + 180f, backTrns),
y + Angles.trnsy(rotation + 180f, backTrns),
(3f + Mathf.absin(Time.time(), 5f, 1f)) * itemtime);
if(number){
Fonts.outline.draw(item.amount + "",
x + Angles.trnsx(rotation + 180f, backTrns),
y + Angles.trnsy(rotation + 180f, backTrns) - 3,
Pal.accent, 0.25f * itemtime / Scl.scl(1f), false, Align.center
);
}
}
Draw.reset();
}
public TextureRegion getPowerCellRegion(){
return Core.atlas.find("power-cell");
}
public void drawAll(){
if(!isDead()){
draw();
drawStats();
}
}
public void drawShadow(float offsetX, float offsetY){
Draw.rect(getIconRegion(), x + offsetX, y + offsetY, rotation - 90);
}
public float getSize(){
hitbox(Tmp.r1);
return Math.max(Tmp.r1.width, Tmp.r1.height) * 2f;
}
public abstract TextureRegion getIconRegion();
public final int getItemCapacity(){
return type.itemCapacity;
}
@Override
public float mass(){
return type.mass;
}
public boolean isFlying(){
return type.flying;
}
}

View File

@ -3,7 +3,6 @@ package mindustry.entities.type.base;
import arc.math.Mathf;
import arc.util.Structs;
import mindustry.content.Blocks;
import mindustry.entities.traits.MinerTrait;
import mindustry.entities.type.TileEntity;
import mindustry.entities.units.UnitState;
import mindustry.gen.Call;

View File

@ -7,8 +7,7 @@ import arc.util.*;
import arc.util.pooling.*;
import mindustry.content.*;
import mindustry.ctype.ContentType;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.entities.*;
import mindustry.type.*;
import java.io.*;
@ -27,7 +26,7 @@ public class Statuses implements Saveable{
private float damageMultiplier;
private float armorMultiplier;
public void handleApply(Unit unit, StatusEffect effect, float duration){
public void handleApply(Unitc unit, StatusEffect effect, float duration){
if(effect == StatusEffects.none || effect == null || unit.isImmune(effect)) return; //don't apply empty or immune effects
if(statuses.size > 0){
@ -76,7 +75,7 @@ public class Statuses implements Saveable{
statuses.clear();
}
public void update(Unit unit){
public void update(Unitc unit){
applied.clear();
speedMultiplier = damageMultiplier = armorMultiplier = 1f;

View File

@ -0,0 +1,5 @@
package mindustry.entities.units;
//TODO rename
public class UnitController{
}

View File

@ -1,13 +1,13 @@
package mindustry.game;
import arc.util.ArcAnnotate.*;
import mindustry.core.GameState.State;
import mindustry.ctype.UnlockableContent;
import mindustry.entities.traits.BuilderTrait;
import mindustry.core.GameState.*;
import mindustry.ctype.*;
import mindustry.entities.type.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.Tile;
import mindustry.world.*;
public class EventType{
@ -280,10 +280,10 @@ public class EventType{
public static class BuildSelectEvent{
public final Tile tile;
public final Team team;
public final BuilderTrait builder;
public final Builderc builder;
public final boolean breaking;
public BuildSelectEvent(Tile tile, Team team, BuilderTrait builder, boolean breaking){
public BuildSelectEvent(Tile tile, Team team, Builderc builder, boolean breaking){
this.tile = tile;
this.team = team;
this.builder = builder;
@ -302,17 +302,17 @@ public class EventType{
}
public static class UnitDestroyEvent{
public final Unit unit;
public final Unitc unit;
public UnitDestroyEvent(Unit unit){
public UnitDestroyEvent(Unitc unit){
this.unit = unit;
}
}
public static class UnitCreateEvent{
public final BaseUnit unit;
public final Unitc unit;
public UnitCreateEvent(BaseUnit unit){
public UnitCreateEvent(Unitc unit){
this.unit = unit;
}
}

View File

@ -22,7 +22,7 @@ import static mindustry.Vars.*;
public class MinimapRenderer implements Disposable{
private static final float baseSize = 16f;
private final Array<Unit> units = new Array<>();
private final Array<Unitc> units = new Array<>();
private Pixmap pixmap;
private Texture texture;
private TextureRegion region;
@ -87,7 +87,7 @@ public class MinimapRenderer implements Disposable{
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
for(Unit unit : units){
for(Unitc unit : units){
if(unit.isDead()) continue;
float rx = !withLabels ? (unit.x - rect.x) / rect.width * w : unit.x / (world.width() * tilesize) * w;
float ry = !withLabels ? (unit.y - rect.y) / rect.width * h : unit.y / (world.height() * tilesize) * h;

View File

@ -16,7 +16,6 @@ import mindustry.*;
import mindustry.content.*;
import mindustry.core.GameState.*;
import mindustry.entities.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
@ -69,7 +68,7 @@ public class MobileInput extends InputHandler implements GestureListener{
/** Check and assign targets for a specific position. */
void checkTargets(float x, float y){
Unit unit = Units.closestEnemy(player.getTeam(), x, y, 20f, u -> !u.isDead());
Unitc unit = Units.closestEnemy(player.getTeam(), x, y, 20f, u -> !u.isDead());
if(unit != null){
player.setMineTile(null);

View File

@ -8,7 +8,6 @@ import mindustry.core.*;
import mindustry.ctype.*;
import mindustry.ctype.ContentType;
import mindustry.entities.*;
import mindustry.entities.traits.*;
import mindustry.game.*;
import mindustry.game.Teams.*;
import mindustry.maps.*;

View File

@ -42,8 +42,8 @@ public class TypeIO{
return id == -1 ? null : playerGroup.getByID(id);
}
@WriteClass(Unit.class)
public static void writeUnit(ByteBuffer buffer, Unit unit){
@WriteClass(Unitc.class)
public static void writeUnit(ByteBuffer buffer, Unitc unit){
if(unit.getGroup() == null){
buffer.put((byte)-1);
return;
@ -52,12 +52,12 @@ public class TypeIO{
buffer.putInt(unit.getID());
}
@ReadClass(Unit.class)
public static Unit readUnit(ByteBuffer buffer){
@ReadClass(Unitc.class)
public static Unitc readUnit(ByteBuffer buffer){
byte gid = buffer.get();
if(gid == -1) return null;
int id = buffer.getInt();
return (Unit)entities.get(gid).getByID(id);
return (Unitc)entities.get(gid).getByID(id);
}
@WriteClass(ShooterTrait.class)

View File

@ -1,7 +1,7 @@
package mindustry.io.versions;
import arc.func.*;
import mindustry.entities.traits.*;
import mindustry.entities.*;
import java.io.*;

View File

@ -1,7 +1,7 @@
package mindustry.io.versions;
import mindustry.ctype.ContentType;
import mindustry.entities.traits.*;
import mindustry.entities.*;
import mindustry.io.*;
import mindustry.type.TypeID;

View File

@ -1,16 +1,14 @@
package mindustry.type;
import arc.struct.*;
import arc.graphics.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.ctype.*;
import mindustry.ctype.ContentType;
import mindustry.entities.*;
import mindustry.entities.Effects.*;
import mindustry.entities.type.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
public class StatusEffect extends MappableContent{
/** Damage dealt by the unit with the effect. */
@ -44,15 +42,15 @@ public class StatusEffect extends MappableContent{
}
/** Runs every tick on the affected unit while time is greater than 0. */
public void update(Unit unit, float time){
public void update(Unitc unit, float time){
if(damage > 0){
unit.damagePeriodic(damage);
unit.damageContinuous(damage);
}else if(damage < 0){ //heal unit
unit.healBy(damage * Time.delta());
unit.heal(damage * Time.delta());
}
if(effect != Fx.none && Mathf.chance(Time.delta() * 0.15f)){
effect.at(unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
effect.at(unit.getX() + Mathf.range(unit.getBounds() / 2f), unit.getY() + Mathf.range(unit.getBounds() / 2f));
}
}
@ -83,7 +81,7 @@ public class StatusEffect extends MappableContent{
* @param time The current status effect time
* @param newTime The time that the new status effect will last
*/
public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){
public StatusEntry getTransition(Unitc unit, StatusEffect to, float time, float newTime, StatusEntry result){
if(transitions.containsKey(to)){
transitions.get(to).handle(unit, time, newTime, result);
return result;
@ -98,6 +96,6 @@ public class StatusEffect extends MappableContent{
}
public interface TransitionHandler{
void handle(Unit unit, float time, float newTime, StatusEntry result);
void handle(Unitc unit, float time, float newTime, StatusEntry result);
}
}

View File

@ -49,7 +49,7 @@ public class UnitDef extends UnlockableContent{
public Sound deathSound = Sounds.bang;
public Array<Weapon> weapons = new Array<>();
public TextureRegion baseRegion, legRegion, region;
public TextureRegion baseRegion, legRegion, region, cellRegion;
public UnitDef(String name){
super(name);
@ -87,6 +87,7 @@ public class UnitDef extends UnlockableContent{
region = Core.atlas.find(name);
legRegion = Core.atlas.find(name + "-leg");
baseRegion = Core.atlas.find(name + "-base");
cellRegion = Core.atlas.find(name + "-cell", Core.atlas.find("power-cell"));
}
@Override
@ -96,13 +97,13 @@ public class UnitDef extends UnlockableContent{
//TODO remove methods below!
public void update(Unit player){
public void update(Unitc player){
}
public void draw(Unit player){
public void draw(Unitc player){
}
public void drawStats(Unit player){
public void drawStats(Unitc player){
if(drawCell){
float health = player.healthf();
Draw.color(Color.black, player.getTeam().color, health + Mathf.absin(Time.time(), health * 5f, 1f - health));
@ -118,25 +119,25 @@ public class UnitDef extends UnlockableContent{
}
}
public float getExtraArmor(Unit player){
public float getExtraArmor(Unitc player){
return 0f;
}
//TODO remove
public float spreadX(Unit player){
public float spreadX(Unitc player){
return 0f;
}
//TODO remove
public float getRotationAlpha(Unit player){
public float getRotationAlpha(Unitc player){
return 1f;
}
public boolean canShoot(Unit player){
public boolean canShoot(Unitc player){
return true;
}
public void onLand(Unit player){
public void onLand(Unitc player){
}
}

View File

@ -8,7 +8,6 @@ import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.core.GameState.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.net.*;
@ -66,7 +65,7 @@ public class PlayerListFragment extends Fragment{
float h = 74f;
playerGroup.all().sort(Structs.comparing(Unit::getTeam));
playerGroup.all().sort(Structs.comparing(Unitc::getTeam));
playerGroup.all().each(user -> {
NetConnection connection = user.con;

View File

@ -358,11 +358,11 @@ public class Block extends BlockStorage{
}
/** Called every frame a unit is on this tile. */
public void unitOn(Tile tile, Unit unit){
public void unitOn(Tile tile, Unitc unit){
}
/** Called when a unit that spawned at this tile is removed. */
public void unitRemoved(Tile tile, Unit unit){
public void unitRemoved(Tile tile, Unitc unit){
}
/** Returns whether ot not this block can be place on the specified tile. */

View File

@ -1,21 +1,18 @@
package mindustry.world;
import arc.struct.Array;
import arc.math.Mathf;
import arc.math.geom.Vec2;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.Vars;
import mindustry.content.Fx;
import mindustry.entities.Effects;
import mindustry.entities.effect.Puddle;
import mindustry.entities.type.TileEntity;
import mindustry.entities.type.Unit;
import mindustry.ctype.UnlockableContent;
import mindustry.type.Item;
import mindustry.type.Liquid;
import mindustry.world.consumers.Consumers;
import mindustry.world.meta.BlockBars;
import mindustry.world.meta.BlockStats;
import mindustry.*;
import mindustry.content.*;
import mindustry.ctype.*;
import mindustry.entities.effect.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.consumers.*;
import mindustry.world.meta.*;
public abstract class BlockStorage extends UnlockableContent{
public boolean hasItems;
@ -51,7 +48,7 @@ public abstract class BlockStorage extends UnlockableContent{
}
/** Returns the amount of items this block can accept. */
public int acceptStack(Item item, int amount, Tile tile, Unit source){
public int acceptStack(Item item, int amount, Tile tile, Teamc source){
if(acceptItem(item, tile, tile) && hasItems && (source == null || source.getTeam() == tile.getTeam())){
return Math.min(getMaximumAccepted(tile, item) - tile.entity.items.get(item), amount);
}else{
@ -73,7 +70,7 @@ public abstract class BlockStorage extends UnlockableContent{
}
/** Handle a stack input. */
public void handleStack(Item item, int amount, Tile tile, Unit source){
public void handleStack(Item item, int amount, Tile tile, Teamc source){
tile.entity.noSleep();
tile.entity.items.add(item, amount);
}

View File

@ -217,7 +217,7 @@ public class BuildBlock extends Block{
private float[] accumulator;
private float[] totalAccumulator;
public boolean construct(Unit builder, @Nullable TileEntity core, float amount, boolean configured){
public boolean construct(Unitc builder, @Nullable TileEntity core, float amount, boolean configured){
if(cblock == null){
kill();
return false;
@ -238,10 +238,7 @@ public class BuildBlock extends Block{
maxProgress = core == null ? maxProgress : checkRequired(core.items, maxProgress, true);
progress = Mathf.clamp(progress + maxProgress);
if(builder instanceof Player){
builderID = builder.getID();
}
builderID = builder.getId();
if(progress >= 1f || state.rules.infiniteResources){
constructed(tile, cblock, builderID, tile.rotation(), builder.getTeam(), configured);
@ -250,7 +247,7 @@ public class BuildBlock extends Block{
return false;
}
public void deconstruct(Unit builder, @Nullable TileEntity core, float amount){
public void deconstruct(Unitc builder, @Nullable TileEntity core, float amount){
float deconstructMultiplier = 0.5f;
if(cblock != null){

View File

@ -1,14 +1,14 @@
package mindustry.world.blocks;
import arc.*;
import arc.struct.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.graphics.g2d.TextureAtlas.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import mindustry.content.*;
import mindustry.entities.Effects.*;
import mindustry.entities.*;
import mindustry.graphics.*;
import mindustry.graphics.MultiPacker.*;
import mindustry.type.*;

View File

@ -9,9 +9,7 @@ import arc.math.geom.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.entities.type.BaseEntity;
import mindustry.graphics.*;
import mindustry.world.*;
import mindustry.world.consumers.*;

View File

@ -4,7 +4,6 @@ import arc.graphics.g2d.Draw;
import arc.graphics.g2d.Fill;
import arc.math.Mathf;
import mindustry.entities.effect.Lightning;
import mindustry.entities.type.Unit;
import mindustry.graphics.Layer;
import mindustry.graphics.Pal;
import mindustry.world.Block;
@ -49,7 +48,7 @@ public class ShockMine extends Block{
}
@Override
public void unitOn(Tile tile, Unit unit){
public void unitOn(Tile tile, Unitc unit){
if(unit.getTeam() != tile.getTeam() && tile.entity.timer.get(timerDamage, cooldown)){
for(int i = 0; i < tendrils; i++){
Lightning.create(tile.getTeam(), Pal.lancerLaser, damage, tile.drawx(), tile.drawy(), Mathf.random(360f), length);

View File

@ -86,7 +86,7 @@ public class ItemTurret extends CooledTurret{
}
@Override
public int acceptStack(Item item, int amount, Tile tile, Unit source){
public int acceptStack(Item item, int amount, Tile tile, Unitc source){
TurretEntity entity = tile.ent();
BulletType type = ammo.get(item);
@ -97,7 +97,7 @@ public class ItemTurret extends CooledTurret{
}
@Override
public void handleStack(Item item, int amount, Tile tile, Unit source){
public void handleStack(Item item, int amount, Tile tile, Unitc source){
for(int i = 0; i < amount; i++){
handleItem(item, tile, null);
}

View File

@ -138,7 +138,7 @@ public class Conveyor extends Block implements Autotiler{
}
@Override
public void unitOn(Tile tile, Unit unit){
public void unitOn(Tile tile, Unitc unit){
ConveyorEntity entity = tile.ent();
if(entity.clogHeat > 0.5f){
@ -256,13 +256,13 @@ public class Conveyor extends Block implements Autotiler{
}
@Override
public int acceptStack(Item item, int amount, Tile tile, Unit source){
public int acceptStack(Item item, int amount, Tile tile, Unitc source){
ConveyorEntity entity = tile.ent();
return Math.min((int)(entity.minitem / itemSpace), amount);
}
@Override
public void handleStack(Item item, int amount, Tile tile, Unit source){
public void handleStack(Item item, int amount, Tile tile, Unitc source){
ConveyorEntity e = tile.ent();
for(int i = amount - 1; i >= 0; i--){

View File

@ -2,7 +2,6 @@ package mindustry.world.blocks.distribution;
import arc.util.Time;
import mindustry.entities.type.TileEntity;
import mindustry.entities.type.Unit;
import mindustry.gen.BufferItem;
import mindustry.type.Item;
import mindustry.world.Block;
@ -31,7 +30,7 @@ public class Junction extends Block{
}
@Override
public int acceptStack(Item item, int amount, Tile tile, Unit source){
public int acceptStack(Item item, int amount, Tile tile, Unitc source){
return 0;
}

View File

@ -8,7 +8,6 @@ import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.game.EventType.*;
@ -239,7 +238,7 @@ public class CoreBlock extends StorageBlock{
protected int storageCapacity;
@Override
public boolean hasUnit(Unit unit){
public boolean hasUnit(Unitc unit){
return unit == spawnPlayer;
}

View File

@ -9,13 +9,11 @@ import arc.math.geom.*;
import arc.util.*;
import arc.util.ArcAnnotate.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.meta.*;
@ -143,7 +141,7 @@ public class MechPad extends Block{
float heat;
@Override
public boolean hasUnit(Unit unit){
public boolean hasUnit(Unitc unit){
return unit == player;
}

View File

@ -10,7 +10,6 @@ import arc.math.geom.Rect;
import arc.util.Time;
import mindustry.entities.Units;
import mindustry.entities.type.TileEntity;
import mindustry.entities.type.Unit;
import mindustry.graphics.*;
import mindustry.world.Block;
import mindustry.world.Tile;
@ -141,7 +140,7 @@ public class RepairPoint extends Block{
}
public class RepairPointEntity extends TileEntity{
public Unit target;
public Unitc target;
public float strength, rotation = 90;
}
}

View File

@ -109,7 +109,7 @@ public class UnitFactory extends Block{
}
@Override
public void unitRemoved(Tile tile, Unit unit){
public void unitRemoved(Tile tile, Unitc unit){
UnitFactoryEntity entity = tile.ent();
entity.spawned--;
entity.spawned = Math.max(entity.spawned, 0);