Merge branch 'master' into crater
# Conflicts: # core/assets/sprites/block_colors.png # core/assets/sprites/sprites.atlas # core/assets/sprites/sprites.png # core/assets/sprites/sprites3.png # core/assets/sprites/sprites5.png
This commit is contained in:
@@ -49,7 +49,7 @@ public class Blocks implements ContentList{
|
||||
melter, separator, sporePress, pulverizer, incinerator, coalCentrifuge,
|
||||
|
||||
//sandbox
|
||||
powerSource, powerVoid, itemSource, itemVoid, liquidSource, message, illuminator,
|
||||
powerSource, powerVoid, itemSource, itemVoid, liquidSource, liquidVoid, message, illuminator,
|
||||
|
||||
//defense
|
||||
copperWall, copperWallLarge, titaniumWall, titaniumWallLarge, plastaniumWall, plastaniumWallLarge, thoriumWall, thoriumWallLarge, door, doorLarge,
|
||||
@@ -1823,6 +1823,11 @@ public class Blocks implements ContentList{
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
|
||||
liquidVoid = new LiquidVoid("liquid-void"){{
|
||||
requirements(Category.liquid, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
|
||||
message = new MessageBlock("message"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.graphite, 5));
|
||||
}};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package mindustry.content;
|
||||
|
||||
import arc.struct.Array;
|
||||
import mindustry.ctype.ContentList;
|
||||
import mindustry.type.ItemStack;
|
||||
import mindustry.world.Block;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.content.Blocks.*;
|
||||
|
||||
@@ -322,7 +323,7 @@ public class TechTree implements ContentList{
|
||||
private static TechNode node(Block block, Runnable children){
|
||||
ItemStack[] requirements = new ItemStack[block.requirements.length];
|
||||
for(int i = 0; i < requirements.length; i++){
|
||||
requirements[i] = new ItemStack(block.requirements[i].item, 30 + block.requirements[i].amount * 6);
|
||||
requirements[i] = new ItemStack(block.requirements[i].item, 40 + Mathf.round(Mathf.pow(block.requirements[i].amount, 1.25f) * 6, 10));
|
||||
}
|
||||
|
||||
return new TechNode(block, requirements, children);
|
||||
|
||||
@@ -47,8 +47,8 @@ public class Logic implements ApplicationListener{
|
||||
//blocks that get broken are appended to the team's broken block queue
|
||||
Tile tile = event.tile;
|
||||
Block block = tile.block();
|
||||
//skip null entities or nukes, for obvious reasons; also skip client since they can't modify these requests
|
||||
if(tile.entity == null || tile.block() instanceof NuclearReactor || net.client()) return;
|
||||
//skip null entities or un-rebuildables, for obvious reasons; also skip client since they can't modify these requests
|
||||
if(tile.entity == null || !tile.block().rebuildable || net.client()) return;
|
||||
|
||||
if(block instanceof BuildBlock){
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ public class NetClient implements ApplicationListener{
|
||||
throw new ValidateException(player, "Player has sent a message above the text limit.");
|
||||
}
|
||||
|
||||
String original = message;
|
||||
Events.fire(new PlayerChatEvent(player, message));
|
||||
|
||||
//check if it's a command
|
||||
CommandResponse response = netServer.clientCommands.handleMessage(message, player);
|
||||
@@ -197,8 +197,6 @@ public class NetClient implements ApplicationListener{
|
||||
player.sendMessage(text);
|
||||
}
|
||||
}
|
||||
|
||||
Events.fire(new PlayerChatEvent(player, message, original));
|
||||
}
|
||||
|
||||
public static String colorizeName(int id, String name){
|
||||
|
||||
@@ -15,6 +15,7 @@ import mindustry.entities.*;
|
||||
import mindustry.entities.traits.BuilderTrait.*;
|
||||
import mindustry.entities.traits.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.net.Administration;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
@@ -35,7 +36,7 @@ import static mindustry.Vars.*;
|
||||
|
||||
public class NetServer implements ApplicationListener{
|
||||
private final static int maxSnapshotSize = 430, timerBlockSync = 0;
|
||||
private final static float serverSyncTime = 12, kickDuration = 30 * 1000, blockSyncTime = 60 * 8;
|
||||
private final static float serverSyncTime = 12, blockSyncTime = 60 * 8;
|
||||
private final static Vec2 vector = new Vec2();
|
||||
private final static Rect viewport = new Rect();
|
||||
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
|
||||
@@ -75,7 +76,7 @@ public class NetServer implements ApplicationListener{
|
||||
public NetServer(){
|
||||
|
||||
net.handleServer(Connect.class, (con, connect) -> {
|
||||
if(admins.isIPBanned(connect.addressTCP)){
|
||||
if(admins.isIPBanned(connect.addressTCP) || admins.isSubnetBanned(connect.addressTCP)){
|
||||
con.kick(KickReason.banned);
|
||||
}
|
||||
});
|
||||
@@ -93,7 +94,7 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
String uuid = packet.uuid;
|
||||
|
||||
if(admins.isIPBanned(con.address)) return;
|
||||
if(admins.isIPBanned(con.address) || admins.isSubnetBanned(con.address)) return;
|
||||
|
||||
if(con.hasBegunConnecting){
|
||||
con.kick(KickReason.idInUse);
|
||||
@@ -115,7 +116,7 @@ public class NetServer implements ApplicationListener{
|
||||
return;
|
||||
}
|
||||
|
||||
if(Time.millis() - info.lastKicked < kickDuration){
|
||||
if(Time.millis() < info.lastKicked){
|
||||
con.kick(KickReason.recentKick);
|
||||
return;
|
||||
}
|
||||
@@ -413,6 +414,12 @@ public class NetServer implements ApplicationListener{
|
||||
if(player.isLocal){
|
||||
player.sendMessage("[scarlet]Re-synchronizing as the host is pointless.");
|
||||
}else{
|
||||
if(Time.timeSinceMillis(player.getInfo().lastSyncTime) < 1000 * 5){
|
||||
player.sendMessage("[scarlet]You may only /sync every 5 seconds.");
|
||||
return;
|
||||
}
|
||||
|
||||
player.getInfo().lastSyncTime = Time.millis();
|
||||
Call.onWorldDataBegin(player.con);
|
||||
netServer.sendWorldData(player);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public enum EditorTool{
|
||||
if(editor.drawBlock.isOverlay()){
|
||||
Block dest = tile.overlay();
|
||||
if(dest == editor.drawBlock) return;
|
||||
tester = t -> t.overlay() == dest;
|
||||
tester = t -> t.overlay() == dest && !t.floor().isLiquid;
|
||||
setter = t -> t.setOverlay(editor.drawBlock);
|
||||
}else if(editor.drawBlock.isFloor()){
|
||||
Block dest = tile.floor();
|
||||
|
||||
@@ -55,7 +55,7 @@ public class Predict{
|
||||
* See {@link #intercept(float, float, float, float, float, float, float)}.
|
||||
*/
|
||||
public static Vec2 intercept(TargetTrait src, TargetTrait dst, float v){
|
||||
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getTargetVelocityX() - src.getTargetVelocityX()/2f, dst.getTargetVelocityY() - src.getTargetVelocityY()/2f, v);
|
||||
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getTargetVelocityX() - src.getTargetVelocityX()/(2f*Time.delta()), dst.getTargetVelocityY() - src.getTargetVelocityY()/(2f*Time.delta()), v);
|
||||
}
|
||||
|
||||
private static Vec2 quad(float a, float b, float c){
|
||||
|
||||
@@ -48,8 +48,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
public float baseRotation;
|
||||
public float pointerX, pointerY;
|
||||
public String name = "noname";
|
||||
public @Nullable
|
||||
String uuid, usid;
|
||||
public @Nullable String uuid, usid;
|
||||
public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping, isBuilding = true;
|
||||
public boolean buildWasAutoPaused = false;
|
||||
public float boostHeat, shootHeat, destructTime;
|
||||
@@ -350,13 +349,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
public void drawBackItems(){
|
||||
drawBackItems(itemtime, isLocal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawStats(){
|
||||
Draw.color(Color.black, team.color, healthf() + Mathf.absin(Time.time(), healthf() * 5f, 1f - healthf()));
|
||||
Draw.rect(getPowerCellRegion(), x + Angles.trnsx(rotation, mech.cellTrnsY, 0f), y + Angles.trnsy(rotation, mech.cellTrnsY, 0f), rotation - 90);
|
||||
Draw.reset();
|
||||
drawBackItems(itemtime, isLocal);
|
||||
drawLight();
|
||||
mech.drawStats(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -252,6 +252,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
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());
|
||||
|
||||
@@ -341,6 +342,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
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(){
|
||||
|
||||
@@ -64,13 +64,10 @@ public class EventType{
|
||||
public static class PlayerChatEvent{
|
||||
public final Player player;
|
||||
public final String message;
|
||||
/** The original, unfiltered message. */
|
||||
public final String originalMessage;
|
||||
|
||||
public PlayerChatEvent(Player player, String message, String originalMessage){
|
||||
public PlayerChatEvent(Player player, String message){
|
||||
this.player = player;
|
||||
this.message = message;
|
||||
this.originalMessage = originalMessage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import arc.graphics.gl.Shader;
|
||||
* @author kalle_h
|
||||
*/
|
||||
public class Bloom{
|
||||
|
||||
/**
|
||||
* To use implement bloom more like a glow. Texture alpha channel can be
|
||||
* used as mask which part are glowing and which are not. see more info at:
|
||||
@@ -61,10 +60,8 @@ public class Bloom{
|
||||
*/
|
||||
public void resume(){
|
||||
bloomShader.begin();
|
||||
{
|
||||
bloomShader.setUniformi("u_texture0", 0);
|
||||
bloomShader.setUniformi("u_texture1", 1);
|
||||
}
|
||||
bloomShader.setUniformi("u_texture0", 0);
|
||||
bloomShader.setUniformi("u_texture1", 1);
|
||||
bloomShader.end();
|
||||
|
||||
setSize(w, h);
|
||||
@@ -83,13 +80,11 @@ public class Bloom{
|
||||
* blending = false 32bits = true
|
||||
*/
|
||||
public Bloom(){
|
||||
initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4,
|
||||
null, false, false, true);
|
||||
initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4, null, false, false, true);
|
||||
}
|
||||
|
||||
public Bloom(boolean useBlending){
|
||||
initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4,
|
||||
null, false, useBlending, true);
|
||||
initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4, null, false, useBlending, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,8 +100,7 @@ public class Bloom{
|
||||
* and only do blooming on certain objects param use32bitFBO does
|
||||
* fbo use higher precision than 16bits.
|
||||
*/
|
||||
public Bloom(int FBO_W, int FBO_H, boolean hasDepth, boolean useBlending,
|
||||
boolean use32bitFBO){
|
||||
public Bloom(int FBO_W, int FBO_H, boolean hasDepth, boolean useBlending, boolean use32bitFBO){
|
||||
initialize(FBO_W, FBO_H, null, hasDepth, useBlending, use32bitFBO);
|
||||
|
||||
}
|
||||
@@ -129,18 +123,14 @@ public class Bloom{
|
||||
* and only do blooming on certain objects param use32bitFBO does
|
||||
* fbo use higher precision than 16bits.
|
||||
*/
|
||||
public Bloom(int FBO_W, int FBO_H, FrameBuffer sceneIsCapturedHere,
|
||||
boolean useBlending, boolean use32bitFBO){
|
||||
|
||||
initialize(FBO_W, FBO_H, sceneIsCapturedHere, false, useBlending,
|
||||
use32bitFBO);
|
||||
public Bloom(int FBO_W, int FBO_H, FrameBuffer sceneIsCapturedHere, boolean useBlending, boolean use32bitFBO){
|
||||
initialize(FBO_W, FBO_H, sceneIsCapturedHere, false, useBlending, use32bitFBO);
|
||||
disposeFBO = false;
|
||||
}
|
||||
|
||||
private void initialize(int FBO_W, int FBO_H, FrameBuffer fbo,
|
||||
boolean hasDepth, boolean useBlending, boolean use32bitFBO){
|
||||
private void initialize(int FBO_W, int FBO_H, FrameBuffer fbo, boolean hasDepth, boolean useBlending, boolean use32bitFBO){
|
||||
blending = useBlending;
|
||||
Format format = null;
|
||||
Format format;
|
||||
|
||||
if(use32bitFBO){
|
||||
if(useBlending){
|
||||
@@ -157,8 +147,7 @@ public class Bloom{
|
||||
}
|
||||
}
|
||||
if(fbo == null){
|
||||
frameBuffer = new FrameBuffer(format, Core.graphics.getWidth(),
|
||||
Core.graphics.getHeight(), hasDepth);
|
||||
frameBuffer = new FrameBuffer(format, Core.graphics.getWidth(), Core.graphics.getHeight(), hasDepth);
|
||||
}else{
|
||||
frameBuffer = fbo;
|
||||
}
|
||||
@@ -190,10 +179,8 @@ public class Bloom{
|
||||
setThreshold(0.5f);
|
||||
|
||||
bloomShader.begin();
|
||||
{
|
||||
bloomShader.setUniformi("u_texture0", 0);
|
||||
bloomShader.setUniformi("u_texture1", 1);
|
||||
}
|
||||
bloomShader.setUniformi("u_texture0", 0);
|
||||
bloomShader.setUniformi("u_texture1", 1);
|
||||
bloomShader.end();
|
||||
}
|
||||
|
||||
@@ -219,8 +206,8 @@ public class Bloom{
|
||||
if(!capturing){
|
||||
capturing = true;
|
||||
frameBuffer.begin();
|
||||
Core.gl.glClearColor(r, g, b, a);
|
||||
Core.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
Gl.clearColor(r, g, b, a);
|
||||
Gl.clear(Gl.colorBufferBit);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -252,23 +239,22 @@ public class Bloom{
|
||||
frameBuffer.end();
|
||||
}
|
||||
|
||||
Core.gl.glDisable(GL20.GL_BLEND);
|
||||
Core.gl.glDisable(GL20.GL_DEPTH_TEST);
|
||||
Core.gl.glDepthMask(false);
|
||||
Gl.disable(Gl.blend);
|
||||
Gl.disable(Gl.depthTest);
|
||||
Gl.depthMask(false);
|
||||
|
||||
gaussianBlur();
|
||||
|
||||
if(blending){
|
||||
Core.gl.glEnable(GL20.GL_BLEND);
|
||||
Core.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
|
||||
Gl.enable(Gl.blend);
|
||||
Gl.blendFunc(Gl.srcAlpha, Gl.oneMinusSrcAlpha);
|
||||
}
|
||||
|
||||
pingPongTex1.bind(1);
|
||||
original.bind(0);
|
||||
|
||||
bloomShader.begin();
|
||||
{
|
||||
fullScreenQuad.render(bloomShader, GL20.GL_TRIANGLE_FAN);
|
||||
}
|
||||
fullScreenQuad.render(bloomShader, Gl.triangleFan);
|
||||
bloomShader.end();
|
||||
|
||||
}
|
||||
@@ -279,15 +265,9 @@ public class Bloom{
|
||||
|
||||
original.bind(0);
|
||||
pingPongBuffer1.begin();
|
||||
{
|
||||
tresholdShader.begin();
|
||||
{
|
||||
// tresholdShader.setUniformi("u_texture0", 0);
|
||||
fullScreenQuad.render(tresholdShader, GL20.GL_TRIANGLE_FAN, 0,
|
||||
4);
|
||||
}
|
||||
tresholdShader.end();
|
||||
}
|
||||
tresholdShader.begin();
|
||||
fullScreenQuad.render(tresholdShader, Gl.triangleFan, 0, 4);
|
||||
tresholdShader.end();
|
||||
pingPongBuffer1.end();
|
||||
|
||||
for(int i = 0; i < blurPasses; i++){
|
||||
@@ -296,30 +276,19 @@ public class Bloom{
|
||||
|
||||
// horizontal
|
||||
pingPongBuffer2.begin();
|
||||
{
|
||||
blurShader.begin();
|
||||
{
|
||||
blurShader.setUniformf("dir", 1f, 0f);
|
||||
fullScreenQuad.render(blurShader, GL20.GL_TRIANGLE_FAN, 0,
|
||||
4);
|
||||
}
|
||||
blurShader.end();
|
||||
}
|
||||
blurShader.begin();
|
||||
blurShader.setUniformf("dir", 1f, 0f);
|
||||
fullScreenQuad.render(blurShader, Gl.triangleFan, 0, 4);
|
||||
blurShader.end();
|
||||
pingPongBuffer2.end();
|
||||
|
||||
pingPongTex2.bind(0);
|
||||
// vertical
|
||||
pingPongBuffer1.begin();
|
||||
{
|
||||
blurShader.begin();
|
||||
{
|
||||
blurShader.setUniformf("dir", 0f, 1f);
|
||||
|
||||
fullScreenQuad.render(blurShader, GL20.GL_TRIANGLE_FAN, 0,
|
||||
4);
|
||||
}
|
||||
blurShader.end();
|
||||
}
|
||||
blurShader.begin();
|
||||
blurShader.setUniformf("dir", 0f, 1f);
|
||||
fullScreenQuad.render(blurShader, Gl.triangleFan, 0, 4);
|
||||
blurShader.end();
|
||||
pingPongBuffer1.end();
|
||||
}
|
||||
}
|
||||
@@ -334,9 +303,7 @@ public class Bloom{
|
||||
public void setBloomIntesity(float intensity){
|
||||
bloomIntensity = intensity;
|
||||
bloomShader.begin();
|
||||
{
|
||||
bloomShader.setUniformf("BloomIntensity", intensity);
|
||||
}
|
||||
bloomShader.setUniformf("BloomIntensity", intensity);
|
||||
bloomShader.end();
|
||||
}
|
||||
|
||||
@@ -350,9 +317,7 @@ public class Bloom{
|
||||
public void setOriginalIntesity(float intensity){
|
||||
originalIntensity = intensity;
|
||||
bloomShader.begin();
|
||||
{
|
||||
bloomShader.setUniformf("OriginalIntensity", intensity);
|
||||
}
|
||||
bloomShader.setUniformf("OriginalIntensity", intensity);
|
||||
bloomShader.end();
|
||||
}
|
||||
|
||||
@@ -364,10 +329,7 @@ public class Bloom{
|
||||
public void setThreshold(float threshold){
|
||||
this.threshold = threshold;
|
||||
tresholdShader.begin();
|
||||
{
|
||||
tresholdShader.setUniformf("threshold", threshold,
|
||||
1f / (1 - threshold));
|
||||
}
|
||||
tresholdShader.setUniformf("threshold", threshold, 1f / (1 - threshold));
|
||||
tresholdShader.end();
|
||||
}
|
||||
|
||||
@@ -384,8 +346,7 @@ public class Bloom{
|
||||
*/
|
||||
public void dispose(){
|
||||
try{
|
||||
if(disposeFBO)
|
||||
frameBuffer.dispose();
|
||||
if(disposeFBO) frameBuffer.dispose();
|
||||
|
||||
fullScreenQuad.dispose();
|
||||
|
||||
@@ -395,16 +356,17 @@ public class Bloom{
|
||||
blurShader.dispose();
|
||||
bloomShader.dispose();
|
||||
tresholdShader.dispose();
|
||||
}catch(Exception ignored){
|
||||
}catch(Throwable ignored){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static Mesh createFullScreenQuad(){
|
||||
float[] verts = {-1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1, -1, 1, 0, 1};
|
||||
Mesh tmpMesh = new Mesh(true, 4, 0, new VertexAttribute(
|
||||
Usage.Position, 2, "a_position"), new VertexAttribute(
|
||||
Usage.TextureCoordinates, 2, "a_texCoord0"));
|
||||
Mesh tmpMesh = new Mesh(true, 4, 0,
|
||||
new VertexAttribute(Usage.position, 2, "a_position"),
|
||||
new VertexAttribute(Usage.textureCoordinates, 2, "a_texCoord0")
|
||||
);
|
||||
|
||||
tmpMesh.setVertices(verts);
|
||||
return tmpMesh;
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.Core;
|
||||
import arc.Events;
|
||||
import arc.struct.*;
|
||||
import arc.struct.IntSet.IntSetIterator;
|
||||
import arc.graphics.Camera;
|
||||
import arc.graphics.GL20;
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.Mathf;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.struct.IntSet.*;
|
||||
import arc.util.*;
|
||||
import mindustry.game.EventType.WorldLoadEvent;
|
||||
import mindustry.world.Tile;
|
||||
import mindustry.world.blocks.Floor;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.*;
|
||||
|
||||
import static mindustry.Vars.tilesize;
|
||||
import static mindustry.Vars.world;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class FloorRenderer implements Disposable{
|
||||
private final static int chunksize = 64;
|
||||
@@ -104,7 +101,7 @@ public class FloorRenderer implements Disposable{
|
||||
cbatch.setProjection(Core.camera.projection());
|
||||
cbatch.beginDraw();
|
||||
|
||||
Core.gl.glEnable(GL20.GL_BLEND);
|
||||
Gl.enable(Gl.blend);
|
||||
}
|
||||
|
||||
public void endDraw(){
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
package mindustry.graphics;
|
||||
|
||||
import arc.Core;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.VertexAttributes.Usage;
|
||||
import arc.graphics.g2d.BatchShader;
|
||||
import arc.graphics.g2d.TextureRegion;
|
||||
import arc.graphics.gl.Shader;
|
||||
import arc.math.Mathf;
|
||||
import arc.math.Matrix3;
|
||||
import arc.util.Disposable;
|
||||
import arc.util.Strings;
|
||||
import arc.graphics.VertexAttributes.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.graphics.gl.*;
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
|
||||
//TODO this class is a trainwreck, remove it
|
||||
public class IndexedRenderer implements Disposable{
|
||||
@@ -17,18 +13,18 @@ public class IndexedRenderer implements Disposable{
|
||||
|
||||
private Shader program = new Shader(
|
||||
Strings.join("\n",
|
||||
"attribute vec4 " + Shader.POSITION_ATTRIBUTE + ";",
|
||||
"attribute vec4 " + Shader.COLOR_ATTRIBUTE + ";",
|
||||
"attribute vec2 " + Shader.TEXCOORD_ATTRIBUTE + "0;",
|
||||
"attribute vec4 " + Shader.positionAttribute + ";",
|
||||
"attribute vec4 " + Shader.colorAttribute + ";",
|
||||
"attribute vec2 " + Shader.texcoordAttribute + "0;",
|
||||
"uniform mat4 u_projTrans;",
|
||||
"varying vec4 v_color;",
|
||||
"varying vec2 v_texCoords;",
|
||||
"",
|
||||
"void main(){",
|
||||
" v_color = " + Shader.COLOR_ATTRIBUTE + ";",
|
||||
" v_color = " + Shader.colorAttribute + ";",
|
||||
" v_color.a = v_color.a * (255.0/254.0);",
|
||||
" v_texCoords = " + Shader.TEXCOORD_ATTRIBUTE + "0;",
|
||||
" gl_Position = u_projTrans * " + Shader.POSITION_ATTRIBUTE + ";",
|
||||
" v_texCoords = " + Shader.texcoordAttribute + "0;",
|
||||
" gl_Position = u_projTrans * " + Shader.positionAttribute + ";",
|
||||
"}"),
|
||||
Strings.join("\n",
|
||||
"#ifdef GL_ES",
|
||||
@@ -60,7 +56,7 @@ public class IndexedRenderer implements Disposable{
|
||||
}
|
||||
|
||||
public void render(Texture texture){
|
||||
Core.gl.glEnable(GL20.GL_BLEND);
|
||||
Gl.enable(Gl.blend);
|
||||
|
||||
updateMatrix();
|
||||
|
||||
@@ -71,7 +67,7 @@ public class IndexedRenderer implements Disposable{
|
||||
program.setUniformMatrix4("u_projTrans", BatchShader.copyTransform(combined));
|
||||
program.setUniformi("u_texture", 0);
|
||||
|
||||
mesh.render(program, GL20.GL_TRIANGLES, 0, vertices.length / vsize);
|
||||
mesh.render(program, Gl.triangles, 0, vertices.length / vsize);
|
||||
|
||||
program.end();
|
||||
}
|
||||
@@ -226,9 +222,9 @@ public class IndexedRenderer implements Disposable{
|
||||
if(mesh != null) mesh.dispose();
|
||||
|
||||
mesh = new Mesh(true, 6 * sprites, 0,
|
||||
new VertexAttribute(Usage.Position, 2, "a_position"),
|
||||
new VertexAttribute(Usage.ColorPacked, 4, "a_color"),
|
||||
new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoord0"));
|
||||
new VertexAttribute(Usage.position, 2, "a_position"),
|
||||
new VertexAttribute(Usage.colorPacked, 4, "a_color"),
|
||||
new VertexAttribute(Usage.textureCoordinates, 2, "a_texCoord0"));
|
||||
vertices = new float[6 * sprites * vsize];
|
||||
mesh.setVertices(vertices);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package mindustry.net;
|
||||
|
||||
import arc.*;
|
||||
import arc.func.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
import arc.util.pooling.*;
|
||||
import arc.util.pooling.Pool.*;
|
||||
import mindustry.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.headless;
|
||||
import static mindustry.game.EventType.*;
|
||||
@@ -16,9 +22,61 @@ public class Administration{
|
||||
private Array<String> bannedIPs = new Array<>();
|
||||
private Array<String> whitelist = new Array<>();
|
||||
private Array<ChatFilter> chatFilters = new Array<>();
|
||||
private Array<ActionFilter> actionFilters = new Array<>();
|
||||
private Array<String> subnetBans = new Array<>();
|
||||
|
||||
public Administration(){
|
||||
load();
|
||||
|
||||
//anti-spam
|
||||
addChatFilter((player, message) -> {
|
||||
long resetTime = Config.messageRateLimit.num() * 1000;
|
||||
if(Config.antiSpam.bool() && !player.isLocal && !player.isAdmin){
|
||||
//prevent people from spamming messages quickly
|
||||
if(resetTime > 0 && Time.timeSinceMillis(player.getInfo().lastMessageTime) < resetTime){
|
||||
//supress message
|
||||
player.sendMessage("[scarlet]You may only send messages every " + Config.messageRateLimit.num() + " seconds.");
|
||||
player.getInfo().messageInfractions ++;
|
||||
//kick player for spamming and prevent connection if they've done this several times
|
||||
if(player.getInfo().messageInfractions >= Config.messageSpamKick.num() && Config.messageSpamKick.num() != 0){
|
||||
player.con.kick("You have been kicked for spamming.", 1000 * 60 * 2);
|
||||
}
|
||||
player.getInfo().lastSentMessage = message;
|
||||
return null;
|
||||
}else{
|
||||
player.getInfo().messageInfractions = 0;
|
||||
}
|
||||
|
||||
//prevent players from sending the same message twice in the span of 50 seconds
|
||||
if(message.equals(player.getInfo().lastSentMessage) && Time.timeSinceMillis(player.getInfo().lastMessageTime) < 1000 * 50){
|
||||
player.sendMessage("[scarlet]You may not send the same message twice.");
|
||||
return null;
|
||||
}
|
||||
|
||||
player.getInfo().lastSentMessage = message;
|
||||
player.getInfo().lastMessageTime = Time.millis();
|
||||
}
|
||||
|
||||
return message;
|
||||
});
|
||||
}
|
||||
|
||||
public Array<String> getSubnetBans(){
|
||||
return subnetBans;
|
||||
}
|
||||
|
||||
public void removeSubnetBan(String ip){
|
||||
subnetBans.remove(ip);
|
||||
save();
|
||||
}
|
||||
|
||||
public void addSubnetBan(String ip){
|
||||
subnetBans.add(ip);
|
||||
save();
|
||||
}
|
||||
|
||||
public boolean isSubnetBanned(String ip){
|
||||
return subnetBans.contains(ip::startsWith);
|
||||
}
|
||||
|
||||
/** Adds a chat filter. This will transform the chat messages of every player.
|
||||
@@ -38,6 +96,25 @@ public class Administration{
|
||||
return current;
|
||||
}
|
||||
|
||||
/** Add a filter to actions, preventing things such as breaking or configuring blocks. */
|
||||
public void addActionFilter(ActionFilter filter){
|
||||
actionFilters.add(filter);
|
||||
}
|
||||
|
||||
/** @return whether this action is allowed by the action filters. */
|
||||
public boolean allowAction(Player player, ActionType type, Tile tile, Cons<PlayerAction> setter){
|
||||
PlayerAction act = Pools.obtain(PlayerAction.class, PlayerAction::new);
|
||||
setter.get(act.set(player, type, tile));
|
||||
for(ActionFilter filter : actionFilters){
|
||||
if(!filter.allow(act)){
|
||||
Pools.free(act);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Pools.free(act);
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getPlayerLimit(){
|
||||
return Core.settings.getInt("playerlimit", 0);
|
||||
}
|
||||
@@ -305,6 +382,7 @@ public class Administration{
|
||||
Core.settings.putObject("player-info", playerInfo);
|
||||
Core.settings.putObject("banned-ips", bannedIPs);
|
||||
Core.settings.putObject("whitelisted", whitelist);
|
||||
Core.settings.putObject("subnet-bans", subnetBans);
|
||||
Core.settings.save();
|
||||
}
|
||||
|
||||
@@ -313,6 +391,7 @@ public class Administration{
|
||||
playerInfo = Core.settings.getObject("player-info", ObjectMap.class, ObjectMap::new);
|
||||
bannedIPs = Core.settings.getObject("banned-ips", Array.class, Array::new);
|
||||
whitelist = Core.settings.getObject("whitelisted", Array.class, Array::new);
|
||||
subnetBans = Core.settings.getObject("subnet-bans", Array.class, Array::new);
|
||||
}
|
||||
|
||||
/** Server configuration definition. Each config value can be a string, boolean or number. */
|
||||
@@ -326,6 +405,9 @@ public class Administration{
|
||||
crashReport("Whether to send crash reports.", false, "crashreport"),
|
||||
logging("Whether to log everything to files.", true),
|
||||
strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true),
|
||||
antiSpam("Whether spammers are automatically kicked and rate-limited.", true),
|
||||
messageRateLimit("Message rate limit in seconds. 0 to disable.", 0),
|
||||
messageSpamKick("How many times a player must send a message before the cooldown to get kicked. 0 to disable.", 3),
|
||||
socketInput("Allows a local application to control this server through a local TCP socket.", false, "socket", () -> Events.fire(Trigger.socketConfigChanged)),
|
||||
socketInputPort("The port for socket input.", 6859, () -> Events.fire(Trigger.socketConfigChanged)),
|
||||
socketInputAddress("The bind address for socket input.", "localhost", () -> Events.fire(Trigger.socketConfigChanged)),
|
||||
@@ -402,7 +484,11 @@ public class Administration{
|
||||
public int timesKicked;
|
||||
public int timesJoined;
|
||||
public boolean banned, admin;
|
||||
public long lastKicked; //last kicked timestamp
|
||||
public long lastKicked; //last kicked time to expiration
|
||||
|
||||
public transient long lastMessageTime, lastSyncTime;
|
||||
public transient String lastSentMessage;
|
||||
public transient int messageInfractions;
|
||||
|
||||
PlayerInfo(String id){
|
||||
this.id = id;
|
||||
@@ -412,11 +498,18 @@ public class Administration{
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles chat messages from players and changes their contents. */
|
||||
public interface ChatFilter{
|
||||
/** @return the filtered message; a null string signals that the message should not be sent. */
|
||||
@Nullable String filter(Player player, String message);
|
||||
}
|
||||
|
||||
/** Allows or disallows player actions. */
|
||||
public interface ActionFilter{
|
||||
/** @return whether this action should be permitted. if applicable, make sure to send this player a message specify why the action was prohibited. */
|
||||
boolean allow(PlayerAction action);
|
||||
}
|
||||
|
||||
public static class TraceInfo{
|
||||
public String ip, uuid;
|
||||
public boolean modded, mobile;
|
||||
@@ -429,4 +522,39 @@ public class Administration{
|
||||
}
|
||||
}
|
||||
|
||||
/** Defines a (potentially dangerous) action that a player has done in the world.
|
||||
* These objects are pooled; do not cache them! */
|
||||
public static class PlayerAction implements Poolable{
|
||||
public @NonNull Player player;
|
||||
public @NonNull ActionType type;
|
||||
public @NonNull Tile tile;
|
||||
|
||||
/** valid for configure and rotation-type events only. */
|
||||
public int config;
|
||||
|
||||
/** valid for item-type events only. */
|
||||
public @Nullable Item item;
|
||||
public int itemAmount;
|
||||
|
||||
public PlayerAction set(Player player, ActionType type, Tile tile){
|
||||
this.player = player;
|
||||
this.type = type;
|
||||
this.tile = tile;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(){
|
||||
item = null;
|
||||
itemAmount = config = 0;
|
||||
player = null;
|
||||
type = null;
|
||||
tile = null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ActionType{
|
||||
breakBlock, placeBlock, rotate, configure, withdrawItem, depositItem
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ import static mindustry.Vars.netServer;
|
||||
public abstract class NetConnection{
|
||||
public final String address;
|
||||
public boolean mobile, modclient;
|
||||
public @Nullable
|
||||
Player player;
|
||||
public @Nullable Player player;
|
||||
|
||||
/** ID of last recieved client snapshot. */
|
||||
public int lastRecievedClientSnapshot = -1;
|
||||
@@ -37,7 +36,7 @@ public abstract class NetConnection{
|
||||
if(player != null && (reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote) && player.uuid != null){
|
||||
PlayerInfo info = netServer.admins.getInfo(player.uuid);
|
||||
info.timesKicked++;
|
||||
info.lastKicked = Math.max(Time.millis(), info.lastKicked);
|
||||
info.lastKicked = Math.max(Time.millis() + 30 * 1000, info.lastKicked);
|
||||
}
|
||||
|
||||
Call.onKick(this, reason);
|
||||
@@ -49,12 +48,17 @@ public abstract class NetConnection{
|
||||
|
||||
/** Kick with an arbitrary reason. */
|
||||
public void kick(String reason){
|
||||
kick(reason, 30 * 1000);
|
||||
}
|
||||
|
||||
/** Kick with an arbitrary reason, and a kick duration in milliseconds. */
|
||||
public void kick(String reason, int kickDuration){
|
||||
Log.info("Kicking connection {0}; Reason: {1}", address, reason.replace("\n", " "));
|
||||
|
||||
if(player != null && player.uuid != null){
|
||||
PlayerInfo info = netServer.admins.getInfo(player.uuid);
|
||||
info.timesKicked++;
|
||||
info.lastKicked = Math.max(Time.millis(), info.lastKicked);
|
||||
info.lastKicked = Math.max(Time.millis() + kickDuration, info.lastKicked);
|
||||
}
|
||||
|
||||
Call.onKick(this, reason);
|
||||
|
||||
@@ -2,9 +2,11 @@ package mindustry.type;
|
||||
|
||||
import arc.Core;
|
||||
import arc.graphics.Color;
|
||||
import arc.graphics.g2d.TextureRegion;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.scene.ui.layout.Table;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.Time;
|
||||
import mindustry.ctype.ContentType;
|
||||
import mindustry.entities.type.Player;
|
||||
import mindustry.ctype.UnlockableContent;
|
||||
@@ -32,6 +34,13 @@ public class Mech extends UnlockableContent{
|
||||
public boolean canHeal = false;
|
||||
public float compoundSpeed, compoundSpeedBoost;
|
||||
|
||||
/** draw the health and team indicator */
|
||||
public boolean drawCell = true;
|
||||
/** draw the items on its back */
|
||||
public boolean drawItems = true;
|
||||
/** draw the engine light if it's flying/boosting */
|
||||
public boolean drawLight = true;
|
||||
|
||||
public float weaponOffsetX, weaponOffsetY, engineOffset = 5f, engineSize = 2.5f;
|
||||
public @NonNull Weapon weapon;
|
||||
|
||||
@@ -52,6 +61,24 @@ public class Mech extends UnlockableContent{
|
||||
public void draw(Player player){
|
||||
}
|
||||
|
||||
public void drawStats(Player player){
|
||||
if(drawCell){
|
||||
float health = player.healthf();
|
||||
Draw.color(Color.black, player.getTeam().color, health + Mathf.absin(Time.time(), health * 5f, 1f - health));
|
||||
Draw.rect(player.getPowerCellRegion(),
|
||||
player.x + Angles.trnsx(player.rotation, cellTrnsY, 0f),
|
||||
player.y + Angles.trnsy(player.rotation, cellTrnsY, 0f),
|
||||
player.rotation - 90);
|
||||
Draw.reset();
|
||||
}
|
||||
if(drawItems){
|
||||
player.drawBackItems();
|
||||
}
|
||||
if(drawLight){
|
||||
player.drawLight();
|
||||
}
|
||||
}
|
||||
|
||||
public float getExtraArmor(Player player){
|
||||
return 0f;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public class AboutDialog extends FloatingDialog{
|
||||
public void showCredits(){
|
||||
FloatingDialog dialog = new FloatingDialog("$credits");
|
||||
dialog.addCloseButton();
|
||||
dialog.cont.add("$credits.text");
|
||||
dialog.cont.add("$credits.text").fillX().wrap().get().setAlignment(Align.center);
|
||||
dialog.cont.row();
|
||||
if(!contributors.isEmpty()){
|
||||
dialog.cont.addImage().color(Pal.accent).fillX().height(3f).pad(3f);
|
||||
|
||||
@@ -268,6 +268,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
}
|
||||
return s + "%";
|
||||
});
|
||||
graphics.sliderPref("bridgeopacity", 75, 0, 100, 5, s -> s + "%");
|
||||
|
||||
if(!mobile){
|
||||
graphics.checkPref("vsync", true, b -> Core.graphics.setVSync(b));
|
||||
|
||||
@@ -55,6 +55,8 @@ public class Block extends BlockStorage{
|
||||
public boolean rotate;
|
||||
/** whether you can break this with rightclick */
|
||||
public boolean breakable;
|
||||
/** whether to add this block to brokenblocks */
|
||||
public boolean rebuildable = true;
|
||||
/** whether this floor can be placed on. */
|
||||
public boolean placeableOn = true;
|
||||
/** whether this block has insulating properties. */
|
||||
|
||||
@@ -26,6 +26,7 @@ public class ShockMine extends Block{
|
||||
solid = false;
|
||||
targetable = false;
|
||||
layer = Layer.overlay;
|
||||
rebuildable = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package mindustry.world.blocks.distribution;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.Mathf;
|
||||
import arc.math.geom.Geometry;
|
||||
import mindustry.world.Tile;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@@ -31,6 +32,10 @@ public class ExtendingItemBridge extends ItemBridge{
|
||||
ex *= uptime;
|
||||
ey *= uptime;
|
||||
|
||||
float opacity = Core.settings.getInt("bridgeopacity") / 100f;
|
||||
if(Mathf.zero(opacity)) return;
|
||||
Draw.alpha(opacity);
|
||||
|
||||
Lines.stroke(8f);
|
||||
Lines.line(bridgeRegion,
|
||||
tile.worldx() + Geometry.d4[i].x * tilesize / 2f,
|
||||
@@ -50,7 +55,7 @@ public class ExtendingItemBridge extends ItemBridge{
|
||||
Draw.color();
|
||||
|
||||
for(int a = 0; a < arrows; a++){
|
||||
Draw.alpha(Mathf.absin(a / (float)arrows - entity.time / 100f, 0.1f, 1f) * uptime);
|
||||
Draw.alpha(Mathf.absin(a / (float)arrows - entity.time / 100f, 0.1f, 1f) * uptime * opacity);
|
||||
Draw.rect(arrowRegion,
|
||||
tile.worldx() + Geometry.d4[i].x * (tilesize / 2f + a * 6f + 2) * uptime,
|
||||
tile.worldy() + Geometry.d4[i].y * (tilesize / 2f + a * 6f + 2) * uptime, i * 90f);
|
||||
|
||||
@@ -219,10 +219,13 @@ public class ItemBridge extends Block{
|
||||
Tile other = world.tile(entity.link);
|
||||
if(!linkValid(tile, other)) return;
|
||||
|
||||
float opacity = Core.settings.getInt("bridgeopacity") / 100f;
|
||||
if(Mathf.zero(opacity)) return;
|
||||
|
||||
int i = tile.absoluteRelativeTo(other.x, other.y);
|
||||
|
||||
Draw.color(Color.white, Color.black, Mathf.absin(Time.time(), 6f, 0.07f));
|
||||
Draw.alpha(Math.max(entity.uptime, 0.25f));
|
||||
Draw.alpha(Math.max(entity.uptime, 0.25f) * opacity);
|
||||
|
||||
Draw.rect(endRegion, tile.drawx(), tile.drawy(), i * 90 + 90);
|
||||
Draw.rect(endRegion, other.drawx(), other.drawy(), i * 90 + 270);
|
||||
@@ -242,7 +245,7 @@ public class ItemBridge extends Block{
|
||||
Draw.color();
|
||||
|
||||
for(int a = 0; a < arrows; a++){
|
||||
Draw.alpha(Mathf.absin(a / (float)arrows - entity.time / 100f, 0.1f, 1f) * entity.uptime);
|
||||
Draw.alpha(Mathf.absin(a / (float)arrows - entity.time / 100f, 0.1f, 1f) * entity.uptime * opacity);
|
||||
Draw.rect(arrowRegion,
|
||||
tile.worldx() + Geometry.d4[i].x * (tilesize / 2f + a * 4f + time % 4f),
|
||||
tile.worldy() + Geometry.d4[i].y * (tilesize / 2f + a * 4f + time % 4f), i * 90f);
|
||||
|
||||
@@ -163,14 +163,22 @@ public class MassDriver extends Block{
|
||||
public void drawPlace(int x, int y, int rotation, boolean valid){
|
||||
Drawf.dashCircle(x * tilesize, y*tilesize, range, Pal.accent);
|
||||
|
||||
// check if a mass driver is selected while placing this driver
|
||||
//check if a mass driver is selected while placing this driver
|
||||
if(!control.input.frag.config.isShown()) return;
|
||||
Tile selected = control.input.frag.config.getSelectedTile();
|
||||
if(!(selected.block() instanceof MassDriver) || !(selected.dst(x * tilesize, y * tilesize) <= range)) return;
|
||||
if(selected == null || !(selected.block() instanceof MassDriver) || !(selected.dst(x * tilesize, y * tilesize) <= range)) return;
|
||||
|
||||
// if so, draw a dotted line towards it while it is in range
|
||||
//if so, draw a dotted line towards it while it is in range
|
||||
float sin = Mathf.absin(Time.time(), 6f, 1f);
|
||||
Tmp.v1.set(x * tilesize + offset(), y * tilesize + offset()).sub(selected.drawx(), selected.drawy()).limit((size / 2f + 1) * tilesize + sin + 0.5f);
|
||||
float x2 = x * tilesize - Tmp.v1.x, y2 = y * tilesize - Tmp.v1.y,
|
||||
x1 = selected.drawx() + Tmp.v1.x, y1 = selected.drawy() + Tmp.v1.y;
|
||||
int segs = (int)(selected.dst(x * tilesize, y * tilesize) / tilesize);
|
||||
|
||||
Lines.stroke(4f, Pal.gray);
|
||||
Lines.dashLine(x1, y1, x2, y2, segs);
|
||||
Lines.stroke(2f, Pal.placing);
|
||||
Lines.dashLine(x * tilesize, y * tilesize, selected.drawx(), selected.drawy(), (int)range / tilesize / 4);
|
||||
Lines.dashLine(x1, y1, x2, y2, segs);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ public class NuclearReactor extends PowerGenerator{
|
||||
hasItems = true;
|
||||
hasLiquids = true;
|
||||
entityType = NuclearReactorEntity::new;
|
||||
rebuildable = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,7 @@ public class PowerDiode extends Block{
|
||||
public void update(Tile tile){
|
||||
super.update(tile);
|
||||
|
||||
if(tile.front() == null || tile.back() == null || !tile.back().block().hasPower || !tile.front().block().hasPower) return;
|
||||
if(tile.front() == null || tile.back() == null || !tile.back().block().hasPower || !tile.front().block().hasPower || tile.back().getTeam() != tile.front().getTeam()) return;
|
||||
|
||||
PowerGraph backGraph = tile.back().entity.power.graph;
|
||||
PowerGraph frontGraph = tile.front().entity.power.graph;
|
||||
|
||||
29
core/src/mindustry/world/blocks/sandbox/LiquidVoid.java
Normal file
29
core/src/mindustry/world/blocks/sandbox/LiquidVoid.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package mindustry.world.blocks.sandbox;
|
||||
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
public class LiquidVoid extends Block{
|
||||
|
||||
public LiquidVoid(String name){
|
||||
super(name);
|
||||
hasLiquids = true;
|
||||
solid = true;
|
||||
update = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
bars.remove("liquid");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){}
|
||||
|
||||
}
|
||||
@@ -73,7 +73,7 @@ public class LaunchPad extends StorageBlock{
|
||||
public void update(Tile tile){
|
||||
TileEntity entity = tile.entity;
|
||||
|
||||
if(world.isZone() && entity.cons.valid() && world.isZone() && entity.items.total() >= itemCapacity && entity.timer.get(timerLaunch, launchTime / entity.timeScale)){
|
||||
if(world.isZone() && entity.cons.valid() && entity.items.total() >= itemCapacity && entity.timer.get(timerLaunch, launchTime / entity.timeScale)){
|
||||
for(Item item : Vars.content.items()){
|
||||
Events.fire(Trigger.itemLaunch);
|
||||
Effects.effect(Fx.padlaunch, tile);
|
||||
|
||||
Reference in New Issue
Block a user