Placement config code cleanup

This commit is contained in:
Anuken
2020-09-05 20:41:50 -04:00
parent c483ae2c23
commit f87bd78674
14 changed files with 67 additions and 92 deletions

View File

@@ -49,11 +49,7 @@ public class BuilderAI extends AIController{
blocks.removeFirst();
}else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid.
//add build request.
BuildPlan req = new BuildPlan(block.x, block.y, block.rotation, content.block(block.block));
if(block.config != null){
req.configure(block.config);
}
builder.addBuild(req);
builder.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config));
}else{
//shift head of queue to tail, try something else next time
blocks.removeFirst();

View File

@@ -325,7 +325,7 @@ public class UnitTypes implements ContentList{
mineSpeed = 7f;
drawShields = false;
abilities.add(new ForceFieldAbility(60f, 0.2f, 300f, 60f * 7));
abilities.add(new ForceFieldAbility(60f, 0.3f, 400f, 60f * 6));
weapons.add(new Weapon("beam-weapon"){{
shake = 2f;

View File

@@ -110,11 +110,7 @@ abstract class BuilderComp implements Unitc{
if(current.breaking){
entity.deconstruct(base(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier);
}else{
if(entity.construct(base(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier, current.hasConfig)){
if(current.hasConfig){
Call.tileConfig(null, tile.build, current.config);
}
}
entity.construct(base(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier, current.config);
}
current.stuck = Mathf.equal(current.progress, entity.progress);

View File

@@ -813,9 +813,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Called after the block is placed by this client. */
@CallSuper
public void playerPlaced(){
if(block.saveConfig && block.lastConfig != null){
configure(block.lastConfig);
}
}
/** Called after the block is placed by anyone. */
@@ -856,7 +854,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
/** Called when arbitrary configuration is applied to a tile. */
public void configured(@Nullable Player player, @Nullable Object value){
public void configured(@Nullable Unit builder, @Nullable Object value){
//null is of type void.class; anonymous classes use their superclass.
Class<?> type = value == null ? void.class : value.getClass().isAnonymousClass() ? value.getClass().getSuperclass() : value.getClass();

View File

@@ -16,8 +16,6 @@ public class BuildPlan{
public @Nullable Block block;
/** Whether this is a break request.*/
public boolean breaking;
/** Whether this request comes with a config int. If yes, any blocks placed with this request will not call playerPlaced.*/
public boolean hasConfig;
/** Config int. Not used unless hasConfig is true.*/
public Object config;
/** Original position, only used in schematics.*/
@@ -40,6 +38,16 @@ public class BuildPlan{
this.breaking = false;
}
/** This creates a build request with a config. */
public BuildPlan(int x, int y, int rotation, Block block, Object config){
this.x = x;
this.y = y;
this.rotation = rotation;
this.block = block;
this.breaking = false;
this.config = config;
}
/** This creates a remove request. */
public BuildPlan(int x, int y){
this.x = x;
@@ -84,7 +92,6 @@ public class BuildPlan{
copy.rotation = rotation;
copy.block = block;
copy.breaking = breaking;
copy.hasConfig = hasConfig;
copy.config = config;
copy.originalX = originalX;
copy.originalY = originalY;
@@ -127,12 +134,6 @@ public class BuildPlan{
return y*tilesize + block.offset;
}
public BuildPlan configure(Object config){
this.config = config;
this.hasConfig = true;
return this;
}
public @Nullable Tile tile(){
return world.tile(x, y);
}

View File

@@ -224,12 +224,14 @@ public class EventType{
public final Team team;
public final @Nullable Unit unit;
public final boolean breaking;
public final @Nullable Object config;
public BlockBuildEndEvent(Tile tile, @Nullable Unit unit, Team team, boolean breaking){
public BlockBuildEndEvent(Tile tile, @Nullable Unit unit, Team team, boolean breaking, @Nullable Object config){
this.tile = tile;
this.team = team;
this.unit = unit;
this.breaking = breaking;
this.config = config;
}
}

View File

@@ -247,7 +247,7 @@ public class Schematics implements Loadable{
Draw.rect(Tmp.tr1, buffer.getWidth()/2f, buffer.getHeight()/2f, buffer.getWidth(), -buffer.getHeight());
Draw.color();
Seq<BuildPlan> requests = schematic.tiles.map(t -> new BuildPlan(t.x, t.y, t.rotation, t.block).configure(t.config));
Seq<BuildPlan> requests = schematic.tiles.map(t -> new BuildPlan(t.x, t.y, t.rotation, t.block, t.config));
Draw.flush();
//scale each request to fit schematic
@@ -278,7 +278,7 @@ public class Schematics implements Loadable{
/** Creates an array of build requests from a schematic's data, centered on the provided x+y coordinates. */
public Seq<BuildPlan> toRequests(Schematic schem, int x, int y){
return schem.tiles.map(t -> new BuildPlan(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block).original(t.x, t.y, schem.width, schem.height).configure(t.config))
return schem.tiles.map(t -> new BuildPlan(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block, t.config).original(t.x, t.y, schem.width, schem.height))
.removeAll(s -> !s.block.isVisible() || !s.block.unlockedNow());
}

View File

@@ -215,11 +215,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
}
@Remote(targets = Loc.both, called = Loc.both, forward = true)
public static void tileConfig(Player player, Building tile, @Nullable Object value){
public static void tileConfig(@Nullable Player player, Building tile, @Nullable Object value){
if(tile == null) return;
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.configure, tile.tile(), action -> action.config = value))) throw new ValidateException(player, "Player cannot configure a tile.");
tile.configured(player, value);
tile.configured(player == null || player.dead() ? null : player.unit(), value);
Core.app.post(() -> Events.fire(new ConfigEvent(tile, player, value)));
}
@@ -645,13 +645,6 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
protected void drawRequest(BuildPlan request){
request.block.drawRequest(request, allRequests(), validPlace(request.x, request.y, request.block, request.rotation));
if(request.block.saveConfig && request.block.lastConfig != null && !request.hasConfig){
Object conf = request.config;
request.config = request.block.lastConfig;
request.block.drawRequestConfig(request, allRequests());
request.config = conf;
}
}
/** Draws a placement icon for a specific block. */
@@ -720,7 +713,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
lineRequests.clear();
iterateLine(x1, y1, x2, y2, l -> {
rotation = l.rotation;
BuildPlan req = new BuildPlan(l.x, l.y, l.rotation, block);
BuildPlan req = new BuildPlan(l.x, l.y, l.rotation, block, block.nextConfig());
req.animScale = 1f;
lineRequests.add(req);
});
@@ -993,13 +986,12 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
if(req != null){
player.builder().plans().remove(req);
}
player.builder().addBuild(new BuildPlan(x, y, rotation, block));
player.builder().addBuild(new BuildPlan(x, y, rotation, block, block.nextConfig()));
}
public void breakBlock(int x, int y){
Tile tile = world.tile(x, y);
//TODO hacky
if(tile != null && tile.build != null) tile = tile.build.tile();
if(tile != null && tile.build != null) tile = tile.build.tile;
player.builder().addBuild(new BuildPlan(tile.x, tile.y));
}

View File

@@ -569,7 +569,7 @@ public class MobileInput extends InputHandler implements GestureListener{
removeRequest(getRequest(cursor));
}else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, block, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, block)){
//add to selection queue if it's a valid place position
selectRequests.add(lastPlaced = new BuildPlan(cursor.x, cursor.y, rotation, block));
selectRequests.add(lastPlaced = new BuildPlan(cursor.x, cursor.y, rotation, block, block.nextConfig()));
}else if(mode == breaking && validBreak(linked.x,linked.y) && !hasRequest(linked)){
//add to selection queue if it's a valid BREAK position
selectRequests.add(new BuildPlan(linked.x, linked.y));

View File

@@ -231,7 +231,7 @@ public class TypeIO{
if(!request.breaking){
write.s(request.block.id);
write.b((byte)request.rotation);
write.b(request.hasConfig ? (byte)1 : 0);
write.b(1); //always has config
writeObject(write, request.config);
}
}
@@ -254,8 +254,9 @@ public class TypeIO{
boolean hasConfig = read.b() == 1;
Object config = readObject(read);
currentRequest = new BuildPlan(Point2.x(position), Point2.y(position), rotation, content.block(block));
//should always happen, but is kept for legacy reasons just in case
if(hasConfig){
currentRequest.configure(config);
currentRequest.config = config;
}
}

View File

@@ -27,21 +27,10 @@ public class Administration{
/** All player info. Maps UUIDs to info. This persists throughout restarts. Do not access directly. */
private ObjectMap<String, PlayerInfo> playerInfo = new ObjectMap<>();
private IntIntMap lastPlaced = new IntIntMap();
public Administration(){
load();
Events.on(ResetEvent.class, e -> lastPlaced = new IntIntMap());
//keep track of who placed what on the server
Events.on(BlockBuildEndEvent.class, e -> {
//players should be able to configure their own tiles
if(net.server() && e.unit != null && e.unit.isPlayer()){
lastPlaced.put(e.tile.pos(), e.unit.getPlayer().id());
}
});
//anti-spam
addChatFilter((player, message) -> {
long resetTime = Config.messageRateLimit.num() * 1000;
@@ -80,12 +69,6 @@ public class Administration{
action.type != ActionType.placeBlock &&
Config.antiSpam.bool()){
//make sure players can configure their own stuff, e.g. in schematics - but only once.
if(lastPlaced.get(action.tile.pos(), -1) == action.player.id()){
lastPlaced.remove(action.tile.pos());
return true;
}
Ratekeeper rate = action.player.getInfo().rate;
if(rate.allow(Config.interactRateWindow.num() * 1000, Config.interactRateLimit.num())){
return true;
@@ -93,13 +76,6 @@ public class Administration{
if(rate.occurences > Config.interactRateKick.num()){
action.player.kick("You are interacting with too many blocks.", 1000 * 30);
}else if(action.player.getInfo().messageTimer.get(60f * 2f)){
//I don't know what causes this so I'll make it log an error instead
new Exception("!!REPORT TO ANUKE: " + action.player.name + " was (likely) incorrectly ratelimited. " +
"action=" + action.type +
" player=" + action.player.name + "#" + action.player.id +
" tile=" + action.tile).printStackTrace();
action.player.sendMessage("[scarlet]You are interacting with blocks too quickly.");
}

View File

@@ -374,6 +374,13 @@ public class Block extends UnlockableContent{
return this;
}
public Object nextConfig(){
if(saveConfig && lastConfig != null){
return lastConfig;
}
return null;
}
public void drawRequest(BuildPlan req, Eachable<BuildPlan> list, boolean valid){
Draw.reset();
Draw.mixcol(!valid ? Pal.breakInvalid : Color.white, (!valid ? 0.4f : 0.24f) + Mathf.absin(Time.globalTime(), 6f, 0.28f));
@@ -389,7 +396,7 @@ public class Block extends UnlockableContent{
TextureRegion reg = getRequestRegion(req, list);
Draw.rect(reg, req.drawx(), req.drawy(), !rotate ? 0 : req.rotation * 90);
if(req.hasConfig){
if(req.config != null){
drawRequestConfig(req, list);
}
}

View File

@@ -48,26 +48,35 @@ public class BuildBlock extends Block{
}
@Remote(called = Loc.server)
public static void deconstructFinish(Tile tile, Block block, int builderID){
public static void deconstructFinish(Tile tile, Block block, Unit builder){
Team team = tile.team();
Fx.breakBlock.at(tile.drawx(), tile.drawy(), block.size);
Events.fire(new BlockBuildEndEvent(tile, Groups.unit.getByID(builderID), team, true));
Events.fire(new BlockBuildEndEvent(tile, builder, team, true, null));
tile.remove();
if(shouldPlay()) Sounds.breaks.at(tile, calcPitch(false));
}
@Remote(called = Loc.server)
public static void constructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){
public static void constructFinish(Tile tile, Block block, Unit builder, byte rotation, Team team, Object config){
if(tile == null) return;
float healthf = tile.build == null ? 1f : tile.build.healthf();
tile.setBlock(block, team, rotation);
if(tile.build != null) tile.build.health = block.health * healthf;
//last builder was this local client player, call placed()
if(tile.build != null && !headless && builderID == player.unit().id()){
if(!skipConfig){
tile.build.playerPlaced();
if(tile.build != null){
tile.build.health = block.health * healthf;
if(config != null){
tile.build.configured(builder, config);
}
}
//last builder was this local client player, call placed()
if(tile.build != null && !headless && builder == player.unit()){
tile.build.playerPlaced();
}
Fx.placeBlock.at(tile.drawx(), tile.drawy(), block.size);
}
@@ -95,11 +104,11 @@ public class BuildBlock extends Block{
}
}
public static void constructed(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){
Call.constructFinish(tile, block, builderID, rotation, team, skipConfig);
public static void constructed(Tile tile, Block block, Unit builder, byte rotation, Team team, Object config){
Call.constructFinish(tile, block, builder, rotation, team, config);
tile.build.placed();
Events.fire(new BlockBuildEndEvent(tile, Groups.unit.getByID(builderID), team, false));
Events.fire(new BlockBuildEndEvent(tile, builder, team, false, config));
if(shouldPlay()) Sounds.place.at(tile, calcPitch(true));
}
@@ -122,7 +131,7 @@ public class BuildBlock extends Block{
* If a non-recipe block is being deconstructed, this is the block that is being deconstructed.
*/
public Block previous;
public int builderID = -1;
public Object lastConfig;
private float[] accumulator;
private float[] totalAccumulator;
@@ -154,7 +163,7 @@ public class BuildBlock extends Block{
if(control.input.buildWasAutoPaused && !control.input.isBuilding && player.isBuilder()){
control.input.isBuilding = true;
}
player.builder().addBuild(new BuildPlan(tile.x, tile.y, rotation, cblock), false);
player.builder().addBuild(new BuildPlan(tile.x, tile.y, rotation, cblock, lastConfig), false);
}
}
@@ -190,12 +199,14 @@ public class BuildBlock extends Block{
});
}
public boolean construct(Unit builder, @Nullable Building core, float amount, boolean configured){
public void construct(Unit builder, @Nullable Building core, float amount, Object config){
if(cblock == null){
kill();
return false;
return;
}
lastConfig = config;
if(cblock.requirements.length != accumulator.length || totalAccumulator.length != cblock.requirements.length){
setConstruct(previous, cblock);
}
@@ -211,16 +222,13 @@ public class BuildBlock extends Block{
maxProgress = core == null || team.rules().infiniteResources ? maxProgress : checkRequired(core.items, maxProgress, true);
progress = Mathf.clamp(progress + maxProgress);
builderID = builder.id;
if(progress >= 1f || state.rules.infiniteResources){
constructed(tile, cblock, builderID, (byte)rotation, builder.team, configured);
return true;
constructed(tile, cblock, builder, (byte)rotation, builder.team, config);
}
return false;
}
public void deconstruct(Unitc builder, @Nullable Building core, float amount){
public void deconstruct(Unit builder, @Nullable Building core, float amount){
float deconstructMultiplier = state.rules.deconstructRefundMultiplier;
if(cblock != null){
@@ -253,10 +261,8 @@ public class BuildBlock extends Block{
progress = Mathf.clamp(progress - amount);
builderID = builder.id();
if(progress <= 0 || state.rules.infiniteResources){
Call.deconstructFinish(tile, this.cblock == null ? previous : this.cblock, builderID);
Call.deconstructFinish(tile, this.cblock == null ? previous : this.cblock, builder);
}
}

View File

@@ -51,7 +51,7 @@ public class Sorter extends Block{
public @Nullable Item sortItem;
@Override
public void configured(Player player, Object value){
public void configured(Unit player, Object value){
super.configured(player, value);
if(!headless){