1
0
mirror of https://github.com/Anuken/Mindustry.git synced 2024-10-26 09:13:28 +03:00

Removing Nulls.unit

This commit is contained in:
Anuken 2024-07-10 15:54:46 -04:00
parent e3ba8b714b
commit 295573142f
12 changed files with 106 additions and 188 deletions

View File

@ -851,89 +851,6 @@ public class EntityProcess extends BaseProcessor{
for(TypeSpec.Builder b : baseClasses){
write(b, imports.toSeq());
}
//TODO nulls were an awful idea
//store nulls
TypeSpec.Builder nullsBuilder = TypeSpec.classBuilder("Nulls").addModifiers(Modifier.PUBLIC).addModifiers(Modifier.FINAL);
//TODO should be dynamic
ObjectSet<String> nullList = ObjectSet.with("unit");
//create mock types of all components
for(Stype interf : allInterfaces){
//indirect interfaces to implement methods for
Seq<Stype> dependencies = interf.allInterfaces().add(interf);
Seq<Smethod> methods = dependencies.flatMap(Stype::methods);
methods.sortComparing(Object::toString);
//optionally add superclass
Stype superclass = dependencies.map(this::interfaceToComp).find(s -> s != null && s.annotation(Component.class).base());
//use the base type when the interface being emulated has a base
TypeName type = superclass != null && interfaceToComp(interf).annotation(Component.class).base() ? tname(baseName(superclass)) : interf.tname();
//used method signatures
ObjectSet<String> signatures = new ObjectSet<>();
//create null builder
String baseName = interf.name().substring(0, interf.name().length() - 1);
//prevent Nulls bloat
if(!nullList.contains(Strings.camelize(baseName))){
continue;
}
String className = "Null" + baseName;
TypeSpec.Builder nullBuilder = TypeSpec.classBuilder(className)
.addModifiers(Modifier.FINAL);
skipDeprecated(nullBuilder);
nullBuilder.addSuperinterface(interf.tname());
if(superclass != null) nullBuilder.superclass(tname(baseName(superclass)));
for(Smethod method : methods){
String signature = method.toString();
if(!signatures.add(signature)) continue;
Stype compType = interfaceToComp(method.type());
MethodSpec.Builder builder = MethodSpec.overriding(method.e).addModifiers(Modifier.PUBLIC, Modifier.FINAL);
int index = 0;
for(ParameterSpec spec : builder.parameters){
Reflect.set(spec, "name", "arg" + index++);
}
builder.addAnnotation(OverrideCallSuper.class); //just in case
if(!method.isVoid()){
String methodName = method.name();
switch(methodName){
case "isNull":
builder.addStatement("return true");
break;
case "id":
builder.addStatement("return -1");
break;
case "toString":
builder.addStatement("return $S", className);
break;
default:
Svar variable = compType == null || method.params().size > 0 ? null : compType.fields().find(v -> v.name().equals(methodName));
String desc = variable == null ? null : variable.descString();
if(variable == null || !varInitializers.containsKey(desc)){
builder.addStatement("return " + getDefault(method.ret().toString()));
}else{
String init = varInitializers.get(desc);
builder.addStatement("return " + (init.equals("{}") ? "new " + variable.mirror().toString() : "") + init);
}
}
}
nullBuilder.addMethod(builder.build());
}
nullsBuilder.addField(FieldSpec.builder(type, Strings.camelize(baseName)).initializer("new " + className + "()").addModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PUBLIC).build());
write(nullBuilder, imports.toSeq());
}
write(nullsBuilder);
}
}

View File

@ -622,21 +622,22 @@ public class NetClient implements ApplicationListener{
void sync(){
if(timer.get(0, playerSyncTime)){
Unit unit = player.dead() ? Nulls.unit : player.unit();
int uid = player.dead() ? -1 : unit.id;
boolean dead = player.dead();
Unit unit = dead ? null : player.unit();
int uid = dead || unit == null ? -1 : unit.id;
Call.clientSnapshot(
lastSent++,
uid,
player.dead(),
player.dead() ? player.x : unit.x, player.dead() ? player.y : unit.y,
player.unit().aimX(), player.unit().aimY(),
unit.rotation,
dead,
dead ? player.x : unit.x, dead ? player.y : unit.y,
dead ? 0f : unit.aimX(), dead ? 0f : unit.aimY(),
unit == null ? 0f : unit.rotation,
unit instanceof Mechc m ? m.baseRotation() : 0,
unit.vel.x, unit.vel.y,
player.unit().mineTile,
unit == null ? 0f : unit.vel.x, unit == null ? 0f : unit.vel.y,
dead ? null : unit.mineTile,
player.boosting, player.shooting, ui.chatfrag.shown(), control.input.isBuilding,
player.isBuilder() ? player.unit().plans : null,
player.isBuilder() && unit != null ? unit.plans : null,
Core.camera.position.x, Core.camera.position.y,
Core.camera.width, Core.camera.height
);

View File

@ -660,12 +660,11 @@ public class NetServer implements ApplicationListener{
player.shooting = shooting;
player.boosting = boosting;
player.unit().controlWeapons(shooting, shooting);
player.unit().aim(pointerX, pointerY);
@Nullable var unit = player.unit();
if(player.isBuilder()){
player.unit().clearBuilding();
player.unit().updateBuilding(building);
unit.clearBuilding();
unit.updateBuilding(building);
if(plans != null){
for(BuildPlan req : plans){
@ -694,12 +693,12 @@ public class NetServer implements ApplicationListener{
}
}
player.unit().mineTile = mining;
con.rejectedRequests.clear();
if(!player.dead()){
Unit unit = player.unit();
unit.controlWeapons(shooting, shooting);
unit.aim(pointerX, pointerY);
unit.mineTile = mining;
long elapsed = Math.min(Time.timeSinceMillis(con.lastReceivedClientTime), 1500);
float maxSpeed = unit.speed();

View File

@ -35,10 +35,6 @@ abstract class EntityComp{
return ((Object)this) instanceof Unitc u && u.isPlayer() && !isLocal();
}
boolean isNull(){
return false;
}
/** Replaced with `this` after code generation. */
<T extends Entityc> T self(){
return (T)this;

View File

@ -33,7 +33,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
@Import float x, y;
@ReadOnly Unit unit = Nulls.unit;
@ReadOnly @Nullable Unit unit;
transient @Nullable NetConnection con;
@ReadOnly Team team = Team.sharded;
@SyncLocal boolean typing, shooting, boosting;
@ -49,12 +49,12 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
transient float textFadeTime;
transient Ratekeeper itemDepositRate = new Ratekeeper();
transient private Unit lastReadUnit = Nulls.unit;
transient private @Nullable Unit lastReadUnit;
transient private int wrongReadUnits;
transient @Nullable Unit justSwitchFrom, justSwitchTo;
public boolean isBuilder(){
return unit.canBuild();
return unit != null && unit.canBuild();
}
public @Nullable CoreBuild closestCore(){
@ -89,7 +89,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
x = y = 0f;
if(!dead()){
unit.resetController();
unit = Nulls.unit;
unit = null;
}
}
@ -105,7 +105,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
@Replace
public float clipSize(){
return unit.isNull() ? 20 : unit.type.hitSize * 2f;
return unit == null ? 20 : unit.type.hitSize * 2f;
}
@Override
@ -131,17 +131,18 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
unit = lastReadUnit;
unit(set);
lastReadUnit = unit;
if(unit != null){
unit.aim(mouseX, mouseY);
//this is only necessary when the thing being controlled isn't synced
unit.controlWeapons(shooting, shooting);
//extra precaution, necessary for non-synced things
unit.controller(this);
}
}
@Override
public void update(){
if(!unit.isValid()){
if(unit != null && !unit.isValid()){
clearUnit();
}
@ -181,42 +182,43 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
@Override
public void remove(){
//clear unit upon removal
if(!unit.isNull()){
if(unit != null){
clearUnit();
}
lastReadUnit = Nulls.unit;
lastReadUnit = null;
justSwitchTo = justSwitchFrom = null;
}
public void team(Team team){
this.team = team;
if(unit != null){
unit.team(team);
}
}
public void clearUnit(){
unit(Nulls.unit);
unit(null);
}
public Unit unit(){
public @Nullable Unit unit(){
return unit;
}
public void unit(Unit unit){
public void unit(@Nullable Unit unit){
//refuse to switch when the unit was just transitioned from
if(isLocal() && unit == justSwitchFrom && justSwitchFrom != null && justSwitchTo != null){
return;
}
if(unit == null) throw new IllegalArgumentException("Unit cannot be null. Use clearUnit() instead.");
if(this.unit == unit) return;
//save last command this unit had
if(unit.controller() instanceof CommandAI ai){
if(unit != null && unit.controller() instanceof CommandAI ai){
lastCommand = ai.command;
}
if(this.unit != Nulls.unit){
if(this.unit != null){
//un-control the old unit
this.unit.resetController();
//restore last command issued before it was controlled
@ -225,7 +227,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
}
}
this.unit = unit;
if(unit != Nulls.unit){
if(unit != null){
unit.team(team);
unit.controller(this);
@ -244,7 +246,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
}
boolean dead(){
return unit.isNull() || !unit.isValid();
return unit == null || !unit.isValid();
}
String ip(){

View File

@ -116,7 +116,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
private WidgetGroup group = new WidgetGroup();
private final Eachable<BuildPlan> allPlans = cons -> {
if(!player.dead()){
player.unit().plans().each(cons);
}
selectPlans.each(cons);
linePlans.each(cons);
};
@ -236,9 +238,6 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
public static void commandUnits(Player player, int[] unitIds, @Nullable Building buildTarget, @Nullable Unit unitTarget, @Nullable Vec2 posTarget, boolean queueCommand, boolean finalBatch){
if(player == null || unitIds == null) return;
//why did I ever think this was a good idea
if(unitTarget != null && unitTarget.isNull()) unitTarget = null;
if(net.server() && !netServer.admins.allowAction(player, ActionType.commandUnits, event -> {
event.unitIDs = unitIds;
})){
@ -489,8 +488,6 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
@Remote(targets = Loc.server, called = Loc.server)
public static void pickedUnitPayload(Unit unit, Unit target){
if(target == Nulls.unit) return;
if(target != null && unit instanceof Payloadc pay){
pay.pickup(target);
}else if(target != null){
@ -697,7 +694,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
player.unit(unit);
if(before != null && !before.isNull()){
if(before != null){
if(before.spawnedByCore){
unit.dockedType = before.type;
}else if(before.dockedType != null && before.dockedType.coreUnitDock){
@ -812,7 +809,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
}
playerPlanTree.clear();
if(!player.dead()){
player.unit().plans.each(playerPlanTree::insert);
}
player.typing = ui.chatfrag.shown();
@ -824,7 +823,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
player.unit().updateBuilding(isBuilding);
}
if(player.shooting && !wasShooting && player.unit().hasWeapons() && state.rules.unitAmmo && !player.team().rules().infiniteAmmo && player.unit().ammo <= 0){
if(!player.dead() && player.shooting && !wasShooting && player.unit().hasWeapons() && state.rules.unitAmmo && !player.team().rules().infiniteAmmo && player.unit().ammo <= 0){
player.unit().type.weapons.first().noAmmoSound.at(player.unit());
}

View File

@ -90,7 +90,7 @@ public class MobileInput extends InputHandler implements GestureListener{
void checkTargets(float x, float y){
Unit unit = Units.closestEnemy(player.team(), x, y, 20f, u -> !u.dead);
if(unit != null && player.unit().type.canAttack){
if(unit != null && !player.dead() && player.unit().type.canAttack){
player.unit().mineTile = null;
target = unit;
}else{
@ -126,6 +126,7 @@ public class MobileInput extends InputHandler implements GestureListener{
}
}
if(!player.dead()){
for(var plan : player.unit().plans()){
Tile other = world.tile(plan.x, plan.y);
@ -138,6 +139,8 @@ public class MobileInput extends InputHandler implements GestureListener{
return true;
}
}
}
return false;
}
@ -263,7 +266,7 @@ public class MobileInput extends InputHandler implements GestureListener{
}
boolean showCancel(){
return (player.unit().isBuilding() || block != null || mode == breaking || !selectPlans.isEmpty()) && !hasSchem();
return !player.dead() && (player.unit().isBuilding() || block != null || mode == breaking || !selectPlans.isEmpty()) && !hasSchem();
}
boolean hasSchem(){
@ -277,7 +280,9 @@ public class MobileInput extends InputHandler implements GestureListener{
t.visible(this::showCancel);
t.bottom().left();
t.button("@cancel", Icon.cancel, () -> {
if(!player.dead()){
player.unit().clearBuilding();
}
selectPlans.clear();
mode = none;
block = null;
@ -864,7 +869,7 @@ public class MobileInput extends InputHandler implements GestureListener{
}
}
if(player.shooting && (player.unit().activelyBuilding() || player.unit().mining())){
if(player.shooting && !player.dead() && (player.unit().activelyBuilding() || player.unit().mining())){
player.shooting = false;
}
}
@ -1037,7 +1042,7 @@ public class MobileInput extends InputHandler implements GestureListener{
unit.movePref(movement);
//update shooting if not building + not mining
if(!player.unit().activelyBuilding() && player.unit().mineTile == null){
if(!unit.activelyBuilding() && unit.mineTile == null){
//autofire targeting
if(manualShooting){
@ -1046,7 +1051,7 @@ public class MobileInput extends InputHandler implements GestureListener{
}else if(target == null){
player.shooting = false;
if(Core.settings.getBool("autotarget") && !(player.unit() instanceof BlockUnitUnit u && u.tile() instanceof ControlBlock c && !c.shouldAutoTarget())){
if(player.unit().type.canAttack){
if(unit.type.canAttack){
target = Units.closestTarget(unit.team, unit.x, unit.y, range, u -> u.checkTarget(type.targetAir, type.targetGround), u -> type.targetGround);
}

View File

@ -279,7 +279,7 @@ public class TypeIO{
}
public static void writeUnit(Writes write, Unit unit){
write.b(unit == null || unit.isNull() ? 0 : unit instanceof BlockUnitc ? 1 : 2);
write.b(unit == null ? 0 : unit instanceof BlockUnitc ? 1 : 2);
//block units are special
if(unit instanceof BlockUnitc){
@ -295,15 +295,14 @@ public class TypeIO{
byte type = read.b();
int id = read.i();
//nothing
if(type == 0) return Nulls.unit;
if(type == 0) return null;
if(type == 2){ //standard unit
Unit unit = Groups.unit.getByID(id);
return unit == null ? Nulls.unit : unit;
return Groups.unit.getByID(id);
}else if(type == 1){ //block
Building tile = world.build(id);
return tile instanceof ControlBlock cont ? cont.unit() : Nulls.unit;
return tile instanceof ControlBlock cont ? cont.unit() : null;
}
return Nulls.unit;
return null;
}
public static void writeCommand(Writes write, @Nullable UnitCommand command){

View File

@ -1242,7 +1242,7 @@ public class LExecutor{
result.setobj(units == null || i < 0 || i >= units.size ? null : units.get(i));
}
}
case player -> result.setobj(i < 0 || i >= data.players.size || data.players.get(i).unit().isNull() ? null : data.players.get(i).unit());
case player -> result.setobj(i < 0 || i >= data.players.size ? null : data.players.get(i).unit());
case core -> result.setobj(i < 0 || i >= data.cores.size ? null : data.cores.get(i));
case build -> {
Block block = extra.obj() instanceof Block b ? b : null;

View File

@ -152,7 +152,7 @@ public class BlockInventoryFragment{
container.add(i);
Boolp canPick = () -> player.unit().acceptsItem(item) && !state.isPaused() && player.within(build, itemTransferRange);
Boolp canPick = () -> !player.dead() && player.unit().acceptsItem(item) && !state.isPaused() && player.within(build, itemTransferRange);
HandCursorListener l = new HandCursorListener();
l.enabled = canPick;

View File

@ -167,7 +167,7 @@ public class HintsFragment{
zoom(visibleDesktop, () -> Core.input.axis(KeyCode.scroll) != 0),
breaking(() -> isTutorial.get() && state.rules.defaultTeam.data().getCount(Blocks.conveyor) > 5, () -> ui.hints.events.contains("break")),
desktopShoot(visibleDesktop, () -> isSerpulo() && Vars.state.enemies > 0, () -> player.shooting),
depositItems(() -> player.unit().hasItem(), () -> !player.unit().hasItem()),
depositItems(() -> !player.dead() && player.unit().hasItem(), () -> !player.dead() && !player.unit().hasItem()),
desktopPause(visibleDesktop, () -> isTutorial.get() && !Vars.net.active() && state.wave >= 2, () -> Core.input.keyTap(Binding.pause)),
unitControl(() -> isSerpulo() && state.rules.defaultTeam.data().units.size > 2 && !net.active() && !player.dead(), () -> !player.dead() && !player.unit().spawnedByCore),
unitSelectControl(() -> isSerpulo() && state.rules.defaultTeam.data().units.size > 3 && !net.active() && !player.dead(),
@ -179,8 +179,8 @@ public class HintsFragment{
boost(visibleDesktop, () -> !player.dead() && player.unit().type.canBoost, () -> Core.input.keyDown(Binding.boost)),
blockInfo(() -> !(state.isCampaign() && state.rules.sector == SectorPresets.groundZero.sector && state.wave < 3), () -> ui.content.isShown()),
derelict(() -> ui.hints.events.contains("derelictmouse") && !isTutorial.get(), () -> ui.hints.events.contains("derelictbreak")),
payloadPickup(() -> isSerpulo() && !player.unit().dead && player.unit() instanceof Payloadc p && p.payloads().isEmpty(), () -> player.unit() instanceof Payloadc p && p.payloads().any()),
payloadDrop(() -> !player.unit().dead && player.unit() instanceof Payloadc p && p.payloads().any(), () -> player.unit() instanceof Payloadc p && p.payloads().isEmpty()),
payloadPickup(() -> isSerpulo() && !player.dead() && player.unit() instanceof Payloadc p && p.payloads().isEmpty(), () -> player.unit() instanceof Payloadc p && p.payloads().any()),
payloadDrop(() -> !player.dead() && player.unit() instanceof Payloadc p && p.payloads().any(), () -> player.unit() instanceof Payloadc p && p.payloads().isEmpty()),
waveFire(() -> Groups.fire.size() > 0 && Blocks.wave.unlockedNow(), () -> indexer.getFlagged(state.rules.defaultTeam, BlockFlag.extinguisher).size > 0),
generator(() -> control.input.block == Blocks.combustionGenerator, () -> ui.hints.placedBlocks.contains(Blocks.combustionGenerator)),
rebuildSelect(() -> state.rules.defaultTeam.data().plans.size >= 10, () -> control.input.isRebuildSelecting()),

View File

@ -767,7 +767,7 @@ public class HudFragment{
}
});
t.add(new SideBar(() -> player.unit().healthf(), () -> true, true)).width(bw).growY().padRight(pad);
t.add(new SideBar(() -> player.dead() ? 0f : player.unit().healthf(), () -> true, true)).width(bw).growY().padRight(pad);
t.image(() -> player.icon()).scaling(Scaling.bounded).grow().maxWidth(54f);
t.add(new SideBar(() -> player.dead() ? 0f : player.displayAmmo() ? player.unit().ammof() : player.unit().healthf(), () -> !player.displayAmmo(), false)).width(bw).growY().padLeft(pad).update(b -> {
b.color.set(player.displayAmmo() ? player.dead() || player.unit() instanceof BlockUnitc ? Pal.ammo : player.unit().type.ammoType.color() : Pal.health);
@ -913,7 +913,7 @@ public class HudFragment{
table.table().update(t -> {
t.left();
Bits applied = player.unit().statusBits();
Bits applied = player.unit() == null ? null : player.unit().statusBits();
if(!statuses.equals(applied)){
t.clear();