mirror of
https://github.com/Anuken/Mindustry.git
synced 2024-11-13 07:15:28 +03:00
New tile edge algorithms / Struct value type generation
This commit is contained in:
parent
5a3ec8f407
commit
54bade668e
@ -22,7 +22,7 @@ public class Annotations{
|
||||
}
|
||||
|
||||
/**Marks a field of a struct. Optional.*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface StructField{
|
||||
/**Size of a struct field in bits. Not valid on booleans or floating point numbers.*/
|
||||
|
@ -9,14 +9,17 @@ import io.anuke.annotations.Annotations.StructField;
|
||||
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.lang.model.util.ElementFilter;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**Generates ""value types"" classes that are packed into integer primitives of the most aproppriate size.
|
||||
* It would be nice if Java didn't make crazy hacks like this necessary.*/
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||
@SupportedAnnotationTypes({
|
||||
"io.anuke.annotations.Annotations.Struct"
|
||||
@ -44,31 +47,114 @@ public class StructAnnotationProcessor extends AbstractProcessor{
|
||||
Set<TypeElement> elements = ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(Struct.class));
|
||||
|
||||
for(TypeElement elem : elements){
|
||||
TypeName type = TypeName.get(elem.asType());
|
||||
|
||||
if(!type.toString().endsWith("Struct")){
|
||||
if(!elem.getSimpleName().toString().endsWith("Struct")){
|
||||
Utils.messager.printMessage(Kind.ERROR, "All classes annotated with @Struct must have their class names end in 'Struct'.", elem);
|
||||
continue;
|
||||
}
|
||||
|
||||
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(packageName + "." + elem.getSimpleName().toString());
|
||||
String structName = elem.getSimpleName().toString().substring(0, elem.getSimpleName().toString().length() - "Struct".length());
|
||||
String structParam = structName.toLowerCase();
|
||||
|
||||
int offset = 0;
|
||||
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(structName)
|
||||
.addModifiers(Modifier.FINAL, Modifier.PUBLIC);
|
||||
|
||||
for(VariableElement var : ElementFilter.fieldsIn(Collections.singletonList(elem))){
|
||||
if(!var.asType().getKind().isPrimitive()){
|
||||
Utils.messager.printMessage(Kind.ERROR, "All struct fields must be primitives.", var);
|
||||
try{
|
||||
List<VariableElement> variables = ElementFilter.fieldsIn(elem.getEnclosedElements());
|
||||
int structSize = variables.stream().mapToInt(StructAnnotationProcessor::varSize).sum();
|
||||
int structTotalSize = (structSize <= 8 ? 8 : structSize <= 16 ? 16 : structSize <= 32 ? 32 : 64);
|
||||
|
||||
if(variables.size() == 0){
|
||||
Utils.messager.printMessage(Kind.ERROR, "making a struct with no fields is utterly pointles.", elem);
|
||||
continue;
|
||||
}
|
||||
|
||||
StructField an = var.getAnnotation(StructField.class);
|
||||
int size = an == null ? typeSize(var.asType().getKind()) : an.value();
|
||||
//obtain type which will be stored
|
||||
Class<?> structType = typeForSize(structSize);
|
||||
|
||||
MethodSpec.Builder getter = MethodSpec.methodBuilder(var.getSimpleName().toString());
|
||||
MethodSpec.Builder setter = MethodSpec.methodBuilder(var.getSimpleName().toString());
|
||||
//[constructor] get(fields...) : structType
|
||||
MethodSpec.Builder constructor = MethodSpec.methodBuilder("get") //TODO 'get'..?
|
||||
.addModifiers(Modifier.STATIC, Modifier.PUBLIC)
|
||||
.returns(structType);
|
||||
|
||||
StringBuilder cons = new StringBuilder();
|
||||
StringBuilder doc = new StringBuilder();
|
||||
doc.append("Bits used: ").append(structSize).append(" / ").append(structTotalSize).append("\n");
|
||||
|
||||
int offset = 0;
|
||||
for(VariableElement var : variables){
|
||||
int size = varSize(var);
|
||||
TypeName varType = TypeName.get(var.asType());
|
||||
String varName = var.getSimpleName().toString();
|
||||
|
||||
//add val param to constructor
|
||||
constructor.addParameter(varType, varName);
|
||||
|
||||
//[get] field(structType) : fieldType
|
||||
MethodSpec.Builder getter = MethodSpec.methodBuilder(var.getSimpleName().toString())
|
||||
.addModifiers(Modifier.STATIC, Modifier.PUBLIC)
|
||||
.returns(varType)
|
||||
.addParameter(structType, structParam);
|
||||
//[set] field(structType, fieldType) : structType
|
||||
MethodSpec.Builder setter = MethodSpec.methodBuilder(var.getSimpleName().toString())
|
||||
.addModifiers(Modifier.STATIC, Modifier.PUBLIC)
|
||||
.returns(structType)
|
||||
.addParameter(structType, structParam).addParameter(varType, "value");
|
||||
|
||||
//[getter]
|
||||
if(varType == TypeName.BOOLEAN){
|
||||
//bools: single bit, is simplified
|
||||
getter.addStatement("return ($L & (1L << $L)) != 0", structParam, offset);
|
||||
}else if(varType == TypeName.FLOAT){
|
||||
//floats: need conversion
|
||||
getter.addStatement("return Float.intBitsToFloat((int)(($L >> $L) & $L))", structParam, offset, bitString(size, structTotalSize));
|
||||
}else{
|
||||
//bytes, shorts, chars, ints
|
||||
getter.addStatement("return ($T)(($L >> $L) & $L)", varType, structParam, offset, bitString(size, structTotalSize));
|
||||
}
|
||||
|
||||
//[setter] + [constructor building]
|
||||
if(varType == TypeName.BOOLEAN){
|
||||
cons.append(" | (").append(varName).append(" ? ").append("1L << ").append(offset).append("L : 0)");
|
||||
|
||||
//bools: single bit, needs special case to clear things
|
||||
setter.beginControlFlow("if(value)");
|
||||
setter.addStatement("return ($T)(($L & ~(1L << $LL)))", structType, structParam, offset);
|
||||
setter.nextControlFlow("else");
|
||||
setter.addStatement("return ($T)(($L & ~(1L << $LL)) | (1L << $LL))", structType, structParam, offset, offset);
|
||||
setter.endControlFlow();
|
||||
}else if(varType == TypeName.FLOAT){
|
||||
cons.append(" | (").append("(").append(structType).append(")").append("Float.floatToIntBits(").append(varName).append(") << ").append(offset).append("L)");
|
||||
|
||||
//floats: need conversion
|
||||
setter.addStatement("return ($T)(($L & $L) | (($T)Float.floatToIntBits(value) << $LL))", structType, structParam, bitString(offset, size, structTotalSize), structType, offset);
|
||||
}else{
|
||||
cons.append(" | (").append("(").append(structType).append(")").append(varName).append(" << ").append(offset).append("L)");
|
||||
|
||||
//bytes, shorts, chars, ints
|
||||
setter.addStatement("return ($T)(($L & $L) | (($T)value << $LL))", structType, structParam, bitString(offset, size, structTotalSize), structType, offset);
|
||||
}
|
||||
|
||||
doc.append("<br> ").append(varName).append(" [").append(offset).append("..").append(size + offset).append("]\n");
|
||||
|
||||
//add finished methods
|
||||
classBuilder.addMethod(getter.build());
|
||||
classBuilder.addMethod(setter.build());
|
||||
|
||||
offset += size;
|
||||
}
|
||||
|
||||
classBuilder.addJavadoc(doc.toString());
|
||||
|
||||
//add constructor final statement + add to class and build
|
||||
constructor.addStatement("return ($T)($L)", structType, cons.toString().substring(3));
|
||||
classBuilder.addMethod(constructor.build());
|
||||
|
||||
JavaFile.builder(packageName, classBuilder.build()).build().writeTo(Utils.filer);
|
||||
}catch(IllegalArgumentException e){
|
||||
e.printStackTrace();
|
||||
Utils.messager.printMessage(Kind.ERROR, e.getMessage(), elem);
|
||||
}
|
||||
|
||||
JavaFile.builder(packageName, classBuilder.build()).build().writeTo(Utils.filer);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -78,8 +164,53 @@ public class StructAnnotationProcessor extends AbstractProcessor{
|
||||
}
|
||||
}
|
||||
|
||||
static String bitString(int offset, int size, int totalSize){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for(int i = 0; i < offset; i++) builder.append('0');
|
||||
for(int i = 0; i < size; i++) builder.append('1');
|
||||
for(int i = 0; i < totalSize - size - offset; i++) builder.append('0');
|
||||
return "0b" + builder.reverse().toString() + "L";
|
||||
}
|
||||
|
||||
static String bitString(int size, int totalSize){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for(int i = 0; i < size; i++) builder.append('1');
|
||||
for(int i = 0; i < totalSize - size; i++) builder.append('0');
|
||||
return "0b" + builder.reverse().toString() + "L";
|
||||
}
|
||||
|
||||
static int varSize(VariableElement var) throws IllegalArgumentException{
|
||||
if(!var.asType().getKind().isPrimitive()){
|
||||
throw new IllegalArgumentException("All struct fields must be primitives: " + var);
|
||||
}
|
||||
|
||||
StructField an = var.getAnnotation(StructField.class);
|
||||
if(var.asType().getKind() == TypeKind.BOOLEAN && an != null && an.value() != 1){
|
||||
throw new IllegalArgumentException("Booleans can only be one bit long... why would you do this?");
|
||||
}
|
||||
|
||||
if(var.asType().getKind() == TypeKind.FLOAT && an != null && an.value() != 32){
|
||||
throw new IllegalArgumentException("Float size can't be changed. Very sad.");
|
||||
}
|
||||
|
||||
return an == null ? typeSize(var.asType().getKind()) : an.value();
|
||||
}
|
||||
|
||||
static Class<?> typeForSize(int size) throws IllegalArgumentException{
|
||||
if(size <= 8){
|
||||
return byte.class;
|
||||
}else if(size <= 16){
|
||||
return short.class;
|
||||
}else if(size <= 32){
|
||||
return int.class;
|
||||
}else if(size <= 64){
|
||||
return long.class;
|
||||
}
|
||||
throw new IllegalArgumentException("Too many fields, must fit in 64 bits. Curent size: " + size);
|
||||
}
|
||||
|
||||
/**returns a type's element size in bits.*/
|
||||
static int typeSize(TypeKind kind){
|
||||
static int typeSize(TypeKind kind) throws IllegalArgumentException{
|
||||
switch(kind){
|
||||
case BOOLEAN:
|
||||
return 1;
|
||||
@ -91,11 +222,8 @@ public class StructAnnotationProcessor extends AbstractProcessor{
|
||||
case CHAR:
|
||||
case INT:
|
||||
return 32;
|
||||
case LONG:
|
||||
case DOUBLE:
|
||||
return 64;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid type kind: " + kind);
|
||||
throw new IllegalArgumentException("Invalid type kind: " + kind + ". Note that doubles and longs are not supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
core/assets-raw/sprites/blocks/environment/edge-stencil.png
Normal file
BIN
core/assets-raw/sprites/blocks/environment/edge-stencil.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 506 B |
BIN
core/assets-raw/sprites/blocks/environment/ice-edge.png
Normal file
BIN
core/assets-raw/sprites/blocks/environment/ice-edge.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 588 B |
Binary file not shown.
Before Width: | Height: | Size: 303 B |
BIN
core/assets-raw/sprites/blocks/environment/white-tree.png
Normal file
BIN
core/assets-raw/sprites/blocks/environment/white-tree.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 KiB |
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 1013 KiB After Width: | Height: | Size: 1013 KiB |
@ -1,7 +1,9 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.graphics.CacheLayer;
|
||||
import io.anuke.mindustry.type.Category;
|
||||
@ -32,8 +34,9 @@ public class Blocks implements ContentList{
|
||||
public static Block
|
||||
|
||||
//environment
|
||||
air, part, spawn, space, metalfloor, deepwater, water, tar, stone, craters, charr, blackstone, dirt, sand, ice, snow, iceSnow,
|
||||
grass, holostone, holostoneSnow, shrub, rock, icerock, blackrock, rocks, icerocks, cliffs, pine, whiteTree, sporeCluster,
|
||||
air, part, spawn, deepwater, water, tar, stone, craters, charr, sand, ice, snow,
|
||||
grass, holostone, rocks, icerocks, cliffs, pine, whiteTree, whiteTreeDead, sporeCluster,
|
||||
iceSnow,
|
||||
|
||||
//crafting
|
||||
siliconSmelter, graphitePress, plastaniumCompressor, multiPress, phaseWeaver, surgeSmelter, pyratiteMixer, blastMixer, cryofluidMixer,
|
||||
@ -83,6 +86,12 @@ public class Blocks implements ContentList{
|
||||
public void draw(Tile tile){}
|
||||
public void load(){}
|
||||
public void init(){}
|
||||
public TextureRegion[] variantRegions(){
|
||||
if(variantRegions == null){
|
||||
variantRegions = new TextureRegion[]{Core.atlas.find("clear")};
|
||||
}
|
||||
return variantRegions;
|
||||
}
|
||||
};
|
||||
|
||||
part = new BlockPart();
|
||||
@ -97,18 +106,6 @@ public class Blocks implements ContentList{
|
||||
new BuildBlock("build" + i);
|
||||
}
|
||||
|
||||
space = new Floor("space"){{
|
||||
placeableOn = false;
|
||||
variants = 0;
|
||||
cacheLayer = CacheLayer.space;
|
||||
solid = true;
|
||||
minimapColor = Color.valueOf("000001");
|
||||
}};
|
||||
|
||||
metalfloor = new Floor("metalfloor"){{
|
||||
variants = 6;
|
||||
}};
|
||||
|
||||
deepwater = new Floor("deepwater"){{
|
||||
liquidColor = Color.valueOf("546bb3");
|
||||
speedMultiplier = 0.2f;
|
||||
@ -161,16 +158,6 @@ public class Blocks implements ContentList{
|
||||
minimapColor = Color.valueOf("323232");
|
||||
}};
|
||||
|
||||
blackstone = new Floor("blackstone"){{
|
||||
minimapColor = Color.valueOf("252525");
|
||||
playerUnmineable = true;
|
||||
hasOres = true;
|
||||
}};
|
||||
|
||||
dirt = new Floor("dirt"){{
|
||||
minimapColor = Color.valueOf("6e501e");
|
||||
}};
|
||||
|
||||
sand = new Floor("sand"){{
|
||||
itemDrop = Items.sand;
|
||||
minimapColor = Color.valueOf("988a67");
|
||||
@ -184,13 +171,12 @@ public class Blocks implements ContentList{
|
||||
minimapColor = Color.valueOf("b8eef8");
|
||||
}};
|
||||
|
||||
snow = new Floor("snow"){{
|
||||
minimapColor = Color.valueOf("c2d1d2");
|
||||
holostone = new Floor("holostone"){{
|
||||
hasOres = true;
|
||||
}};
|
||||
|
||||
iceSnow = new Floor("ice-snow"){{
|
||||
snow = new Floor("snow"){{
|
||||
minimapColor = Color.valueOf("c2d1d2");
|
||||
variants = 3;
|
||||
}};
|
||||
|
||||
grass = new Floor("grass"){{
|
||||
@ -198,8 +184,6 @@ public class Blocks implements ContentList{
|
||||
minimapColor = Color.valueOf("549d5b");
|
||||
}};
|
||||
|
||||
shrub = new Rock("shrub");
|
||||
|
||||
cliffs = new StaticWall("cliffs"){{
|
||||
variants = 1;
|
||||
fillsTile = false;
|
||||
@ -218,19 +202,18 @@ public class Blocks implements ContentList{
|
||||
variants = 0;
|
||||
}};
|
||||
|
||||
whiteTree = new TreeBlock("white-tree-dead"){{
|
||||
whiteTreeDead = new TreeBlock("white-tree-dead"){{
|
||||
}};
|
||||
|
||||
whiteTree = new TreeBlock("white-tree"){{
|
||||
}};
|
||||
|
||||
sporeCluster = new Rock("spore-cluster"){{
|
||||
variants = 3;
|
||||
}};
|
||||
|
||||
holostone = new Floor("holostone"){{
|
||||
hasOres = true;
|
||||
}};
|
||||
|
||||
holostoneSnow = new Floor("holostone-snow"){{
|
||||
|
||||
iceSnow = new Floor("iceSnow"){{
|
||||
variants = 3;
|
||||
}};
|
||||
|
||||
//endregion
|
||||
|
@ -167,7 +167,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
editor.beginEdit(data, meta.tags, false);
|
||||
view.clearStack();
|
||||
}catch(Exception e){
|
||||
ui.showError(Core.bundle.format("editor.errormapload", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
|
||||
Log.err(e);
|
||||
}
|
||||
}));
|
||||
|
@ -201,7 +201,7 @@ public class FloorRenderer{
|
||||
int chunksx = Mathf.ceil((float) (world.width()) / chunksize),
|
||||
chunksy = Mathf.ceil((float) (world.height()) / chunksize) ;
|
||||
cache = new Chunk[chunksx][chunksy];
|
||||
SpriteCache sprites = new SpriteCache(world.width() * world.height() * 3, (world.width() / chunksize) * (world.height() / chunksize) * 2, false);
|
||||
SpriteCache sprites = new SpriteCache(world.width() * world.height() * 5, (world.width() / chunksize) * (world.height() / chunksize) * 2, false);
|
||||
cbatch = new CacheBatch(sprites);
|
||||
|
||||
Time.mark();
|
||||
|
@ -13,6 +13,7 @@ import io.anuke.mindustry.maps.MapTileData.TileDataMarker;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
||||
import io.anuke.mindustry.world.blocks.StaticWall;
|
||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@ -89,7 +90,8 @@ public class MapGenerator extends Generator{
|
||||
int newX = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x, y) * distortion + x), 0, data.width()-1);
|
||||
int newY = Mathf.clamp((int)(simplex.octaveNoise2D(1, 1, 1.0 / scl, x + 9999, y + 9999) * distortion + y), 0, data.height()-1);
|
||||
|
||||
if(tiles[newX][newY].block() != Blocks.spawn && !tile.block().synthetic()&& !tiles[newX][newY].block().synthetic()){
|
||||
if(tile.block() instanceof StaticWall
|
||||
&& tiles[newX][newY].block() instanceof StaticWall){
|
||||
tile.setBlock(tiles[newX][newY].block());
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ public class Block extends BlockStorage{
|
||||
protected Array<Tile> tempTiles = new Array<>();
|
||||
protected TextureRegion[] icons = new TextureRegion[Icon.values().length];
|
||||
protected TextureRegion[] generatedIcons;
|
||||
protected TextureRegion[] variants;
|
||||
protected TextureRegion[] variantRegions;
|
||||
protected TextureRegion region;
|
||||
|
||||
public Block(String name){
|
||||
@ -503,10 +503,10 @@ public class Block extends BlockStorage{
|
||||
}
|
||||
|
||||
public TextureRegion[] variantRegions(){
|
||||
if(variants == null){
|
||||
variants = new TextureRegion[]{icon(Icon.full)};
|
||||
if(variantRegions == null){
|
||||
variantRegions = new TextureRegion[]{icon(Icon.full)};
|
||||
}
|
||||
return variants;
|
||||
return variantRegions;
|
||||
}
|
||||
|
||||
public boolean hasEntity(){
|
||||
|
@ -20,7 +20,8 @@ public class LegacyColorMapper implements ContentList{
|
||||
public void load(){
|
||||
defaultValue = new LegacyBlock(Blocks.stone, Blocks.air);
|
||||
|
||||
map("ff0000", Blocks.dirt, 0);
|
||||
//TODO remap colors later
|
||||
// map("ff0000", Blocks.dirt, 0);
|
||||
map("00ff00", Blocks.stone, 0);
|
||||
map("323232", Blocks.stone, 0);
|
||||
map("646464", Blocks.stone, 1);
|
||||
@ -28,15 +29,15 @@ public class LegacyColorMapper implements ContentList{
|
||||
map("5ab464", Blocks.grass, 1);
|
||||
map("506eb4", Blocks.water, 0);
|
||||
map("465a96", Blocks.deepwater, 0);
|
||||
map("252525", Blocks.blackstone, 0);
|
||||
map("575757", Blocks.blackstone, 1);
|
||||
//map("252525", Blocks.blackstone, 0);
|
||||
//map("575757", Blocks.blackstone, 1);
|
||||
map("988a67", Blocks.sand, 0);
|
||||
map("e5d8bb", Blocks.sand, 1);
|
||||
map("c2d1d2", Blocks.snow, 0);
|
||||
map("c4e3e7", Blocks.ice, 0);
|
||||
map("f7feff", Blocks.snow, 1);
|
||||
map("6e501e", Blocks.dirt, 0);
|
||||
map("ed5334", Blocks.blackstone, 0);
|
||||
//map("6e501e", Blocks.dirt, 0);
|
||||
//map("ed5334", Blocks.blackstone, 0);
|
||||
map("292929", Blocks.tar, 0);
|
||||
map("c3a490", OreBlock.get(Blocks.stone, Items.copper), 0);
|
||||
map("161616", OreBlock.get(Blocks.stone, Items.coal), 0);
|
||||
|
@ -6,6 +6,8 @@ import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Point2;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.content.StatusEffects;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
@ -51,8 +53,9 @@ public class Floor extends Block{
|
||||
public float heat = 0f;
|
||||
/** if true, this block cannot be mined by players. useful for annoying things like sand. */
|
||||
public boolean playerUnmineable = false;
|
||||
protected TextureRegion[] regions;
|
||||
|
||||
protected TextureRegion[][] edges;
|
||||
protected byte eq = 0;
|
||||
|
||||
public Floor(String name){
|
||||
super(name);
|
||||
@ -65,24 +68,26 @@ public class Floor extends Block{
|
||||
|
||||
//load variant regions for drawing
|
||||
if(variants > 0){
|
||||
regions = new TextureRegion[variants];
|
||||
variantRegions = new TextureRegion[variants];
|
||||
|
||||
for(int i = 0; i < variants; i++){
|
||||
regions[i] = Core.atlas.find(name + (i + 1));
|
||||
variantRegions[i] = Core.atlas.find(name + (i + 1));
|
||||
}
|
||||
}else{
|
||||
regions = new TextureRegion[1];
|
||||
regions[0] = Core.atlas.find(name);
|
||||
variantRegions = new TextureRegion[1];
|
||||
variantRegions[0] = Core.atlas.find(name);
|
||||
}
|
||||
|
||||
int size = (int)(tilesize / Draw.scl);
|
||||
edges = Core.atlas.find(name + "-edge").split(size, size);
|
||||
region = regions[0];
|
||||
if(Core.atlas.has(name + "-edge")){
|
||||
edges = Core.atlas.find(name + "-edge").split(size, size);
|
||||
}
|
||||
region = variantRegions[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion[] variantRegions(){
|
||||
return regions;
|
||||
public TextureRegion[] generateIcons(){
|
||||
return new TextureRegion[]{Core.atlas.find(Core.atlas.has(name) ? name : name + "1")};
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -98,12 +103,57 @@ public class Floor extends Block{
|
||||
public void draw(Tile tile){
|
||||
Mathf.random.setSeed(tile.pos());
|
||||
|
||||
Draw.rect(regions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, regions.length - 1))], tile.worldx(), tile.worldy());
|
||||
Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy());
|
||||
|
||||
drawEdges(tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion[] generateIcons(){
|
||||
return new TextureRegion[]{Core.atlas.find(Core.atlas.has(name) ? name : name + "1")};
|
||||
protected void drawEdges(Tile tile){
|
||||
eq = 0;
|
||||
|
||||
Floor floor = tile.floor();
|
||||
|
||||
for(int i = 0; i < 8; i++){
|
||||
Point2 point = Geometry.d8[i];
|
||||
Tile other = tile.getNearby(point);
|
||||
if(other != null && other.floor().id < floor.id && other.floor().edges != null){
|
||||
eq |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < 8; i++){
|
||||
if(eq(i)){
|
||||
Point2 point = Geometry.d8[i];
|
||||
Tile other = tile.getNearby(point);
|
||||
|
||||
TextureRegion region = edge(other.floor(), type(i), 2-(point.x + 1), 2-(point.y + 1));
|
||||
Draw.rect(region, tile.worldx(), tile.worldy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int type(int i){
|
||||
if(!eq(i - 1) && !eq(i + 1)){
|
||||
//case 0: touching
|
||||
return 0;
|
||||
}else if(eq(i - 1) && eq(i - 2) && eq(i + 1) && eq(i + 2)){
|
||||
//case 2: surrounded
|
||||
return 2;
|
||||
}else if(eq(i - 1) && eq(i + 1)){
|
||||
//case 1: flat
|
||||
return 1;
|
||||
}else{
|
||||
//case 0 is rounded, so it's the safest choice, should work for most possibilities
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
boolean eq(int i){
|
||||
return (eq & (1 << Mathf.mod(i, 8))) != 0;
|
||||
}
|
||||
|
||||
TextureRegion edge(Floor block, int type, int x, int y){
|
||||
return block.edges[x + type*3][2-y];
|
||||
}
|
||||
|
||||
}
|
@ -31,7 +31,7 @@ public class OreBlock extends Floor{
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){
|
||||
Draw.rect(regions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, regions.length - 1))], tile.worldx(), tile.worldy());
|
||||
Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy());
|
||||
}
|
||||
|
||||
public static Block get(Block floor, Item item){
|
||||
|
@ -9,6 +9,7 @@ import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Mech;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
@ -143,6 +144,31 @@ public class Generators {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ImagePacker.generate("edges", () -> {
|
||||
for(Block block : content.blocks()){
|
||||
if(!(block instanceof Floor)) continue;
|
||||
|
||||
Floor floor = (Floor)block;
|
||||
|
||||
if(ImagePacker.has(floor.name + "-edge")){
|
||||
continue;
|
||||
}
|
||||
|
||||
try{
|
||||
Image image = ImagePacker.get(floor.generateIcons()[0]);
|
||||
Image edge = ImagePacker.get("edge-stencil");
|
||||
|
||||
for(int x = 0; x < edge.width(); x++){
|
||||
for(int y = 0; y < edge.height(); y++){
|
||||
edge.draw(x, y, edge.getColor(x, y).mul(image.getColor(x % image.width(), y % image.height())));
|
||||
}
|
||||
}
|
||||
|
||||
edge.save(floor.name + "-edge");
|
||||
}catch(Exception ignored){}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -111,6 +111,10 @@ public class ImagePacker{
|
||||
return get(Core.atlas.find(name));
|
||||
}
|
||||
|
||||
static boolean has(String name){
|
||||
return Core.atlas.has(name);
|
||||
}
|
||||
|
||||
static Image get(TextureRegion region){
|
||||
GenRegion.validate(region);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user