From 270c9402c20923df43086f2fb05f6d5f528e6bfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Balogh?= Date: Thu, 16 Feb 2017 14:58:31 +0100 Subject: [PATCH 01/16] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0eab3678..199407c3 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,4 @@ CodeMetropolis See your software as never before. Official community page: https://plus.google.com/communities/110235162339639686953 +BlockModifier-API aviable at: https://github.com/blip24/BlockModifier-API From 0432da3a86db7dd7209b080e10e92ce38160a6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Balogh?= Date: Thu, 16 Feb 2017 14:58:41 +0100 Subject: [PATCH 02/16] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 199407c3..7bdbb380 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,5 @@ CodeMetropolis See your software as never before. Official community page: https://plus.google.com/communities/110235162339639686953 + BlockModifier-API aviable at: https://github.com/blip24/BlockModifier-API From 70f2b856aefa771c466f4865e77636237946e15c Mon Sep 17 00:00:00 2001 From: Dominik Hirling Date: Thu, 20 Apr 2017 20:42:38 +0200 Subject: [PATCH 03/16] test --- README.md | 1 + .../1.0.1/cmblockmodifier-1.0.1.jar | Bin 31763 -> 7037 bytes .../1.0.1/sav/cmblockmodifier-1.0.1.jar | Bin 0 -> 31763 bytes .../pom.xml | 22 +++++++++++++++--- .../.classpath | 4 ++-- 5 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 dependencies/codemetropolis/cmblockmodifier/1.0.1/sav/cmblockmodifier-1.0.1.jar diff --git a/README.md b/README.md index 7bdbb380..1a3c8a06 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,4 @@ See your software as never before. Official community page: https://plus.google.com/communities/110235162339639686953 BlockModifier-API aviable at: https://github.com/blip24/BlockModifier-API +hh \ No newline at end of file diff --git a/dependencies/codemetropolis/cmblockmodifier/1.0.1/cmblockmodifier-1.0.1.jar b/dependencies/codemetropolis/cmblockmodifier/1.0.1/cmblockmodifier-1.0.1.jar index ad74625ab8363713aed5744b50f6153cef853b40..28ec9035f6caa521ed44316f67dfece8a5274130 100644 GIT binary patch literal 7037 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 M*Y;L({(ba+0C#@(-~a#s diff --git a/dependencies/codemetropolis/cmblockmodifier/1.0.1/sav/cmblockmodifier-1.0.1.jar b/dependencies/codemetropolis/cmblockmodifier/1.0.1/sav/cmblockmodifier-1.0.1.jar new file mode 100644 index 0000000000000000000000000000000000000000..ad74625ab8363713aed5744b50f6153cef853b40 GIT binary patch literal 31763 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 M*Y;L({(ba+0C#@(-~a#s literal 0 HcmV?d00001 diff --git a/sources/codemetropolis-toolchain-converter/pom.xml b/sources/codemetropolis-toolchain-converter/pom.xml index 3fc4dfe9..ea95f48b 100644 --- a/sources/codemetropolis-toolchain-converter/pom.xml +++ b/sources/codemetropolis-toolchain-converter/pom.xml @@ -52,17 +52,33 @@ codemetropolis.toolchain codemetropolis-toolchain-commons - 1.4.0 args4j args4j - 2.32 sed graphlib - 1.0 + + + + args4j + args4j + 2.32 + + + sed + graphlib + 1.0 + + + codemetropolis.toolchain + codemetropolis-toolchain-commons + 1.4.0 + + + diff --git a/sources/codemetropolis-toolchain-mapping/.classpath b/sources/codemetropolis-toolchain-mapping/.classpath index e7a868fb..9339420e 100644 --- a/sources/codemetropolis-toolchain-mapping/.classpath +++ b/sources/codemetropolis-toolchain-mapping/.classpath @@ -24,12 +24,12 @@ - + - + From 7903e33da19fe3c33a55c14d585beb97ea2b210c Mon Sep 17 00:00:00 2001 From: Dominik Hirling Date: Fri, 21 Apr 2017 09:33:30 +0200 Subject: [PATCH 04/16] enabled the usage of pigs --- .../java/codemetropolis/toolchain/mapping/model/Linking.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java b/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java index f14233fd..f76aed75 100644 --- a/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java +++ b/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java @@ -24,7 +24,7 @@ public class Linking { static { SUPPORTED_TARGETS.put(Type.FLOOR, new String[]{"width", "height", "length", "character", "external_character", "torches"}); SUPPORTED_TARGETS.put(Type.CELLAR, new String[]{"width", "height", "length", "character", "external_character", "torches"}); - SUPPORTED_TARGETS.put(Type.GARDEN, new String[]{"tree-ratio", "mushroom-ratio", "flower-ratio"}); + SUPPORTED_TARGETS.put(Type.GARDEN, new String[]{"tree-ratio", "mushroom-ratio", "flower-ratio", "pigs"}); SUPPORTED_TARGETS.put(Type.GROUND, new String[]{}); } From edf194f22b43700946c4ac5df2c6b41f2b25417f Mon Sep 17 00:00:00 2001 From: herdinaik Date: Fri, 21 Apr 2017 10:52:39 +0200 Subject: [PATCH 05/16] biome - rendering --- CodeMetropolis | 1 + .../pom.xml | 5 - .../toolchain/rendering/control/Chunk.java | 383 +++++++++++++ .../rendering/control/FileHandler.java | 55 ++ .../toolchain/rendering/control/Level.java | 79 +++ .../rendering/control/LevelFile.java | 44 ++ .../rendering/control/NBTException.java | 29 + .../toolchain/rendering/control/NBTTag.java | 522 ++++++++++++++++++ .../toolchain/rendering/control/Region.java | 89 +++ .../rendering/control/RegionFile.java | 375 +++++++++++++ .../toolchain/rendering/control/World.java | 203 +++++++ .../rendering/control/WorldBuilder.java | 3 +- .../rendering/model/primitive/Boxel.java | 2 +- 13 files changed, 1782 insertions(+), 8 deletions(-) create mode 160000 CodeMetropolis create mode 100644 sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java create mode 100644 sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/FileHandler.java create mode 100644 sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Level.java create mode 100644 sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/LevelFile.java create mode 100644 sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/NBTException.java create mode 100644 sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/NBTTag.java create mode 100644 sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Region.java create mode 100644 sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/RegionFile.java create mode 100644 sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java diff --git a/CodeMetropolis b/CodeMetropolis new file mode 160000 index 00000000..cf25f428 --- /dev/null +++ b/CodeMetropolis @@ -0,0 +1 @@ +Subproject commit cf25f428d7e9be77833bdff730c2d9796b1997ac diff --git a/sources/codemetropolis-toolchain-rendering/pom.xml b/sources/codemetropolis-toolchain-rendering/pom.xml index 3bbb1592..e54c7e53 100644 --- a/sources/codemetropolis-toolchain-rendering/pom.xml +++ b/sources/codemetropolis-toolchain-rendering/pom.xml @@ -62,11 +62,6 @@ sed graphlib 1.0 - - - codemetropolis - cmblockmodifier - 1.0.1 org.apache.commons diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java new file mode 100644 index 00000000..47877152 --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java @@ -0,0 +1,383 @@ +package codemetropolis.toolchain.rendering.control; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + + +public class Chunk { + + public NBTTag tag; + + private Chunk(NBTTag tag) { + if(tag.getType() != NBTTag.Type.TAG_Compound) { + try { + throw new NBTException("Chunk tag must be compound."); + } catch (NBTException e) { + e.printStackTrace(); + } + } + this.tag = tag; + + } + + + + public Chunk(int x, int z, byte biomId) { + + byte terrainPopulated = 1; + long inhabitedTime = 0L; + long lastUpdate = 0L; + + int[] heightMap = new int[256]; + Arrays.fill(heightMap, 0); + + byte[] biomes = new byte[256]; + Arrays.fill(biomes, (byte)biomId); + + NBTTag terrainPopulatedTag = new NBTTag(NBTTag.Type.TAG_Byte, "TerrainPopulated", terrainPopulated); + NBTTag xPosTag = new NBTTag(NBTTag.Type.TAG_Int, "xPos", x); + NBTTag zPosTag = new NBTTag(NBTTag.Type.TAG_Int, "zPos", z); + NBTTag inhabitedTimeTag = new NBTTag(NBTTag.Type.TAG_Long, "InhabitedTime", inhabitedTime); + NBTTag lastUpdateTag = new NBTTag(NBTTag.Type.TAG_Long, "LastUpdate", lastUpdate); + NBTTag biomesTag = new NBTTag(NBTTag.Type.TAG_Byte_Array, "Biomes", biomes); + NBTTag entitiesTag = new NBTTag(NBTTag.Type.TAG_List, "Entities", NBTTag.Type.TAG_Byte); + NBTTag tileEntitiesTag = new NBTTag(NBTTag.Type.TAG_List, "TileEntities", NBTTag.Type.TAG_Byte); + NBTTag heightMapTag = new NBTTag(NBTTag.Type.TAG_Int_Array, "HeightMap", heightMap); + NBTTag sectionsTag = new NBTTag("Sections", NBTTag.Type.TAG_List); + + NBTTag[] tagList = new NBTTag[] {terrainPopulatedTag, xPosTag, zPosTag, inhabitedTimeTag, biomesTag, lastUpdateTag, sectionsTag, entitiesTag, tileEntitiesTag, heightMapTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; + NBTTag levelTag = new NBTTag(NBTTag.Type.TAG_Compound, "Level", tagList); + this.tag = new NBTTag(NBTTag.Type.TAG_Compound, "", new NBTTag[]{ levelTag, new NBTTag(NBTTag.Type.TAG_End, null, null) }); + + } + + public static Chunk parseNBT(NBTTag t) { + return new Chunk(t); + } + + public NBTTag toNBT() { + return tag; + } + + public void setBlock(int x, int y, int z, byte type, byte data) { + int index = y >> 4; + NBTTag section = getSection(index); + if(section == null) { + section = addSection(index); + } + + int blockIndex = (y % 16) * 256 + z * 16 + x; + ((byte[]) section.getSubtagByName("Blocks").getValue()) [blockIndex] = type; + + boolean lastBits = ((double)x / 2) % 1 == 0 ? true : false; + byte value = ((byte[]) section.getSubtagByName("Data").getValue()) [blockIndex / 2]; + if(lastBits) { + value = (byte)((value & 0xF0) | data); + } else { + value = (byte)((value & 0x0F) | (data << 4)); + } + ((byte[]) section.getSubtagByName("Data").getValue()) [blockIndex / 2] = value; + + int[] heightMap = (int[])tag.getSubtagByName("Level").getSubtagByName("HeightMap").getValue(); + + if(heightMap[z * 16 + x] < y + 1) + heightMap[z * 16 + x] = y + 1; + } + + public void setSignText(int x, int y, int z, String text) { + + String[] texts = new String[4]; + for(int i = 0; i < 4; i++) { + if(text.length() > 15) { + texts[i] = text.substring(0, 14); + text = text.substring(14); + } else if(text.length() > 0) { + texts[i] = text.substring(0); + text = ""; + } else { + texts[i] = ""; + } + } + + NBTTag tileEntities = tag.getSubtagByName("Level").getSubtagByName("TileEntities"); + for(NBTTag t : (NBTTag[])tileEntities.getValue()) { + if( + (int)t.getSubtagByName("x").getValue() == x && + (int)t.getSubtagByName("y").getValue() == y && + (int)t.getSubtagByName("z").getValue() == z && + ((String)t.getSubtagByName("id").getValue()).equals("Sign") + ) { + + for(int i = 0; i < texts.length; i++) { + t.getSubtagByName("Text" + (i + 1)).setValue(texts[i]); + } + return; + } + } + + NBTTag xTag = new NBTTag(NBTTag.Type.TAG_Int, "x", x); + NBTTag yTag = new NBTTag(NBTTag.Type.TAG_Int, "y", y); + NBTTag zTag = new NBTTag(NBTTag.Type.TAG_Int, "z", z); + NBTTag idTag = new NBTTag(NBTTag.Type.TAG_String, "id", "Sign"); + NBTTag text1Tag = new NBTTag(NBTTag.Type.TAG_String, "Text1", texts[0]); + NBTTag text2Tag = new NBTTag(NBTTag.Type.TAG_String, "Text2", texts[1]); + NBTTag text3Tag = new NBTTag(NBTTag.Type.TAG_String, "Text3", texts[2]); + NBTTag text4Tag = new NBTTag(NBTTag.Type.TAG_String, "Text4", texts[3]); + NBTTag[] tagList = new NBTTag[] {xTag, yTag, zTag, idTag, text1Tag, text2Tag, text3Tag, text4Tag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; + NBTTag tileEntityTag = new NBTTag(NBTTag.Type.TAG_Compound, "", tagList); + + tileEntities.addTag(tileEntityTag); + + } + + public void setBannerColor(int x, int y, int z, int color) { + + NBTTag tileEntities = tag.getSubtagByName("Level").getSubtagByName("TileEntities"); + for(NBTTag t : (NBTTag[])tileEntities.getValue()) { + if( + (int)t.getSubtagByName("x").getValue() == x && + (int)t.getSubtagByName("y").getValue() == y && + (int)t.getSubtagByName("z").getValue() == z && + ((String)t.getSubtagByName("id").getValue()).equals("Banner") + ) { + t.getSubtagByName("Base").setValue(color); + return; + } + } + + NBTTag baseTag = new NBTTag(NBTTag.Type.TAG_Int, "Base", color); + NBTTag xTag = new NBTTag(NBTTag.Type.TAG_Int, "x", x); + NBTTag yTag = new NBTTag(NBTTag.Type.TAG_Int, "y", y); + NBTTag zTag = new NBTTag(NBTTag.Type.TAG_Int, "z", z); + NBTTag idTag = new NBTTag(NBTTag.Type.TAG_String, "id", "Banner"); + NBTTag[] tagList = new NBTTag[] {baseTag, xTag, yTag, zTag, idTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; + NBTTag tileEntityTag = new NBTTag(NBTTag.Type.TAG_Compound, "", tagList); + + tileEntities.addTag(tileEntityTag); + + } + + public void removeSignText(int x, int y, int z) { + removeTileEntity(x, y, z, "Sign"); + } + + public void addChestItem(int x, int y, int z, int id, int quantity) { + NBTTag tileEntity = getTileEntity(x, y, z, "Chest"); + + if(tileEntity == null) { + NBTTag xTag = new NBTTag(NBTTag.Type.TAG_Int, "x", x); + NBTTag yTag = new NBTTag(NBTTag.Type.TAG_Int, "y", y); + NBTTag zTag = new NBTTag(NBTTag.Type.TAG_Int, "z", z); + NBTTag idTag = new NBTTag(NBTTag.Type.TAG_String, "id", "Chest"); + NBTTag itemsTag = new NBTTag("Items", NBTTag.Type.TAG_Compound); + NBTTag[] tagList = new NBTTag[] {xTag, yTag, zTag, idTag, itemsTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; + tileEntity = new NBTTag(NBTTag.Type.TAG_Compound, "", tagList); + tag.getSubtagByName("Level").getSubtagByName("TileEntities").addTag(tileEntity); + } + + NBTTag items = tileEntity.getSubtagByName("Items"); + Set usedSlots = new HashSet(); + for(NBTTag t : (NBTTag[])items.getValue()) { + usedSlots.add((byte)t.getSubtagByName("Slot").getValue()); + } + + for(byte i = 0; i < 27; i++) { + if(!usedSlots.contains(i)) { + NBTTag idTag = new NBTTag(NBTTag.Type.TAG_Short, "id", (short)id); + NBTTag slotTag = new NBTTag(NBTTag.Type.TAG_Byte, "Slot", i); + NBTTag countTag = new NBTTag(NBTTag.Type.TAG_Byte, "Count", (byte)quantity); + NBTTag damageTag = new NBTTag(NBTTag.Type.TAG_Short, "Damage", (short)0); + NBTTag[] tagList = new NBTTag[] {idTag, slotTag, countTag, damageTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; + items.addTag(new NBTTag(NBTTag.Type.TAG_Compound, "", tagList)); + return; + } + } + + } + + public void clearChestItems(int x, int y, int z) { + removeTileEntity(x, y, z, "Chest"); + } + + private NBTTag getTileEntity(int x, int y, int z, String id) { + NBTTag tileEntities = tag.getSubtagByName("Level").getSubtagByName("TileEntities"); + for(NBTTag t : (NBTTag[])tileEntities.getValue()) { + if( + (int)t.getSubtagByName("x").getValue() == x && + (int)t.getSubtagByName("y").getValue() == y && + (int)t.getSubtagByName("z").getValue() == z && + ((String)t.getSubtagByName("id").getValue()).equals(id) + ) { + return t; + } + } + return null; + } + + public void removeTileEntity(int x, int y, int z, String id) { + + Set tagsToRemoveIndex = new HashSet(); + NBTTag tileEntities = tag.getSubtagByName("Level").getSubtagByName("TileEntities"); + NBTTag[] tileEntitiesArray = (NBTTag[])tileEntities.getValue(); + for(int i = 0; i < tileEntitiesArray.length; i++) { + NBTTag t = tileEntitiesArray[i]; + if( + (int)t.getSubtagByName("x").getValue() == x && + (int)t.getSubtagByName("y").getValue() == y && + (int)t.getSubtagByName("z").getValue() == z + ) { + if(id == null) { + tagsToRemoveIndex.add(i); + } else if(((String)t.getSubtagByName("id").getValue()).equals(id)) { + tagsToRemoveIndex.add(i); + break; + } + } + } + for(int i : tagsToRemoveIndex) + tileEntities.removeTag(i); + + } + + public void clearTileEntitiesAt(int x, int y, int z) { + removeTileEntity(x, y, z, null); + } + + private NBTTag getSection(int y) { + for(NBTTag t : tag.getSubtagByName("Level").getSubtagByName("Sections").getSubtags()) { + if((byte)t.getSubtagByName("Y").getValue() == y) { + return t; + } + } + return null; + } + + private NBTTag addSection(int y) { + + byte[] blockLight = new byte[2048]; + Arrays.fill(blockLight, (byte)0); + + byte[] blocks = new byte[4096]; + Arrays.fill(blocks, (byte)0); + + byte[] data = new byte[2048]; + Arrays.fill(data, (byte)0); + + byte[] skyLight = new byte[2048]; + Arrays.fill(skyLight, (byte)255); + + + NBTTag yTag = new NBTTag(NBTTag.Type.TAG_Byte, "Y", (byte)y); + NBTTag blockLightTag = new NBTTag(NBTTag.Type.TAG_Byte_Array, "BlockLight", blockLight); + NBTTag blocksTag = new NBTTag(NBTTag.Type.TAG_Byte_Array, "Blocks", blocks); + NBTTag dataTag = new NBTTag(NBTTag.Type.TAG_Byte_Array, "Data", data); + NBTTag skyLightTag = new NBTTag(NBTTag.Type.TAG_Byte_Array, "SkyLight", skyLight); + NBTTag[] tagList = new NBTTag[] {dataTag, skyLightTag, blockLightTag, yTag, blocksTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; + NBTTag sectionTag = new NBTTag(NBTTag.Type.TAG_Compound, "", tagList); + tag.getSubtagByName("Level").getSubtagByName("Sections").addTag(sectionTag); + + return sectionTag; + } + + public NBTTag addSection(int y, byte[] blocks, byte[] skyLight) { + NBTTag section = addSection(y); + section.getSubtagByName("Blocks").setValue(blocks); + section.getSubtagByName("SkyLight").setValue(skyLight); + return section; + } + + public NBTTag addSectionFilled(int y, byte type, int height) { + byte[] blocks = new byte[4096]; + byte[] skyLight = new byte[2048]; + + for(int _x = 0; _x < 16; _x++) { + for(int _y = 0; _y < 16; _y++) { + for(int _z = 0; _z < 16; _z++) { + if(_y < height) { + blocks[_y * 256 + _z * 16 + _x] = type; + } else { + blocks[_y * 256 + _z * 16 + _x] = 0; + } + } + } + } + + int[] heightMap = (int[])tag.getSubtagByName("Level").getSubtagByName("HeightMap").getValue(); + for(int i = 0; i < 256; i++) { + if(heightMap[i] < y * 16 + height) + heightMap[i] = y * 16 + height; + } + + Arrays.fill(skyLight, 0, height * 128, (byte)0); + Arrays.fill(skyLight, height * 128, 2048, (byte)255); + + return addSection(y, blocks, skyLight); + } + + public NBTTag addSectionFilled(int y, byte type) { + return addSectionFilled(y, type, 16); + } + + public void fill(int y, byte type) { + + for(int _y = 0; _y < (y >> 4); _y++) { + addSectionFilled(_y, type); + } + addSectionFilled(y >> 4, type, y % 16 + 1); + + } + + public void calculateLighting() { + byte[] lightingObjects = new byte[] {50, 124}; + NBTTag[] sectionTags = tag.getSubtagByName("Level").getSubtagByName("Sections").getSubtags(); + for(NBTTag section : sectionTags) { + byte[] skyLight = (byte[])section.getSubtagByName("SkyLight").getValue(); + byte[] blockLight = (byte[])section.getSubtagByName("BlockLight").getValue(); + byte[] blocks = (byte[])section.getSubtagByName("Blocks").getValue(); + //int sectionY = (byte)section.getSubtagByName("Y").getValue(); + for(int blockZ = 0; blockZ < 16; blockZ++) + for(int y = 0; y < 16; y++) + for(int blockX = 0; blockX < 16; blockX++) { + //Temporary solution + if(blocks[y * 256 + blockZ * 16 + blockX] != 0) { + setNibble(skyLight, (y * 256 + blockZ * 16 + blockX), (byte) 0); + for(byte b : lightingObjects) { + if(blocks[y * 256 + blockZ * 16 + blockX] == b) { + setNibble(blockLight, (y * 256 + blockZ * 16 + blockX), (byte) 15); + setNibble(blockLight, (y * 256 + blockZ * 16 + blockX + 1), (byte) 15); + setNibble(blockLight, (y * 256 + blockZ * 16 + blockX - 1), (byte) 15); + setNibble(blockLight, ((y + 1) * 256 + blockZ * 16 + blockX), (byte) 15); + setNibble(blockLight, ((y - 1) * 256 + blockZ * 16 + blockX), (byte) 15); + setNibble(blockLight, (y * 256 + (blockZ + 1) * 16 + blockX), (byte) 15); + setNibble(blockLight, (y * 256 + (blockZ - 1) * 16 + blockX), (byte) 15); + } + } + } + + } + section.getSubtagByName("SkyLight").setValue(skyLight); + section.getSubtagByName("BlockLight").setValue(blockLight); + } + } + + private static void setNibble(byte[] a, int index, byte value) { + if(index / 2 < 0 || index / 2 > a.length - 1) return; + + boolean lastBits = ((double)index / 2) % 1 == 0 ? true : false; + + if(lastBits) { + value = (byte)((a[index / 2] & 0xF0) | value); + } else { + value = (byte)((a[index / 2] & 0x0F) | (value << 4)); + } + + a[index / 2] = value; + } + + @Override + public String toString() { + return tag.toString(); + } + +} diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/FileHandler.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/FileHandler.java new file mode 100644 index 00000000..a134fffa --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/FileHandler.java @@ -0,0 +1,55 @@ +package codemetropolis.toolchain.rendering.control; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class FileHandler { + + public static void copy(String srcPath, String destPath, String... ignore) { + File sourceLocation = new File(srcPath); + File targetLocation = new File(destPath); + copy(sourceLocation, targetLocation, ignore); + } + + public static void copy(File sourceLocation, File targetLocation, String... ignore) { + for(String s : ignore) + if(sourceLocation.getName().equals(s)) return; + try { + if (sourceLocation.isDirectory()) { + copyDirectory(sourceLocation, targetLocation, ignore); + } else { + copyFile(sourceLocation, targetLocation); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static void copyDirectory(File source, File target, String... ignore) throws IOException { + if (!target.exists()) { + target.mkdirs(); + } + + for (String f : source.list()) { + copy(new File(source, f), new File(target, f), ignore); + } + } + + private static void copyFile(File source, File target) throws IOException { + try ( + InputStream in = new FileInputStream(source); + OutputStream out = new FileOutputStream(target) + ) { + byte[] buf = new byte[1024]; + int length; + while ((length = in.read(buf)) > 0) { + out.write(buf, 0, length); + } + } + } + +} diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Level.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Level.java new file mode 100644 index 00000000..331bcea0 --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Level.java @@ -0,0 +1,79 @@ +package codemetropolis.toolchain.rendering.control; + +import java.io.File; +import java.io.IOException; + + +public class Level { + + private LevelFile levelFile; + private NBTTag tag; + + public Level(World world) { + File file = new File(String.format("%s/level.dat", world.PATH)); + boolean alreadyExists = file.exists(); + this.levelFile = new LevelFile(file); + + if(alreadyExists) { + try { + tag = NBTTag.readFrom(levelFile.getLevelDataInputStream()); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + NBTTag allowCommandsTag = new NBTTag(NBTTag.Type.TAG_Byte, "allowCommands", (byte)0); + NBTTag hardcoreTag = new NBTTag(NBTTag.Type.TAG_Byte, "hardcore", (byte)0); + NBTTag initializedTag = new NBTTag(NBTTag.Type.TAG_Byte, "initialized", (byte)1); + NBTTag mapFeaturesTag = new NBTTag(NBTTag.Type.TAG_Byte, "MapFeatures", (byte)0); + NBTTag rainingTag = new NBTTag(NBTTag.Type.TAG_Byte, "raining", (byte)0); + NBTTag thunderingTag = new NBTTag(NBTTag.Type.TAG_Byte, "thundering", (byte)0); + NBTTag gameTypeTag = new NBTTag(NBTTag.Type.TAG_Int, "GameType", 1); + NBTTag generatorVersionTag = new NBTTag(NBTTag.Type.TAG_Int, "generatorVersion", 1); + NBTTag rainTimeTag = new NBTTag(NBTTag.Type.TAG_Int, "rainTime", Integer.MAX_VALUE); + NBTTag spawnXTag = new NBTTag(NBTTag.Type.TAG_Int, "SpawnX", 0); + NBTTag spawnYTag = new NBTTag(NBTTag.Type.TAG_Int, "SpawnY", world.GROUNDLEVEL + 1); + NBTTag spawnZTag = new NBTTag(NBTTag.Type.TAG_Int, "SpawnZ", 0); + NBTTag thunderTimeTag = new NBTTag(NBTTag.Type.TAG_Int, "thunderTime", Integer.MAX_VALUE); + NBTTag versionTag = new NBTTag(NBTTag.Type.TAG_Int, "version", 19133); + NBTTag dayTimeTag = new NBTTag(NBTTag.Type.TAG_Long, "DayTime", 3000L); + NBTTag lastPlayedTag = new NBTTag(NBTTag.Type.TAG_Long, "LastPlayed", 0L); + NBTTag randomSeedTag = new NBTTag(NBTTag.Type.TAG_Long, "RandomSeed", 0L); + NBTTag sizeOnDiskTag = new NBTTag(NBTTag.Type.TAG_Long, "SizeOnDisk", 0L); + NBTTag timeTag = new NBTTag(NBTTag.Type.TAG_Long, "Time", 3000L); + NBTTag generatorNameTag = new NBTTag(NBTTag.Type.TAG_String, "generatorName", "flat"); + NBTTag generatorOptionsTag = new NBTTag(NBTTag.Type.TAG_String, "generatorOptions", "3;minecraft:bedrock," + (world.GROUNDLEVEL - 1) + "*minecraft:dirt,minecraft:grass"); + NBTTag levelNameTag = new NBTTag(NBTTag.Type.TAG_String, "LevelName", world.NAME); + + NBTTag commandBlockOutputTag = new NBTTag(NBTTag.Type.TAG_String, "commandBlockOutput", "true"); + NBTTag doDaylightCycleTag = new NBTTag(NBTTag.Type.TAG_String, "doDaylightCycle", "false"); + NBTTag doFireTickTag = new NBTTag(NBTTag.Type.TAG_String, "doFireTick", "true"); + NBTTag doMobLootTag = new NBTTag(NBTTag.Type.TAG_String, "doMobLoot", "true"); + NBTTag doMobSpawningTag = new NBTTag(NBTTag.Type.TAG_String, "doMobSpawning", "false"); + NBTTag doTileDropsTag = new NBTTag(NBTTag.Type.TAG_String, "doTileDrops", "true"); + NBTTag keepInventoryTag = new NBTTag(NBTTag.Type.TAG_String, "keepInventory", "true"); + NBTTag mobGriefingTag = new NBTTag(NBTTag.Type.TAG_String, "mobGriefing", "false"); + NBTTag naturalRegenerationTag = new NBTTag(NBTTag.Type.TAG_String, "naturalRegeneration", "true"); + + NBTTag[] ruleList = new NBTTag[] {commandBlockOutputTag, doDaylightCycleTag, doFireTickTag, doMobLootTag, doMobSpawningTag, doTileDropsTag, + keepInventoryTag, mobGriefingTag, naturalRegenerationTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; + NBTTag gameRulesTag = new NBTTag(NBTTag.Type.TAG_Compound, "GameRules", ruleList); + + NBTTag[] tagList = new NBTTag[] {versionTag, initializedTag, levelNameTag, generatorNameTag, generatorVersionTag, generatorOptionsTag, randomSeedTag, + mapFeaturesTag, lastPlayedTag, sizeOnDiskTag, allowCommandsTag, hardcoreTag, gameTypeTag, timeTag, dayTimeTag, spawnXTag, spawnYTag, + spawnZTag, rainingTag, rainTimeTag, thunderingTag, thunderTimeTag, gameRulesTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; + NBTTag dataTag = new NBTTag(NBTTag.Type.TAG_Compound, "Data", tagList); + tag = new NBTTag(NBTTag.Type.TAG_Compound, "", new NBTTag[] {dataTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}); + } + + } + + public void writeToFile() { + try { + tag.writeTo(levelFile.getLevelDataOutputStream()); + levelFile.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/LevelFile.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/LevelFile.java new file mode 100644 index 00000000..62dcb813 --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/LevelFile.java @@ -0,0 +1,44 @@ +package codemetropolis.toolchain.rendering.control; + +import java.io.*; +import java.util.zip.*; + +public class LevelFile { + + private final File fileName; + private RandomAccessFile file; + + public LevelFile(File path) { + fileName = path; + path.getParentFile().mkdirs(); + try { + file = new RandomAccessFile(path, "rw"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public synchronized DataInputStream getLevelDataInputStream() { + try { + byte[] data = new byte[(int) file.length()]; + file.read(data); + return new DataInputStream(new BufferedInputStream(new GZIPInputStream(new ByteArrayInputStream(data)))); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public DataOutputStream getLevelDataOutputStream() { + try { + return new DataOutputStream(new GZIPOutputStream(new FileOutputStream(fileName))); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public void close() throws IOException { + file.close(); + } +} \ No newline at end of file diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/NBTException.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/NBTException.java new file mode 100644 index 00000000..ba0c266f --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/NBTException.java @@ -0,0 +1,29 @@ +package codemetropolis.toolchain.rendering.control; + +public class NBTException extends Exception { + + private static final long serialVersionUID = 1L; + + public NBTException() { + super(); + } + + public NBTException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public NBTException(String message, Throwable cause) { + super(message, cause); + } + + public NBTException(String message) { + super(message); + } + + public NBTException(Throwable cause) { + super(cause); + } + + + +} diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/NBTTag.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/NBTTag.java new file mode 100644 index 00000000..75acdd08 --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/NBTTag.java @@ -0,0 +1,522 @@ +package codemetropolis.toolchain.rendering.control; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class NBTTag { + private final Type type; + private Type listType = null; + private final String name; + private Object value; + + public enum Type { + TAG_End, + TAG_Byte, + TAG_Short, + TAG_Int, + TAG_Long, + TAG_Float, + TAG_Double, + TAG_Byte_Array, + TAG_String, + TAG_List, + TAG_Compound, + TAG_Int_Array + } + + /** + * Create a new TAG_List or TAG_Compound NBT tag. + * + * @param type either TAG_List or TAG_Compound + * @param name name for the new tag or null to create an unnamed tag. + * @param value list of tags to add to the new tag. + */ + public NBTTag(Type type, String name, NBTTag[] value) { + this(type, name, (Object) value); + } + + /** + * Create a new TAG_List with an empty list. Use {@link NBTTag#addTag(NBTTag)} to add tags later. + * + * @param name name for this tag or null to create an unnamed tag. + * @param listType type of the elements in this empty list. + */ + public NBTTag(String name, Type listType) { + this(Type.TAG_List, name, listType); + } + + /** + * Create a new NBT tag. + * + * @param type any value from the {@link Type} enum. + * @param name name for the new tag or null to create an unnamed tag. + * @param value an object that fits the tag type or a {@link Type} to create an empty TAG_List with this list type. + */ + public NBTTag(Type type, String name, Object value) { + switch (type) { + case TAG_End: + if (value != null) + throw new IllegalArgumentException(); + break; + case TAG_Byte: + if (!(value instanceof Byte)) + throw new IllegalArgumentException(); + break; + case TAG_Short: + if (!(value instanceof Short)) + throw new IllegalArgumentException(); + break; + case TAG_Int: + if (!(value instanceof Integer)) + throw new IllegalArgumentException(); + break; + case TAG_Long: + if (!(value instanceof Long)) + throw new IllegalArgumentException(); + break; + case TAG_Float: + if (!(value instanceof Float)) + throw new IllegalArgumentException(); + break; + case TAG_Double: + if (!(value instanceof Double)) + throw new IllegalArgumentException(); + break; + case TAG_Byte_Array: + if (!(value instanceof byte[])) + throw new IllegalArgumentException(); + break; + case TAG_String: + if (!(value instanceof String)) + throw new IllegalArgumentException(); + break; + case TAG_List: + if (value instanceof Type) { + this.listType = (Type) value; + value = new NBTTag[0]; + } else { + if (!(value instanceof NBTTag[])) + throw new IllegalArgumentException(); + this.listType = (((NBTTag[]) value)[0]).getType(); + } + break; + case TAG_Compound: + if (!(value instanceof NBTTag[])) + throw new IllegalArgumentException(); + break; + case TAG_Int_Array: + if (!(value instanceof int[])) + throw new IllegalArgumentException(); + break; + default: + throw new IllegalArgumentException(); + } + this.type = type; + this.name = name; + this.value = value; + } + + public Type getType() { + return type; + } + + public String getName() { + return name; + } + + public Object getValue() { + return value; + } + + public void setValue(Object newValue) + { + switch (type) { + case TAG_End: + if (value != null) + throw new IllegalArgumentException(); + break; + case TAG_Byte: + if (!(value instanceof Byte)) + throw new IllegalArgumentException(); + break; + case TAG_Short: + if (!(value instanceof Short)) + throw new IllegalArgumentException(); + break; + case TAG_Int: + if (!(value instanceof Integer)) + throw new IllegalArgumentException(); + break; + case TAG_Long: + if (!(value instanceof Long)) + throw new IllegalArgumentException(); + break; + case TAG_Float: + if (!(value instanceof Float)) + throw new IllegalArgumentException(); + break; + case TAG_Double: + if (!(value instanceof Double)) + throw new IllegalArgumentException(); + break; + case TAG_Byte_Array: + if (!(value instanceof byte[])) + throw new IllegalArgumentException(); + break; + case TAG_String: + if (!(value instanceof String)) + throw new IllegalArgumentException(); + break; + case TAG_List: + if (value instanceof Type) { + this.listType = (Type) value; + value = new NBTTag[0]; + } else { + if (!(value instanceof NBTTag[])) + throw new IllegalArgumentException(); + this.listType = (((NBTTag[]) value)[0]).getType(); + } + break; + case TAG_Compound: + if (!(value instanceof NBTTag[])) + throw new IllegalArgumentException(); + break; + case TAG_Int_Array: + if (!(value instanceof int[])) + throw new IllegalArgumentException(); + break; + default: + throw new IllegalArgumentException(); + } + + value = newValue; + } + + public void clearList() { + value = new NBTTag[0]; + } + + public Type getListType() { + return listType; + } + + /** + * Add a tag to a TAG_List or a TAG_Compound. + */ + public void addTag(NBTTag tag) { + if (type != Type.TAG_List && type != Type.TAG_Compound) + throw new RuntimeException(); + NBTTag[] subtags = (NBTTag[]) value; + + int index = subtags.length; + + //For TAG_Compund entries, we need to add the tag BEFORE the end, + //or the new tag gets placed after the TAG_End, messing up the data. + //TAG_End MUST be kept at the very end of the TAG_Compound. + if(type == Type.TAG_Compound) index--; + insertTag(tag, index); + } + + /** + * Add a tag to a TAG_List or a TAG_Compound at the specified index. + */ + public void insertTag(NBTTag tag, int index) { + if (type != Type.TAG_List && type != Type.TAG_Compound) + throw new RuntimeException(); + NBTTag[] subtags = (NBTTag[]) value; + if (subtags.length > 0) { + if (type == Type.TAG_List && tag.getType() != getListType()) { + throw new IllegalArgumentException(); + } + } else { + if (type == Type.TAG_List) { + listType = tag.getType(); // qqDPS + } + } + if (index > subtags.length) + throw new IndexOutOfBoundsException(); + NBTTag[] newValue = new NBTTag[subtags.length + 1]; + System.arraycopy(subtags, 0, newValue, 0, index); + newValue[index] = tag; + System.arraycopy(subtags, index, newValue, index + 1, subtags.length - index); + value = newValue; + } + + /** + * Remove a tag from a TAG_List or a TAG_Compound at the specified index. + * + * @return the removed tag + */ + public NBTTag removeTag(int index) { + if (type != Type.TAG_List && type != Type.TAG_Compound) + throw new RuntimeException(); + NBTTag[] subtags = (NBTTag[]) value; + NBTTag victim = subtags[index]; + NBTTag[] newValue = new NBTTag[subtags.length - 1]; + System.arraycopy(subtags, 0, newValue, 0, index); + index++; + System.arraycopy(subtags, index, newValue, index - 1, subtags.length - index); + value = newValue; + return victim; + } + + /** + * Remove a tag from a TAG_List or a TAG_Compound. If the tag is not a child of this tag then nested tags are searched. + * + * @param tag tag to look for + */ + public void removeSubtag(NBTTag tag) { + if (type != Type.TAG_List && type != Type.TAG_Compound) + throw new RuntimeException(); + if (tag == null) + return; + NBTTag[] subtags = (NBTTag[]) value; + for (int i = 0; i < subtags.length; i++) { + if (subtags[i] == tag) { + removeTag(i); + return; + } else { + if (subtags[i].type == Type.TAG_List || subtags[i].type == Type.TAG_Compound) { + subtags[i].removeSubtag(tag); + } + } + } + } + + /** + * Find the first nested tag with specified name in a TAG_Compound. + * + * @param name the name to look for. May be null to look for unnamed tags. + * @return the first nested tag that has the specified name. + */ + + public NBTTag getSubtagByName(String name) { + for(NBTTag t : getSubtags()) { + if(name == null || name.equals("")) { + if(t.getName() == null || t.getName().equals("")) return t; + } else { + if(t.getName() != null && t.getName().equals(name)) return t; + } + } + return null; + } + + /** + * Returns an array of all nested tags. + */ + public NBTTag[] getSubtags() { + if (type != Type.TAG_List && type != Type.TAG_Compound) + return null; + return (NBTTag[]) value; + } + + /** + * Read a tag and its nested tags from an InputStream. + * + * @param is stream to read from, like a FileInputStream + * @return NBT tag or structure read from the InputStream + * @throws IOException if there was no valid NBT structure in the InputStream or if another IOException occurred. + */ + public static NBTTag readFrom(InputStream is) throws IOException { + DataInputStream dis = new DataInputStream(is); + byte type = dis.readByte(); + NBTTag tag = null; + + if (type == 0) { + tag = new NBTTag(Type.TAG_End, null, null); + } else { + tag = new NBTTag(Type.values()[type], dis.readUTF(), readPayload(dis, type)); + } + + dis.close(); + + return tag; + } + + private static Object readPayload(DataInputStream dis, byte type) throws IOException { + switch (type) { + case 0: + return null; + case 1: + return dis.readByte(); + case 2: + return dis.readShort(); + case 3: + return dis.readInt(); + case 4: + return dis.readLong(); + case 5: + return dis.readFloat(); + case 6: + return dis.readDouble(); + case 7: + int length = dis.readInt(); + byte[] ba = new byte[length]; + dis.readFully(ba); + return ba; + case 8: + return dis.readUTF(); + case 9: + byte lt = dis.readByte(); + int ll = dis.readInt(); + NBTTag[] lo = new NBTTag[ll]; + for (int i = 0; i < ll; i++) { + lo[i] = new NBTTag(Type.values()[lt], null, readPayload(dis, lt)); + } + if (lo.length == 0) + return Type.values()[lt]; + else + return lo; + case 10: + byte stt; + NBTTag[] tags = new NBTTag[0]; + do { + stt = dis.readByte(); + String name = null; + if (stt != 0) { + name = dis.readUTF(); + } + NBTTag[] newTags = new NBTTag[tags.length + 1]; + System.arraycopy(tags, 0, newTags, 0, tags.length); + newTags[tags.length] = new NBTTag(Type.values()[stt], name, readPayload(dis, stt)); + tags = newTags; } while (stt != 0); + return tags; + case 11: + int len = dis.readInt(); + int[] ia = new int[len]; + for (int qq = 0; qq < len; qq++) { + ia[qq] = dis.readInt(); + } + return ia; + + } + return null; + } + + /** + * Write a tag and its nested tags to an OutputStream. + * + * @param os stream to write to, like a FileOutputStream + * @throws IOException if this is not a valid NBT structure or if any IOException occurred. + */ + public void writeTo(OutputStream os) throws IOException { + DataOutputStream dos = new DataOutputStream(os); + dos.writeByte(type.ordinal()); + if (type != Type.TAG_End) { + if (name != null) { dos.writeUTF(name); } // qqDPS + writePayload(dos); + } + dos.flush(); + dos.close(); + } + + private void writePayload(DataOutputStream dos) throws IOException { + switch (type) { + case TAG_End: + break; + case TAG_Byte: + dos.writeByte((Byte) value); + break; + case TAG_Short: + dos.writeShort((Short) value); + break; + case TAG_Int: + dos.writeInt((Integer) value); + break; + case TAG_Long: + dos.writeLong((Long) value); + break; + case TAG_Float: + dos.writeFloat((Float) value); + break; + case TAG_Double: + dos.writeDouble((Double) value); + break; + case TAG_Byte_Array: + byte[] ba = (byte[]) value; + dos.writeInt(ba.length); + dos.write(ba); + break; + case TAG_String: + dos.writeUTF((String) value); + break; + case TAG_List: + NBTTag[] list = (NBTTag[]) value; + dos.writeByte(getListType().ordinal()); + dos.writeInt(list.length); + for (NBTTag tt : list) { + tt.writePayload(dos); + } + break; + case TAG_Compound: + NBTTag[] subtags = (NBTTag[]) value; + for (NBTTag subtag : subtags) { + Type type = subtag.getType(); + dos.writeByte(type.ordinal()); + if (type != Type.TAG_End) { + dos.writeUTF(subtag.getName()); + subtag.writePayload(dos); + } + } + break; + case TAG_Int_Array: + int[] ia = (int[]) value; + dos.writeInt(ia.length); + for (int qq = 0; qq < ia.length; qq++) { + dos.writeInt(ia[qq]); + } + break; + + } + } + + @Override + public String toString() { + return toString(0); + } + + private String toString(int indentLevel) { + if (type == Type.TAG_End) return ""; + NBTTag[] nestedTags = getSubtags(); + StringBuilder sb = new StringBuilder(); + indent(sb, indentLevel); + sb.append(type.toString() + "("); + if(name != null && !name.equals("")) sb.append("\"" + name + "\""); + sb.append(")"); + switch(type) { + case TAG_Byte_Array: + sb.append(" [" + ((byte[])value).length + " bytes]"); + break; + case TAG_Int_Array: + sb.append(" [" + ((int[])value).length + " * 4 bytes]"); + break; + case TAG_List: + sb.append(": " + (nestedTags.length) + " entries"); + break; + case TAG_Compound: + sb.append(": " + (nestedTags.length - 1) + " entries"); + break; + default: + sb.append(": " + value); + } + sb.append("\n"); + if(type == Type.TAG_Compound || type == Type.TAG_List) { + indent(sb, indentLevel); + sb.append("{\n"); + for(NBTTag t : nestedTags) sb.append(t.toString(indentLevel + 1)); + indent(sb, indentLevel); + sb.append("}\n"); + } + return sb.toString(); + } + + private StringBuilder indent(StringBuilder sb, int indentLevel) { + String indent = " "; + for(int i = 0; i < indentLevel; i++) sb.append(indent); + return sb; + } + +} diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Region.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Region.java new file mode 100644 index 00000000..bed0024c --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Region.java @@ -0,0 +1,89 @@ +package codemetropolis.toolchain.rendering.control; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; + + +public class Region { + + private int x; + private int z; + RegionFile regionFile; + private Chunk[] chunks = new Chunk[1024]; + + public Region(int x, int z, World world) { + + this.x = x; + this.z = z; + File file = new File(String.format("%s/region/r.%d.%d.mca", world.PATH, x, z)); + file.getParentFile().mkdirs(); + this.regionFile = new RegionFile(file); + + try { + + for(int chunkX = 0; chunkX < 32; chunkX++) { + for(int chunkZ = 0; chunkZ < 32; chunkZ++) { + if(regionFile.hasChunk(chunkX, chunkZ)) { + DataInputStream inputStream = regionFile.getChunkDataInputStream(chunkX, chunkZ); + NBTTag chunkTag = NBTTag.readFrom(inputStream); + Chunk chunk = Chunk.parseNBT(chunkTag); + setChunk(chunkX, chunkZ, chunk); + } + } + } + + } catch (IOException e) { + e.printStackTrace(); + } + + } + + public void setChunk(int x, int z, Chunk c) { + chunks[z * 32 + x] = c; + } + + public Chunk getChunk(int x, int z) { + return chunks[z * 32 + x]; + } + + public static Region loadFromFile(int x, int z, World world) { + return new Region(x, z, world); + } + + public void writeToFile() { + try { + for(int i = 0; i < 1024; i++) { + Chunk c = chunks[i]; + if(c != null) { + DataOutputStream outputStream = regionFile.getChunkDataOutputStream(i % 32, i / 32); + c.calculateLighting(); + c.toNBT().writeTo(outputStream); + } + } + regionFile.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for(Chunk c : chunks) { + if(c != null) + sb.append(c.toString()); + } + return sb.toString(); + } + + public int getX() { + return x; + } + + public int getZ() { + return z; + } + +} diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/RegionFile.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/RegionFile.java new file mode 100644 index 00000000..b829582b --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/RegionFile.java @@ -0,0 +1,375 @@ +package codemetropolis.toolchain.rendering.control; +/* + ** 2011 January 5 + ** + ** The author disclaims copyright to this source code. In place of + ** a legal notice, here is a blessing: + ** + ** May you do good and not evil. + ** May you find forgiveness for yourself and forgive others. + ** May you share freely, never taking more than you give. + **/ + +/* + * 2011 February 16 + * + * This source code is based on the work of Scaevolus (see notice above). + * It has been slightly modified by Mojang AB (constants instead of magic + * numbers, a chunk timestamp header, and auto-formatted according to our + * formatter template). + * + */ + +// Interfaces with region files on the disk + +/* + + Region File Format + + Concept: The minimum unit of storage on hard drives is 4KB. 90% of Minecraft + chunks are smaller than 4KB. 99% are smaller than 8KB. Write a simple + container to store chunks in single files in runs of 4KB sectors. + + Each region file represents a 32x32 group of chunks. The conversion from + chunk number to region number is floor(coord / 32): a chunk at (30, -3) + would be in region (0, -1), and one at (70, -30) would be at (3, -1). + Region files are named "r.x.z.data", where x and z are the region coordinates. + + A region file begins with a 4KB header that describes where chunks are stored + in the file. A 4-byte big-endian integer represents sector offsets and sector + counts. The chunk offset for a chunk (x, z) begins at byte 4*(x+z*32) in the + file. The bottom byte of the chunk offset indicates the number of sectors the + chunk takes up, and the top 3 bytes represent the sector number of the chunk. + Given a chunk offset o, the chunk data begins at byte 4096*(o/256) and takes up + at most 4096*(o%256) bytes. A chunk cannot exceed 1MB in size. If a chunk + offset is 0, the corresponding chunk is not stored in the region file. + + Chunk data begins with a 4-byte big-endian integer representing the chunk data + length in bytes, not counting the length field. The length must be smaller than + 4096 times the number of sectors. The next byte is a version field, to allow + backwards-compatible updates to how chunks are encoded. + + A version of 1 represents a gzipped NBT file. The gzipped data is the chunk + length - 1. + + A version of 2 represents a deflated (zlib compressed) NBT file. The deflated + data is the chunk length - 1. + + */ + +import java.io.*; +import java.util.ArrayList; +import java.util.zip.*; + +public class RegionFile { + + private static final int VERSION_GZIP = 1; + private static final int VERSION_DEFLATE = 2; + + private static final int SECTOR_BYTES = 4096; + private static final int SECTOR_INTS = SECTOR_BYTES / 4; + + static final int CHUNK_HEADER_SIZE = 5; + private static final byte emptySector[] = new byte[4096]; + + private final File fileName; + private RandomAccessFile file; + private final int offsets[]; + private final int chunkTimestamps[]; + private ArrayList sectorFree; + private int sizeDelta; + private long lastModified = 0; + + public RegionFile(File path) { + offsets = new int[SECTOR_INTS]; + chunkTimestamps = new int[SECTOR_INTS]; + + fileName = path; + debugln("REGION LOAD " + fileName); + + sizeDelta = 0; + + try { + if (path.exists()) { + lastModified = path.lastModified(); + } + + file = new RandomAccessFile(path, "rw"); + + if (file.length() < SECTOR_BYTES) { + /* we need to write the chunk offset table */ + for (int i = 0; i < SECTOR_INTS; ++i) { + file.writeInt(0); + } + // write another sector for the timestamp info + for (int i = 0; i < SECTOR_INTS; ++i) { + file.writeInt(0); + } + + sizeDelta += SECTOR_BYTES * 2; + } + + if ((file.length() & 0xfff) != 0) { + /* the file size is not a multiple of 4KB, grow it */ + for (int i = 0; i < (file.length() & 0xfff); ++i) { + file.write((byte) 0); + } + } + + /* set up the available sector map */ + int nSectors = (int) file.length() / SECTOR_BYTES; + sectorFree = new ArrayList(nSectors); + + for (int i = 0; i < nSectors; ++i) { + sectorFree.add(true); + } + + sectorFree.set(0, false); // chunk offset table + sectorFree.set(1, false); // for the last modified info + + file.seek(0); + for (int i = 0; i < SECTOR_INTS; ++i) { + int offset = file.readInt(); + offsets[i] = offset; + if (offset != 0 && (offset >> 8) + (offset & 0xFF) <= sectorFree.size()) { + for (int sectorNum = 0; sectorNum < (offset & 0xFF); ++sectorNum) { + sectorFree.set((offset >> 8) + sectorNum, false); + } + } + } + for (int i = 0; i < SECTOR_INTS; ++i) { + int lastModValue = file.readInt(); + chunkTimestamps[i] = lastModValue; + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + /* the modification date of the region file when it was first opened */ + public long lastModified() { + return lastModified; + } + + /* gets how much the region file has grown since it was last checked */ + public synchronized int getSizeDelta() { + int ret = sizeDelta; + sizeDelta = 0; + return ret; + } + + // various small debug printing helpers + private void debug(String in) { +// System.out.print(in); + } + + private void debugln(String in) { + debug(in + "\n"); + } + + private void debug(String mode, int x, int z, String in) { + debug("REGION " + mode + " " + fileName.getName() + "[" + x + "," + z + "] = " + in); + } + + private void debug(String mode, int x, int z, int count, String in) { + debug("REGION " + mode + " " + fileName.getName() + "[" + x + "," + z + "] " + count + "B = " + in); + } + + private void debugln(String mode, int x, int z, String in) { + debug(mode, x, z, in + "\n"); + } + + /* + * gets an (uncompressed) stream representing the chunk data returns null if + * the chunk is not found or an error occurs + */ + public synchronized DataInputStream getChunkDataInputStream(int x, int z) { + if (outOfBounds(x, z)) { + debugln("READ", x, z, "out of bounds"); + return null; + } + + try { + int offset = getOffset(x, z); + if (offset == 0) { + // debugln("READ", x, z, "miss"); + return null; + } + + int sectorNumber = offset >> 8; + int numSectors = offset & 0xFF; + + if (sectorNumber + numSectors > sectorFree.size()) { + debugln("READ", x, z, "invalid sector"); + return null; + } + + file.seek(sectorNumber * SECTOR_BYTES); + int length = file.readInt(); + + if (length > SECTOR_BYTES * numSectors) { + debugln("READ", x, z, "invalid length: " + length + " > 4096 * " + numSectors); + return null; + } + + byte version = file.readByte(); + if (version == VERSION_GZIP) { + byte[] data = new byte[length - 1]; + file.read(data); + DataInputStream ret = new DataInputStream(new BufferedInputStream(new GZIPInputStream(new ByteArrayInputStream(data)))); + // debug("READ", x, z, " = found"); + return ret; + } else if (version == VERSION_DEFLATE) { + byte[] data = new byte[length - 1]; + file.read(data); + DataInputStream ret = new DataInputStream(new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(data)))); + // debug("READ", x, z, " = found"); + return ret; + } + + debugln("READ", x, z, "unknown version " + version); + return null; + } catch (IOException e) { + debugln("READ", x, z, "exception"); + return null; + } + } + + public DataOutputStream getChunkDataOutputStream(int x, int z) { + if (outOfBounds(x, z)) return null; + + return new DataOutputStream(new DeflaterOutputStream(new ChunkBuffer(x, z))); + } + + /* + * lets chunk writing be multithreaded by not locking the whole file as a + * chunk is serializing -- only writes when serialization is over + */ + class ChunkBuffer extends ByteArrayOutputStream { + private int x, z; + + public ChunkBuffer(int x, int z) { + super(8096); // initialize to 8KB + this.x = x; + this.z = z; + } + + public void close() { + RegionFile.this.write(x, z, buf, count); + } + } + + /* write a chunk at (x,z) with length bytes of data to disk */ + protected synchronized void write(int x, int z, byte[] data, int length) { + try { + int offset = getOffset(x, z); + int sectorNumber = offset >> 8; + int sectorsAllocated = offset & 0xFF; + int sectorsNeeded = (length + CHUNK_HEADER_SIZE) / SECTOR_BYTES + 1; + + // maximum chunk size is 1MB + if (sectorsNeeded >= 256) { + return; + } + + if (sectorNumber != 0 && sectorsAllocated == sectorsNeeded) { + /* we can simply overwrite the old sectors */ + debug("SAVE", x, z, length, "rewrite"); + write(sectorNumber, data, length); + } else { + /* we need to allocate new sectors */ + + /* mark the sectors previously used for this chunk as free */ + for (int i = 0; i < sectorsAllocated; ++i) { + sectorFree.set(sectorNumber + i, true); + } + + /* scan for a free space large enough to store this chunk */ + int runStart = sectorFree.indexOf(true); + int runLength = 0; + if (runStart != -1) { + for (int i = runStart; i < sectorFree.size(); ++i) { + if (runLength != 0) { + if (sectorFree.get(i)) runLength++; + else runLength = 0; + } else if (sectorFree.get(i)) { + runStart = i; + runLength = 1; + } + if (runLength >= sectorsNeeded) { + break; + } + } + } + + if (runLength >= sectorsNeeded) { + /* we found a free space large enough */ + debug("SAVE", x, z, length, "reuse"); + sectorNumber = runStart; + setOffset(x, z, (sectorNumber << 8) | sectorsNeeded); + for (int i = 0; i < sectorsNeeded; ++i) { + sectorFree.set(sectorNumber + i, false); + } + write(sectorNumber, data, length); + } else { + /* + * no free space large enough found -- we need to grow the + * file + */ + debug("SAVE", x, z, length, "grow"); + file.seek(file.length()); + sectorNumber = sectorFree.size(); + for (int i = 0; i < sectorsNeeded; ++i) { + file.write(emptySector); + sectorFree.add(false); + } + sizeDelta += SECTOR_BYTES * sectorsNeeded; + + write(sectorNumber, data, length); + setOffset(x, z, (sectorNumber << 8) | sectorsNeeded); + } + } + setTimestamp(x, z, (int) (System.currentTimeMillis() / 1000L)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /* write a chunk data to the region file at specified sector number */ + private void write(int sectorNumber, byte[] data, int length) throws IOException { + debugln(" " + sectorNumber); + file.seek(sectorNumber * SECTOR_BYTES); + file.writeInt(length + 1); // chunk length + file.writeByte(VERSION_DEFLATE); // chunk version number + file.write(data, 0, length); // chunk data + } + + /* is this an invalid chunk coordinate? */ + private boolean outOfBounds(int x, int z) { + return x < 0 || x >= 32 || z < 0 || z >= 32; + } + + private int getOffset(int x, int z) { + return offsets[x + z * 32]; + } + + public boolean hasChunk(int x, int z) { + return getOffset(x, z) != 0; + } + + private void setOffset(int x, int z, int offset) throws IOException { + offsets[x + z * 32] = offset; + file.seek((x + z * 32) * 4); + file.writeInt(offset); + } + + private void setTimestamp(int x, int z, int value) throws IOException { + chunkTimestamps[x + z * 32] = value; + file.seek(SECTOR_BYTES + (x + z * 32) * 4); + file.writeInt(value); + } + + public void close() throws IOException { + file.close(); + } +} \ No newline at end of file diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java new file mode 100644 index 00000000..120f3324 --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java @@ -0,0 +1,203 @@ +package codemetropolis.toolchain.rendering.control; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.LinkedList; + + +public class World { + + public final String PATH; + public final String NAME; + public final int GROUNDLEVEL; + public final byte BIOMEID; + private boolean groundBuilding = true; + private int maxLoadedRegions = 1; + private LinkedList loadedRegions = new LinkedList(); + + public World(String path, int groundLevel, byte id) { + + this.PATH = path; + this.GROUNDLEVEL = groundLevel; + this.BIOMEID = id; + String[] splitPath = path.split("[/\\\\]"); + this.NAME = splitPath[splitPath.length - 1]; + Level level = new Level(this); + level.writeToFile(); + } + + private void setBlock(int x, int y, int z, int type, int data, Object other) { + + if(y < 0 || y > 255) { + try { + throw new NBTException("Block's 'y' coordinate must be between 0 and 255"); + } catch (NBTException e) { + e.printStackTrace(); + } + } + + int regionX = x >> 9; + int regionZ = z >> 9; + int chunkX = x >> 4; + int chunkZ = z >> 4; + int chunkIndexX = (x % 512) >> 4; + int chunkIndexZ = (z % 512) >> 4; + chunkIndexX = chunkIndexX < 0 ? chunkIndexX + 32 : chunkIndexX; + chunkIndexZ = chunkIndexZ < 0 ? chunkIndexZ + 32 : chunkIndexZ; + int blockX = (x % 512) % 16; + int blockZ = (z % 512) % 16; + blockX = x < 0 ? blockX + 15 : blockX; + blockZ = z < 0 ? blockZ + 15 : blockZ; + + Region region = getRegion(regionX, regionZ); + Chunk chunk = region.getChunk(chunkIndexX, chunkIndexZ); + if(chunk == null) { + chunk = new Chunk(chunkX, chunkZ, BIOMEID); + if(groundBuilding) + chunk.fill(GROUNDLEVEL, (byte) 2); + region.setChunk(chunkIndexX, chunkIndexZ, chunk); + } + chunk.setBlock(blockX, y, blockZ, (byte) type, (byte) data); + + if(type == 63 || type == 68) { + chunk.setSignText(x, y, z, (String) other); + } else if (type == 54) { + chunk.clearChestItems(x, y, z); + int[] items = (int[])other; + for(int i = 0; i < items.length; i += 2) + chunk.addChestItem(x, y, z, items[i], items[i+1]); + } else if (type == 176) { + chunk.setBannerColor(x, y, z, (int)other); + } else { + chunk.clearTileEntitiesAt(x, y, z); + } + + } + + public void setBlock(int x, int y, int z, int type, int data) { + setBlock(x, y, z, type, data, null); + } + + public void setBlock(int x, int y, int z, int type) { + setBlock(x, y, z, type, 0, null); + } + + public void removeBlock(int x, int y, int z) { + setBlock(x, y, z, 0); + } + + public void setSignPost(int x, int y, int z, int data, String text) { + setBlock(x, y, z, 63, data, text); + } + + public void setSignPost(int x, int y, int z, String text) { + setSignPost(x, y, z, 0, text); + } + + public void setWallSign(int x, int y, int z, int data, String text) { + setBlock(x, y, z, 68, data, text); + } + + public void setWallSign(int x, int y, int z, String text) { + setWallSign(x, y, z, 0, text); + } + + public void setChest(int x, int y, int z, int data, int[] items) { + setBlock(x, y, z, 54, data, items); + } + + public void setChest(int x, int y, int z, int[] items) { + setChest(x, y, z, 0, items); + } + + public void setBanner(int x, int y, int z, int data, BannerColor color) { + setBlock(x, y, z, 176, data, color.ordinal()); + } + + private Region getRegion(int x, int z) { + + for(Region r : loadedRegions) { + if(r.getX() == x && r.getZ() == z) { + return r; + } + } + + if(loadedRegions.size() >= maxLoadedRegions) { + loadedRegions.removeFirst().writeToFile(); + } + + Region result = Region.loadFromFile(x, z, this); + loadedRegions.add(result); + return result; + } + + public void groundBuildingOn() { + this.groundBuilding = true; + } + + public void groundBuildingOff() { + this.groundBuilding = false; + } + + public void setMaximumNumberOfLoadedRegions(int max) { + this.maxLoadedRegions = max; + } + + public void finish() { + for(Region r : loadedRegions) { + r.writeToFile(); + } + loadedRegions.clear(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + File regionDirectory = new File(PATH + "/region"); + for(File f : regionDirectory.listFiles()) { + if(f.getName().matches("r\\.-?[0-9]*\\.-?[0-9]*.mca")) { + String[] parts = f.getName().split("\\."); + Region region = getRegion(Integer.parseInt(parts[1]), Integer.parseInt(parts[2])); + sb.append("** RegionFile: " + f.getName() + " **\n"); + sb.append(region.toString()); + sb.append("\n"); + } + } + return sb.toString(); + } + + public void toNBTFile(String path) { + try { + PrintWriter writer = new PrintWriter(new File(path + ".nbt")); + writer.println(this); + writer.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + public void toNBTFile() { + toNBTFile(NAME); + } + + public enum BannerColor { + BLACK, + RED, + GREEN, + BROWN, + BLUE, + PURPLE, + TURQUOISE, + LIGHT_GRAY, + GRAY, + PINK, + LIGHT_GREEN, + YELLOW, + LIGHT_BLUE, + LIGHT_PURPLE, + ORANGE, + WHITE; + } + +} diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java index c8b174c2..3e666771 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java @@ -10,7 +10,6 @@ import org.apache.commons.lang3.time.StopWatch; -import codemetropolis.blockmodifier.World; import codemetropolis.toolchain.commons.cmxml.Buildable; import codemetropolis.toolchain.commons.cmxml.BuildableTree; import codemetropolis.toolchain.commons.cmxml.exceptions.CmxmlReaderException; @@ -34,7 +33,7 @@ public class WorldBuilder { private int total = 0; public WorldBuilder(String worldPath) { - world = new World(worldPath, GROUND_LEVEL); + world = new World(worldPath, GROUND_LEVEL, (byte)11); } public void createBuildings(String inputPath) throws BuildingTypeMismatchException{ diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java index 931fff2c..d5106ca3 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java @@ -7,7 +7,7 @@ import java.io.IOException; import java.io.PrintWriter; -import codemetropolis.blockmodifier.World; +import codemetropolis.toolchain.rendering.control.World; import codemetropolis.toolchain.commons.cmxml.Point; import codemetropolis.toolchain.rendering.model.BasicBlock; From 15beb983907c85985416cb36d8c91be66b0acd00 Mon Sep 17 00:00:00 2001 From: Dominik Hirling Date: Fri, 21 Apr 2017 11:45:06 +0200 Subject: [PATCH 06/16] added biome id-s --- .../toolchain/mapping/model/Linking.java | 2 +- .../rendering/RenderingExecutor.java | 2 +- .../rendering/control/WorldBuilder.java | 32 +++++++++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java b/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java index f76aed75..6db1409d 100644 --- a/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java +++ b/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java @@ -25,7 +25,7 @@ public class Linking { SUPPORTED_TARGETS.put(Type.FLOOR, new String[]{"width", "height", "length", "character", "external_character", "torches"}); SUPPORTED_TARGETS.put(Type.CELLAR, new String[]{"width", "height", "length", "character", "external_character", "torches"}); SUPPORTED_TARGETS.put(Type.GARDEN, new String[]{"tree-ratio", "mushroom-ratio", "flower-ratio", "pigs"}); - SUPPORTED_TARGETS.put(Type.GROUND, new String[]{}); + SUPPORTED_TARGETS.put(Type.GROUND, new String[]{"biome-id"}); } @XmlAttribute diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/RenderingExecutor.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/RenderingExecutor.java index fad5b7de..1730f6bd 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/RenderingExecutor.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/RenderingExecutor.java @@ -64,7 +64,7 @@ public boolean execute(ExecutorArgs args) { return false; } - WorldBuilder worldBuilder = new WorldBuilder(renderingArgs.getWorldPath()); + WorldBuilder worldBuilder = new WorldBuilder(renderingArgs.getWorldPath(), renderingArgs.getInputFile()); for(EventListener listener : listeners) { worldBuilder.addEventListener((ProgressEventListener) listener); } diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java index 3e666771..5acfa822 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java @@ -31,9 +31,37 @@ public class WorldBuilder { private int count = 0; private int total = 0; + private int biomeID; - public WorldBuilder(String worldPath) { - world = new World(worldPath, GROUND_LEVEL, (byte)11); + public WorldBuilder(String worldPath, String inputPath) { + BuildableTree buildables = new BuildableTree(); + try { + buildables.loadFromFile(inputPath); + } catch (CmxmlReaderException e) { + e.printStackTrace(); + return; + } + + List grounds = new ArrayList(); + for(Buildable b : buildables.getBuildables()) { + switch(b.getType()) { + case FLOOR: + break; + case CELLAR: + break; + case GARDEN: + break; + case GROUND: + if (b.hasAttribute("biome-id")) { + biomeID = Integer.parseInt(b.getAttributeValue("biome-id")); + } + break; + case CONTAINER: + break; + } + + } + world = new World(worldPath, GROUND_LEVEL, (byte)biomeID); } public void createBuildings(String inputPath) throws BuildingTypeMismatchException{ From e1cc3ec7b53fcf48f3e9f5358dd3786ab13c850f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Berta?= Date: Sat, 22 Apr 2017 00:30:41 +0200 Subject: [PATCH 07/16] Add Mobs support to Rendering --- .../toolchain/rendering/control/Chunk.java | 17 +++++++++++ .../toolchain/rendering/control/World.java | 12 +++++++- .../rendering/model/building/Garden.java | 5 ++++ .../rendering/model/primitive/Mob.java | 30 +++++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Mob.java diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java index 47877152..a2eee3ab 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java @@ -130,6 +130,23 @@ public void setSignText(int x, int y, int z, String text) { tileEntities.addTag(tileEntityTag); } + + public void setMob(int x, int y, int z, String name) { + + NBTTag entities = tag.getSubtagByName("Level").getSubtagByName("Entities"); + + NBTTag xTag = new NBTTag(NBTTag.Type.TAG_Double, "x", x); + NBTTag yTag = new NBTTag(NBTTag.Type.TAG_Double, "y", y); + NBTTag zTag = new NBTTag(NBTTag.Type.TAG_Double, "z", z); + NBTTag pos = new NBTTag(NBTTag.Type.TAG_List, "Pos", new NBTTag[]{xTag, yTag, zTag}); + NBTTag idTag = new NBTTag(NBTTag.Type.TAG_String, "id", name); + NBTTag noAiTag = new NBTTag(NBTTag.Type.TAG_Byte, "NoAI", 1); + NBTTag[] tagList = new NBTTag[] {pos, idTag, noAiTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; + NBTTag entityTag = new NBTTag(NBTTag.Type.TAG_Compound, "", tagList); + + entities.addTag(entityTag); + + } public void setBannerColor(int x, int y, int z, int color) { diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java index 120f3324..bbbbcc64 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java @@ -1,5 +1,7 @@ package codemetropolis.toolchain.rendering.control; +import codemetropolis.toolchain.rendering.model.primitive.Mob; + import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; @@ -72,7 +74,13 @@ private void setBlock(int x, int y, int z, int type, int data, Object other) { } else { chunk.clearTileEntitiesAt(x, y, z); } - + + for(String s : Mob.SupportedMobs){ + if(s.equals((String)other)){ + chunk.setMob(x, y, z, (String) other); + } + } + } public void setBlock(int x, int y, int z, int type, int data) { @@ -110,6 +118,8 @@ public void setChest(int x, int y, int z, int data, int[] items) { public void setChest(int x, int y, int z, int[] items) { setChest(x, y, z, 0, items); } + + public void setMob(int x, int y, int z, String name){ setBlock(x, y, z, 0, 0, name); } public void setBanner(int x, int y, int z, int data, BannerColor color) { setBlock(x, y, z, 176, data, color.ordinal()); diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Garden.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Garden.java index 88b163b9..b79e7afe 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Garden.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Garden.java @@ -8,6 +8,7 @@ import codemetropolis.toolchain.rendering.model.pattern.RandomPattern; import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern; import codemetropolis.toolchain.rendering.model.pattern.YSplitPattern; +import codemetropolis.toolchain.rendering.model.primitive.Mob; import codemetropolis.toolchain.rendering.model.primitive.SignPost; import codemetropolis.toolchain.rendering.model.primitive.SolidBox; import codemetropolis.toolchain.rendering.util.Orientation; @@ -23,6 +24,7 @@ public Garden(Buildable innerBuildable) throws BuildingTypeMismatchException { prepareBase(); prepareDoor(); prepareSigns(); + prepareMobs(); } private void prepareBase( ) { @@ -144,5 +146,8 @@ private void prepareSigns( ) { primitives.add(new SignPost(position.getX(), position.getY() + 2, position.getZ() + size.getZ() - 1, SignPost.Orientation.SOUTHWEST, innerBuildable.getName())); primitives.add(new SignPost(position.getX() + size.getX() - 1, position.getY() + 2, position.getZ() + size.getZ() - 1, SignPost.Orientation.SOUTHEAST, innerBuildable.getName())); } + private void prepareMobs(){ + primitives.add(new Mob(position.getX() + size.getX()/2, position.getY() + 2, position.getZ() + size.getZ()/2, innerBuildable.getName())); + } } diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Mob.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Mob.java new file mode 100644 index 00000000..9470bf8e --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Mob.java @@ -0,0 +1,30 @@ +package codemetropolis.toolchain.rendering.model.primitive; + +import codemetropolis.toolchain.commons.cmxml.Point; +import codemetropolis.toolchain.rendering.model.BasicBlock; + +import java.io.File; + + +public class Mob implements Primitive{ + + public static String[] SupportedMobs = {"Pig", "Cow", "Rabbit", "Chicken", "Sheep"}; + + private Point position; + private String name; + + public Mob(int x, int y, int z, String name){ + super(); + this.position = new Point(x, y, z); + this.name = name; + } + + @Override + public int toCSVFile(File directory){ + new Boxel(new BasicBlock(BasicBlock.NonBlock), position, name).toCSVFile(directory); + return 1; + } + + @Override + public int getNumberOfBlocks(){ return 1; } +} From 6069b90df2a003af8383e6dd15ee3bdef95147fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Berta?= Date: Sat, 22 Apr 2017 00:36:58 +0200 Subject: [PATCH 08/16] Add additional Mob support to Mapping --- .../java/codemetropolis/toolchain/mapping/model/Linking.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java b/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java index 6db1409d..8f66ddd3 100644 --- a/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java +++ b/sources/codemetropolis-toolchain-mapping/src/main/java/codemetropolis/toolchain/mapping/model/Linking.java @@ -24,7 +24,7 @@ public class Linking { static { SUPPORTED_TARGETS.put(Type.FLOOR, new String[]{"width", "height", "length", "character", "external_character", "torches"}); SUPPORTED_TARGETS.put(Type.CELLAR, new String[]{"width", "height", "length", "character", "external_character", "torches"}); - SUPPORTED_TARGETS.put(Type.GARDEN, new String[]{"tree-ratio", "mushroom-ratio", "flower-ratio", "pigs"}); + SUPPORTED_TARGETS.put(Type.GARDEN, new String[]{"tree-ratio", "mushroom-ratio", "flower-ratio", "pig" , "cow", "rabbit", "chicken", "sheep"}); SUPPORTED_TARGETS.put(Type.GROUND, new String[]{"biome-id"}); } From 92c6bf825bc8518b9483baa1b660cb6f73cf25c0 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Apr 2017 10:18:34 +0200 Subject: [PATCH 09/16] WorldBuilder useless attributum deleted, and made a biomeid try catch block; all of the example xml files supplement with biomes and mobs --- .../mapping/sonarqube_mapping_example_1_0.xml | 25 +++++++++++++++++-- .../mapping/sonarqube_mapping_example_2_0.xml | 24 ++++++++++++++++++ .../sonarqube_split_mapping_example_1_0.xml | 25 +++++++++++++++++-- .../sonarqube_split_mapping_example_2_0.xml | 22 ++++++++++++++++ .../sourcemeter_mapping_example_1_0.xml | 25 +++++++++++++++++-- .../sourcemeter_mapping_example_2_0.xml | 24 +++++++++++++++++- .../rendering/control/WorldBuilder.java | 12 +++++++-- 7 files changed, 148 insertions(+), 9 deletions(-) diff --git a/examples/mapping/sonarqube_mapping_example_1_0.xml b/examples/mapping/sonarqube_mapping_example_1_0.xml index 37ed8956..2f90dd00 100644 --- a/examples/mapping/sonarqube_mapping_example_1_0.xml +++ b/examples/mapping/sonarqube_mapping_example_1_0.xml @@ -1,7 +1,28 @@ - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/mapping/sonarqube_mapping_example_2_0.xml b/examples/mapping/sonarqube_mapping_example_2_0.xml index b26ff456..357c09d9 100644 --- a/examples/mapping/sonarqube_mapping_example_2_0.xml +++ b/examples/mapping/sonarqube_mapping_example_2_0.xml @@ -1,5 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/mapping/sonarqube_split_mapping_example_1_0.xml b/examples/mapping/sonarqube_split_mapping_example_1_0.xml index 34f0ce57..968aa0a3 100644 --- a/examples/mapping/sonarqube_split_mapping_example_1_0.xml +++ b/examples/mapping/sonarqube_split_mapping_example_1_0.xml @@ -1,7 +1,15 @@ - - + + + + + + + + + + @@ -10,6 +18,19 @@ + + + + + + + + + + + + + diff --git a/examples/mapping/sonarqube_split_mapping_example_2_0.xml b/examples/mapping/sonarqube_split_mapping_example_2_0.xml index 2c007da9..5697c5e5 100644 --- a/examples/mapping/sonarqube_split_mapping_example_2_0.xml +++ b/examples/mapping/sonarqube_split_mapping_example_2_0.xml @@ -1,11 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/mapping/sourcemeter_mapping_example_1_0.xml b/examples/mapping/sourcemeter_mapping_example_1_0.xml index e289f3e4..24c97aca 100644 --- a/examples/mapping/sourcemeter_mapping_example_1_0.xml +++ b/examples/mapping/sourcemeter_mapping_example_1_0.xml @@ -4,8 +4,16 @@ - - + + + + + + + + + + @@ -60,6 +68,19 @@ + + + + + + + + + + + + + diff --git a/examples/mapping/sourcemeter_mapping_example_2_0.xml b/examples/mapping/sourcemeter_mapping_example_2_0.xml index efaa60e5..b41ccc29 100644 --- a/examples/mapping/sourcemeter_mapping_example_2_0.xml +++ b/examples/mapping/sourcemeter_mapping_example_2_0.xml @@ -3,13 +3,35 @@ - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java index 5acfa822..a63cdc02 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java @@ -31,7 +31,6 @@ public class WorldBuilder { private int count = 0; private int total = 0; - private int biomeID; public WorldBuilder(String worldPath, String inputPath) { BuildableTree buildables = new BuildableTree(); @@ -43,6 +42,7 @@ public WorldBuilder(String worldPath, String inputPath) { } List grounds = new ArrayList(); + int biomeID=1; for(Buildable b : buildables.getBuildables()) { switch(b.getType()) { case FLOOR: @@ -53,7 +53,15 @@ public WorldBuilder(String worldPath, String inputPath) { break; case GROUND: if (b.hasAttribute("biome-id")) { - biomeID = Integer.parseInt(b.getAttributeValue("biome-id")); + if(Integer.parseInt(b.getAttributeValue("biome-id"))>-1 && Integer.parseInt(b.getAttributeValue("biome-id"))<40){ + biomeID = Integer.parseInt(b.getAttributeValue("biome-id")); + }else{ + try { + throw new NBTException("Biome ID must be between 0 and 39"); + } catch (NBTException e) { + e.printStackTrace(); + } + } } break; case CONTAINER: From 10eba5b71441696ddaa2f11b23b70393aac922a2 Mon Sep 17 00:00:00 2001 From: Dominik Hirling Date: Sat, 22 Apr 2017 10:41:41 +0200 Subject: [PATCH 10/16] Removed unnecessary lines of code --- CodeMetropolis | 1 - generate.bat | 16 ++++++++++++++++ .../rendering/control/WorldBuilder.java | 11 ++--------- 3 files changed, 18 insertions(+), 10 deletions(-) delete mode 160000 CodeMetropolis create mode 100644 generate.bat diff --git a/CodeMetropolis b/CodeMetropolis deleted file mode 160000 index cf25f428..00000000 --- a/CodeMetropolis +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cf25f428d7e9be77833bdff730c2d9796b1997ac diff --git a/generate.bat b/generate.bat new file mode 100644 index 00000000..730a8449 --- /dev/null +++ b/generate.bat @@ -0,0 +1,16 @@ +@echo off +echo CodeMetropolis example + +echo Processing SourceMeter graph +java -jar CodeMetropolis_1.4-bin\codemetropolis-toolchain-converter-1.4.0.jar -t sourcemeter -i input\example.graph + +echo Processing Map file +java -jar CodeMetropolis_1.4-bin\codemetropolis-toolchain-mapping-1.4.0.jar -i converterToMapping.xml -m examples\sourcemeter_mapping_example.xml + +echo Placing +java -jar CodeMetropolis_1.4-bin\codemetropolis-toolchain-placing-1.4.0.jar -i mappingToPlacing.xml + +echo Rendering +java -jar CodeMetropolis_1.4-bin\codemetropolis-toolchain-rendering-1.4.0.jar -i placingToRendering.xml -w worlds\demo + +echo done. diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java index a63cdc02..b005060a 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java @@ -44,13 +44,7 @@ public WorldBuilder(String worldPath, String inputPath) { List grounds = new ArrayList(); int biomeID=1; for(Buildable b : buildables.getBuildables()) { - switch(b.getType()) { - case FLOOR: - break; - case CELLAR: - break; - case GARDEN: - break; + switch (b.getType()) { case GROUND: if (b.hasAttribute("biome-id")) { if(Integer.parseInt(b.getAttributeValue("biome-id"))>-1 && Integer.parseInt(b.getAttributeValue("biome-id"))<40){ @@ -64,9 +58,8 @@ public WorldBuilder(String worldPath, String inputPath) { } } break; - case CONTAINER: - break; } + } world = new World(worldPath, GROUND_LEVEL, (byte)biomeID); From 53b5d8f920bb5221bc9002b80e1a51a6bba5d016 Mon Sep 17 00:00:00 2001 From: Dominik Hirling Date: Sat, 22 Apr 2017 10:43:08 +0200 Subject: [PATCH 11/16] Removed unnecessary lines of code --- generate.bat | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 generate.bat diff --git a/generate.bat b/generate.bat deleted file mode 100644 index 730a8449..00000000 --- a/generate.bat +++ /dev/null @@ -1,16 +0,0 @@ -@echo off -echo CodeMetropolis example - -echo Processing SourceMeter graph -java -jar CodeMetropolis_1.4-bin\codemetropolis-toolchain-converter-1.4.0.jar -t sourcemeter -i input\example.graph - -echo Processing Map file -java -jar CodeMetropolis_1.4-bin\codemetropolis-toolchain-mapping-1.4.0.jar -i converterToMapping.xml -m examples\sourcemeter_mapping_example.xml - -echo Placing -java -jar CodeMetropolis_1.4-bin\codemetropolis-toolchain-placing-1.4.0.jar -i mappingToPlacing.xml - -echo Rendering -java -jar CodeMetropolis_1.4-bin\codemetropolis-toolchain-rendering-1.4.0.jar -i placingToRendering.xml -w worlds\demo - -echo done. From 18bb1eb2b14b7752d028f59db56764f2709d34f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Apr 2017 11:58:18 +0200 Subject: [PATCH 12/16] change pigs to pig --- examples/mapping/sonarqube_mapping_example_1_0.xml | 2 +- examples/mapping/sonarqube_mapping_example_2_0.xml | 2 +- examples/mapping/sonarqube_split_mapping_example_1_0.xml | 2 +- examples/mapping/sonarqube_split_mapping_example_2_0.xml | 2 +- examples/mapping/sourcemeter_mapping_example_1_0.xml | 2 +- examples/mapping/sourcemeter_mapping_example_2_0.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/mapping/sonarqube_mapping_example_1_0.xml b/examples/mapping/sonarqube_mapping_example_1_0.xml index 2f90dd00..438bb11b 100644 --- a/examples/mapping/sonarqube_mapping_example_1_0.xml +++ b/examples/mapping/sonarqube_mapping_example_1_0.xml @@ -13,7 +13,7 @@ - + diff --git a/examples/mapping/sonarqube_mapping_example_2_0.xml b/examples/mapping/sonarqube_mapping_example_2_0.xml index 357c09d9..99fe6e12 100644 --- a/examples/mapping/sonarqube_mapping_example_2_0.xml +++ b/examples/mapping/sonarqube_mapping_example_2_0.xml @@ -12,7 +12,7 @@ - + diff --git a/examples/mapping/sonarqube_split_mapping_example_1_0.xml b/examples/mapping/sonarqube_split_mapping_example_1_0.xml index 968aa0a3..0dea9347 100644 --- a/examples/mapping/sonarqube_split_mapping_example_1_0.xml +++ b/examples/mapping/sonarqube_split_mapping_example_1_0.xml @@ -20,7 +20,7 @@ - + diff --git a/examples/mapping/sonarqube_split_mapping_example_2_0.xml b/examples/mapping/sonarqube_split_mapping_example_2_0.xml index 5697c5e5..28712572 100644 --- a/examples/mapping/sonarqube_split_mapping_example_2_0.xml +++ b/examples/mapping/sonarqube_split_mapping_example_2_0.xml @@ -17,7 +17,7 @@ - + diff --git a/examples/mapping/sourcemeter_mapping_example_1_0.xml b/examples/mapping/sourcemeter_mapping_example_1_0.xml index 24c97aca..33cf6d2b 100644 --- a/examples/mapping/sourcemeter_mapping_example_1_0.xml +++ b/examples/mapping/sourcemeter_mapping_example_1_0.xml @@ -71,7 +71,7 @@ - + diff --git a/examples/mapping/sourcemeter_mapping_example_2_0.xml b/examples/mapping/sourcemeter_mapping_example_2_0.xml index b41ccc29..68d08383 100644 --- a/examples/mapping/sourcemeter_mapping_example_2_0.xml +++ b/examples/mapping/sourcemeter_mapping_example_2_0.xml @@ -21,7 +21,7 @@ - + From ec6c996e314456b246b8268362d9e06f2ce034a4 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Apr 2017 12:00:19 +0200 Subject: [PATCH 13/16] change pigs to pig --- CodeMetropolis | 1 + 1 file changed, 1 insertion(+) create mode 160000 CodeMetropolis diff --git a/CodeMetropolis b/CodeMetropolis new file mode 160000 index 00000000..cf25f428 --- /dev/null +++ b/CodeMetropolis @@ -0,0 +1 @@ +Subproject commit cf25f428d7e9be77833bdff730c2d9796b1997ac From c06ef4026cdd963b115da5611b471d84676cc68f Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Apr 2017 15:32:41 +0200 Subject: [PATCH 14/16] xml example fix --- examples/mapping/sonarqube_mapping_example_1_0.xml | 4 ++-- examples/mapping/sonarqube_mapping_example_2_0.xml | 4 ++-- examples/mapping/sonarqube_split_mapping_example_1_0.xml | 4 ++-- examples/mapping/sonarqube_split_mapping_example_2_0.xml | 4 ++-- examples/mapping/sourcemeter_mapping_example_1_0.xml | 4 ++-- examples/mapping/sourcemeter_mapping_example_2_0.xml | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/mapping/sonarqube_mapping_example_1_0.xml b/examples/mapping/sonarqube_mapping_example_1_0.xml index 438bb11b..2e165955 100644 --- a/examples/mapping/sonarqube_mapping_example_1_0.xml +++ b/examples/mapping/sonarqube_mapping_example_1_0.xml @@ -6,8 +6,8 @@ - - + + diff --git a/examples/mapping/sonarqube_mapping_example_2_0.xml b/examples/mapping/sonarqube_mapping_example_2_0.xml index 99fe6e12..ee158386 100644 --- a/examples/mapping/sonarqube_mapping_example_2_0.xml +++ b/examples/mapping/sonarqube_mapping_example_2_0.xml @@ -5,8 +5,8 @@ - - + + diff --git a/examples/mapping/sonarqube_split_mapping_example_1_0.xml b/examples/mapping/sonarqube_split_mapping_example_1_0.xml index 0dea9347..a627ce25 100644 --- a/examples/mapping/sonarqube_split_mapping_example_1_0.xml +++ b/examples/mapping/sonarqube_split_mapping_example_1_0.xml @@ -6,8 +6,8 @@ - - + + diff --git a/examples/mapping/sonarqube_split_mapping_example_2_0.xml b/examples/mapping/sonarqube_split_mapping_example_2_0.xml index 28712572..d59cb000 100644 --- a/examples/mapping/sonarqube_split_mapping_example_2_0.xml +++ b/examples/mapping/sonarqube_split_mapping_example_2_0.xml @@ -5,8 +5,8 @@ - - + + diff --git a/examples/mapping/sourcemeter_mapping_example_1_0.xml b/examples/mapping/sourcemeter_mapping_example_1_0.xml index 33cf6d2b..8206a44b 100644 --- a/examples/mapping/sourcemeter_mapping_example_1_0.xml +++ b/examples/mapping/sourcemeter_mapping_example_1_0.xml @@ -10,8 +10,8 @@ - - + + diff --git a/examples/mapping/sourcemeter_mapping_example_2_0.xml b/examples/mapping/sourcemeter_mapping_example_2_0.xml index 68d08383..4f51f697 100644 --- a/examples/mapping/sourcemeter_mapping_example_2_0.xml +++ b/examples/mapping/sourcemeter_mapping_example_2_0.xml @@ -9,8 +9,8 @@ - - + + From 2efca8ff5b85b5b1fbcbc4298e57d13f1693e4f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Berta?= Date: Tue, 2 May 2017 02:10:50 +0200 Subject: [PATCH 15/16] Mobs HotFix --- .../toolchain/rendering/control/Chunk.java | 4 +-- .../toolchain/rendering/control/World.java | 19 +++++++---- .../rendering/control/WorldBuilder.java | 32 ++++++++++++------- .../toolchain/rendering/model/BasicBlock.java | 2 ++ .../rendering/model/primitive/Boxel.java | 3 ++ .../rendering/model/primitive/Mob.java | 4 +-- 6 files changed, 42 insertions(+), 22 deletions(-) diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java index a2eee3ab..4f1edca9 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java @@ -131,7 +131,7 @@ public void setSignText(int x, int y, int z, String text) { } - public void setMob(int x, int y, int z, String name) { + public void setMob(double x, double y, double z, String name) { NBTTag entities = tag.getSubtagByName("Level").getSubtagByName("Entities"); @@ -140,7 +140,7 @@ public void setMob(int x, int y, int z, String name) { NBTTag zTag = new NBTTag(NBTTag.Type.TAG_Double, "z", z); NBTTag pos = new NBTTag(NBTTag.Type.TAG_List, "Pos", new NBTTag[]{xTag, yTag, zTag}); NBTTag idTag = new NBTTag(NBTTag.Type.TAG_String, "id", name); - NBTTag noAiTag = new NBTTag(NBTTag.Type.TAG_Byte, "NoAI", 1); + NBTTag noAiTag = new NBTTag(NBTTag.Type.TAG_Byte, "NoAI", (byte)1); NBTTag[] tagList = new NBTTag[] {pos, idTag, noAiTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; NBTTag entityTag = new NBTTag(NBTTag.Type.TAG_Compound, "", tagList); diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java index bbbbcc64..a154d664 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java @@ -13,16 +13,20 @@ public class World { public final String PATH; public final String NAME; public final int GROUNDLEVEL; + public final boolean HASMOB; public final byte BIOMEID; private boolean groundBuilding = true; private int maxLoadedRegions = 1; + private int mobCounter = 0; + public final long mobLimit = 100; private LinkedList loadedRegions = new LinkedList(); - public World(String path, int groundLevel, byte id) { + public World(String path, int groundLevel, byte id, boolean hasMob) { this.PATH = path; this.GROUNDLEVEL = groundLevel; this.BIOMEID = id; + this.HASMOB = hasMob; String[] splitPath = path.split("[/\\\\]"); this.NAME = splitPath[splitPath.length - 1]; Level level = new Level(this); @@ -75,11 +79,14 @@ private void setBlock(int x, int y, int z, int type, int data, Object other) { chunk.clearTileEntitiesAt(x, y, z); } - for(String s : Mob.SupportedMobs){ - if(s.equals((String)other)){ - chunk.setMob(x, y, z, (String) other); - } + + + if(HASMOB && type == -1 && mobCounter < mobLimit){ + chunk.setMob(x, y, z, "Pig"); + mobCounter++; } + + } @@ -119,7 +126,7 @@ public void setChest(int x, int y, int z, int[] items) { setChest(x, y, z, 0, items); } - public void setMob(int x, int y, int z, String name){ setBlock(x, y, z, 0, 0, name); } + public void setMob(int x, int y, int z, String name){ setBlock(x, y, z, -1, 0, name); } public void setBanner(int x, int y, int z, int data, BannerColor color) { setBlock(x, y, z, 176, data, color.ordinal()); diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java index b005060a..a73b1527 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java @@ -8,6 +8,7 @@ import java.util.EventListener; import java.util.List; +import codemetropolis.toolchain.rendering.model.primitive.Mob; import org.apache.commons.lang3.time.StopWatch; import codemetropolis.toolchain.commons.cmxml.Buildable; @@ -43,26 +44,33 @@ public WorldBuilder(String worldPath, String inputPath) { List grounds = new ArrayList(); int biomeID=1; + boolean hasMob = false; + List mobs = new ArrayList(); for(Buildable b : buildables.getBuildables()) { switch (b.getType()) { - case GROUND: - if (b.hasAttribute("biome-id")) { - if(Integer.parseInt(b.getAttributeValue("biome-id"))>-1 && Integer.parseInt(b.getAttributeValue("biome-id"))<40){ - biomeID = Integer.parseInt(b.getAttributeValue("biome-id")); - }else{ - try { - throw new NBTException("Biome ID must be between 0 and 39"); - } catch (NBTException e) { - e.printStackTrace(); + case GROUND: + if (b.hasAttribute("biome-id")) { + if(Integer.parseInt(b.getAttributeValue("biome-id"))>-1 && Integer.parseInt(b.getAttributeValue("biome-id"))<40){ + biomeID = Integer.parseInt(b.getAttributeValue("biome-id")); + }else{ + try { + throw new NBTException("Biome ID must be between 0 and 39"); + } catch (NBTException e) { + e.printStackTrace(); + } } } - } - break; + break; + case GARDEN: + if(b.hasAttribute("pig")){ + hasMob = true; + } + break; } } - world = new World(worldPath, GROUND_LEVEL, (byte)biomeID); + world = new World(worldPath, GROUND_LEVEL, (byte)biomeID, hasMob); } public void createBuildings(String inputPath) throws BuildingTypeMismatchException{ diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/BasicBlock.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/BasicBlock.java index dc71b59d..77788236 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/BasicBlock.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/BasicBlock.java @@ -12,6 +12,7 @@ public class BasicBlock { public static final BasicBlock NonBlock; + public static final BasicBlock Mob; public static final Map idToName; public static final Map idToHumanReadableName; public static final Map nameToId; @@ -19,6 +20,7 @@ public class BasicBlock { static { NonBlock = new BasicBlock((short)-1 ); + Mob = new BasicBlock((short)-2 ); idToName = new HashMap(); idToHumanReadableName = new HashMap(); nameToId = new HashMap(); diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java index d5106ca3..eb43f353 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java @@ -41,9 +41,12 @@ public void render(World world) { case 176: world.setBanner(position.getX(), position.getY(), position.getZ(), block.getData(), World.BannerColor.valueOf(info.toUpperCase())); break; + case -2: + world.setMob(position.getX(), position.getY(), position.getZ(), block.getName()); default: world.setBlock(position.getX(), position.getY(), position.getZ(), block.getId(), block.getData()); } + } public String toCSV() { diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Mob.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Mob.java index 9470bf8e..f8c33c5b 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Mob.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Mob.java @@ -8,7 +8,7 @@ public class Mob implements Primitive{ - public static String[] SupportedMobs = {"Pig", "Cow", "Rabbit", "Chicken", "Sheep"}; + public static final String[] SupportedMobs = {"pig", "cow", "rabbit", "chicken", "sheep"}; private Point position; private String name; @@ -21,7 +21,7 @@ public Mob(int x, int y, int z, String name){ @Override public int toCSVFile(File directory){ - new Boxel(new BasicBlock(BasicBlock.NonBlock), position, name).toCSVFile(directory); + new Boxel(new BasicBlock(BasicBlock.Mob), position, name).toCSVFile(directory); return 1; } From 836b2405d3dcae015762818013cb214f22cb9dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Berta?= Date: Thu, 18 May 2017 00:23:07 +0200 Subject: [PATCH 16/16] Remove gates for the request of the project owner so mobs dont walk out from the garden. Basic refactoring on biomes code. --- CodeMetropolis | 1 - .../toolchain/rendering/control/Chunk.java | 16 ++++++++++------ .../toolchain/rendering/control/Region.java | 2 +- .../toolchain/rendering/control/World.java | 14 +++++++++++--- .../rendering/control/WorldBuilder.java | 1 - .../rendering/model/building/Garden.java | 11 ++++++++++- 6 files changed, 32 insertions(+), 13 deletions(-) delete mode 160000 CodeMetropolis diff --git a/CodeMetropolis b/CodeMetropolis deleted file mode 160000 index cf25f428..00000000 --- a/CodeMetropolis +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cf25f428d7e9be77833bdff730c2d9796b1997ac diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java index 4f1edca9..09a14c0f 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Chunk.java @@ -23,7 +23,7 @@ private Chunk(NBTTag tag) { - public Chunk(int x, int z, byte biomId) { + public Chunk(int x, int z) { byte terrainPopulated = 1; long inhabitedTime = 0L; @@ -32,21 +32,18 @@ public Chunk(int x, int z, byte biomId) { int[] heightMap = new int[256]; Arrays.fill(heightMap, 0); - byte[] biomes = new byte[256]; - Arrays.fill(biomes, (byte)biomId); NBTTag terrainPopulatedTag = new NBTTag(NBTTag.Type.TAG_Byte, "TerrainPopulated", terrainPopulated); NBTTag xPosTag = new NBTTag(NBTTag.Type.TAG_Int, "xPos", x); NBTTag zPosTag = new NBTTag(NBTTag.Type.TAG_Int, "zPos", z); NBTTag inhabitedTimeTag = new NBTTag(NBTTag.Type.TAG_Long, "InhabitedTime", inhabitedTime); NBTTag lastUpdateTag = new NBTTag(NBTTag.Type.TAG_Long, "LastUpdate", lastUpdate); - NBTTag biomesTag = new NBTTag(NBTTag.Type.TAG_Byte_Array, "Biomes", biomes); NBTTag entitiesTag = new NBTTag(NBTTag.Type.TAG_List, "Entities", NBTTag.Type.TAG_Byte); NBTTag tileEntitiesTag = new NBTTag(NBTTag.Type.TAG_List, "TileEntities", NBTTag.Type.TAG_Byte); NBTTag heightMapTag = new NBTTag(NBTTag.Type.TAG_Int_Array, "HeightMap", heightMap); NBTTag sectionsTag = new NBTTag("Sections", NBTTag.Type.TAG_List); - NBTTag[] tagList = new NBTTag[] {terrainPopulatedTag, xPosTag, zPosTag, inhabitedTimeTag, biomesTag, lastUpdateTag, sectionsTag, entitiesTag, tileEntitiesTag, heightMapTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; + NBTTag[] tagList = new NBTTag[] {terrainPopulatedTag, xPosTag, zPosTag, inhabitedTimeTag, lastUpdateTag, sectionsTag, entitiesTag, tileEntitiesTag, heightMapTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; NBTTag levelTag = new NBTTag(NBTTag.Type.TAG_Compound, "Level", tagList); this.tag = new NBTTag(NBTTag.Type.TAG_Compound, "", new NBTTag[]{ levelTag, new NBTTag(NBTTag.Type.TAG_End, null, null) }); @@ -60,6 +57,13 @@ public NBTTag toNBT() { return tag; } + public void setBiome(byte biomeId){ + byte[] biomes = new byte[256]; + Arrays.fill(biomes, (byte)biomeId); + NBTTag biomesTag = new NBTTag(NBTTag.Type.TAG_Byte_Array, "Biomes", biomes); + tag.getSubtagByName("Level").addTag(biomesTag); + } + public void setBlock(int x, int y, int z, byte type, byte data) { int index = y >> 4; NBTTag section = getSection(index); @@ -140,7 +144,7 @@ public void setMob(double x, double y, double z, String name) { NBTTag zTag = new NBTTag(NBTTag.Type.TAG_Double, "z", z); NBTTag pos = new NBTTag(NBTTag.Type.TAG_List, "Pos", new NBTTag[]{xTag, yTag, zTag}); NBTTag idTag = new NBTTag(NBTTag.Type.TAG_String, "id", name); - NBTTag noAiTag = new NBTTag(NBTTag.Type.TAG_Byte, "NoAI", (byte)1); + NBTTag noAiTag = new NBTTag(NBTTag.Type.TAG_Byte, "NoAI", (byte)0); NBTTag[] tagList = new NBTTag[] {pos, idTag, noAiTag, new NBTTag(NBTTag.Type.TAG_End, null, null)}; NBTTag entityTag = new NBTTag(NBTTag.Type.TAG_Compound, "", tagList); diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Region.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Region.java index bed0024c..e282628e 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Region.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/Region.java @@ -11,7 +11,7 @@ public class Region { private int x; private int z; RegionFile regionFile; - private Chunk[] chunks = new Chunk[1024]; + public Chunk[] chunks = new Chunk[1024]; public Region(int x, int z, World world) { diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java index a154d664..ae4ea9e0 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/World.java @@ -1,6 +1,5 @@ package codemetropolis.toolchain.rendering.control; -import codemetropolis.toolchain.rendering.model.primitive.Mob; import java.io.File; import java.io.FileNotFoundException; @@ -18,7 +17,7 @@ public class World { private boolean groundBuilding = true; private int maxLoadedRegions = 1; private int mobCounter = 0; - public final long mobLimit = 100; + public final long mobLimit = 300; private LinkedList loadedRegions = new LinkedList(); public World(String path, int groundLevel, byte id, boolean hasMob) { @@ -59,7 +58,7 @@ private void setBlock(int x, int y, int z, int type, int data, Object other) { Region region = getRegion(regionX, regionZ); Chunk chunk = region.getChunk(chunkIndexX, chunkIndexZ); if(chunk == null) { - chunk = new Chunk(chunkX, chunkZ, BIOMEID); + chunk = new Chunk(chunkX, chunkZ); if(groundBuilding) chunk.fill(GROUNDLEVEL, (byte) 2); region.setChunk(chunkIndexX, chunkIndexZ, chunk); @@ -163,10 +162,19 @@ public void setMaximumNumberOfLoadedRegions(int max) { public void finish() { for(Region r : loadedRegions) { + setBiomeForRegion(r); r.writeToFile(); } loadedRegions.clear(); } + + public void setBiomeForRegion(Region r){ + for(Chunk c : r.chunks){ + if(c != null){ + c.setBiome(BIOMEID); + } + } + } @Override public String toString() { diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java index a73b1527..44cc57ad 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java @@ -45,7 +45,6 @@ public WorldBuilder(String worldPath, String inputPath) { List grounds = new ArrayList(); int biomeID=1; boolean hasMob = false; - List mobs = new ArrayList(); for(Buildable b : buildables.getBuildables()) { switch (b.getType()) { case GROUND: diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Garden.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Garden.java index b79e7afe..89f39599 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Garden.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Garden.java @@ -22,7 +22,16 @@ public Garden(Buildable innerBuildable) throws BuildingTypeMismatchException { throw new BuildingTypeMismatchException(innerBuildable.getType(), getClass()); prepareBase(); - prepareDoor(); + /* + * Removed the gates on the + * sides of the gardens + * at the request of the + * project owner, so the + * mobs do not wonder around. + * To re-enable just uncomment + * this. + */ + //prepareDoor(); prepareSigns(); prepareMobs(); }