mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-12-05 18:30:22 -08:00
Compare commits
5 commits
5397d8426c
...
f48900d6de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f48900d6de | ||
|
|
bb4534afde | ||
|
|
e8fc33ca9e | ||
|
|
11542f8e17 | ||
|
|
45e744949e |
15 changed files with 181 additions and 21 deletions
|
|
@ -290,6 +290,7 @@ public class Blocks{
|
|||
liquidDrop = Liquids.oil;
|
||||
isLiquid = true;
|
||||
cacheLayer = CacheLayer.tar;
|
||||
obstructsLight = true;
|
||||
}};
|
||||
|
||||
cryofluid = new Floor("pooled-cryofluid"){{
|
||||
|
|
@ -308,6 +309,8 @@ public class Blocks{
|
|||
emitLight = true;
|
||||
lightRadius = 25f;
|
||||
lightColor = Color.cyan.cpy().a(0.19f);
|
||||
obstructsLight = true;
|
||||
forceDrawLight = true;
|
||||
}};
|
||||
|
||||
slag = new Floor("molten-slag"){{
|
||||
|
|
@ -324,6 +327,8 @@ public class Blocks{
|
|||
emitLight = true;
|
||||
lightRadius = 40f;
|
||||
lightColor = Color.orange.cpy().a(0.38f);
|
||||
obstructsLight = true;
|
||||
forceDrawLight = true;
|
||||
}};
|
||||
|
||||
space = new Floor("space"){{
|
||||
|
|
@ -486,6 +491,7 @@ public class Blocks{
|
|||
drownTime = 200f;
|
||||
cacheLayer = CacheLayer.arkycite;
|
||||
albedo = 0.9f;
|
||||
obstructsLight = true;
|
||||
}};
|
||||
|
||||
arkyicStone = new Floor("arkyic-stone"){{
|
||||
|
|
@ -688,6 +694,7 @@ public class Blocks{
|
|||
sporeCluster = new Prop("spore-cluster"){{
|
||||
variants = 3;
|
||||
breakSound = Sounds.plantBreak;
|
||||
obstructsLight = false;
|
||||
}};
|
||||
|
||||
redweed = new Seaweed("redweed"){{
|
||||
|
|
@ -765,6 +772,7 @@ public class Blocks{
|
|||
variants = 3;
|
||||
customShadow = true;
|
||||
arkyicStone.asFloor().decoration = this;
|
||||
obstructsLight = false;
|
||||
}};
|
||||
|
||||
crystalCluster = new TallBlock("crystal-cluster"){{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import mindustry.game.*;
|
|||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
import mindustry.world.blocks.environment.Floor.*;
|
||||
import mindustry.world.blocks.power.*;
|
||||
|
||||
|
|
@ -50,6 +51,7 @@ public class BlockRenderer{
|
|||
|
||||
private BlockQuadtree blockTree = new BlockQuadtree(new Rect(0, 0, 1, 1));
|
||||
private BlockLightQuadtree blockLightTree = new BlockLightQuadtree(new Rect(0, 0, 1, 1));
|
||||
private OverlayQuadtree overlayTree = new OverlayQuadtree(new Rect(0, 0, 1, 1));
|
||||
private FloorQuadtree floorTree = new FloorQuadtree(new Rect(0, 0, 1, 1));
|
||||
|
||||
public BlockRenderer(){
|
||||
|
|
@ -76,13 +78,14 @@ public class BlockRenderer{
|
|||
});
|
||||
|
||||
Events.on(TilePreChangeEvent.class, event -> {
|
||||
if(blockTree == null || floorTree == null) return;
|
||||
if(blockTree == null || floorTree == null || overlayTree == null) return;
|
||||
|
||||
if(indexBlock(event.tile)){
|
||||
blockTree.remove(event.tile);
|
||||
blockLightTree.remove(event.tile);
|
||||
}
|
||||
if(indexFloor(event.tile)) floorTree.remove(event.tile);
|
||||
if(indexOverlay(event.tile)) overlayTree.remove(event.tile);
|
||||
});
|
||||
|
||||
Events.on(TileChangeEvent.class, event -> {
|
||||
|
|
@ -112,6 +115,7 @@ public class BlockRenderer{
|
|||
public void reload(){
|
||||
blockTree = new BlockQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight()));
|
||||
blockLightTree = new BlockLightQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight()));
|
||||
overlayTree = new OverlayQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight()));
|
||||
floorTree = new FloorQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight()));
|
||||
|
||||
shadowEvents.clear();
|
||||
|
|
@ -233,13 +237,25 @@ public class BlockRenderer{
|
|||
if(indexFloor(tile)) floorTree.insert(tile);
|
||||
}
|
||||
|
||||
public void removeOverlayIndex(Tile tile){
|
||||
if(indexOverlay(tile)) overlayTree.remove(tile);
|
||||
}
|
||||
|
||||
public void addOverlayIndex(Tile tile){
|
||||
if(indexOverlay(tile)) overlayTree.insert(tile);
|
||||
}
|
||||
|
||||
boolean indexBlock(Tile tile){
|
||||
var block = tile.block();
|
||||
return tile.isCenter() && block != Blocks.air && block.cacheLayer == CacheLayer.normal;
|
||||
}
|
||||
|
||||
boolean indexOverlay(Tile tile){
|
||||
return !tile.block().obstructsLight && tile.overlay().emitLight && world.getDarkness(tile.x, tile.y) < 3;
|
||||
}
|
||||
|
||||
boolean indexFloor(Tile tile){
|
||||
return tile.block() == Blocks.air && tile.floor().emitLight && world.getDarkness(tile.x, tile.y) < 3;
|
||||
return !tile.block().obstructsLight && tile.floor().emitLight && world.getDarkness(tile.x, tile.y) < 3;
|
||||
}
|
||||
|
||||
void recordIndex(Tile tile){
|
||||
|
|
@ -247,6 +263,7 @@ public class BlockRenderer{
|
|||
blockTree.insert(tile);
|
||||
blockLightTree.insert(tile);
|
||||
}
|
||||
if(indexOverlay(tile)) overlayTree.insert(tile);
|
||||
if(indexFloor(tile)) floorTree.insert(tile);
|
||||
}
|
||||
|
||||
|
|
@ -399,6 +416,7 @@ public class BlockRenderer{
|
|||
|
||||
//draw floor lights
|
||||
floorTree.intersect(bounds, lightview::add);
|
||||
overlayTree.intersect(bounds, lightview::add);
|
||||
|
||||
blockLightTree.intersect(bounds, tile -> {
|
||||
if(tile.block().emitLight && (tile.build == null || procLights.add(tile.build.pos()))){
|
||||
|
|
@ -518,8 +536,18 @@ public class BlockRenderer{
|
|||
entity.drawLight();
|
||||
}else if(tile.block().emitLight){
|
||||
tile.block().drawEnvironmentLight(tile);
|
||||
}else if(tile.floor().emitLight && tile.block() == Blocks.air){ //only draw floor light under non-solid blocks
|
||||
tile.floor().drawEnvironmentLight(tile);
|
||||
}
|
||||
|
||||
if(!tile.block().obstructsLight){
|
||||
Floor floor = tile.floor();
|
||||
Floor overlay = tile.overlay();
|
||||
|
||||
if(!floor.obstructsLight && overlay.emitLight){
|
||||
overlay.drawEnvironmentLight(tile);
|
||||
}
|
||||
if(floor.forceDrawLight || (!overlay.obstructsLight && floor.emitLight)){
|
||||
floor.drawEnvironmentLight(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -588,6 +616,23 @@ public class BlockRenderer{
|
|||
}
|
||||
}
|
||||
|
||||
static class OverlayQuadtree extends QuadTree<Tile>{
|
||||
public OverlayQuadtree(Rect bounds){
|
||||
super(bounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hitbox(Tile tile){
|
||||
var overlay = tile.overlay();
|
||||
tmp.setCentered(tile.worldx(), tile.worldy(), overlay.lightClipSize, overlay.lightClipSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected QuadTree<Tile> newChild(Rect rect){
|
||||
return new OverlayQuadtree(rect);
|
||||
}
|
||||
}
|
||||
|
||||
static class FloorQuadtree extends QuadTree<Tile>{
|
||||
|
||||
public FloorQuadtree(Rect bounds){
|
||||
|
|
|
|||
|
|
@ -197,12 +197,62 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||
build.items.set(item, amount);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void setItems(Building build, ItemStack[] items){
|
||||
if(build == null || build.items == null) return;
|
||||
|
||||
for(ItemStack stack : items){
|
||||
build.items.set(stack.item, stack.amount);
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void setTileItems(Item item, int amount, int[] positions){
|
||||
for(int pos : positions){
|
||||
Building build = world.build(pos);
|
||||
if(build != null && build.items != null){
|
||||
build.items.set(item, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void clearItems(Building build){
|
||||
if(build == null || build.items == null) return;
|
||||
build.items.clear();
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void setLiquid(Building build, Liquid liquid, float amount){
|
||||
if(build == null || build.liquids == null) return;
|
||||
build.liquids.set(liquid, amount);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void setLiquids(Building build, LiquidStack[] liquids){
|
||||
if(build == null || build.liquids == null) return;
|
||||
|
||||
for(LiquidStack stack : liquids){
|
||||
build.liquids.set(stack.liquid, stack.amount);
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void setTileLiquids(Liquid liquid, float amount, int[] positions){
|
||||
for(int pos : positions){
|
||||
Building build = world.build(pos);
|
||||
if(build != null && build.liquids != null){
|
||||
build.liquids.set(liquid, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void clearLiquids(Building build){
|
||||
if(build == null || build.liquids == null) return;
|
||||
build.liquids.clear();
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void transferItemTo(@Nullable Unit unit, Item item, int amount, float x, float y, Building build){
|
||||
if(build == null || build.items == null || item == null) return;
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
|||
//set block only if this is the center; otherwise, it's handled elsewhere
|
||||
if(isCenter){
|
||||
tile.setBlock(block);
|
||||
if(tile.build != null) tile.build.enabled = true;
|
||||
}
|
||||
|
||||
//must be assigned after setBlock, because that can reset data
|
||||
|
|
|
|||
|
|
@ -829,6 +829,39 @@ public class TypeIO{
|
|||
return new ItemStack(readItem(read), read.i());
|
||||
}
|
||||
|
||||
public static void writeItemStacks(Writes write, ItemStack[] stacks){
|
||||
write.s(stacks.length);
|
||||
for(ItemStack stack : stacks){
|
||||
writeItems(write, stack);
|
||||
}
|
||||
}
|
||||
|
||||
public static ItemStack[] readItemStacks(Reads read){
|
||||
short count = read.s();
|
||||
ItemStack[] stacks = new ItemStack[count];
|
||||
for(int i = 0; i < count; i++)
|
||||
stacks[i] = readItems(read);
|
||||
return stacks;
|
||||
}
|
||||
|
||||
public static void writeLiquidStacks(Writes write, LiquidStack[] stacks){
|
||||
write.s(stacks.length);
|
||||
for(LiquidStack stack : stacks){
|
||||
writeLiquid(write, stack.liquid);
|
||||
write.f(stack.amount);
|
||||
}
|
||||
}
|
||||
|
||||
public static LiquidStack[] readLiquidStacks(Reads read){
|
||||
short count = read.s();
|
||||
LiquidStack[] stacks = new LiquidStack[count];
|
||||
for(int i = 0; i < count; i++){
|
||||
Liquid liquid = readLiquid(read);
|
||||
stacks[i] = new LiquidStack(liquid, read.f());
|
||||
}
|
||||
return stacks;
|
||||
}
|
||||
|
||||
public static void writeTeam(Writes write, Team team){
|
||||
write.b(team == null ? 0 : team.id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ public abstract class LegacySaveVersion extends LegacyRegionSaveVersion{
|
|||
//do not override occupied cells
|
||||
if(!occupied){
|
||||
tile.setBlock(block);
|
||||
if(tile.build != null) tile.build.enabled = true;
|
||||
}
|
||||
|
||||
if(block.hasBuilding()){
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ public class ShortChunkSaveVersion extends SaveVersion{
|
|||
//set block only if this is the center; otherwise, it's handled elsewhere
|
||||
if(isCenter){
|
||||
tile.setBlock(block);
|
||||
if(tile.build != null) tile.build.enabled = true;
|
||||
}
|
||||
|
||||
//must be assigned after setBlock, because that can reset data
|
||||
|
|
|
|||
|
|
@ -321,6 +321,8 @@ public class Block extends UnlockableContent implements Senseable{
|
|||
public Color lightColor = Color.white.cpy();
|
||||
/** If true, drawLight() will be called for this block. */
|
||||
public boolean emitLight = false;
|
||||
/** If true, this block obstructs light emitted by other blocks. */
|
||||
public boolean obstructsLight = true;
|
||||
/** Radius of the light emitted by this block. */
|
||||
public float lightRadius = 60f;
|
||||
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ public class ForceProjector extends Block{
|
|||
float liquidHeat = (1f + (liquid.heatCapacity - 0.4f) * 0.9f);
|
||||
float regenBoost = ((cooldownNormal * (cooldownLiquid * liquidHeat)) - cooldownNormal) * 60f;
|
||||
float cooldownBoost = (shieldHealth / (cooldownBrokenBase * (cooldownLiquid * liquidHeat)) - shieldHealth / cooldownBrokenBase) / 60f;
|
||||
|
||||
|
||||
b.table(bt -> {
|
||||
bt.right().defaults().padRight(3).left();
|
||||
bt.add("[lightgray]+" + Core.bundle.format("bar.regenerationrate", Strings.autoFixed(regenBoost, 2))).pad(5).row();
|
||||
|
|
@ -156,6 +156,15 @@ public class ForceProjector extends Block{
|
|||
public boolean broken = true;
|
||||
public float buildup, radscl, hit, warmup, phaseHeat;
|
||||
|
||||
@Override
|
||||
public void setProp(LAccess prop, double value){
|
||||
if(prop == LAccess.shield){
|
||||
buildup = Math.max(shieldHealth + phaseShieldBoost * phaseHeat - (float)value, 0f);
|
||||
}else{
|
||||
super.setProp(prop, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float range(){
|
||||
return realRadius();
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ public class Floor extends Block{
|
|||
public Block decoration = Blocks.air;
|
||||
/** Whether units can draw shadows over this. */
|
||||
public boolean canShadow = true;
|
||||
/** If true, this floor ignores the obstructsLight flag of overlays. */
|
||||
public boolean forceDrawLight = false;
|
||||
/** Whether this overlay needs a surface to be on. False for floating blocks, like spawns. */
|
||||
public boolean needsSurface = true;
|
||||
/** If true, cores can be placed on this floor. */
|
||||
|
|
@ -110,6 +112,7 @@ public class Floor extends Block{
|
|||
allowRectanglePlacement = true;
|
||||
instantBuild = true;
|
||||
ignoreBuildDarkness = true;
|
||||
obstructsLight = false;
|
||||
placeEffect = Fx.rotateBlock;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ public class SeaBush extends Prop{
|
|||
public SeaBush(String name){
|
||||
super(name);
|
||||
variants = 0;
|
||||
obstructsLight = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ public class Seaweed extends Prop{
|
|||
|
||||
public Seaweed(String name){
|
||||
super(name);
|
||||
|
||||
obstructsLight = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ public class CanvasBlock extends Block{
|
|||
clipSize = Math.max(clipSize, size * 8 - padding);
|
||||
|
||||
previewPixmap = new Pixmap(canvasSize, canvasSize);
|
||||
|
||||
if(!Mathf.isPowerOfTwo(palette.length)) throw new RuntimeException("Non power-of-two palettes for canvas blocks are not supported.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -150,7 +152,7 @@ public class CanvasBlock extends Block{
|
|||
public @Nullable Texture texture;
|
||||
public byte[] data = new byte[Mathf.ceil(canvasSize * canvasSize * bitsPerPixel / 8f)];
|
||||
public int blending;
|
||||
|
||||
|
||||
protected boolean updated = false;
|
||||
|
||||
public void setPixel(int pos, int index){
|
||||
|
|
@ -286,7 +288,7 @@ public class CanvasBlock extends Block{
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double sense(LAccess sensor){
|
||||
return switch(sensor){
|
||||
|
|
@ -314,12 +316,12 @@ public class CanvasBlock extends Block{
|
|||
int[] curColor = {palette[0]};
|
||||
boolean[] modified = {false};
|
||||
boolean[] fill = {false};
|
||||
|
||||
|
||||
dialog.hidden(() -> {
|
||||
texture.dispose();
|
||||
pix.dispose();
|
||||
});
|
||||
|
||||
|
||||
dialog.resized(dialog::hide);
|
||||
|
||||
dialog.cont.table(Tex.pane, body -> {
|
||||
|
|
|
|||
|
|
@ -118,17 +118,19 @@ public class DesktopLauncher extends ClientLauncher{
|
|||
testMobile = Seq.with(args).contains("-testMobile");
|
||||
|
||||
if(useDiscord){
|
||||
try{
|
||||
DiscordRPC.connect(discordID);
|
||||
Log.info("Initialized Discord rich presence.");
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(DiscordRPC::close));
|
||||
}catch(NoDiscordClientException none){
|
||||
//don't log if no client is found
|
||||
useDiscord = false;
|
||||
}catch(Throwable t){
|
||||
useDiscord = false;
|
||||
Log.warn("Failed to initialize Discord RPC - you are likely using a JVM <16.");
|
||||
}
|
||||
Threads.daemon(() -> {
|
||||
try{
|
||||
DiscordRPC.connect(discordID);
|
||||
Log.info("Initialized Discord rich presence.");
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(DiscordRPC::close));
|
||||
}catch(NoDiscordClientException none){
|
||||
//don't log if no client is found
|
||||
useDiscord = false;
|
||||
}catch(Throwable t){
|
||||
useDiscord = false;
|
||||
Log.warn("Failed to initialize Discord RPC - you are likely using a JVM <16.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(useSteam){
|
||||
|
|
|
|||
|
|
@ -26,4 +26,4 @@ org.gradle.caching=true
|
|||
org.gradle.internal.http.socketTimeout=100000
|
||||
org.gradle.internal.http.connectionTimeout=100000
|
||||
android.enableR8.fullMode=false
|
||||
archash=9b4648505a
|
||||
archash=65d654d634
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue