diff --git a/examples/mapping/sourcemeter_mapping_example_2_0.xml b/examples/mapping/sourcemeter_mapping_example_2_0.xml
index efaa60e5..c613abb6 100644
--- a/examples/mapping/sourcemeter_mapping_example_2_0.xml
+++ b/examples/mapping/sourcemeter_mapping_example_2_0.xml
@@ -11,6 +11,13 @@
+
+
+
+
+
+
+
diff --git a/sources/codemetropolis-toolchain-commons/.classpath b/sources/codemetropolis-toolchain-commons/.classpath
index e7a868fb..cd555fe2 100644
--- a/sources/codemetropolis-toolchain-commons/.classpath
+++ b/sources/codemetropolis-toolchain-commons/.classpath
@@ -18,12 +18,6 @@
-
-
-
-
-
-
diff --git a/sources/codemetropolis-toolchain-commons/pom.xml b/sources/codemetropolis-toolchain-commons/pom.xml
index 5e3a3413..bbd89ca5 100644
--- a/sources/codemetropolis-toolchain-commons/pom.xml
+++ b/sources/codemetropolis-toolchain-commons/pom.xml
@@ -17,5 +17,13 @@
gson
2.6.1
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
\ No newline at end of file
diff --git a/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/Buildable.java b/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/Buildable.java
index 6ce6fda9..7e548cbe 100644
--- a/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/Buildable.java
+++ b/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/Buildable.java
@@ -15,6 +15,7 @@ public enum Type {
GROUND,
GARDEN,
FLOOR,
+ DECORATION_FLOOR,
CELLAR,
CONTAINER;
}
@@ -101,6 +102,10 @@ public String getAttributeValue(String name) {
return null;
}
+ public void setAttributes(List attributes) {
+ this.attributes = attributes;
+ }
+
public Buildable[] getAncestors() {
List result = new ArrayList();
Buildable temp = this;
@@ -178,6 +183,12 @@ public void clearAttributes() {
attributes.clear();
}
+ public void addFirstChild(Buildable b) {
+ if(!b.isRoot()) b.parent.children.remove(b);
+ children.add(0, b);
+ b.parent = this;
+ }
+
public void addChild(Buildable b) {
if(!b.isRoot()) b.parent.children.remove(b);
children.add(b);
@@ -317,10 +328,18 @@ public Attribute[] getAttributes() {
public Buildable[] getChildren() {
return children.toArray(new Buildable[children.size()]);
}
+
+ public List getChildrenList() {
+ return children;
+ }
public Buildable getParent() {
return parent;
}
+
+ public void setParent(Buildable parent) {
+ this.parent = parent;
+ }
public boolean isRoot() {
return parent == null;
diff --git a/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/BuildableTree.java b/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/BuildableTree.java
index 06ebe60b..8bfc07b7 100644
--- a/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/BuildableTree.java
+++ b/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/BuildableTree.java
@@ -128,6 +128,8 @@ public void loadFromFile(String path) throws CmxmlReaderException {
break;
case "floor": type = Type.FLOOR;
break;
+ case "decoration_floor": type = Type.DECORATION_FLOOR;
+ break;
case "cellar": type = Type.CELLAR;
break;
case "container": type = Type.CONTAINER;
diff --git a/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/Point.java b/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/Point.java
index dd3fa473..fbace43b 100644
--- a/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/Point.java
+++ b/sources/codemetropolis-toolchain-commons/src/main/java/codemetropolis/toolchain/commons/cmxml/Point.java
@@ -49,4 +49,16 @@ protected void setZ(int z) {
this.z = z;
}
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Point) {
+ Point point = (Point) obj;
+ return (this.x == point.getX() &&
+ this.y == point.getY() &&
+ this.z == point.getZ());
+ } else {
+ return false;
+ }
+ }
+
}
diff --git a/sources/codemetropolis-toolchain-commons/src/main/resources/resources.properties b/sources/codemetropolis-toolchain-commons/src/main/resources/resources.properties
index 83de1655..c47e50ea 100644
--- a/sources/codemetropolis-toolchain-commons/src/main/resources/resources.properties
+++ b/sources/codemetropolis-toolchain-commons/src/main/resources/resources.properties
@@ -1,91 +1,96 @@
-# Message prefixes
-error_prefix = Error:
-converter_prefix = Converter:
-mapping_prefix = Mapping:
-placing_prefix = Placing:
-rendering_prefix = Rendering:
-
-# Converter info
-converter_introduction = CodeMetropolis CDF Converter (c) University of Szeged, Department of Software Engineering
-converter_usage = Usage: java -jar converter.jar -t -s [-o ] [-p ]
-
-# Converter notifications
-converting_to_cdf = Converting input to CDF format...
-converting_to_cdf_done = Converting input to CDF format done.
-printing_cdf = Printing CDF document...
-printing_cdf_done = Printing CDF document done.
-
-#SonarQube converter
-sonar_downloading_project = Downloading data of project %s.
-
-# Mapping info
-mapping_introduction = CodeMetropolis Toolchain Mapping (c) University of Szeged, Department of Software Engineering
-mapping_usage = Usage: java -jar mapping.jar -i -m [-o ]
-
-# Mapping notifications
-reading_mapping = Reading map file...
-reading_mapping_done = Reading map file done.
-validating_mapping = Validating mapping...
-validating_mapping_done = Validating mapping done.
-reading_graph = Reading CDF file...
-reading_graph_done = Reading CDF file done.
-linking_metrics = Linking metrics to buildables...
-linking_metrics_done = Linking metrics to buildables done.
-mapping_printing_output = Generating input for placing...
-mapping_printing_output_done = Generating input for placing done.
-
-# Placing info
-placing_introduction = CodeMetropolis Toolchain Placing (c) University of Szeged, Department of Software Engineering
-placing_usage = Usage: java -jar placing.jar -i [-o ] [-m]
-
-# Placing notifications
-placing_reading_input = Reading input file...
-placing_reading_input_done = Reading input file done.
-calculating_size_and_pos = Calculating building sizes and positions...
-calculating_size_and_pos_done = Calculating building sizes and positions done.
-placing_printing_output = Generating input for rendering...
-placing_printing_output_done = Generating input for rendering done.
-
-# Rendering info
-rendering_introduction = CodeMetropolis Toolchain Rendering (c) University of Szeged, Department of Software Engineering
-rendering_usage = Usage: java -jar rendering.jar -i -world
-
-# Rendering notifications
-world_already_exists = Another world with the same name might exist or being built right now. Do you want to overwrite? [Y/N]
-render_interrupted = Interrupted. End of program.
-rendering_reading_input = Reading input file...
-rendering_reading_input_done = Reading input file done.
-buildables_found = %d buildables were found.
-creating_blocks = Generating blocks...
-creating_blocks_progress = Generating blocks... %.2f%% (Remaining: %2d hours, %2d minutes)
-creating_blocks_done = Generating blocks done. %d blocks were generated in %d hours and %d minutes.
-placing_blocks = Placing blocks...
-placing_blocks_progress = Placing blocks... %.2f%% (Remaining: %2d hours, %2d minutes)
-placing_blocks_done = Placing blocks done in %d hours and %d minutes.
-
-# Errors
-command_line_error = Incorrect command line arguments.
-invalid_linking_error = Linking ( %s, %s -> %s, %s ) is not supported.
-invalid_linking_target_error = '%s' is not a valid linking target.
-missing_resource_error = Mapping resource '%s' is not declared.
-invalid_input_xml_error = Input XML is not in CMXML format.
-missing_input_xml_error = The given input XML does not exits.
-missing_layout_error = Layout with the given identifier does not exist.
-mapping_reader_error = An error has occurred while reading the mapping file. For more information please check the log file.
-cmxml_writer_error = An error has occurred while writing the output file. For more information please check the log file.
-cmxml_reader_error = An error has occurred while reading the input file. For more information please check the log file.
-layout_error = An error has occurred during layout creation. For more information please check the log file.
-cdf_error = An error has occurred while processing CDF. For more information please check the log file.
-cdf_writer_error = An error has occurred while writing CDF to file. For more information please check the log file.
-cdf_not_found_error = No CDF file was found on the given path.
-mapping_not_found_error = No mapping file was found on the given path.
-building_creation_failed_error = An error has occurred while processing building data. Please make sure you are using a valid input file.
-too_long_render_duration_error = Generating world would take more time then the maximum allowed (%d minutes)
-placing_blocks_failed_error = An error has occurred while placing blocks. For more information please check the log file.
-converter_error = An error has occurred while converting to CDF format. For more information please check the log file.
-invalid_hierarchy_error = Invalid structure has been found in buildable hierarchy.
-invalid_scale_error = Scale value must be between %.2f and %.2f.
-invalid_converter_type = Converter with the given identifier does not exist.
-invalid_params = Invalid parameter format.
-sonar_connect_error = Could not connect to SonarQube server.
-sonar_unauthorized_error = Unauthorized server access. Please provide your username and password in converter parameters if you are accessing a non-public SonarQube resource.
\ No newline at end of file
+# Message prefixes
+error_prefix = Error:
+converter_prefix = Converter:
+mapping_prefix = Mapping:
+placing_prefix = Placing:
metrics_prefix = Metrics processing:
+rendering_prefix = Rendering:
+
+# Converter info
+converter_introduction = CodeMetropolis CDF Converter (c) University of Szeged, Department of Software Engineering
+converter_usage = Usage: java -jar converter.jar -t -s [-o ] [-p ]
+
+# Converter notifications
+converting_to_cdf = Converting input to CDF format...
+converting_to_cdf_done = Converting input to CDF format done.
+printing_cdf = Printing CDF document...
+printing_cdf_done = Printing CDF document done.
+
+#SonarQube converter
+sonar_downloading_project = Downloading data of project %s.
+
+# Mapping info
+mapping_introduction = CodeMetropolis Toolchain Mapping (c) University of Szeged, Department of Software Engineering
+mapping_usage = Usage: java -jar mapping.jar -i -m [-o ]
+
+# Mapping notifications
+reading_mapping = Reading map file...
+reading_mapping_done = Reading map file done.
+validating_mapping = Validating mapping...
+validating_mapping_done = Validating mapping done.
+reading_graph = Reading CDF file...
+reading_graph_done = Reading CDF file done.
+linking_metrics = Linking metrics to buildables...
+linking_metrics_done = Linking metrics to buildables done.
+mapping_printing_output = Generating input for placing...
+mapping_printing_output_done = Generating input for placing done.
+
+# Placing info
+placing_introduction = CodeMetropolis Toolchain Placing (c) University of Szeged, Department of Software Engineering
+placing_usage = Usage: java -jar placing.jar -i [-o ] [-m]
+
+# Placing notifications
+placing_reading_input = Reading input file...
+placing_reading_input_done = Reading input file done.
+calculating_size_and_pos = Calculating building sizes and positions...
+calculating_size_and_pos_done = Calculating building sizes and positions done.
+placing_printing_output = Generating input for rendering...
+placing_printing_output_done = Generating input for rendering done.
+
+# Metrics processing notifications
+metrics_generating_began = Generating metrics for display...
+metrics_generating_done = Metrics created.
+
+# Rendering info
+rendering_introduction = CodeMetropolis Toolchain Rendering (c) University of Szeged, Department of Software Engineering
+rendering_usage = Usage: java -jar rendering.jar -i -world [-t ]
+
+# Rendering notifications
+world_already_exists = Another world with the same name might exist or being built right now. Do you want to overwrite? [Y/N]
+render_interrupted = Interrupted. End of program.
+rendering_reading_input = Reading input file...
+rendering_reading_input_done = Reading input file done.
+buildables_found = %d buildables were found.
+creating_blocks = Generating blocks...
+creating_blocks_progress = Generating blocks... %.2f%% (Remaining: %2d hours, %2d minutes)
+creating_blocks_done = Generating blocks done. %d blocks were generated in %d hours and %d minutes.
+placing_blocks = Placing blocks...
+placing_blocks_progress = Placing blocks... %.2f%% (Remaining: %2d hours, %2d minutes)
+placing_blocks_done = Placing blocks done in %d hours and %d minutes.
+
+# Errors
+command_line_error = Incorrect command line arguments.
+invalid_linking_error = Linking ( %s, %s -> %s, %s ) is not supported.
+invalid_linking_target_error = '%s' is not a valid linking target.
+missing_resource_error = Mapping resource '%s' is not declared.
+invalid_input_xml_error = Input XML is not in CMXML format.
+missing_input_xml_error = The given input XML does not exits.
+missing_layout_error = Layout with the given identifier does not exist.
+mapping_reader_error = An error has occurred while reading the mapping file. For more information please check the log file.
+cmxml_writer_error = An error has occurred while writing the output file. For more information please check the log file.
+cmxml_reader_error = An error has occurred while reading the input file. For more information please check the log file.
+layout_error = An error has occurred during layout creation. For more information please check the log file.
+cdf_error = An error has occurred while processing CDF. For more information please check the log file.
+cdf_writer_error = An error has occurred while writing CDF to file. For more information please check the log file.
+cdf_not_found_error = No CDF file was found on the given path.
+mapping_not_found_error = No mapping file was found on the given path.
+building_creation_failed_error = An error has occurred while processing building data. Please make sure you are using a valid input file.
+too_long_render_duration_error = Generating world would take more time then the maximum allowed (%d minutes)
+placing_blocks_failed_error = An error has occurred while placing blocks. For more information please check the log file.
+converter_error = An error has occurred while converting to CDF format. For more information please check the log file.
+invalid_hierarchy_error = Invalid structure has been found in buildable hierarchy.
+invalid_scale_error = Scale value must be between %.2f and %.2f.
+invalid_converter_type = Converter with the given identifier does not exist.
+invalid_params = Invalid parameter format.
+sonar_connect_error = Could not connect to SonarQube server.
+sonar_unauthorized_error = Unauthorized server access. Please provide your username and password in converter parameters if you are accessing a non-public SonarQube resource.
sourcemeter_only_error = Only SourceMeter metrics are allowed for the in-game display.
+xml_not_found = XML not found, expected location:
\ No newline at end of file
diff --git a/sources/codemetropolis-toolchain-commons/src/main/resources/settings.properties b/sources/codemetropolis-toolchain-commons/src/main/resources/settings.properties
index 1b8e4bd5..0f4574a0 100644
--- a/sources/codemetropolis-toolchain-commons/src/main/resources/settings.properties
+++ b/sources/codemetropolis-toolchain-commons/src/main/resources/settings.properties
@@ -1,4 +1,4 @@
-converter_log_file = CodeMetropolis_toolchain.log
-mapping_log_file = CodeMetropolis_toolchain.log
-placing_log_file = CodeMetropolis_toolchain.log
+converter_log_file = CodeMetropolis_toolchain.log
+mapping_log_file = CodeMetropolis_toolchain.log
+placing_log_file = CodeMetropolis_toolchain.log
metrics_log_file = CodeMetropolis_toolchain.log
rendering_log_file = CodeMetropolis_toolchain.log
\ No newline at end of file
diff --git a/sources/codemetropolis-toolchain-commons/src/test/java/codemetropolis/toolchain/commons/cmxml/PointTest.java b/sources/codemetropolis-toolchain-commons/src/test/java/codemetropolis/toolchain/commons/cmxml/PointTest.java
new file mode 100644
index 00000000..3531c40e
--- /dev/null
+++ b/sources/codemetropolis-toolchain-commons/src/test/java/codemetropolis/toolchain/commons/cmxml/PointTest.java
@@ -0,0 +1,99 @@
+package codemetropolis.toolchain.commons.cmxml;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test class for {@link Point}. Testing functions on different positions.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class PointTest {
+
+ /**
+ * Check if given points equality is determined correctly.
+ */
+ @Test
+ public void testEquals() {
+ Assert.assertTrue(new Point(0, 0, 0).equals(new Point(0, 0, 0)));
+ }
+
+ /**
+ * Check if given points inequality is determined correctly.
+ */
+ @Test
+ public void testNonEquals() {
+ Assert.assertFalse(new Point(0, 0, 0).equals(new Point(0, 2, 0)));
+ }
+
+ /**
+ * Check if the point won't be translated when there is no translation in origo.
+ */
+ @Test
+ public void testZeroTranslateFromZeroAll() {
+ Point testPoint = new Point(0, 0, 0);
+
+ Assert.assertEquals(new Point(0, 0, 0), testPoint.translate(new Point(0, 0, 0)));
+ }
+
+ /**
+ * Check if negative point will be in the right point after translation in all directions.
+ */
+ @Test
+ public void testTranslateFromNegativeAll() {
+ Point testPoint = new Point(-8, -10, -9);
+
+ Assert.assertEquals(new Point(-12, -5, -10), testPoint.translate(new Point(-4, 5, -1)));
+ }
+
+ /**
+ * Check if positive point will be in the right point after translation in all directions.
+ */
+ @Test
+ public void testTranslateFromPositiveAll() {
+ Point testPoint = new Point(8, 10, 9);
+
+ Assert.assertEquals(new Point(4, 15, 8), testPoint.translate(new Point(-4, 5, -1)));
+ }
+
+ /**
+ * Check if negative point will be in the right point after translation in one direction.
+ */
+ @Test
+ public void testTranslateFromNegativeOne() {
+ Point testPoint = new Point(-8, -10, -9);
+
+ Assert.assertEquals(new Point(-12, -10, -9), testPoint.translate(new Point(-4, 0, 0)));
+ }
+
+ /**
+ * Check if negative point will be in the right point after translation in two directions.
+ */
+ @Test
+ public void testTranslateFromNegativeTwo() {
+ Point testPoint = new Point(-8, -10, -9);
+
+ Assert.assertEquals(new Point(-12, -10, -4), testPoint.translate(new Point(-4, 0, 5)));
+ }
+
+ /**
+ * Check if positive point will be in the right point after translation in one direction.
+ */
+ @Test
+ public void testPositiveTranslateFromPositiveOne() {
+ Point testPoint = new Point(8, 10, 9);
+
+ Assert.assertEquals(new Point(12, 10, 9), testPoint.translate(new Point(4, 0, 0)));
+ }
+
+ /**
+ * Check if positive point will be in the right point after translation in two direction.
+ */
+ @Test
+ public void testPositiveTranslateFromPositiveTwo() {
+ Point testPoint = new Point(8, 10, 9);
+
+ Assert.assertEquals(new Point(12, 15, 9), testPoint.translate(new Point(4, 5, 0)));
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-commons/src/test/java/codemetropolis/toolchain/commons/util/TimeTest.java b/sources/codemetropolis-toolchain-commons/src/test/java/codemetropolis/toolchain/commons/util/TimeTest.java
new file mode 100644
index 00000000..1c8df190
--- /dev/null
+++ b/sources/codemetropolis-toolchain-commons/src/test/java/codemetropolis/toolchain/commons/util/TimeTest.java
@@ -0,0 +1,181 @@
+package codemetropolis.toolchain.commons.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test class for {@link Time}. Testing functions on different times.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class TimeTest {
+
+ /**
+ * Test for zero time.
+ */
+ @Test
+ public void testZero() {
+ Time time = new Time(0);
+
+ Assert.assertEquals(0, time.getHours());
+ Assert.assertEquals(0, time.getMinutes());
+ Assert.assertEquals(0, time.getSeconds());
+ }
+
+ /**
+ * Test for 999ms.
+ */
+ @Test
+ public void testBarelyLessThanOneSecond() {
+ Time time = new Time(999);
+
+ Assert.assertEquals(0, time.getHours());
+ Assert.assertEquals(0, time.getMinutes());
+ Assert.assertEquals(0, time.getSeconds());
+ }
+
+ /**
+ * Test for 1s.
+ */
+ @Test
+ public void testOneSecond() {
+ Time time = new Time(1000);
+
+ Assert.assertEquals(0, time.getHours());
+ Assert.assertEquals(0, time.getMinutes());
+ Assert.assertEquals(1, time.getSeconds());
+ }
+
+ /**
+ * Test for 30s.
+ */
+ @Test
+ public void testHalfMinute() {
+ Time time = new Time(30000);
+
+ Assert.assertEquals(0, time.getHours());
+ Assert.assertEquals(0, time.getMinutes());
+ Assert.assertEquals(30, time.getSeconds());
+ }
+
+ /**
+ * Test for 59s 999ms.
+ */
+ @Test
+ public void testFiftyNineSeconds() {
+ Time time = new Time(59999);
+
+ Assert.assertEquals(0, time.getHours());
+ Assert.assertEquals(0, time.getMinutes());
+ Assert.assertEquals(59, time.getSeconds());
+ }
+
+ /**
+ * Test for 60s. It checks if it turns into 1m instead of 60s.
+ */
+ @Test
+ public void testSixtySecond() {
+ Time time = new Time(60000);
+
+ Assert.assertEquals(0, time.getHours());
+ Assert.assertEquals(1, time.getMinutes());
+ Assert.assertEquals(0, time.getSeconds());
+ }
+
+ /**
+ * Test for 30m.
+ */
+ @Test
+ public void testHalfHour() {
+ Time time = new Time(1800000);
+
+ Assert.assertEquals(0, time.getHours());
+ Assert.assertEquals(30, time.getMinutes());
+ Assert.assertEquals(0, time.getSeconds());
+ }
+
+ /**
+ * Test for 59m 59s.
+ */
+ @Test
+ public void testFiftyNineMinutes() {
+ Time time = new Time(3599999);
+
+ Assert.assertEquals(0, time.getHours());
+ Assert.assertEquals(59, time.getMinutes());
+ Assert.assertEquals(59, time.getSeconds());
+ }
+
+ /**
+ * Test for 60m. It checks if it turns into 1h instead of 60m.
+ */
+ @Test
+ public void testSixtyMinutes() {
+ Time time = new Time(3600000);
+
+ Assert.assertEquals(1, time.getHours());
+ Assert.assertEquals(0, time.getMinutes());
+ Assert.assertEquals(0, time.getSeconds());
+ }
+
+ /**
+ * Test for 1h 1m.
+ */
+ @Test
+ public void testOneHourOneMinute() {
+ Time time = new Time(3660000);
+
+ Assert.assertEquals(1, time.getHours());
+ Assert.assertEquals(1, time.getMinutes());
+ Assert.assertEquals(0, time.getSeconds());
+ }
+
+ /**
+ * Test for 1h 1m 1s.
+ */
+ @Test
+ public void testOneHourOneMinuteOneSecond() {
+ Time time = new Time(3661000);
+
+ Assert.assertEquals(1, time.getHours());
+ Assert.assertEquals(1, time.getMinutes());
+ Assert.assertEquals(1, time.getSeconds());
+ }
+
+ /**
+ * Test for 22h 33m 20s.
+ */
+ @Test
+ public void testTwentyHoursThrityTwoMinutesTwentySeconds() {
+ Time time = new Time(81200000);
+
+ Assert.assertEquals(22, time.getHours());
+ Assert.assertEquals(33, time.getMinutes());
+ Assert.assertEquals(20, time.getSeconds());
+ }
+
+ /**
+ * Test for 4h 4s.
+ */
+ @Test
+ public void testFourHoursFourSeconds() {
+ Time time = new Time(14404000);
+
+ Assert.assertEquals(4, time.getHours());
+ Assert.assertEquals(0, time.getMinutes());
+ Assert.assertEquals(4, time.getSeconds());
+ }
+
+ /**
+ * Test for 2d 2h 7m 3s 627ms.
+ */
+ @Test
+ public void testTwoDaysTwoHoursSevenMinutesThreeSeconds() {
+ Time time = new Time(180423627);
+
+ Assert.assertEquals(50, time.getHours());
+ Assert.assertEquals(7, time.getMinutes());
+ Assert.assertEquals(3, time.getSeconds());
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-converter/pom.xml b/sources/codemetropolis-toolchain-converter/pom.xml
index 3fc4dfe9..73dc1de9 100644
--- a/sources/codemetropolis-toolchain-converter/pom.xml
+++ b/sources/codemetropolis-toolchain-converter/pom.xml
@@ -64,5 +64,12 @@
graphlib
1.0
+
+
+ junit
+ junit
+ 4.12
+ test
+
diff --git a/sources/codemetropolis-toolchain-converter/src/test/java/codemetropolis/toolchain/converter/control/ConverterLoaderTest.java b/sources/codemetropolis-toolchain-converter/src/test/java/codemetropolis/toolchain/converter/control/ConverterLoaderTest.java
new file mode 100644
index 00000000..5f1ce12c
--- /dev/null
+++ b/sources/codemetropolis-toolchain-converter/src/test/java/codemetropolis/toolchain/converter/control/ConverterLoaderTest.java
@@ -0,0 +1,37 @@
+package codemetropolis.toolchain.converter.control;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import codemetropolis.toolchain.converter.sonarqube.SonarQubeConverter;
+import codemetropolis.toolchain.converter.sourcemeter.GraphConverter;
+
+/**
+ * Test class for {@link ConvertLoader} for properly handling {@link ConverterType}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class ConverterLoaderTest {
+
+ private Map params = new HashMap();
+
+ /**
+ * Checks if {@link GraphConverter} was created properly.
+ */
+ @Test
+ public void testLoadGraphConverter() {
+ Assert.assertEquals(ConverterLoader.load(ConverterType.SOURCEMETER, params).getClass(), GraphConverter.class);
+ }
+
+ /**
+ * Checks if {@link SonarQubeConverter} was created properly.
+ */
+ @Test
+ public void testLoadSonarQubeConverter() {
+ Assert.assertEquals(ConverterLoader.load(ConverterType.SONARQUBE, params).getClass(), SonarQubeConverter.class);
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-gui/pom.xml b/sources/codemetropolis-toolchain-gui/pom.xml
index fdfa3406..fd818c1b 100644
--- a/sources/codemetropolis-toolchain-gui/pom.xml
+++ b/sources/codemetropolis-toolchain-gui/pom.xml
@@ -1,93 +1,97 @@
-
-
-
- 4.0.0
-
-
- codemetropolis.toolchain
- codemetropolis-toolchain
- 1.4.0
-
-
- codemetropolis-toolchain-gui
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
-
-
-
- codemetropolis.toolchain.gui.Main
- true
- lib/
-
-
- .
-
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
- 2.10
-
-
- copy-dependencies
- package
-
- copy-dependencies
-
-
- ${project.build.directory}/lib
- false
- false
- true
- junit
-
-
-
-
-
-
-
-
-
-
- codemetropolis.toolchain
- codemetropolis-toolchain-commons
- 1.4.0
-
-
- codemetropolis.toolchain
- codemetropolis-toolchain-converter
- 1.4.0
-
-
- codemetropolis.toolchain
- codemetropolis-toolchain-mapping
- 1.4.0
-
-
- codemetropolis.toolchain
- codemetropolis-toolchain-placing
- 1.4.0
-
-
- codemetropolis.toolchain
- codemetropolis-toolchain-rendering
- 1.4.0
-
-
-
-
- junit
- junit
- 4.12
-
-
-
-
+
+
+
+ 4.0.0
+
+
+ codemetropolis.toolchain
+ codemetropolis-toolchain
+ 1.4.0
+
+
+ codemetropolis-toolchain-gui
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ codemetropolis.toolchain.gui.Main
+ true
+ lib/
+
+
+ .
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 2.10
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+ ${project.build.directory}/lib
+ false
+ false
+ true
+ junit
+
+
+
+
+
+
+
+
+
+
+ codemetropolis.toolchain
+ codemetropolis-toolchain-commons
+ 1.4.0
+
+
+ codemetropolis.toolchain
+ codemetropolis-toolchain-converter
+ 1.4.0
+
+
+ codemetropolis.toolchain
+ codemetropolis-toolchain-mapping
+ 1.4.0
+
+
+ codemetropolis.toolchain
+ codemetropolis-toolchain-placing
+ 1.4.0
+
+
+ codemetropolis.toolchain
+ codemetropolis-toolchain-rendering
+ 1.4.0
+
+ codemetropolis.toolchain
+ codemetropolis-toolchain-metrics
+ 1.4.0
+
+
+
+
+ junit
+ junit
+ 4.12
+
+
+
+
diff --git a/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/CodeMetropolisGUI.java b/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/CodeMetropolisGUI.java
index 7ef2ae8a..9b8b7d0a 100644
--- a/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/CodeMetropolisGUI.java
+++ b/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/CodeMetropolisGUI.java
@@ -33,6 +33,7 @@
import codemetropolis.toolchain.gui.utils.Translations;
import codemetropolis.toolchain.gui.utils.XmlFileFilter;
import codemetropolis.toolchain.placing.layout.LayoutAlgorithm;
+import codemetropolis.toolchain.rendering.model.Themes;
/**
* GUI window for the CodeMetropolis toolchain.
@@ -56,7 +57,7 @@ public class CodeMetropolisGUI extends JFrame {
private CMCheckBox showMap;
private CMCheckBox validateStructure;
private CMSpinner scaleSpinner;
- private CMComboBox layoutSelector;
+ private CMComboBox layoutSelector;
/**
* Instantiates the CodeMetropolis GUI.
@@ -225,7 +226,7 @@ private final void addMappingOptions(JPanel panel) {
*/
private final void addPlacingOptions(JPanel panel) {
CMLabel layoutLabel = new CMLabel(Translations.t("gui_l_layout"), 15, 625, 120, 30);
- layoutSelector = new CMComboBox(LayoutAlgorithm.values());
+ layoutSelector = new CMComboBox(Themes.values());
layoutSelector.setBounds(145, 625, 120, 30);
showMap = new CMCheckBox(275, 625, 20, 30);
@@ -306,11 +307,16 @@ private final boolean fillAndValidateMetricOptions(ExecutionOptions executionOpt
*/
private final void fillOptions(ExecutionOptions executionOptions) {
Double scale = (Double) scaleSpinner.getValue();
+ String selectedItemS = layoutSelector.getSelectedItem().toString();
+ String layout = ("BASIC".equals(selectedItemS) || "MINIMALIST".equals(selectedItemS)) ?
+ "PACK" :
+ selectedItemS;
executionOptions.setProjectName(projectName.getText());
executionOptions.setMappingXml(new File(mappingPath.getText()));
executionOptions.setScale(scale.floatValue());
executionOptions.setValidate(validateStructure.isSelected());
- executionOptions.setLayoutAlgorithm((LayoutAlgorithm) layoutSelector.getSelectedItem());
+ executionOptions.setLayoutAlgorithm(LayoutAlgorithm.valueOf(layout));
+ executionOptions.setThemes(Themes.valueOf(selectedItemS));
executionOptions.setShowMap(showMap.isSelected());
executionOptions.setMinecraftRoot(new File(mcRootPath.getText()));
}
diff --git a/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/GUIController.java b/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/GUIController.java
index 3c512a63..5015e054 100644
--- a/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/GUIController.java
+++ b/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/GUIController.java
@@ -13,6 +13,7 @@
import codemetropolis.toolchain.gui.executors.ConverterToolExecutor;
import codemetropolis.toolchain.gui.executors.MappingToolExecutor;
import codemetropolis.toolchain.gui.executors.MetricGeneratorExecutor;
+import codemetropolis.toolchain.gui.executors.MetricsGUIFileExecutor;
import codemetropolis.toolchain.gui.executors.PlacingToolExecutor;
import codemetropolis.toolchain.gui.executors.RenderingToolExecutor;
import codemetropolis.toolchain.gui.metricgenerators.SonarQubeGenerator;
@@ -58,6 +59,7 @@ public void execute(PrintStream out) throws ExecutionException {
new MappingToolExecutor().execute(projectRoot, executionOptions, out);
new PlacingToolExecutor().execute(projectRoot, executionOptions, out);
new RenderingToolExecutor().execute(projectRoot, executionOptions, out);
+ new MetricsGUIFileExecutor().execute(projectRoot, executionOptions, out);
} catch (Exception e) {
throw new ExecutionException("Toolchain execution failed!", e);
}
@@ -69,7 +71,7 @@ public void execute(PrintStream out) throws ExecutionException {
* @return The {@link File} object for the generated directory.
* @throws ExecutionException if creating the directory failed.
*/
- private File createTargetFolder() throws ExecutionException {
+ public File createTargetFolder() throws ExecutionException {
File cmRoot = new File(executionOptions.getMinecraftRoot().getAbsolutePath() + File.separator + ".code-metropolis");
if (!cmRoot.exists()) {
cmRoot.mkdir();
diff --git a/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/beans/ExecutionOptions.java b/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/beans/ExecutionOptions.java
index 33f2523a..7ae70da2 100644
--- a/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/beans/ExecutionOptions.java
+++ b/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/beans/ExecutionOptions.java
@@ -6,6 +6,7 @@
import codemetropolis.toolchain.converter.control.ConverterType;
import codemetropolis.toolchain.placing.layout.LayoutAlgorithm;
+import codemetropolis.toolchain.rendering.model.Themes;
/**
* Contains the parameters required for running the CodeMetropolis toolchain on a given project.
@@ -32,6 +33,7 @@ public class ExecutionOptions {
// Rendering tool
private File minecraftRoot;
+ private Themes theme;
/**
* Constructs an {@link ExecutionOptions} instance with default values.
@@ -42,6 +44,7 @@ public ExecutionOptions() {
this.scale = 1.0f;
this.validate = false;
this.layoutAlgorithm = LayoutAlgorithm.PACK;
+ this.theme = Themes.BASIC;
this.showMap = false;
}
@@ -72,6 +75,10 @@ public boolean isValidate() {
public LayoutAlgorithm getLayoutAlgorithm() {
return layoutAlgorithm;
}
+
+ public Themes getTheme() {
+ return theme;
+ }
public boolean isShowMap() {
return showMap;
@@ -108,6 +115,10 @@ public void setValidate(boolean validate) {
public void setLayoutAlgorithm(LayoutAlgorithm layoutAlgorithm) {
this.layoutAlgorithm = layoutAlgorithm;
}
+
+ public void setThemes(Themes theme) {
+ this.theme = theme;
+ }
public void setShowMap(boolean showMap) {
this.showMap = showMap;
diff --git a/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/executors/MetricsGUIFileExecutor.java b/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/executors/MetricsGUIFileExecutor.java
new file mode 100644
index 00000000..bcdf0622
--- /dev/null
+++ b/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/executors/MetricsGUIFileExecutor.java
@@ -0,0 +1,36 @@
+package codemetropolis.toolchain.gui.executors;
+
+import java.io.File;
+import java.io.PrintStream;
+
+import codemetropolis.toolchain.commons.util.Resources;
+import codemetropolis.toolchain.gui.beans.ExecutionException;
+import codemetropolis.toolchain.gui.beans.ExecutionOptions;
+import codemetropolis.toolchain.metrics.MetricsExecutor;
+import codemetropolis.toolchain.metrics.MetricsExecutorArgs;
+
+public class MetricsGUIFileExecutor implements ToolchainExecutor{
+
+ @Override
+ public void execute(File cmRoot, ExecutionOptions executionOptions, PrintStream out) throws ExecutionException {
+ MetricsExecutorArgs args = assembleArguments(cmRoot.getAbsolutePath(), executionOptions);
+ MetricsExecutor executor = new MetricsExecutor();
+ executor.setPrintStream(out);
+ executor.setErrorStream(out);
+ executor.setPrefix(Resources.get("metrics_prefix"));
+ executor.setErrorPrefix(Resources.get("error_prefix"));
+ if (!executor.execute(args)) {
+ throw new ExecutionException("Failed to complete creating metrics visualization!");
+ }
+ }
+
+ private MetricsExecutorArgs assembleArguments(String cmRootString, ExecutionOptions executionOptions){
+ File sourceMeterExe = (File) executionOptions.getMetricGenerationParams().get("sourceMeterExe");
+ return new MetricsExecutorArgs(
+ executionOptions.getConverterType().toString(),
+ cmRootString,
+ executionOptions.getProjectName(),
+ executionOptions.getMinecraftRoot().getAbsolutePath(),
+ sourceMeterExe.getParent() + File.separator + "WindowsTools" + File.separator + "MetricHunter.threshold");
+ }
+}
\ No newline at end of file
diff --git a/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/executors/RenderingToolExecutor.java b/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/executors/RenderingToolExecutor.java
index 5d0854a8..103bbb91 100644
--- a/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/executors/RenderingToolExecutor.java
+++ b/sources/codemetropolis-toolchain-gui/src/main/java/codemetropolis/toolchain/gui/executors/RenderingToolExecutor.java
@@ -48,7 +48,8 @@ private RenderingExecutorArgs assembleArguments(File cmRoot, ExecutionOptions ex
cmRoot.getAbsolutePath() + File.separator + "placing-results.xml",
executionOptions.getMinecraftRoot().getAbsolutePath() + File.separator + "saves" + File.separator
+ executionOptions.getProjectName().replace(" +;\\/\"?", ""),
- true);
+ true,
+ executionOptions.getTheme());
}
}
diff --git a/sources/codemetropolis-toolchain-gui/src/main/resources/translations.properties b/sources/codemetropolis-toolchain-gui/src/main/resources/translations.properties
index f56865a2..adb23679 100644
--- a/sources/codemetropolis-toolchain-gui/src/main/resources/translations.properties
+++ b/sources/codemetropolis-toolchain-gui/src/main/resources/translations.properties
@@ -22,7 +22,7 @@ gui_l_scale = Scale:
gui_l_validate_structure = Validate structure elements
# Placing
-gui_l_layout = Layout algorithm:
+gui_l_layout = Theme:
gui_l_show_map = Show generated map
# Rendering
diff --git a/sources/codemetropolis-toolchain-mapping/.classpath b/sources/codemetropolis-toolchain-mapping/.classpath
index e7a868fb..af1430be 100644
--- a/sources/codemetropolis-toolchain-mapping/.classpath
+++ b/sources/codemetropolis-toolchain-mapping/.classpath
@@ -6,24 +6,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/sources/codemetropolis-toolchain-mapping/pom.xml b/sources/codemetropolis-toolchain-mapping/pom.xml
index 1c677c2b..31f3eee8 100644
--- a/sources/codemetropolis-toolchain-mapping/pom.xml
+++ b/sources/codemetropolis-toolchain-mapping/pom.xml
@@ -65,5 +65,12 @@
commons-collections4
4.1
+
+
+ junit
+ junit
+ 4.12
+ test
+
diff --git a/sources/codemetropolis-toolchain-mapping/src/test/java/codemetropolis/toolchain/mapping/model/BindingTest_2.java b/sources/codemetropolis-toolchain-mapping/src/test/java/codemetropolis/toolchain/mapping/model/BindingTest_2.java
new file mode 100644
index 00000000..ec2b7e36
--- /dev/null
+++ b/sources/codemetropolis-toolchain-mapping/src/test/java/codemetropolis/toolchain/mapping/model/BindingTest_2.java
@@ -0,0 +1,24 @@
+package codemetropolis.toolchain.mapping.model;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+/**
+ * Test class for {@link Binding}.
+ *
+ * @author Gecs Bernat {@literal }
+ */
+
+public class BindingTest_2 {
+
+ String from = "valami.xml";
+ String to = "csv";
+
+ @Test
+ public final void testGetVariableId() {
+ Binding binding = new Binding(from,to);
+ assertNull(binding.getVariableId());
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-mapping/src/test/java/codemetropolis/toolchain/mapping/model/LimitTest.java b/sources/codemetropolis-toolchain-mapping/src/test/java/codemetropolis/toolchain/mapping/model/LimitTest.java
new file mode 100644
index 00000000..29f00a2f
--- /dev/null
+++ b/sources/codemetropolis-toolchain-mapping/src/test/java/codemetropolis/toolchain/mapping/model/LimitTest.java
@@ -0,0 +1,171 @@
+package codemetropolis.toolchain.mapping.model;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test class for {@link Limit}. Testing if after using {@code add} functions getter methods will work properly.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class LimitTest {
+
+ private static final double DELTA = 1e-15;
+
+ /**
+ * Check if size is correct when no values are added.
+ */
+ @Test
+ public void testGetValueTestSizeDefault() {
+ Limit limit = new Limit();
+ Assert.assertEquals(limit.getValueSetSize(), 0);
+ }
+
+ /**
+ * Check if size is correct when one positive value is added.
+ */
+ @Test
+ public void testGetValueTestSizeOne() {
+ Limit limit = new Limit();
+ limit.add(5);
+ Assert.assertEquals(limit.getValueSetSize(), 1);
+ }
+
+ /**
+ * Check if size is correct when one negative value is added.
+ */
+ @Test
+ public void testGetValueTestSizeOneNegative() {
+ Limit limit = new Limit();
+ limit.add(-63234.2);
+ Assert.assertEquals(limit.getValueSetSize(), 1);
+ }
+
+ /**
+ * Check if size is correct when two values are added.
+ */
+ @Test
+ public void testGetValueTestSizeTwo() {
+ Limit limit = new Limit();
+ limit.add(5342);
+ limit.add(-6.2);
+ Assert.assertEquals(limit.getValueSetSize(), 2);
+ }
+
+ /**
+ * Check if size is correct when more values are added.
+ */
+ @Test
+ public void testGetValueTestSizeMore() {
+ Limit limit = new Limit();
+ for (int i = -9; i < 30; i++) {
+ limit.add(i);
+ }
+ Assert.assertEquals(limit.getValueSetSize(), 39);
+ }
+
+ /**
+ * Check if max value is correct when no values are added.
+ */
+ @Test
+ public void testGetMaxDefault() {
+ Limit limit = new Limit();
+ Assert.assertEquals(limit.getMax(), Double.NEGATIVE_INFINITY, DELTA);
+ }
+
+ /**
+ * Check if max value is correct when one positive value is added.
+ */
+ @Test
+ public void testGetMaxOne() {
+ Limit limit = new Limit();
+ limit.add(5);
+ Assert.assertEquals(limit.getMax(), 5, DELTA);
+ }
+
+ /**
+ * Check if max value is correct when one negative value is added.
+ */
+ @Test
+ public void testGetMaxOneNegative() {
+ Limit limit = new Limit();
+ limit.add(-63234.2);
+ Assert.assertEquals(limit.getMax(), -63234.2, DELTA);
+ }
+
+ /**
+ * Check if max value is correct when two values are added.
+ */
+ @Test
+ public void testGetMaxTwo() {
+ Limit limit = new Limit();
+ limit.add(5342);
+ limit.add(-6.2);
+ Assert.assertEquals(limit.getMax(), 5342, DELTA);
+ }
+
+ /**
+ * Check if max value is correct when more values are added.
+ */
+ @Test
+ public void testGetMaxMore() {
+ Limit limit = new Limit();
+ for (int i = -9; i < 30; i++) {
+ limit.add(i);
+ }
+ Assert.assertEquals(limit.getMax(), 29, DELTA);
+ }
+
+ /**
+ * Check if min value is correct when no values are added.
+ */
+ @Test
+ public void testGetMinDefault() {
+ Limit limit = new Limit();
+ Assert.assertEquals(limit.getMin(), Double.POSITIVE_INFINITY, DELTA);
+ }
+
+ /**
+ * Check if min value is correct when one positive value is added.
+ */
+ @Test
+ public void testGetMinOne() {
+ Limit limit = new Limit();
+ limit.add(5);
+ Assert.assertEquals(limit.getMin(), 5, DELTA);
+ }
+
+ /**
+ * Check if min value is correct when one negative value is added.
+ */
+ @Test
+ public void testGetMinOneNegative() {
+ Limit limit = new Limit();
+ limit.add(-63234.2);
+ Assert.assertEquals(limit.getMin(), -63234.2, DELTA);
+ }
+
+ /**
+ * Check if min value is correct when two values are added.
+ */
+ @Test
+ public void testGetMinTwo() {
+ Limit limit = new Limit();
+ limit.add(5342);
+ limit.add(-6.2);
+ Assert.assertEquals(limit.getMin(), -6.2, DELTA);
+ }
+
+ /**
+ * Check if min value is correct when more values are added.
+ */
+ @Test
+ public void testGetMinMore() {
+ Limit limit = new Limit();
+ for (int i = -9; i < 30; i++) {
+ limit.add(i);
+ }
+ Assert.assertEquals(limit.getMin(), -9, DELTA);
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-mapping/src/test/java/codemetropolis/toolchain/mapping/model/ParameterTest.java b/sources/codemetropolis-toolchain-mapping/src/test/java/codemetropolis/toolchain/mapping/model/ParameterTest.java
new file mode 100644
index 00000000..0ab2891a
--- /dev/null
+++ b/sources/codemetropolis-toolchain-mapping/src/test/java/codemetropolis/toolchain/mapping/model/ParameterTest.java
@@ -0,0 +1,41 @@
+package codemetropolis.toolchain.mapping.model;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test class for {@link Parameter}.
+ *
+ * @author Gecs Bernat {@literal }
+ */
+
+public class ParameterTest {
+
+ String parameter1 = "param1";
+ String parameter2 = "param2";
+
+ @Test
+ public final void testGetName() {
+ Parameter parameter = new Parameter(parameter1,parameter2);
+ Assert.assertEquals(parameter.getName(), parameter1);
+ }
+
+ @Test
+ public final void testSetName() {
+ Parameter parameter = new Parameter(parameter1,parameter2);
+ Assert.assertEquals(parameter.getName(), parameter1);
+ }
+
+ @Test
+ public final void testGetValue() {
+ Parameter parameter = new Parameter(parameter1,parameter2);
+ Assert.assertEquals(parameter.getValue(), parameter2);
+ }
+
+ @Test
+ public final void testSetValue() {
+ Parameter parameter = new Parameter(parameter1,parameter2);
+ Assert.assertEquals(parameter.getValue(), parameter2);
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-metrics/.classpath b/sources/codemetropolis-toolchain-metrics/.classpath
new file mode 100644
index 00000000..1862a692
--- /dev/null
+++ b/sources/codemetropolis-toolchain-metrics/.classpath
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sources/codemetropolis-toolchain-metrics/pom.xml b/sources/codemetropolis-toolchain-metrics/pom.xml
new file mode 100644
index 00000000..b026e8a9
--- /dev/null
+++ b/sources/codemetropolis-toolchain-metrics/pom.xml
@@ -0,0 +1,68 @@
+
+
+ 4.0.0
+
+ codemetropolis-toolchain
+ codemetropolis.toolchain
+ 1.4.0
+
+ codemetropolis-toolchain-metrics
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ codemetropolis.toolchain.metrics.Main
+ true
+ lib/
+
+
+ .
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 2.10
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+ ${project.build.directory}/lib
+ false
+ false
+ true
+ junit
+
+
+
+
+
+
+
+
+ codemetropolis.toolchain
+ codemetropolis-toolchain-commons
+ 1.4.0
+
+
+ args4j
+ args4j
+ 2.32
+
+
+ sed
+ graphlib
+ 1.0
+
+
+
diff --git a/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/CommandLineOptions.java b/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/CommandLineOptions.java
new file mode 100644
index 00000000..ffba9548
--- /dev/null
+++ b/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/CommandLineOptions.java
@@ -0,0 +1,43 @@
+package codemetropolis.toolchain.metrics;
+
+import org.kohsuke.args4j.Option;
+import org.kohsuke.args4j.spi.StringArrayOptionHandler;
+
+public class CommandLineOptions {
+
+ @Option(name="-h", aliases = { "--help" })
+ private boolean showHelp = false;
+
+ @Option(name="-t", aliases = {"--type"})
+ private String type = null;
+
+ @Option(name="-s", aliases = { "--source", "-i", "--input" })
+ private String source = null;
+
+ @Option(name="-o", aliases = {"--output"})
+ private String outputFile = "converterToMapping.xml";
+
+ @Option(name="-p", handler = StringArrayOptionHandler.class, aliases = {"--params"})
+ private String[] params = null;
+
+ public String getOutputFile(){
+ return outputFile;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public boolean showHelp() {
+ return showHelp;
+ }
+
+ public String[] getParams() {
+ return params;
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/MetricsExecutor.java b/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/MetricsExecutor.java
new file mode 100644
index 00000000..0c14a149
--- /dev/null
+++ b/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/MetricsExecutor.java
@@ -0,0 +1,408 @@
+package codemetropolis.toolchain.metrics;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import codemetropolis.toolchain.commons.executor.AbstractExecutor;
+import codemetropolis.toolchain.commons.executor.ExecutorArgs;
+import codemetropolis.toolchain.commons.util.FileLogger;
+import codemetropolis.toolchain.commons.util.Resources;
+import codemetropolis.toolchain.metrics.util.Descriptions;
+
+/**
+ * Class for creating a csv file with metrics for in-game display.
+ * @author Dora Borsos {@literal }
+ */
+
+public class MetricsExecutor extends AbstractExecutor {
+
+ /**
+ * Get the path of the xml file with the coordinates, the xml file with the metrics and the metrics threshold file holding the threshold values.
+ * If all of the files are available, store the metrics and coords in a csv file, in the current MC world's folder (by calling {@link MetricsExecutor#createMetricsCsv(String, String, String, Map)}).
+ * Only SourceMeter metrics are accepted.
+ * @param args contains the paths and the project name set by the user.
+ * @return If csv creation is successful, return true; if any of the files is missing, or the csv generation failed, return false.
+ */
+
+ @Override
+ public boolean execute(ExecutorArgs args) {
+ String message = String.format("%s%s", Resources.get("metrics_generating_done"), Resources.get("metrics_generating_began"));
+ FileLogger.logInfo(message);
+
+ MetricsExecutorArgs metricsArgs = (MetricsExecutorArgs) args;
+ if (metricsArgs.getType().toString() != "SOURCEMETER") {
+ message = String.format("%s%s", Resources.get("error_prefix"), Resources.get("sourcemeter_only_error"));
+ System.err.println(message);
+ FileLogger.logInfo(message);
+ return false;
+ }
+
+ String converterPath = metricsArgs.getCmRoot() + File.separator + "converter-results.xml";
String placingPath = metricsArgs.getCmRoot() + File.separator + "placing-results.xml";
+ String outputPath = metricsArgs.getMinecraftRoot() + File.separator + "saves" + File.separator + metricsArgs.getProjectName() + File.separator + "metrics.csv";
+
+ if (!checkIfXmlExists(placingPath) || !checkIfXmlExists(converterPath)) {
+ return false;
+ }
+
+ Map thresholds = new HashMap();
+ if (!getThresholds(thresholds, metricsArgs.getThresholdPath())){
+ return false;
+ }
+
+ return createMetricsCsv(converterPath, placingPath, outputPath, thresholds);
+ }
+
+
+ /**
+ * Check if the XML file exists.
+ * @param xmlPath the path of the XML file.
+ * @return true if the XML file exists, is readable and is a file; else return false.
+ */
+
+ public boolean checkIfXmlExists(String xmlPath) {
+ File xml = new File(xmlPath);
+
+ if (xml.exists() && xml.isFile() && xml.canRead()) {
+ return true;
+ }
+ else {
+ String message = String.format("%s%s%s", Resources.get("error_prefix"), Resources.get("xml_not_found"), xmlPath);
+ System.err.println(message);
+ FileLogger.logInfo(message);
+ return false;
+ }
+ }
+
+ /**
+ * Geting the metric thresholds and their default values.
+ * @param thresholds Map storing the values.
+ * @param thresholdPath Path of the thresholds file.
+ * @return False on any error occurring while processing data, else true.
+ */
+
+ public boolean getThresholds(Map thresholds, String thresholdPath){
+ try {
+ DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
+ Document document = docBuilder.parse(new File(thresholdPath));
+
+ NodeList nodeList = document.getElementsByTagName("threshold");
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ Node node = nodeList.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element elem = (Element) node;
+ if (elem.getAttribute("Entity").equals("Method")){
+ thresholds.put(elem.getAttribute("Mid"), elem.getAttribute("Value"));
+ }
+ }
+ }
+ } catch (SAXException | ParserConfigurationException | IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Generate the metrics.csv file in the gameworld's folder, which is the data source of the in-game metric display.
+ * Each row contains the six coordinates of the graphical representation of the code entity, followed by the metrics (display order: meaning, abbreviation, average value from SourceMeter and the calculated value).
+ * @param converterPath Path of the converter data, containing the metrics.
+ * @param placingPath Path of the placing data, containing the coordinates.
+ * @param outputPath Output path, which equals to %APPDATA%/.minecraft/saves/project-name/metrics.csv
+ * @param thresholds Map containing the metric thresholds.
+ * @return true if the data processing is successful (which doesn't equal to the creation of the file, since it is possible to have zero displayable entities, e.g. an empty package as the source). If the processing fails, the function returns false.
+ */
+
+ public boolean createMetricsCsv(String converterPath,String placingPath, String outputPath, Map thresholds) {
+ Map characterWidths = new HashMap();
+ setCharacterWidths(characterWidths);
+ int displayWidthBPoint = 230;
+
+ try {
+ new File(outputPath).delete();
+ DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ NodeList converterElements = docBuilder.parse(new File(converterPath)).getElementsByTagName("element");
+ NodeList placingElements = docBuilder.parse(new File(placingPath)).getElementsByTagName("buildable");
+ int placingElementsLength = placingElements.getLength();
+
+ for (int i = 0; i < placingElementsLength; i++) {
+ Element placingElem = (Element) placingElements.item(i);
+ if (!placingElem.getAttribute("type").equals("decoration_floor")) {
+ int [] coords = new int[6];
+ Node placingChildNode = placingElem.getFirstChild();
+ if (placingElem.getAttribute("name").equals("")) continue;
+
+ while (placingChildNode.getNextSibling() != null){
+ placingChildNode = placingChildNode.getNextSibling();
+ if (placingChildNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element placingChildElement = (Element) placingChildNode;
+ if (placingChildElement.getNodeName().equals("position")){
+ coords[0] = Integer.parseInt(placingChildElement.getAttribute("x"));
+ coords[1] = Integer.parseInt(placingChildElement.getAttribute("y"));
+ coords[2] = Integer.parseInt(placingChildElement.getAttribute("z"));
+ }
+ else if (placingChildElement.getNodeName().equals("size")){
+ coords[3] = Integer.parseInt(placingChildElement.getAttribute("x"));
+ coords[5] = Integer.parseInt(placingChildElement.getAttribute("z"));
+ if (placingElem.getAttribute("type").equals("cellar") || placingElem.getAttribute("type").equals("floor")) {
+ coords[4] = Integer.parseInt(placingChildElement.getAttribute("y"));
+ }
+ else {
+ coords[4] = 0;
+ }
+ }
+ }
+ }
+ coords[3] = coords[0] + coords[3];
+ coords[4] = coords[1] + coords[4];
+ coords[5] = coords[2] + coords[5];
+
+ // Initializing DOM traverse (XPath is slower and doesn't support escaped characters in name attributes)
+ ArrayList elementPath = new ArrayList();
+ while (placingChildNode.getParentNode() != null){
+ placingChildNode = placingChildNode.getParentNode();
+ if (placingChildNode.getNodeType() == Node.ELEMENT_NODE){
+ if (placingChildNode.getNodeName().equals("buildable") && !((Element) placingChildNode).getAttribute("name").equals("")){
+ elementPath.add(((Element) placingChildNode).getAttribute("name"));
+ }
+ }
+ }
+ ArrayList metrics = new ArrayList();
+ Element converterElem = (Element) converterElements.item(0);
+ int elementPathSize = elementPath.size();
+ boolean elementFound = false;
+
+ for (int j = elementPathSize - 1; j >= 0 ; j--){
+ elementFound = false;
+ NodeList elemNodes = converterElem.getElementsByTagName("element");
+ int elemNodesSize = elemNodes.getLength();
+ for (int k = 0; k < elemNodesSize; k++){
+ if (((Element) elemNodes.item(k)).getAttribute("name").equals(elementPath.get(j))){
+ converterElem = (Element) elemNodes.item(k);
+ elementFound = true;
+ continue;
+ }
+ }
+ if (!elementFound) continue;
+ }
+ if (elementFound){
+ Node childNode = converterElem.getFirstChild();
+ while (childNode.getNextSibling() != null){
+ childNode = childNode.getNextSibling();
+ if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element childElement = (Element) childNode;
+ if (childElement.getNodeName().equals("properties")){
+ NodeList properties = childElement.getElementsByTagName("*");
+ for (int k = 0; k < properties.getLength(); k++){
+ Element property = (Element) properties.item(k);
+ if (!property.getAttribute("name").equals("source_id") &&
+ !property.getAttribute("name").equals("Name") &&
+ !property.getAttribute("name").equals("LongName"))
+ {
+ String currentDescription = (Descriptions.get(property.getAttribute("name")) == null) ? "" : "(" + Descriptions.get(property.getAttribute("name")) + ")";
+ String currentThreshold = (thresholds.get(property.getAttribute("name")) == null) ? "" : "(" + thresholds.get(property.getAttribute("name")) + ")";
+ metrics.add(property.getAttribute("name") + currentDescription + currentThreshold + ": " + property.getAttribute("value"));
+ }
+ }
+ }
+ }
+ }
+
+ if (metrics.size() > 0){
+ try (BufferedWriter bw = new BufferedWriter(new FileWriter(outputPath, true))) {
+
+ String outputLine = Integer.toString(coords[0]) + ',' +
+ Integer.toString(coords[1]) + ',' +
+ Integer.toString(coords[2]) + ',' +
+ Integer.toString(coords[3]) + ',' +
+ Integer.toString(coords[4]) + ',' +
+ Integer.toString(coords[5]) + ',' +
+ placingElem.getAttribute("name") + ',';
+
+ String displayLine = "";
+
+ for (int j = 0; j < metrics.size(); j++){
+ if (displayLine.isEmpty()){
+ displayLine = metrics.get(j).toString();
+ }
+ else {
+ int stringWidth = getStringWidth(displayLine, characterWidths);
+ if (stringWidth > displayWidthBPoint){
+ outputLine += displayLine + ',';
+ j--;
+ }
+ else {
+ outputLine += padStringByFontWidth(displayLine, stringWidth, displayWidthBPoint) + metrics.get(j) + ',';
+ }
+
+ displayLine = "";
+ }
+ }
+
+ bw.write(outputLine + System.lineSeparator());
+ }
+ }
+ }
+ }
+ }
+
+ } catch (Exception e){
+ e.printStackTrace();
+ return false;
+ }
+
+ String message = String.format("%s%s", Resources.get("metrics_prefix"), Resources.get("metrics_generating_done"));
+ FileLogger.logInfo(message);
+ return true;
+ }
+
+ /**
+ * Get the given string's input.
+ * @param string The string to calculate the width for.
+ * @param characterWidths Map containing the characters with their width values.
+ * @return Display width of the string.
+ */
+ private int getStringWidth(String string, Map characterWidths){
+ int stringLength = string.length();
+ int width = 0;
+ for (int i = 0; i < stringLength; i++){
+ width += characterWidths.get(string.charAt(i));
+ }
+ return width;
+ }
+
+ /**
+ * Padding the input string by the given breakpoint.
+ * @param string String to convert.
+ * @param originalWidth The original width of the given string.
+ * @param widthBPoint The breakpoint.
+ * @return The padded string.
+ */
+ private String padStringByFontWidth(String string, int originalWidth, int widthBPoint){
+ int width = originalWidth;
+ while (width < widthBPoint){
+ string += ' ';
+ width += 4;
+ }
+ return string;
+ }
+
+ /**
+ * Private method for setting the font widths, used for calculating the metrics breakpoint in the UI.
+ * @param characterWidths Widths mapped to characters
+ */
+ private void setCharacterWidths(Map characterWidths){
+ characterWidths.clear();
+ characterWidths.put(' ', 4);
+ characterWidths.put('!', 2);
+ characterWidths.put('"', 5);
+ characterWidths.put('#', 6);
+ characterWidths.put('$', 6);
+ characterWidths.put('%', 6);
+ characterWidths.put('&', 6);
+ characterWidths.put('\'', 3);
+ characterWidths.put('(', 5);
+ characterWidths.put(')', 5);
+ characterWidths.put('*', 5);
+ characterWidths.put('+', 6);
+ characterWidths.put(',', 2);
+ characterWidths.put('-', 6);
+ characterWidths.put('.', 2);
+ characterWidths.put('/', 6);
+ characterWidths.put('0', 6);
+ characterWidths.put('1', 6);
+ characterWidths.put('2', 6);
+ characterWidths.put('3', 6);
+ characterWidths.put('4', 6);
+ characterWidths.put('5', 6);
+ characterWidths.put('6', 6);
+ characterWidths.put('7', 6);
+ characterWidths.put('8', 6);
+ characterWidths.put('9', 6);
+ characterWidths.put(':', 2);
+ characterWidths.put(';', 2);
+ characterWidths.put('<', 5);
+ characterWidths.put('=', 6);
+ characterWidths.put('>', 5);
+ characterWidths.put('?', 6);
+ characterWidths.put('@', 7);
+ characterWidths.put('A', 6);
+ characterWidths.put('B', 6);
+ characterWidths.put('C', 6);
+ characterWidths.put('D', 6);
+ characterWidths.put('E', 6);
+ characterWidths.put('F', 6);
+ characterWidths.put('G', 6);
+ characterWidths.put('H', 6);
+ characterWidths.put('I', 4);
+ characterWidths.put('J', 6);
+ characterWidths.put('K', 6);
+ characterWidths.put('L', 6);
+ characterWidths.put('M', 6);
+ characterWidths.put('N', 6);
+ characterWidths.put('O', 6);
+ characterWidths.put('P', 6);
+ characterWidths.put('Q', 6);
+ characterWidths.put('R', 6);
+ characterWidths.put('S', 6);
+ characterWidths.put('T', 6);
+ characterWidths.put('U', 6);
+ characterWidths.put('V', 6);
+ characterWidths.put('W', 6);
+ characterWidths.put('X', 6);
+ characterWidths.put('Y', 6);
+ characterWidths.put('Z', 6);
+ characterWidths.put('[', 4);
+ characterWidths.put('\\', 6);
+ characterWidths.put(']', 4);
+ characterWidths.put('^', 6);
+ characterWidths.put('_', 6);
+ characterWidths.put('`', 0);
+ characterWidths.put('a', 6);
+ characterWidths.put('b', 6);
+ characterWidths.put('c', 6);
+ characterWidths.put('d', 6);
+ characterWidths.put('e', 6);
+ characterWidths.put('f', 5);
+ characterWidths.put('g', 6);
+ characterWidths.put('h', 6);
+ characterWidths.put('i', 2);
+ characterWidths.put('j', 6);
+ characterWidths.put('k', 5);
+ characterWidths.put('l', 3);
+ characterWidths.put('m', 6);
+ characterWidths.put('n', 6);
+ characterWidths.put('o', 6);
+ characterWidths.put('p', 6);
+ characterWidths.put('q', 6);
+ characterWidths.put('r', 6);
+ characterWidths.put('s', 6);
+ characterWidths.put('t', 4);
+ characterWidths.put('u', 6);
+ characterWidths.put('v', 6);
+ characterWidths.put('w', 6);
+ characterWidths.put('x', 6);
+ characterWidths.put('y', 6);
+ characterWidths.put('z', 6);
+ characterWidths.put('{', 5);
+ characterWidths.put('|', 2);
+ characterWidths.put('}', 5);
+ characterWidths.put('~', 7);
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/MetricsExecutorArgs.java b/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/MetricsExecutorArgs.java
new file mode 100644
index 00000000..673484f9
--- /dev/null
+++ b/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/MetricsExecutorArgs.java
@@ -0,0 +1,53 @@
+package codemetropolis.toolchain.metrics;
+
+import codemetropolis.toolchain.commons.executor.ExecutorArgs;
+
+/**
+ * MetricsExecutorArgs class for the MetricsExecutor.
+ * This class is the instance which the MetricsExecutor uses.
+ *
+ * @author Dora Borsos {@literal }
+ */
+
+public class MetricsExecutorArgs extends ExecutorArgs {
+
+ private String conversionType;
+ private String projectName;
+ private String cmPath;
+ private String minecraftPath;
+ private String thresHoldPath;
+
+ public MetricsExecutorArgs(String conversionType, String cmRootString, String projectName, String minecraftRootString, String thresHoldPath) {
+ super();
+ this.conversionType = conversionType;
+ this.cmPath = cmRootString;
+ this.projectName = projectName;
+ this.minecraftPath = minecraftRootString;
+ this.thresHoldPath = thresHoldPath;
+ }
+
+ public String getType() {
+ return conversionType;
+ }
+
+ public String getCmRoot() {
+ return cmPath;
+ }
+
+ public String getProjectName() {
+ return projectName;
+ }
+
+ public String getMinecraftRoot(){
+ return minecraftPath;
+ }
+
+ public String getThresholdPath() {
+ return thresHoldPath;
+ }
+
+ public void setThresholdPath(String thresHoldPath) {
+ this.thresHoldPath = thresHoldPath;
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/util/Descriptions.java b/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/util/Descriptions.java
new file mode 100644
index 00000000..738e8f5c
--- /dev/null
+++ b/sources/codemetropolis-toolchain-metrics/src/main/java/codemetropolis/toolchain/metrics/util/Descriptions.java
@@ -0,0 +1,20 @@
+package codemetropolis.toolchain.metrics.util;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public final class Descriptions {
+
+ private static ResourceBundle descriptions = ResourceBundle.getBundle("descriptions");
+
+ private Descriptions() { }
+
+ public static String get(String key) {
+ try {
+ return descriptions.getString(key);
+ } catch (MissingResourceException e) {
+ return null;
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-metrics/src/main/resources/descriptions.properties b/sources/codemetropolis-toolchain-metrics/src/main/resources/descriptions.properties
new file mode 100644
index 00000000..696a4560
--- /dev/null
+++ b/sources/codemetropolis-toolchain-metrics/src/main/resources/descriptions.properties
@@ -0,0 +1,27 @@
+# Metric descriptions
+
+LOC = Lines of Code
+LLOC = Logical Lines of Code
+NUMPAR = Number of Parameters
+NOS = Number of Statements
+TLOC = Total Lines of Code
+TLLOC = Total Logical Lines of Code
+TNOS = Total Number of Statements
+CD = Comment Density
+CLOC = Comment Lines of Code
+DLOC = Documentation Lines
+TCD = Total Comment Density
+TCLOC = Total Comment Lines of Code
+McCC = McCabe's Cyclomatic Complexity
+NL = Nesting Level
+NLE = Nesting Level Else-If
+NII = Number of Incoming Invocations
+NOI = Number of Outgoing Invocations
+CCL = Clone Classes
+CCO = Clone Complexity
+CC = Clone Coverage
+CI = Clone Instances
+CLC = Clone Line Coverage
+CLLC = Clone Logical Line Coverage
+LDC = Lines of Duplicated Code
+LLDC = Logical Lines of Duplicated Code
\ No newline at end of file
diff --git a/sources/codemetropolis-toolchain-placing/.classpath b/sources/codemetropolis-toolchain-placing/.classpath
index e7a868fb..af1430be 100644
--- a/sources/codemetropolis-toolchain-placing/.classpath
+++ b/sources/codemetropolis-toolchain-placing/.classpath
@@ -6,24 +6,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/CityMapGUI.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/CityMapGUI.java
index f3a7fed7..28825c62 100644
--- a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/CityMapGUI.java
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/CityMapGUI.java
@@ -85,6 +85,7 @@ public void paint(Graphics g) {
g2d.setColor(new Color(40, 80, 140)); //blue
break;
case FLOOR :
+ case DECORATION_FLOOR :
g2d.setColor(new Color(170, 200, 30)); //green
break;
case CELLAR :
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/PlacingExecutor.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/PlacingExecutor.java
index c6d40ff7..97ae1fe3 100644
--- a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/PlacingExecutor.java
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/PlacingExecutor.java
@@ -46,7 +46,11 @@ public boolean execute(ExecutorArgs args) {
print(Resources.get("calculating_size_and_pos"));
try {
- Layout layout = Layout.parse(placingArgs.getLayout());
+ String layoutString = placingArgs.getLayout();
+ if("BASIC".equals(layoutString) && "MINIMALIST".equals(layoutString)) {
+ placingArgs.setLayout("PACK");
+ }
+ Layout layout = Layout.parse(layoutString);
layout.apply(buildables);
} catch (NonExistentLayoutException e) {
printError(e, Resources.get("missing_layout_error"));
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/PlacingExecutorArgs.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/PlacingExecutorArgs.java
index 6bad53e6..d323a066 100644
--- a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/PlacingExecutorArgs.java
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/PlacingExecutorArgs.java
@@ -32,6 +32,10 @@ public String getOutputFile() {
public String getLayout() {
return layout;
}
+
+ public void setLayout(String layout) {
+ this.layout = layout;
+ }
public boolean showMap() {
return showMap;
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/Layout.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/Layout.java
index 625f730a..23d33e8c 100644
--- a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/Layout.java
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/Layout.java
@@ -4,7 +4,9 @@
import codemetropolis.toolchain.placing.exceptions.LayoutException;
import codemetropolis.toolchain.placing.exceptions.NonExistentLayoutException;
import codemetropolis.toolchain.placing.layout.pack.PackLayout;
+import codemetropolis.toolchain.placing.layout.railway.RailwayLayout;
//import codemetropolis.toolchain.placing.layout.tetris.TetrisLayout;
+import codemetropolis.toolchain.placing.layout.town.TownLayout;
public abstract class Layout {
@@ -17,9 +19,13 @@ public static Layout parse(String algorithm) throws NonExistentLayoutException {
switch(LayoutAlgorithm.valueOf(algorithm.toUpperCase())) {
case PACK:
return new PackLayout();
+ case RAILWAY:
+ return new RailwayLayout();
//TODO tetris layout is out of date and needs to be updated
//case TETRIS:
// return new TetrisLayout();
+ case TOWN:
+ return new TownLayout();
}
} catch (IllegalArgumentException e) {
throw new NonExistentLayoutException(algorithm);
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/LayoutAlgorithm.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/LayoutAlgorithm.java
index 22e15c25..b84a9097 100644
--- a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/LayoutAlgorithm.java
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/LayoutAlgorithm.java
@@ -2,5 +2,8 @@
public enum LayoutAlgorithm {
PACK,
- //TETRIS
+ RAILWAY,
+ //TETRIS,
+ TOWN,
+
}
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/LayoutUtils.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/LayoutUtils.java
new file mode 100644
index 00000000..7a4df49f
--- /dev/null
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/LayoutUtils.java
@@ -0,0 +1,80 @@
+package codemetropolis.toolchain.placing.layout;
+
+import java.util.List;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.BuildableTree;
+import codemetropolis.toolchain.placing.layout.railway.RailwayLayout;
+import codemetropolis.toolchain.placing.layout.town.TownLayout;
+
+/**
+ * Frequently used preparing functions for the {@link RailwayLayout} and the {@link TownLayout}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class LayoutUtils {
+
+ private static final String ROOT_PACKAGE = "";
+
+ /**
+ * Collect all the packages, and put them as a child of the root recursively.
+ *
+ * @param node The current node, where we're searching for packages.
+ * @param root The root where to packages will be added.
+ */
+ public static void preparePackages(Buildable node, Buildable root) {
+ List children = node.getChildrenList();
+ for (int i = 0; i < children.size(); i++) {
+ Buildable child = children.get(i);
+ if (child.getType() == Buildable.Type.GROUND && child.getParent().getType() != Buildable.Type.CONTAINER) {
+ if (!child.getParent().getName().equals(ROOT_PACKAGE)) {
+ child.setName(child.getParent().getName() + "." + child.getName());
+ }
+
+ children.remove(child);
+ child.setParent(null);
+ root.addChild(child);
+ i--;
+ }
+
+ preparePackages(child, root);
+ }
+ }
+
+ /**
+ * Removing from the package list the empty ones, where rails can't be found.
+ *
+ * @param node The node whose children we're iterating over.
+ */
+ public static void removeEmptyPackages(Buildable node) {
+ List children = node.getChildrenList();
+ for (int i = 0; i < children.size(); i++) {
+ Buildable child = children.get(i);
+ if (child.getType() == Buildable.Type.GROUND && child.getChildrenList().isEmpty()) {
+ children.remove(child);
+ i--;
+ }
+ }
+ }
+
+ /**
+ * Collecting gardens to the same level in {@link BuildableTree} hierarchy.
+ *
+ * @param node The current node.
+ */
+ public static void prepareGardens(Buildable node) {
+ List children = node.getChildrenList();
+ for (int i = 0; i < children.size(); i++) {
+ Buildable child = children.get(i);
+ if (child.getType() == Buildable.Type.GARDEN && child.getParent().getType() == Buildable.Type.GARDEN) {
+ child.setName(child.getParent().getName() + "#" + child.getName());
+ children.remove(child);
+ child.setParent(child.getParent().getParent());
+ child.getParent().addChild(child);
+ i--;
+ }
+ prepareGardens(child);
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/BuildableWrapper.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/BuildableWrapper.java
index 462015e1..8ce0c5df 100644
--- a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/BuildableWrapper.java
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/BuildableWrapper.java
@@ -66,7 +66,7 @@ public List getChildren(Map> houses) {
List result = new ArrayList();
if(buildable instanceof House) return result;
for(Buildable c : ((Buildable)buildable).getChildren()) {
- if(c.getType() == Buildable.Type.FLOOR || c.getType() == Buildable.Type.CELLAR) continue;
+ if(c.getType() == Buildable.Type.FLOOR || c.getType() == Buildable.Type.DECORATION_FLOOR || c.getType() == Buildable.Type.CELLAR) continue;
result.add(new BuildableWrapper(c));
}
if(houses.get((Buildable)buildable) != null) {
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/House.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/House.java
index 11481ba4..22d76ea4 100644
--- a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/House.java
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/House.java
@@ -8,16 +8,16 @@
public class House {
- private final int minHeight;
- private final int maxHeight;
+ protected final int minHeight;
+ protected final int maxHeight;
- private Buildable parent;
- private List floors = new ArrayList();
- private List cellars = new ArrayList();
- private Buildable topFloor;
- private Buildable bottomFloor;
- private Buildable topCellar;
- private Buildable bottomCellar;
+ protected Buildable parent;
+ protected List floors = new ArrayList();
+ protected List cellars = new ArrayList();
+ protected Buildable topFloor;
+ protected Buildable bottomFloor;
+ protected Buildable topCellar;
+ protected Buildable bottomCellar;
public House(int minHeight, int maxHeight) {
this.minHeight = minHeight;
@@ -25,14 +25,14 @@ public House(int minHeight, int maxHeight) {
}
public boolean add(Buildable b) throws LayoutException {
- if(b.getType() == Buildable.Type.FLOOR)
+ if(b.getType() == Buildable.Type.FLOOR || b.getType() == Buildable.Type.DECORATION_FLOOR)
return addFloor(b);
else
return addCellar(b);
}
public boolean addFloor(Buildable floor) throws LayoutException {
- if(floor.getType() != Buildable.Type.FLOOR) {
+ if(floor.getType() != Buildable.Type.FLOOR && floor.getType() != Buildable.Type.DECORATION_FLOOR) {
throw new LayoutException(String.format("Cannot add %s %d as a floor. Wrong buildable type.", floor.getType().toString(), floor.getId()));
}
if(bottomFloor == null) {
@@ -148,8 +148,16 @@ public void setPositionZR(int z) {
}
}
+ public Buildable getTopFloor() {
+ return this.topFloor;
+ }
+
public Buildable getParent() {
return parent;
}
+ public void setParent(Buildable parent) {
+ this.parent = parent;
+ }
+
}
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/PackLayout.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/PackLayout.java
index 3983d2bd..e992df91 100644
--- a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/PackLayout.java
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/pack/PackLayout.java
@@ -1,11 +1,13 @@
package codemetropolis.toolchain.placing.layout.pack;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import codemetropolis.toolchain.commons.cmxml.Buildable;
import codemetropolis.toolchain.commons.cmxml.BuildableTree;
@@ -151,6 +153,41 @@ private Map> createHouses(BuildableTree buildables) throw
housesOfParent.add(h);
}
}
+
+ addDecorationFloors(houses);
+
return houses;
}
+
+ /**
+ * Adds a nice roof onto the top of the houses.
+ *
+ * @param houses The houses.
+ */
+ private void addDecorationFloors(Map> houses) {
+ for(List houseList : houses.values()) {
+ for(House house : houseList) {
+ if(house.getTopFloor() != null) {
+ Buildable oldTopFloor = house.getTopFloor();
+
+ Buildable decorationFloor = new Buildable(UUID.randomUUID().toString(), "decorationFloor",
+ Buildable.Type.DECORATION_FLOOR);
+ decorationFloor.setSizeX(oldTopFloor.getSizeX());
+ decorationFloor.setSizeY(9);
+ decorationFloor.setSizeZ(oldTopFloor.getSizeZ());
+ decorationFloor.setAttributes(Arrays.asList(oldTopFloor.getAttributes()));
+ decorationFloor.setCdfNames(oldTopFloor.getCdfNames());
+ decorationFloor.setParent(oldTopFloor.getParent());
+ decorationFloor.getParent().addChild(decorationFloor);
+
+ try {
+ house.add(decorationFloor);
+ } catch (LayoutException e) {
+ // Should not happen, as we explicitly add a Buildable.Type.DECORATION_FLOOR
+ }
+ }
+ }
+ }
+ }
+
}
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/railway/RailwayLayout.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/railway/RailwayLayout.java
new file mode 100644
index 00000000..d8e25c34
--- /dev/null
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/railway/RailwayLayout.java
@@ -0,0 +1,188 @@
+package codemetropolis.toolchain.placing.layout.railway;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.BuildableTree;
+import codemetropolis.toolchain.placing.exceptions.LayoutException;
+import codemetropolis.toolchain.placing.layout.Layout;
+import codemetropolis.toolchain.placing.layout.LayoutUtils;
+
+/**
+ * An easy, clear representation of {@link Layout}. Each garden is represented as a rail, with trains on top of them.
+ * Rails are laid next to each other.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class RailwayLayout extends Layout {
+
+ private static final int GROUND_LEVEL = 61;
+
+ /**
+ * An easier, clearer representation of Gardens, without wrapper.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void apply(BuildableTree buildables) throws LayoutException {
+ createTrains(buildables);
+
+ LayoutUtils.preparePackages(buildables.getRoot(), buildables.getRoot());
+ LayoutUtils.removeEmptyPackages(buildables.getRoot());
+ LayoutUtils.prepareGardens(buildables.getRoot());
+
+ findGardens(buildables.getRoot(), 0);
+ }
+
+ /**
+ * A recursive function for discovering all of the gardens in {@link BuildableTree}. Whenever a garden is found a
+ * rail is laid down, and all the houses are laid on them like wagons. The next garden is laid next to the previous
+ * one.
+ *
+ * @param node The current {@link Buildable}.
+ * @param position For setting the position of each rail.
+ * @return With the {@code position}, so next rail will be next to the previous one.
+ */
+ private int findGardens(Buildable node, int position) {
+ if (node.getType() == Buildable.Type.CONTAINER || node.getType() == Buildable.Type.GROUND) {
+ node.setSizeX(1);
+ node.setSizeY(11);
+ node.setSizeZ(11 * node.getChildrenList().size() + 5 * (node.getChildrenList().size() - 1));
+ node.setPositionX(0);
+ node.setPositionY(GROUND_LEVEL);
+ node.setPositionZ(position * 16);
+ }
+
+ Buildable[] children = node.getChildren();
+ for (Buildable child : children) {
+ if (child.getType() == Buildable.Type.GARDEN) {
+ layDownRail(child, position);
+ position++;
+ } else {
+ position = findGardens(child, position);
+ }
+ }
+
+ return position;
+ }
+
+ /**
+ * It lays down all along one rail, and puts down all the wagons which are included in this rail.
+ *
+ * @param rail The current garden, as a rail.
+ * @param position Where next rail goes.
+ */
+ private void layDownRail(Buildable rail, int position) {
+ int previous = 2;
+ for (Buildable wagon : rail.getChildren()) {
+ wagon.setSizeX(wagon.getSizeY());
+ wagon.setSizeY(9);
+ wagon.setSizeZ(9);
+ wagon.setPositionX(previous + 2);
+ wagon.setPositionY(GROUND_LEVEL + 2);
+ wagon.setPositionZ(position * 16 + 1);
+ previous = wagon.getPositionX() + wagon.getSizeX();
+ }
+
+ rail.setPositionX(0);
+ rail.setPositionY(GROUND_LEVEL);
+ rail.setPositionZ(position * 16);
+ rail.setSizeX(previous + (previous % 3));
+ rail.setSizeY(2);
+ rail.setSizeZ(11);
+ }
+
+ /**
+ * Collecting all the train elements. It collects a city's elements if it is a {@link Buildable.Type#FLOOR}, a
+ * {@link Buildable.Type#CELLAR} or a {@link Buildable.Type#DECORATION_FLOOR}.
+ *
+ * @param buildables All the elements of the city.
+ * @return A list of the wagons of one train.
+ */
+ private List getTrains(BuildableTree buildables) {
+ List result = new ArrayList();
+
+ for (Buildable b : buildables.getBuildables()) {
+ if (b.getType() == Buildable.Type.FLOOR ||
+ b.getType() == Buildable.Type.DECORATION_FLOOR ||
+ b.getType() == Buildable.Type.CELLAR) {
+
+ result.add(b);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Creates a train by putting all the wagons one-by-one after each other. Also adds at the beginning of the train an
+ * engine.
+ *
+ * @param buildables All the train wagons are added in this {@link BuildableTree}.
+ * @return The created list of wagons, as a train.
+ * @throws LayoutException Throws exception, if wagon's type is incorrect.
+ */
+ private Map> createTrains(BuildableTree buildables) throws LayoutException {
+ Map> trains = new HashMap>();
+ for (Buildable b : getTrains(buildables)) {
+ List trainsOfParent = trains.get(b.getParent());
+ if (trainsOfParent == null) {
+ trainsOfParent = new ArrayList();
+ trains.put(b.getParent(), trainsOfParent);
+ }
+
+ boolean addedSuccessfully = false;
+ for (Train t : trainsOfParent) {
+ if (t.addWagon(b)) {
+ addedSuccessfully = true;
+ break;
+ }
+ }
+
+ if (!addedSuccessfully) {
+ Train t = new Train();
+ t.addWagon(b);
+ trainsOfParent.add(t);
+ }
+ }
+
+ addEngines(trains);
+
+ return trains;
+ }
+
+ /**
+ * Adds an engine at the beginning of the train.
+ *
+ * @param houses The trains.
+ */
+ private void addEngines(Map> trains) {
+ for (List listOfTrains : trains.values()) {
+ for (Train train : listOfTrains) {
+ Buildable firstWagon = train.getFirstWagon();
+
+ Buildable engine = new Buildable(UUID.randomUUID().toString(), "engine",
+ Buildable.Type.DECORATION_FLOOR);
+ engine.setSizeX(9);
+ engine.setSizeY(15);
+ engine.setSizeZ(9);
+ engine.setAttributes(Arrays.asList(firstWagon.getAttributes()));
+ engine.setCdfNames(firstWagon.getCdfNames());
+ firstWagon.getParent().addFirstChild(engine);
+ firstWagon.setParent(engine);
+
+ try {
+ train.addEngine(engine);
+ } catch (LayoutException e) {
+ // Should not happen, as we explicitly add a Buildable.Type.DECORATION_FLOOR
+ }
+ }
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/railway/Train.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/railway/Train.java
new file mode 100644
index 00000000..a06fe9ee
--- /dev/null
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/railway/Train.java
@@ -0,0 +1,242 @@
+package codemetropolis.toolchain.placing.layout.railway;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.placing.exceptions.LayoutException;
+import codemetropolis.toolchain.placing.layout.pack.House;
+
+/**
+ * A new type of {@link House}, represented as a train. Now you can represent your buildings with a list of wagons.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class Train {
+
+ private Buildable parent;
+ private Buildable firstWagon;
+
+ private List wagons = new ArrayList();
+
+ /**
+ * Adding wagons one-by-one to a train.
+ *
+ * @param wagon The wagon which is going to be added to the train.
+ * @return Returns true if it could successfully add the train.
+ * @throws LayoutException Throws exception, if wagon's type is incorrect.
+ */
+ public boolean addWagon(Buildable wagon) throws LayoutException {
+ if (wagon.getType() != Buildable.Type.FLOOR && wagon.getType() != Buildable.Type.CELLAR) {
+ throw new LayoutException(String.format("Cannot add %s %d as a wagon. Wrong buildable type.",
+ wagon.getType().toString(), wagon.getId()));
+ }
+
+ if (firstWagon == null) {
+ wagons.add(wagon);
+ parent = wagon.getParent();
+ firstWagon = wagon;
+ return true;
+ }
+
+ if (wagon.getParent() != parent) {
+ throw new LayoutException(
+ String.format("Cannot add %s %d as a wagon. Wagons in the train must be childs of the same parent.",
+ wagon.getType().toString(), wagon.getId()));
+ }
+
+ wagons.add(wagon);
+
+ return true;
+ }
+
+ /**
+ * Add an engine at the beginning of the train, to make it realistic.
+ *
+ * @param engine The generated engine, which is going to be added to the train.
+ * @return Returns true if it could successfully add the train.
+ * @throws LayoutException Throws exception, if wagon's type is incorrect.
+ */
+ public boolean addEngine(Buildable engine) throws LayoutException {
+ if (engine.getType() != Buildable.Type.DECORATION_FLOOR) {
+ throw new LayoutException(String.format("Cannot add %s %d as an engine. Wrong buildable type.",
+ engine.getType().toString(), engine.getId()));
+ }
+
+ if (engine.getParent() != parent) {
+ throw new LayoutException(
+ String.format("Cannot add %s %d as an engine. Wagons in the train must be childs of the same parent.",
+ engine.getType().toString(), engine.getId()));
+ }
+
+ wagons.add(0, engine);
+ return true;
+ }
+
+ /**
+ * Get the parent of the current wagon.
+ *
+ * @return Returns with the parent
+ */
+ public Buildable getParent() {
+ return parent;
+ }
+
+ /**
+ * Set the parent for the current wagon.
+ *
+ * @param parent The desired parent.
+ */
+ public void setParent(Buildable parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Gets the first wagon of a train. So engine can be added before this one.
+ *
+ * @return The first wagon of a train.
+ */
+ public Buildable getFirstWagon() {
+ return this.firstWagon;
+ }
+
+ /**
+ * Gets the x dimensional size of a wagon.
+ *
+ * @return The size of the wagon in x dimension.
+ */
+ public int getSizeX() {
+ return wagons.get(wagons.size() - 1).getSizeX();
+ }
+
+ /**
+ * Gets the y dimensional size of a wagon.
+ *
+ * @return The size of the wagon in y dimension.
+ */
+ public int getSizeY() {
+ return wagons.get(wagons.size() - 1).getSizeY();
+ }
+
+ /**
+ * Gets the z dimensional size of a wagon.
+ *
+ * @return The size of the wagon in z dimension.
+ */
+ public int getSizeZ() {
+ return wagons.get(wagons.size() - 1).getSizeZ();
+ }
+
+ /**
+ * Sets the x dimensional size of a wagon.
+ *
+ * @param size The desired x dimensional size.
+ */
+ public void setSizeX(int size) {
+ wagons.get(wagons.size() - 1).setSizeX(size);
+ }
+
+ /**
+ * Sets the y dimensional size of a wagon.
+ *
+ * @param size The desired y dimensional size.
+ */
+ public void setSizeY(int size) {
+ wagons.get(wagons.size() - 1).setSizeY(size);
+ }
+
+ /**
+ * Sets the z dimensional size of a wagon.
+ *
+ * @param size The desired z dimensional size.
+ */
+ public void setSizeZ(int size) {
+ wagons.get(wagons.size() - 1).setSizeZ(size);
+ }
+
+ /**
+ * Transforms the wagons matrix in x dimension.
+ *
+ * @param x The value of transformation.
+ */
+ public void translateNearX(int x) {
+ for (Buildable b : wagons) {
+ b.setPositionXR(b.getPositionX() + x);
+ }
+ }
+
+ /**
+ * Transforms the wagons matrix in z dimension.
+ *
+ * @param x The value of transformation.
+ */
+ public void translateNearZ(int z) {
+ for (Buildable b : wagons) {
+ b.setPositionZR(b.getPositionZ() + z);
+ }
+ }
+
+ /**
+ * Gets the x dimensional position of a wagon.
+ *
+ * @return The position of the wagon in x dimension.
+ */
+ public int getPositionX() {
+ return wagons.get(wagons.size() - 1).getPositionX();
+ }
+
+ /**
+ * Gets the y dimensional position of a wagon.
+ *
+ * @return The position of the wagon in y dimension.
+ */
+ public int getPositionY() {
+ return wagons.get(wagons.size() - 1).getPositionY();
+ }
+
+ /**
+ * Gets the z dimensional position of a wagon.
+ *
+ * @return The position of the wagon in z dimension.
+ */
+ public int getPositionZ() {
+ return wagons.get(wagons.size() - 1).getPositionZ();
+ }
+
+ /**
+ * Sets the new position of a wagon with an x dimensional transformation.
+ *
+ * @param x The value of the transformation.
+ */
+ public void setPositionXR(int x) {
+ for (Buildable b : wagons) {
+ int offset = b.getPositionX() - b.getParent().getPositionX();
+ b.setPositionXR(x + offset);
+ }
+ }
+
+ /**
+ * Sets the new position of a wagon with an y dimensional transformation.
+ *
+ * @param x The value of the transformation.
+ */
+ public void setPositionYR(int y) {
+ for (Buildable b : wagons) {
+ int offset = b.getPositionY() - b.getParent().getPositionY();
+ b.setPositionYR(y + offset);
+ }
+ }
+
+ /**
+ * Sets the new position of a wagon with an z dimensional transformation.
+ *
+ * @param x The value of the transformation.
+ */
+ public void setPositionZR(int z) {
+ for (Buildable b : wagons) {
+ int offset = b.getPositionZ() - b.getParent().getPositionZ();
+ b.setPositionZR(z + offset);
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/town/BuildableWrapper.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/town/BuildableWrapper.java
new file mode 100644
index 00000000..6530556f
--- /dev/null
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/town/BuildableWrapper.java
@@ -0,0 +1,195 @@
+package codemetropolis.toolchain.placing.layout.town;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.placing.layout.pack.PackLayout;
+import codemetropolis.toolchain.placing.layout.town.TownHouse;
+
+/**
+ * A wrapper class for preparing houses for the {@link PackLayout} packer.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class BuildableWrapper implements Comparable {
+
+ private Object buildable;
+
+ /**
+ * Creates a {@link BuildableWrapper} of a {@link Buildable}.
+ *
+ * @param buildable {@link Buildable} type {@code buildable}.
+ */
+ public BuildableWrapper(Buildable buildable) {
+ this.buildable = buildable;
+ }
+
+ /**
+ * Creates a {@link BuildableWrapper} of a {@link TownHouse}.
+ *
+ * @param buildable {@link TownHouse} type {@code buildable}.
+ */
+ public BuildableWrapper(TownHouse buildable) {
+ this.buildable = buildable;
+ }
+
+ /**
+ * Gets a {@link Buildable} object of a wrapper.
+ *
+ * @return
+ */
+ public Object getInnerBuildable() {
+ return buildable;
+ }
+
+ /**
+ * Get the x dimensional position depending on the type of the {@link Buildable}.
+ *
+ * @return The x dimensional position as an integer.
+ */
+ public int getPositionX() {
+ if (buildable instanceof Buildable) return ((Buildable) buildable).getPositionX();
+ if (buildable instanceof TownHouse) return ((TownHouse) buildable).getPositionX();
+ return 0;
+ }
+
+ /**
+ * Get the z dimensional position depending on the type of the {@link Buildable}.
+ *
+ * @return The z dimensional position as an integer.
+ */
+ public int getPositionZ() {
+ if (buildable instanceof Buildable) return ((Buildable) buildable).getPositionZ();
+ if (buildable instanceof TownHouse) return ((TownHouse) buildable).getPositionZ();
+ return 0;
+ }
+
+ /**
+ * Get the x dimensional size depending on the type of the {@link Buildable}.
+ *
+ * @return The x dimensional size as an integer.
+ */
+ public int getSizeX() {
+ if (buildable instanceof Buildable) return ((Buildable) buildable).getSizeX();
+ if (buildable instanceof TownHouse) return ((TownHouse) buildable).getSizeX();
+ return 0;
+ }
+
+ /**
+ * Get the z dimensional size depending on the type of the {@link Buildable}.
+ *
+ * @return The z dimensional size as an integer.
+ */
+ public int getSizeZ() {
+ if (buildable instanceof Buildable) return ((Buildable) buildable).getSizeZ();
+ if (buildable instanceof TownHouse) return ((TownHouse) buildable).getSizeZ();
+ return 0;
+ }
+
+ /**
+ * Set the x dimensional position depending on the type of the {@link Buildable}.
+ *
+ * @param x The x dimensional position.
+ */
+ public void setPositionX(int x) {
+ if (buildable instanceof Buildable) ((Buildable) buildable).setPositionXR(x);
+ if (buildable instanceof TownHouse) ((TownHouse) buildable).setPositionXR(x);
+ }
+
+ /**
+ * Set the z dimensional position depending on the type of the {@link Buildable}.
+ *
+ * @param z The z dimensional position.
+ */
+ public void setPositionZ(int z) {
+ if (buildable instanceof Buildable) ((Buildable) buildable).setPositionZR(z);
+ if (buildable instanceof TownHouse) ((TownHouse) buildable).setPositionZR(z);
+ }
+
+ /**
+ * Gets the parent of a {@link Buildable} depending on the type of the the {@link Buildable}.
+ *
+ * @return The desired parent.
+ */
+ public Buildable getParent() {
+ if (buildable instanceof Buildable) return ((Buildable) buildable).getParent();
+ if (buildable instanceof TownHouse) return ((TownHouse) buildable).getParent();
+ return null;
+ }
+
+ /**
+ * Collect all the children of a garden as a list.
+ *
+ * @param houses The houses which are tested.
+ * @return The list of a garden's houses.
+ */
+ public List getTownChildren(Map> houses) {
+ List result = new ArrayList();
+ if (buildable instanceof TownHouse) {
+ return result;
+ }
+
+ for (Buildable child : ((Buildable) buildable).getChildren()) {
+ if (child.getType() == Buildable.Type.FLOOR ||
+ child.getType() == Buildable.Type.DECORATION_FLOOR ||
+ child.getType() == Buildable.Type.CELLAR) {
+
+ continue;
+ }
+
+ result.add(new BuildableWrapper(child));
+ }
+
+ if (houses.get((Buildable) buildable) != null) {
+ for (TownHouse h : houses.get((Buildable) buildable)) {
+ result.add(new BuildableWrapper(h));
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((buildable == null) ? 0 : buildable.hashCode());
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ BuildableWrapper other = (BuildableWrapper) obj;
+ if (buildable == null) {
+ if (other.buildable != null)
+ return false;
+ } else if (!buildable.equals(other.buildable))
+ return false;
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int compareTo(BuildableWrapper o) {
+ int result = this.getSizeX() - o.getSizeX();
+ return result == 0 ? this.getSizeZ() - o.getSizeZ() : result;
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/town/TownHouse.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/town/TownHouse.java
new file mode 100644
index 00000000..6577dd11
--- /dev/null
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/town/TownHouse.java
@@ -0,0 +1,161 @@
+package codemetropolis.toolchain.placing.layout.town;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.placing.exceptions.LayoutException;
+import codemetropolis.toolchain.placing.layout.pack.House;
+
+/**
+ * A subclass for {@link House} with a little modification for {@link Buildable.Type#CELLAR} floors. So cellars are not
+ * under the ground.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class TownHouse extends House {
+
+ /**
+ * Set the min and max height. So houses will be realistic in height.
+ *
+ * @param minHeight The minimum height.
+ * @param maxHeight The maximum height.
+ */
+ public TownHouse(int minHeight, int maxHeight) {
+ super(minHeight, maxHeight);
+ }
+
+ /**
+ * Height of a house can only be 1 floor height.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean addFloor(Buildable floor) throws LayoutException {
+ // Only allow a single floor (except for an additional decoration floor
+ if (topFloor != null && floor.getType() != Buildable.Type.DECORATION_FLOOR) {
+ return false;
+ }
+
+ if (floor.getType() != Buildable.Type.FLOOR && floor.getType() != Buildable.Type.DECORATION_FLOOR) {
+ throw new LayoutException(String.format("Cannot add %s %d as a floor. Wrong buildable type.",
+ floor.getType().toString(), floor.getId()));
+ }
+
+ if (bottomFloor == null) {
+ floors.add(floor);
+ if (topCellar != null) {
+ floor.setPositionX(topCellar.getCenter().getX() - (floor.getSizeX() / 2));
+ floor.setPositionZ(topCellar.getCenter().getZ() - (floor.getSizeZ() / 2));
+ } else {
+ floor.setPositionY(minHeight);
+ }
+ parent = floor.getParent();
+ bottomFloor = floor;
+ topFloor = floor;
+ return true;
+ }
+
+ if (floor.getParent() != parent) {
+ throw new LayoutException(String.format(
+ "Cannot add %s %d as a floor. Floors and cellars in the house must be childs of the same parent.",
+ floor.getType().toString(), floor.getId()));
+ }
+
+ if (topFloor.getPositionY() + topFloor.getSizeY() + floor.getSizeY() > maxHeight)
+ return false;
+ if (floor.getSizeX() > topFloor.getSizeX() || floor.getSizeZ() > topFloor.getSizeZ())
+ return false;
+
+ floors.add(floor);
+ floor.setPositionY(topFloor.getPositionY() + topFloor.getSizeY());
+ floor.setPositionX(topFloor.getCenter().getX() - (floor.getSizeX() / 2));
+ floor.setPositionZ(topFloor.getCenter().getZ() - (floor.getSizeZ() / 2));
+ topFloor = floor;
+
+ return true;
+ }
+
+ /**
+ * Cellars are added similarly to floors, so they won't be under the ground. Height is maximum one floor height.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean addCellar(Buildable cellar) throws LayoutException {
+ // Only allow a single floor
+ if (topFloor != null) {
+ return false;
+ }
+
+ if (cellar.getType() != Buildable.Type.CELLAR) {
+ throw new LayoutException(String.format("Cannot add %s %d as a cellar. Wrong buildable type.",
+ cellar.getType().toString(), cellar.getId()));
+ }
+
+ if (bottomFloor == null) {
+ floors.add(cellar);
+ if (topCellar != null) {
+ cellar.setPositionX(topCellar.getCenter().getX() - (cellar.getSizeX() / 2));
+ cellar.setPositionZ(topCellar.getCenter().getZ() - (cellar.getSizeZ() / 2));
+ } else {
+ cellar.setPositionY(minHeight);
+ }
+ setParent(cellar.getParent());
+ bottomFloor = cellar;
+ topFloor = cellar;
+ return true;
+ }
+
+ if (cellar.getParent() != getParent()) {
+ throw new LayoutException(String.format(
+ "Cannot add %s %d as a cellar. Floors and cellars in the house must be childs of the same parent.",
+ cellar.getType().toString(), cellar.getId()));
+ }
+
+ if (getTopFloor().getPositionY() + getTopFloor().getSizeY() + cellar.getSizeY() > maxHeight)
+ return false;
+ if (cellar.getSizeX() > getTopFloor().getSizeX() || cellar.getSizeZ() > getTopFloor().getSizeZ())
+ return false;
+
+ floors.add(cellar);
+ cellar.setPositionY(getTopFloor().getPositionY() + getTopFloor().getSizeY());
+ cellar.setPositionX(getTopFloor().getCenter().getX() - (cellar.getSizeX() / 2));
+ cellar.setPositionZ(getTopFloor().getCenter().getZ() - (cellar.getSizeZ() / 2));
+ topFloor = cellar;
+
+ return true;
+ }
+
+ /**
+ * Parent's size is no more subtracted.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void setPositionXR(int x) {
+ for (Buildable b : floors) {
+ int offset = b.getPositionX();
+ b.setPositionXR(x + offset);
+ }
+ for (Buildable b : cellars) {
+ int offset = b.getPositionX();
+ b.setPositionXR(x + offset);
+ }
+ }
+
+ /**
+ * Parent's position is no more subtracted.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void setPositionZR(int z) {
+ for (Buildable b : floors) {
+ int offset = b.getPositionZ();
+ b.setPositionZR(z + offset);
+ }
+ for (Buildable b : cellars) {
+ int offset = b.getPositionZ();
+ b.setPositionZR(z + offset);
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/town/TownLayout.java b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/town/TownLayout.java
new file mode 100644
index 00000000..7225bc4d
--- /dev/null
+++ b/sources/codemetropolis-toolchain-placing/src/main/java/codemetropolis/toolchain/placing/layout/town/TownLayout.java
@@ -0,0 +1,343 @@
+package codemetropolis.toolchain.placing.layout.town;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.BuildableTree;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.placing.exceptions.LayoutException;
+import codemetropolis.toolchain.placing.layout.Layout;
+import codemetropolis.toolchain.placing.layout.LayoutUtils;
+import codemetropolis.toolchain.placing.layout.pack.PackLayout;
+import codemetropolis.toolchain.placing.layout.pack.RectanglePacker;
+import codemetropolis.toolchain.placing.layout.pack.RectanglePacker.Rectangle;
+
+/**
+ * {@link TownLayout} gives the look and feel of a real "small" town. So houses are built not so high, they are in
+ * gardens, along streets.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class TownLayout extends Layout {
+
+ private static final int SPACE = 3;
+ private static final int GROUND_LEVEL = 61;
+
+ private boolean left = true;
+ private Buildable leftRef = null;
+ private Buildable rightRef = null;
+ private int mostNegativeZ = 0;
+
+ /**
+ * An easier, clearer representation of Gardens, without wrapper.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void apply(BuildableTree buildables) throws LayoutException {
+ LayoutUtils.preparePackages(buildables.getRoot(), buildables.getRoot());
+ LayoutUtils.removeEmptyPackages(buildables.getRoot());
+ LayoutUtils.prepareGardens(buildables.getRoot());
+
+ Map> houses = createHouses(buildables);
+ BuildableWrapper wrapper = new BuildableWrapper(buildables.getRoot());
+ findGardens(buildables.getRoot(), wrapper, houses);
+ postProcess(buildables.getRoot());
+ }
+
+ /**
+ * A recursive function for discovering all of the gardens and grounds Grounds position is set in this function. To
+ * put gardens into their places {@code layDownGarden} function is called.
+ *
+ * @param node The current {@link Buildable}, which we are positioning.
+ * @param wrapper Wrapper holds all of the houses.
+ * @param houses This holds all of the houses in a map.
+ * @throws LayoutException For {@link PackLayout}, it type of current element is incorrect.
+ */
+ private void findGardens(Buildable node, BuildableWrapper wrapper, Map> houses)
+ throws LayoutException {
+
+ if (node.getType() == Buildable.Type.CONTAINER || node.getType() == Buildable.Type.GROUND) {
+ if (left) {
+ node.addAttribute("left", "true");
+ node.setPositionX(leftRef == null ? 0 : leftRef.getPositionX() + leftRef.getSizeX() + 5);
+ } else {
+ node.addAttribute("left", "false");
+ node.setPositionX(rightRef == null ? 0 : rightRef.getPositionX() + rightRef.getSizeX() + 5);
+ }
+
+ node.setPositionY(GROUND_LEVEL - 1);
+ node.setPositionZ(-5);
+ node.setSizeY(1);
+ node.setSizeZ(10);
+ }
+
+ Buildable[] children = node.getChildren();
+ for (Buildable child : children) {
+ if (child.getType() == Buildable.Type.GARDEN) {
+ layDownGarden(child, wrapper, houses);
+ } else {
+ findGardens(child, wrapper, houses);
+ }
+ }
+
+ int leftEnd = leftRef != null ? leftRef.getPositionX() + leftRef.getSizeX() + 5 : 0;
+ int rightEnd = rightRef != null ? rightRef.getPositionX() + rightRef.getSizeX() + 5 : 0;
+ int targetEnd = leftEnd < rightEnd ? rightEnd : leftEnd;
+
+ node.setSizeX(targetEnd - node.getPositionX());
+
+ left = !left;
+ }
+
+ /**
+ * Gardens in this theme are built up using {@link PackLayout} algorithm, but their height is limited more strictly.
+ *
+ * @param garden The current garden which holds all of its houses.
+ * @throws LayoutException For {@link PackLayout}, it type of current element is incorrect.
+ */
+ private void layDownGarden(Buildable garden, BuildableWrapper wrapper, Map> houses)
+ throws LayoutException {
+
+ BuildableWrapper root = new BuildableWrapper(garden);
+ packRecursive(root, houses, new Point(garden.getPositionX(), garden.getPositionY(), garden.getPositionZ()));
+
+ if (left) {
+ root.setPositionX(leftRef == null ? 0 : leftRef.getPositionX() + leftRef.getSizeX() + 5);
+ root.setPositionZ(-(garden.getSizeZ() + 5));
+ mostNegativeZ = (root.getPositionZ() < mostNegativeZ) ? root.getPositionZ() : mostNegativeZ;
+ leftRef = garden;
+ } else {
+ root.setPositionX(rightRef == null ? 0 : rightRef.getPositionX() + rightRef.getSizeX() + 5);
+ root.setPositionZ(5);
+ rightRef = garden;
+ }
+
+ garden.setPositionY(GROUND_LEVEL - 1);
+ }
+
+ /**
+ * Collecting all the house elements, including {@link Buildable.Type#CELLAR} as garage. It collects a city's
+ * elements if it is a {@link Buildable.Type#FLOOR}, a {@link Buildable.Type#CELLAR} or a
+ * {@link Buildable.Type#DECORATION_FLOOR}.
+ *
+ * @param buildables All the elements of the city.
+ * @return A list of the floors of one house.
+ */
+ private List getHouses(BuildableTree buildables) {
+ List result = new ArrayList();
+ for (Buildable b : buildables.getBuildables()) {
+ if (b.getType() != Buildable.Type.FLOOR && b.getType() != Buildable.Type.CELLAR &&
+ b.getType() != Buildable.Type.DECORATION_FLOOR)
+ continue;
+ result.add(b);
+ }
+ return result;
+ }
+
+ /**
+ * Creates a house by putting all the floor on top of each other until the max height. Also adds decoration floor on
+ * top of the houses and cellars as garages.
+ *
+ * @param buildables All the house elements are added in this {@link BuildableTree}.
+ * @return The created list of floors, as a train.
+ * @throws LayoutException Throws exception, if floor's type is incorrect.
+ */
+ private Map> createHouses(BuildableTree buildables) throws LayoutException {
+ Map> houses = new HashMap>();
+ for (Buildable b : getHouses(buildables)) {
+ List housesOfParent = houses.get(b.getParent());
+ if (housesOfParent == null) {
+ housesOfParent = new ArrayList();
+ houses.put(b.getParent(), housesOfParent);
+ }
+
+ boolean addedSuccessfully = false;
+ for (TownHouse h : housesOfParent) {
+ if (h.add(b)) {
+ addedSuccessfully = true;
+ break;
+ }
+ }
+
+ if (!addedSuccessfully) {
+ TownHouse h = new TownHouse(GROUND_LEVEL - 1, MAX_HEIGHT);
+ h.add(b);
+ housesOfParent.add(h);
+ }
+ }
+
+ addRoofs(houses);
+
+ return houses;
+ }
+
+ /**
+ * Adds a nice roof onto the top of the houses.
+ *
+ * @param houses The houses.
+ */
+ private void addRoofs(Map> houses) {
+ for (List houseList : houses.values()) {
+ for (TownHouse house : houseList) {
+ if (house.getTopFloor() != null && house.getTopFloor().getType() != Buildable.Type.CELLAR) {
+ Buildable oldTopFloor = house.getTopFloor();
+
+ Buildable roof = new Buildable(UUID.randomUUID().toString(), "roof",
+ Buildable.Type.DECORATION_FLOOR);
+ roof.setSizeX(oldTopFloor.getSizeX());
+ roof.setSizeY(9);
+ roof.setSizeZ(oldTopFloor.getSizeZ());
+ roof.setAttributes(Arrays.asList(oldTopFloor.getAttributes()));
+ roof.setCdfNames(oldTopFloor.getCdfNames());
+ roof.setParent(oldTopFloor.getParent());
+ roof.getParent().addChild(roof);
+
+ try {
+ house.add(roof);
+ } catch (LayoutException e) {
+ // Should not happen, as we explicitly add a Buildable.Type.DECORATION_FLOOR
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Maximum sizes in 3 dimensions is determined depending on the expected size of the garden.
+ *
+ * @param buildables A collection of {@link BuildableWrapper} object.
+ * @return A new point which contains maximum sizes in 3 dimensions.
+ */
+ private Point getMaxSizes(Collection buildables) {
+ int maxX = 0, maxZ = 0;
+ for (BuildableWrapper b : buildables) {
+ if (b.getSizeX() > maxX)
+ maxX = b.getSizeX();
+ if (b.getSizeZ() > maxZ)
+ maxZ = b.getSizeZ();
+ }
+ return new Point(maxX, 0, maxZ);
+ }
+
+ /**
+ * We use {@link PackLayout}'s packing algorithm inside the garden. So in a garden houses are packed on the smallest
+ * possible space.
+ *
+ * @param root The garden from where we start packing.
+ * @param houses All the houses we want to put into the same garden.
+ * @param startPos The garden's position.
+ */
+ private void packRecursive(BuildableWrapper root, Map> houses, Point startPos) {
+ List children = root.getTownChildren(houses);
+ for (BuildableWrapper c : children) {
+ if (!c.getTownChildren(houses).isEmpty()) {
+ packRecursive(c, houses, startPos);
+ }
+ }
+ Collections.sort(children);
+ Collections.reverse(children);
+ pack(children, SPACE, startPos);
+ }
+
+ /**
+ * Calculate the starting size of the garden.
+ *
+ * @param buildables A collection of the houses in a garden.
+ * @param space The space between houses.
+ * @param startPos The starting position of the garden.
+ */
+ private void pack(Collection buildables, int space, Point startPos) {
+ Point startingSize = getMaxSizes(buildables);
+ pack(buildables, startingSize.getX(), startingSize.getZ(), space, startPos);
+ }
+
+ /**
+ * A recursive algorithm, using {@link RectanglePacker} to minimize the space of a garden.
+ *
+ * @param buildables The list of houses.
+ * @param sizeX The starting x size.
+ * @param sizeZ The starting z size.
+ * @param space The spaces between houses.
+ * @param startPos The starting point of the garden.
+ */
+ private void pack(Collection buildables, int sizeX, int sizeZ, int space, Point startPos) {
+ RectanglePacker packer = new RectanglePacker(sizeX, sizeZ, space);
+
+ for (BuildableWrapper b : buildables) {
+ if (packer.insert(b.getSizeX(), b.getSizeZ(), b) == null) {
+ if (sizeX > sizeZ) {
+ sizeZ++;
+ } else {
+ sizeX++;
+ }
+ pack(buildables, sizeX, sizeZ, space, startPos);
+ return;
+ }
+ }
+
+ for (BuildableWrapper b : buildables) {
+ Rectangle r = packer.findRectangle(b);
+ b.setPositionX(startPos.getX() + r.x + space);
+ b.setPositionZ(startPos.getZ() + r.y + space);
+ }
+
+ if (!buildables.isEmpty()) {
+ Point parentSize = calculateParentSize(buildables, space);
+ Buildable parent = buildables.iterator().next().getParent();
+ parent.setSizeX(parentSize.getX());
+ parent.setSizeZ(parentSize.getZ());
+ }
+ }
+
+ /**
+ * Set the size of the parent depending on the maximum sizes of the inside houses.
+ *
+ * @param buildables The houses.
+ * @param space The space between houses.
+ * @return Parent element's size held a point, without y dimension size.
+ */
+ private Point calculateParentSize(Collection buildables, int space) {
+ BuildableWrapper firstChild = buildables.iterator().next();
+ int minX = firstChild.getPositionX();
+ int maxX = firstChild.getPositionX() + firstChild.getSizeX();
+ int minZ = firstChild.getPositionZ();
+ int maxZ = firstChild.getPositionZ() + firstChild.getSizeZ();
+
+ for (BuildableWrapper b : buildables) {
+ if (b.getPositionX() < minX)
+ minX = b.getPositionX();
+ if (b.getPositionX() + b.getSizeX() > maxX)
+ maxX = b.getPositionX() + b.getSizeX();
+ if (b.getPositionZ() < minZ)
+ minZ = b.getPositionZ();
+ if (b.getPositionZ() + b.getSizeZ() > maxZ)
+ maxZ = b.getPositionZ() + b.getSizeZ();
+ }
+
+ return new Point(
+ maxX - minX + 2 * space,
+ 0,
+ maxZ - minZ + 2 * space);
+ }
+
+ /**
+ * Updates z dimensional positions, so all of the buildings will have a positive z position.
+ *
+ * @param node The current node, whose children z dimensional position will be updated.
+ */
+ private void postProcess(Buildable node) {
+ for (Buildable child : node.getChildrenList()) {
+ child.setPositionZ(child.getPositionZ() - mostNegativeZ);
+ postProcess(child);
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/.classpath b/sources/codemetropolis-toolchain-rendering/.classpath
index e7a868fb..cd555fe2 100644
--- a/sources/codemetropolis-toolchain-rendering/.classpath
+++ b/sources/codemetropolis-toolchain-rendering/.classpath
@@ -18,12 +18,6 @@
-
-
-
-
-
-
diff --git a/sources/codemetropolis-toolchain-rendering/pom.xml b/sources/codemetropolis-toolchain-rendering/pom.xml
index 3bbb1592..557fe3f0 100644
--- a/sources/codemetropolis-toolchain-rendering/pom.xml
+++ b/sources/codemetropolis-toolchain-rendering/pom.xml
@@ -73,5 +73,13 @@
commons-lang3
3.4
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
\ No newline at end of file
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/CommandLineOptions.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/CommandLineOptions.java
index 42f67dd5..0388e4ec 100644
--- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/CommandLineOptions.java
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/CommandLineOptions.java
@@ -2,6 +2,8 @@
import org.kohsuke.args4j.Option;
+import codemetropolis.toolchain.rendering.model.Themes;
+
public class CommandLineOptions {
@Option(name="-h", aliases = { "--help" })
@@ -16,6 +18,9 @@ public class CommandLineOptions {
@Option(name="-s", aliases = { "-ow", "--overwrite", "--silent" })
private boolean overwriteSilently = false;
+ @Option(name="-t", aliases = { "-theme", "--theme" })
+ private Themes theme = Themes.BASIC;
+
public boolean showHelp() {
return showHelp;
}
@@ -31,5 +36,9 @@ public String getWorld() {
public boolean overwriteSilently() {
return overwriteSilently;
}
+
+ public Themes getTheme() {
+ return theme;
+ }
}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/Main.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/Main.java
index 2de98730..d93585e9 100644
--- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/Main.java
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/Main.java
@@ -74,7 +74,8 @@ private void printProgress(String message, ProgressEvent event) {
new RenderingExecutorArgs(
options.getInputFile(),
options.getWorld(),
- options.overwriteSilently())
+ options.overwriteSilently(),
+ options.getTheme())
);
}
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..7b73e8a0 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
@@ -71,7 +71,7 @@ public boolean execute(ExecutorArgs args) {
print(Resources.get("rendering_reading_input"));
try {
- worldBuilder.createBuildings(renderingArgs.getInputFile());
+ worldBuilder.createBuildings(renderingArgs.getInputFile(), renderingArgs.getTheme());
} catch (BuildingTypeMismatchException e) {
printError(e, Resources.get("building_creation_failed_error"));
return false;
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/RenderingExecutorArgs.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/RenderingExecutorArgs.java
index d6b26410..58c06e32 100644
--- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/RenderingExecutorArgs.java
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/RenderingExecutorArgs.java
@@ -1,27 +1,36 @@
package codemetropolis.toolchain.rendering;
import codemetropolis.toolchain.commons.executor.ExecutorArgs;
+import codemetropolis.toolchain.rendering.model.Themes;
public class RenderingExecutorArgs extends ExecutorArgs {
-
+
private String inputFile;
private String worldPath;
private boolean overwriteSilently;
private int maxTime;
-
+ private Themes theme;
+
public RenderingExecutorArgs(String inputFile, String worldPath) {
this(inputFile, worldPath, false);
}
-
+
public RenderingExecutorArgs(String inputFile, String worldPath, boolean overwriteSilently) {
- this(inputFile, worldPath, overwriteSilently, Integer.MAX_VALUE);
+ this(inputFile, worldPath, overwriteSilently, Themes.BASIC, Integer.MAX_VALUE);
+ }
+
+ public RenderingExecutorArgs(String inputFile, String worldPath, boolean overwriteSilently, Themes theme) {
+ this(inputFile, worldPath, overwriteSilently, theme, Integer.MAX_VALUE);
}
-
- public RenderingExecutorArgs(String inputFile, String worldPath, boolean overwriteSilently, int maxTime) {
+
+ public RenderingExecutorArgs(String inputFile, String worldPath, boolean overwriteSilently, Themes theme,
+ int maxTime) {
+
super();
this.inputFile = inputFile;
this.worldPath = worldPath;
this.overwriteSilently = overwriteSilently;
+ this.theme = theme;
this.maxTime = maxTime;
}
@@ -40,5 +49,9 @@ public boolean isSilentOverwriteEnabled() {
public int getMaxTime() {
return maxTime;
}
-
+
+ public Themes getTheme() {
+ return theme;
+ }
+
}
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..8491d1ee 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
@@ -19,7 +19,13 @@
import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
import codemetropolis.toolchain.rendering.exceptions.RenderingException;
import codemetropolis.toolchain.rendering.exceptions.TooLongRenderDurationException;
+import codemetropolis.toolchain.rendering.model.Themes;
import codemetropolis.toolchain.rendering.model.building.*;
+import codemetropolis.toolchain.rendering.model.building.factory.CellarFactory;
+import codemetropolis.toolchain.rendering.model.building.factory.DecorationFloorFactory;
+import codemetropolis.toolchain.rendering.model.building.factory.FloorFactory;
+import codemetropolis.toolchain.rendering.model.building.factory.GardenFactory;
+import codemetropolis.toolchain.rendering.model.building.factory.GroundFactory;
import codemetropolis.toolchain.rendering.model.primitive.Boxel;
public class WorldBuilder {
@@ -37,7 +43,7 @@ public WorldBuilder(String worldPath) {
world = new World(worldPath, GROUND_LEVEL);
}
- public void createBuildings(String inputPath) throws BuildingTypeMismatchException{
+ public void createBuildings(String inputPath, Themes theme) throws BuildingTypeMismatchException{
BuildableTree buildables = new BuildableTree();
try {
buildables.loadFromFile(inputPath);
@@ -47,29 +53,35 @@ public void createBuildings(String inputPath) throws BuildingTypeMismatchExcepti
}
List floors = new ArrayList();
+ List decorationFloors = new ArrayList();
List cellars = new ArrayList();
List gardens = new ArrayList();
List grounds = new ArrayList();
for(Buildable b : buildables.getBuildables()) {
switch(b.getType()) {
- case FLOOR:
- Floor floor = new Floor(b);
+ case FLOOR:
+ Floor floor = FloorFactory.createFloor(b, theme);
floors.add(floor);
total += floor.getNumberOfBlocks();
break;
+ case DECORATION_FLOOR:
+ DecorationFloor decorationFloor = DecorationFloorFactory.createDecorationFloor(b, theme);
+ decorationFloors.add(decorationFloor);
+ total += decorationFloor.getNumberOfBlocks();
+ break;
case CELLAR:
- Cellar cellar = new Cellar(b);
+ Cellar cellar = CellarFactory.createCellar(b, theme);
cellars.add(cellar);
total += cellar.getNumberOfBlocks();
break;
case GARDEN:
- Garden garden = new Garden(b);
+ Garden garden = GardenFactory.createGarden(b, theme);
gardens.add(garden);
total += garden.getNumberOfBlocks();
break;
case GROUND:
- Ground ground = new Ground(b);
+ Ground ground = GroundFactory.createGround(b, theme);
grounds.add(ground);
total += ground.getNumberOfBlocks();
break;
@@ -82,6 +94,7 @@ public void createBuildings(String inputPath) throws BuildingTypeMismatchExcepti
buildings.addAll(gardens);
buildings.addAll(cellars);
buildings.addAll(floors);
+ buildings.addAll(decorationFloors);
raiseProgressEvent(BuildPhase.READING_INPUT_FILE, 1, 1, -1);
}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/Themes.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/Themes.java
new file mode 100644
index 00000000..978626f5
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/Themes.java
@@ -0,0 +1,15 @@
+package codemetropolis.toolchain.rendering.model;
+
+/**
+ * An enum class for storing themes.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public enum Themes {
+
+ BASIC,
+ MINIMALIST,
+ RAILWAY,
+ TOWN,
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Building.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Building.java
index 87e2f213..41bb1812 100644
--- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Building.java
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Building.java
@@ -81,4 +81,8 @@ public int getNumberOfBlocks() {
return result;
}
+ public LinkedList getPrimitives() {
+ return this.primitives;
+ }
+
}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/DecorationFloor.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/DecorationFloor.java
new file mode 100644
index 00000000..cd4d971b
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/DecorationFloor.java
@@ -0,0 +1,41 @@
+package codemetropolis.toolchain.rendering.model.building;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Buildable.Type;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+
+/**
+ * A new type of {@link Building}, which is meant to close the top of buildings. On top of this floor you can add fancy
+ * decorations.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class DecorationFloor extends Building {
+
+ public DecorationFloor(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+
+ if (innerBuildable.getType() != Type.DECORATION_FLOOR)
+ throw new BuildingTypeMismatchException(innerBuildable.getType(), getClass());
+
+ prepareCeiling();
+ prepareRoof();
+ }
+
+ /**
+ * This function creates one simple layer. It closes the top of the building with the same block, which was used for
+ * the {@link Floor}.
+ */
+ protected void prepareCeiling() {
+ // The BASIC theme doesn't use decoration floors.
+ }
+
+ /**
+ * This function creates some fancy decoration on the top of the building. It can even be a creative decoration or a
+ * simple roof.
+ */
+ protected void prepareRoof() {
+ // The BASIC theme doesn't use decoration floors.
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Floor.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Floor.java
index ced4a538..bbad3e3a 100644
--- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Floor.java
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Floor.java
@@ -241,7 +241,7 @@ protected void prepareWalls() {
);
}
- private void prepareSigns( ) {
+ protected void prepareSigns( ) {
//Wall signs outside
primitives.add(new WallSign(position.getX() + size.getX() / 2, position.getY() + 3, position.getZ() - 1, WallSign.Orientation.NORTH, innerBuildable.getName()));
primitives.add(new WallSign(position.getX() + size.getX() / 2, position.getY() + 3, position.getZ() + size.getZ(), WallSign.Orientation.SOUTH, innerBuildable.getName()));
@@ -254,7 +254,7 @@ private void prepareSigns( ) {
primitives.add(new WallSign(position.getX() + size.getX() - 2, position.getY() + 3, position.getZ() + size.getZ() / 2, WallSign.Orientation.WEST, innerBuildable.getName()));
}
- private void prepareTorches( ) {
+ protected void prepareTorches( ) {
if(!innerBuildable.hasAttribute( "torches" )) return;
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..1b023fa6 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
@@ -25,7 +25,7 @@ public Garden(Buildable innerBuildable) throws BuildingTypeMismatchException {
prepareSigns();
}
- private void prepareBase( ) {
+ protected void prepareBase( ) {
BasicBlock _fnc = new BasicBlock( "minecraft:fence" );
BasicBlock _sns = new BasicBlock( "minecraft:sandstone" );
RandomPattern _flowers = new RandomPattern( new RepeationPattern( new BasicBlock[][][]{ { { BasicBlock.NonBlock } } } ) );
@@ -138,7 +138,7 @@ protected void prepareDoor( )
);
}
- private void prepareSigns( ) {
+ protected void prepareSigns( ) {
primitives.add(new SignPost(position.getX(), position.getY() + 2, position.getZ(), SignPost.Orientation.NORTHWEST, innerBuildable.getName()));
primitives.add(new SignPost(position.getX() + size.getX() - 1, position.getY() + 2, position.getZ(), SignPost.Orientation.NORTHEAST, innerBuildable.getName()));
primitives.add(new SignPost(position.getX(), position.getY() + 2, position.getZ() + size.getZ() - 1, SignPost.Orientation.SOUTHWEST, innerBuildable.getName()));
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Ground.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Ground.java
index b7f24d6f..496449bf 100644
--- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Ground.java
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/Ground.java
@@ -22,7 +22,7 @@ public Ground(Buildable innerBuildable) throws BuildingTypeMismatchException {
prepareSigns();
}
- private void prepareBase( ) {
+ protected void prepareBase( ) {
primitives.add(
new SolidBox(
position,
@@ -32,7 +32,7 @@ private void prepareBase( ) {
Orientation.NearX ) );
}
- private void prepareSigns( ) {
+ protected void prepareSigns( ) {
primitives.add(new SignPost(position.getX(), position.getY() + 1, position.getZ(), SignPost.Orientation.NORTHWEST, innerBuildable.getName()));
primitives.add(new SignPost(position.getX() + size.getX() - 1, position.getY() + 1, position.getZ(), SignPost.Orientation.NORTHEAST, innerBuildable.getName()));
primitives.add(new SignPost(position.getX(), position.getY() + 1, position.getZ() + size.getZ() - 1, SignPost.Orientation.SOUTHWEST, innerBuildable.getName()));
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/CellarFactory.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/CellarFactory.java
new file mode 100644
index 00000000..3a6764f7
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/CellarFactory.java
@@ -0,0 +1,40 @@
+package codemetropolis.toolchain.rendering.model.building.factory;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Cellar;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownCellar;
+
+/**
+ * Create the proper {@link Cellar} subclass depending on the {@link Themes}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class CellarFactory {
+
+ /**
+ * Depending on the {@link Themes} parameter create a proper {@link Cellar} subclass.
+ *
+ * @param buildable A {@link Buildable} object to be used for instantiation.
+ * @param theme The requested style, defined as {@link Themes}.
+ * @return The proper {@link Cellar} subclass.
+ * @throws BuildingTypeMismatchException If type of {@code buildable} is incorrect.
+ */
+ public static Cellar createCellar(Buildable buildable, Themes theme) throws BuildingTypeMismatchException {
+ switch (theme) {
+ case MINIMALIST:
+ return new MinimalistCellar(buildable);
+ case RAILWAY:
+ return new RailwayCellar(buildable);
+ case TOWN:
+ return new TownCellar(buildable);
+ case BASIC:
+ default:
+ return new Cellar(buildable);
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/DecorationFloorFactory.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/DecorationFloorFactory.java
new file mode 100644
index 00000000..b74d1a8d
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/DecorationFloorFactory.java
@@ -0,0 +1,42 @@
+package codemetropolis.toolchain.rendering.model.building.factory;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.DecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownDecorationFloor;
+
+/**
+ * Create the proper {@link DecorationFloor} subclass depending on the {@link Themes}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class DecorationFloorFactory {
+
+ /**
+ * Depending on the {@link Themes} parameter create a proper {@link DecorationFloor} subclass.
+ *
+ * @param buildable A {@link Buildable} object to be used for instantiation.
+ * @param theme The requested style, defined as {@link Themes}.
+ * @return The proper {@link DecorationFloor} subclass.
+ * @throws BuildingTypeMismatchException If type of {@code buildable} is incorrect.
+ */
+ public static DecorationFloor createDecorationFloor(Buildable buildable, Themes theme)
+ throws BuildingTypeMismatchException {
+
+ switch (theme) {
+ case MINIMALIST:
+ return new MinimalistDecorationFloor(buildable);
+ case RAILWAY:
+ return new RailwayDecorationFloor(buildable);
+ case TOWN:
+ return new TownDecorationFloor(buildable);
+ case BASIC:
+ default:
+ return new DecorationFloor(buildable);
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/FloorFactory.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/FloorFactory.java
new file mode 100644
index 00000000..e8d43dc1
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/FloorFactory.java
@@ -0,0 +1,40 @@
+package codemetropolis.toolchain.rendering.model.building.factory;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownFloor;
+
+/**
+ * Create the proper {@link Floor} subclass depending on the {@link Themes}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class FloorFactory {
+
+ /**
+ * Depending on the {@link Themes} parameter create a proper {@link Floor} subclass.
+ *
+ * @param buildable A {@link Buildable} object to be used for instantiation.
+ * @param theme The requested style, defined as {@link Themes}.
+ * @return The proper {@link Floor} subclass.
+ * @throws BuildingTypeMismatchException If type of {@code buildable} is incorrect.
+ */
+ public static Floor createFloor(Buildable buildable, Themes theme) throws BuildingTypeMismatchException {
+ switch (theme) {
+ case MINIMALIST:
+ return new MinimalistFloor(buildable);
+ case RAILWAY:
+ return new RailwayFloor(buildable);
+ case TOWN:
+ return new TownFloor(buildable);
+ case BASIC:
+ default:
+ return new Floor(buildable);
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/GardenFactory.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/GardenFactory.java
new file mode 100644
index 00000000..5567cf31
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/GardenFactory.java
@@ -0,0 +1,40 @@
+package codemetropolis.toolchain.rendering.model.building.factory;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Garden;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGarden;
+
+/**
+ * Create the proper {@link Garden} subclass depending on the {@link Themes}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class GardenFactory {
+
+ /**
+ * Depending on the {@link Themes} parameter create a proper {@link Garden} subclass.
+ *
+ * @param buildable A {@link Buildable} object to be used for instantiation.
+ * @param theme The requested style, defined as {@link Themes}.
+ * @return The proper {@link Garden} subclass.
+ * @throws BuildingTypeMismatchException If type of {@code buildable} is incorrect.
+ */
+ public static Garden createGarden(Buildable buildable, Themes theme) throws BuildingTypeMismatchException {
+ switch (theme) {
+ case MINIMALIST:
+ return new MinimalistGarden(buildable);
+ case RAILWAY:
+ return new RailwayGarden(buildable);
+ case TOWN:
+ return new TownGarden(buildable);
+ case BASIC:
+ default:
+ return new Garden(buildable);
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/GroundFactory.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/GroundFactory.java
new file mode 100644
index 00000000..f2f66325
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/factory/GroundFactory.java
@@ -0,0 +1,40 @@
+package codemetropolis.toolchain.rendering.model.building.factory;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Ground;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGround;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGround;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGround;
+
+/**
+ * Create the proper {@link Ground} subclass depending on the {@link Themes}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class GroundFactory {
+
+ /**
+ * Depending on the {@link Themes} parameter create a proper {@link Ground} subclass.
+ *
+ * @param buildable A {@link Buildable} object to be used for instantiation.
+ * @param theme The requested style, defined as {@link Themes}.
+ * @return The proper {@link Ground} subclass.
+ * @throws BuildingTypeMismatchException If type of {@code buildable} is incorrect.
+ */
+ public static Ground createGround(Buildable buildable, Themes theme) throws BuildingTypeMismatchException {
+ switch (theme) {
+ case MINIMALIST:
+ return new MinimalistGround(buildable);
+ case RAILWAY:
+ return new RailwayGround(buildable);
+ case TOWN:
+ return new TownGround(buildable);
+ case BASIC:
+ default:
+ return new Ground(buildable);
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistBlocks.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistBlocks.java
new file mode 100644
index 00000000..5d7950ff
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistBlocks.java
@@ -0,0 +1,20 @@
+package codemetropolis.toolchain.rendering.model.building.theme.minimalist;
+
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+
+/**
+ * Collection of the used blocks in the {@link Themes#MINIMALIST} theme.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class MinimalistBlocks {
+
+ public final static BasicBlock GARDEN = new BasicBlock("minecraft:sand", 1);
+ public final static BasicBlock FENCE = new BasicBlock((short) 192);
+ public final static BasicBlock EMPTY_BLOCK = BasicBlock.NonBlock;
+ public final static BasicBlock BASE = new BasicBlock((short) 98);
+ public final static BasicBlock PILLAR = new BasicBlock("minecraft:bedrock");
+ public final static BasicBlock WALL = new BasicBlock((short) 20);
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistCellar.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistCellar.java
new file mode 100644
index 00000000..45c2251b
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistCellar.java
@@ -0,0 +1,79 @@
+package codemetropolis.toolchain.rendering.model.building.theme.minimalist;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Buildable.Type;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Cellar;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SolidBox;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Cellar} subclass for the {@link Themes#MINIMALIST} theme. Repeating {@link Floor} downwards, also without
+ * stairs.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class MinimalistCellar extends Cellar {
+
+ /**
+ * Creates a simple cellar, without stairs. It creates an instance of {@link MinimalistFloor}, then in this one
+ * stairs are removed.
+ *
+ * @param innerBuildable The buildable of which cellar type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public MinimalistCellar(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+
+ if (innerBuildable.getType() != Type.CELLAR)
+ throw new BuildingTypeMismatchException(innerBuildable.getType(), getClass());
+
+ MinimalistFloor minFloor = new MinimalistFloor(innerBuildable);
+ primitives = minFloor.getPrimitives();
+
+ primitives.add(
+ 0,
+ new SolidBox(
+ position.translate(new Point(1, size.getY() - (size.getY() / 2), 1)),
+ size.translate(new Point(-2, -2, -2)),
+ new RepeationPattern(new BasicBlock[][][] { { { MinimalistBlocks.EMPTY_BLOCK } } }),
+ new RepeationPattern(new BasicBlock[][][] { { { MinimalistBlocks.EMPTY_BLOCK } } }),
+ Orientation.NearX));
+ }
+
+ /**
+ * Walls are copied from {@link MinimalistFloor}.
+ */
+ @Override
+ protected void prepareWalls() {}
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no stairs.
+ */
+ @Override
+ protected void prepareStairs() {}
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no doors.
+ */
+ @Override
+ protected void prepareDoor() {}
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no signs.
+ */
+ @Override
+ protected void prepareSigns() {}
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no torches.
+ */
+ @Override
+ protected void prepareTorches() {}
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistDecorationFloor.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistDecorationFloor.java
new file mode 100644
index 00000000..764705c2
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistDecorationFloor.java
@@ -0,0 +1,50 @@
+package codemetropolis.toolchain.rendering.model.building.theme.minimalist;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.DecorationFloor;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link DecorationFloor} subclass for the {@link Themes#MINIMALIST} theme. Closing the top of the building with only
+ * a horizontal layer.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class MinimalistDecorationFloor extends DecorationFloor {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which decoration floor type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public MinimalistDecorationFloor(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * Closing the top of the building with only a horizontal layer.
+ */
+ @Override
+ protected void prepareCeiling() {
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, -1, 0)),
+ new Point(size.getX(), 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { MinimalistBlocks.PILLAR } } }),
+ Orientation.NearY));
+ }
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there is no top decoration.
+ */
+ @Override
+ protected void prepareRoof() {}
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistFloor.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistFloor.java
new file mode 100644
index 00000000..1329c04c
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistFloor.java
@@ -0,0 +1,121 @@
+package codemetropolis.toolchain.rendering.model.building.theme.minimalist;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Floor} subclass for the {@link Themes#MINIMALIST} theme. Transparent floors, for a simple look-and-feel,
+ * with only pillars, without stairs.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class MinimalistFloor extends Floor {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which floor type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public MinimalistFloor(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * Transparent glass walls, with a simple stone frame, without floor bases.
+ */
+ @Override
+ protected void prepareWalls() {
+ BasicBlock[][][] sideWallSection = createSection(MinimalistBlocks.WALL);
+ BasicBlock[][][] bottomSection = createSection(MinimalistBlocks.PILLAR);
+
+ primitives.add(
+ new SimpleBox(
+ position,
+ new Point(size.getX(), size.getY() - 1, size.getZ()),
+ new RepeationPattern(sideWallSection),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, size.getY() - 1, 0)),
+ new Point(size.getX(), 1, size.getZ()),
+ new RepeationPattern(bottomSection),
+ Orientation.NearX));
+ }
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no stairs.
+ */
+ @Override
+ protected void prepareStairs() {
+
+ }
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no doors.
+ */
+ @Override
+ protected void prepareDoor() {
+
+ }
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no signs.
+ */
+ @Override
+ protected void prepareSigns() {
+
+ }
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no torches.
+ */
+ @Override
+ protected void prepareTorches() {
+
+ }
+
+ /**
+ * Create a layer of the current floor according to the type, so it can be a middle or a bottom layer.
+ *
+ * @param type Define if it is a middle or a bottom layer.
+ * @return The requested layer.
+ */
+ private BasicBlock[][][] createSection(BasicBlock type) {
+ BasicBlock[][][] section = new BasicBlock[size.getX()][1][size.getZ()];
+
+ // Initialize the matrix
+ for (int i = 0; i < section.length; i++) {
+ for (int j = 0; j < section[0][0].length; j++) {
+ section[i][0][j] = MinimalistBlocks.EMPTY_BLOCK;
+ }
+ }
+
+ // Add sides based on the type (sidewall-section or bottom section)
+ for (int i = 0; i < section.length; i++) {
+ section[i][0][0] = type;
+ section[i][0][size.getZ() - 1] = type;
+ }
+ for (int j = 0; j < section[0][0].length; j++) {
+ section[0][0][j] = type;
+ section[size.getX() - 1][0][j] = type;
+ }
+
+ // Add pillars to the corners
+ section[0][0][0] = MinimalistBlocks.PILLAR;
+ section[0][0][size.getZ() - 1] = MinimalistBlocks.PILLAR;
+ section[size.getX() - 1][0][0] = MinimalistBlocks.PILLAR;
+ section[size.getX() - 1][0][size.getZ() - 1] = MinimalistBlocks.PILLAR;
+
+ return section;
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistGarden.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistGarden.java
new file mode 100644
index 00000000..476832bd
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistGarden.java
@@ -0,0 +1,82 @@
+package codemetropolis.toolchain.rendering.model.building.theme.minimalist;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Garden;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.pattern.YSplitPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Garden} subclass for the {@link Themes#MINIMALIST} theme. A simple garden without flowers, or any kind of
+ * obstacles.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class MinimalistGarden extends Garden {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which garden type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public MinimalistGarden(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * A simple garden without flowers, or any kind of obstacles.
+ */
+ @Override
+ protected void prepareBase() {
+ BasicBlock[][][] fence = new BasicBlock[size.getX()][1][size.getZ()];
+
+ // Initialize the matrix
+ for (int i = 0; i < fence.length; i++) {
+ for (int j = 0; j < fence[0][0].length; j++) {
+ fence[i][0][j] = MinimalistBlocks.EMPTY_BLOCK;
+ }
+ }
+
+ // Add fence to the outer edges
+ for (int i = 0; i < fence.length; i++) {
+ fence[i][0][0] = MinimalistBlocks.FENCE;
+ fence[i][0][size.getZ() - 1] = MinimalistBlocks.FENCE;
+ }
+ for (int j = 0; j < fence[0][0].length; j++) {
+ fence[0][0][j] = MinimalistBlocks.FENCE;
+ fence[size.getX() - 1][0][j] = MinimalistBlocks.FENCE;
+ }
+
+ primitives.add(
+ new SimpleBox(
+ position, new Point(size.getX(), 2, size.getZ()),
+ new YSplitPattern(
+ 0,
+ new RepeationPattern(new BasicBlock[][][] { { { MinimalistBlocks.GARDEN } } }),
+ new RepeationPattern(fence)),
+ Orientation.NearX));
+ }
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no doors.
+ */
+ @Override
+ protected void prepareDoor() {
+
+ }
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no signs.
+ */
+ @Override
+ protected void prepareSigns() {
+
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistGround.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistGround.java
new file mode 100644
index 00000000..412fa70d
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/minimalist/MinimalistGround.java
@@ -0,0 +1,52 @@
+package codemetropolis.toolchain.rendering.model.building.theme.minimalist;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Ground;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Ground} subclass for the {@link Themes#MINIMALIST} theme. Creates a simple base for the buildings, using a
+ * simple block type.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class MinimalistGround extends Ground {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which ground type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public MinimalistGround(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * Creates a simple base for the buildings, using a simple block type.
+ */
+ @Override
+ protected void prepareBase() {
+ primitives.add(
+ new SimpleBox(
+ position,
+ new Point(size.getX(), 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { MinimalistBlocks.BASE } } }),
+ Orientation.NearX));
+ }
+
+ /**
+ * According to {@link Themes#MINIMALIST} theme there are no signs.
+ */
+ @Override
+ protected void prepareSigns() {
+
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayBlocks.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayBlocks.java
new file mode 100644
index 00000000..17af8edb
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayBlocks.java
@@ -0,0 +1,27 @@
+package codemetropolis.toolchain.rendering.model.building.theme.railway;
+
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+
+/**
+ * Collection of the used blocks in the {@link Themes#RAILWAY} theme.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class RailwayBlocks {
+
+ public final static BasicBlock EMPTY_BLOCK = BasicBlock.NonBlock;
+ public final static BasicBlock RAIL_DIRT = new BasicBlock("minecraft:dirt", 1);
+ public final static BasicBlock RAIL_WOOD = new BasicBlock((short) 5);
+ public final static BasicBlock RAIL_IRON = new BasicBlock((short) 42);
+ public final static BasicBlock GATE = new BasicBlock("minecraft:planks", 5);
+ public final static BasicBlock WAGON_WALL = new BasicBlock("minecraft:stained_glass", 11);
+ public final static BasicBlock WAGON_CHIMNEY = new BasicBlock("minecraft:wool", 7);
+ public final static BasicBlock[] WAGON_PILLARS = {
+ new BasicBlock((short) 22),
+ new BasicBlock((short) 152),
+ new BasicBlock((short) 41),
+ new BasicBlock((short) 133)
+ };
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayCellar.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayCellar.java
new file mode 100644
index 00000000..b11ab571
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayCellar.java
@@ -0,0 +1,72 @@
+package codemetropolis.toolchain.rendering.model.building.theme.railway;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Cellar;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.model.primitive.WallSign;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Cellar} subclass for the {@link Themes#RAILWAY} theme. Representing cellars with only an empty wagon base.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class RailwayCellar extends Cellar {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which cellar type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public RailwayCellar(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * In this theme there are no walls for wagons, which represents cellars.
+ */
+ @Override
+ protected void prepareWalls() {
+ primitives.add(
+ new SimpleBox(
+ position,
+ new Point(size.getX() + 2, 2, size.getZ()),
+ new RepeationPattern(RailwayUtils.createWagonBase(2, size.getZ(), size.getX() + 2)),
+ Orientation.NearY));
+ }
+
+ /**
+ * According to {@link Themes#RAILWAY} theme there are no stairs.
+ */
+ @Override
+ protected void prepareStairs() {}
+
+ /**
+ * According to {@link Themes#RAILWAY} theme there are no doors.
+ */
+ @Override
+ protected void prepareDoor() {}
+
+ /**
+ * Sings are on the sides of these wagons.
+ */
+ @Override
+ protected void prepareSigns() {
+ primitives.add(new WallSign(position.getX() + (size.getX() + 2) / 2, position.getY() + 1, position.getZ() - 1,
+ WallSign.Orientation.NORTH, innerBuildable.getName()));
+ primitives.add(new WallSign(position.getX() + (size.getX() + 2) / 2, position.getY() + 1,
+ position.getZ() + size.getZ(), WallSign.Orientation.SOUTH, innerBuildable.getName()));
+ }
+
+ /**
+ * According to {@link Themes#RAILWAY} theme there are no torches.
+ */
+ @Override
+ protected void prepareTorches() {}
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayDecorationFloor.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayDecorationFloor.java
new file mode 100644
index 00000000..6415e861
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayDecorationFloor.java
@@ -0,0 +1,193 @@
+package codemetropolis.toolchain.rendering.model.building.theme.railway;
+
+import java.util.Random;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.DecorationFloor;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link DecorationFloor} subclass for the {@link Themes#RAILWAY} theme. Adding an engine at the beginning of the
+ * train.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class RailwayDecorationFloor extends DecorationFloor {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which decoration floor type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public RailwayDecorationFloor(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * Just a simple base for the engine.
+ */
+ @Override
+ protected void prepareCeiling() {
+ primitives.add(
+ new SimpleBox(
+ position,
+ new Point(17, 2, 9),
+ new RepeationPattern(createWagonBase()),
+ Orientation.NearY));
+ }
+
+ /**
+ * Adding a good looking engine to the beginning of the train.
+ */
+ @Override
+ protected void prepareRoof() {
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(1, 2, 0)),
+ new Point(15, 7, 9),
+ new RepeationPattern(createEngine()),
+ Orientation.NearY));
+ }
+
+ /**
+ * Creates the whole engine.
+ *
+ * @return The requested layer.
+ */
+ private BasicBlock[][][] createEngine() {
+ Random rand = new Random();
+ BasicBlock O = RailwayBlocks.WAGON_PILLARS[rand.nextInt(RailwayBlocks.WAGON_PILLARS.length)];
+ BasicBlock X = RailwayBlocks.WAGON_CHIMNEY;
+ BasicBlock I = RailwayBlocks.EMPTY_BLOCK;
+
+ BasicBlock[][][] engine = new BasicBlock[][][] {
+ {
+ { I, I, I, I, I, I, I, I, I, I, I, I, I, I, I },
+ { I, I, I, I, I, I, I, I, I, I, I, I, I, I, I },
+ { X, X, X, X, I, I, I, I, I, I, I, I, I, I, I },
+ { X, X, X, X, I, I, I, I, I, I, I, I, I, I, I },
+ { X, X, X, X, I, I, I, I, I, I, I, I, I, X, I },
+ { X, X, X, X, I, I, I, I, I, I, I, I, I, I, I },
+ { X, X, X, X, I, I, I, I, I, I, I, I, I, I, I },
+ { I, I, I, I, I, I, I, I, I, I, I, I, I, I, I },
+ { I, I, I, I, I, I, I, I, I, I, I, I, I, I, I }
+ },
+ {
+ { I, I, I, I, I, I, I, I, I, I, I, I, I, I, I },
+ { O, O, O, O, I, I, I, I, I, I, I, I, I, I, I },
+ { O, I, I, O, I, I, I, I, I, I, I, I, I, I, I },
+ { O, I, I, O, I, I, I, I, I, I, I, I, I, I, I },
+ { O, I, I, O, I, I, I, I, I, I, I, I, I, X, I },
+ { O, I, I, O, I, I, I, I, I, I, I, I, I, I, I },
+ { O, I, I, O, I, I, I, I, I, I, I, I, I, I, I },
+ { O, O, O, O, I, I, I, I, I, I, I, I, I, I, I },
+ { I, I, I, I, I, I, I, I, I, I, I, I, I, I, I }
+
+ },
+ {
+ { O, O, O, O, I, I, I, I, I, I, I, I, I, I, I },
+ { O, I, I, I, O, I, I, I, I, I, I, I, I, I, I },
+ { O, I, I, I, O, O, I, I, I, I, I, I, I, I, I },
+ { O, I, I, I, O, O, O, O, I, I, I, I, I, I, I },
+ { O, I, I, I, O, O, O, O, O, O, O, O, X, X, X },
+ { O, I, I, I, O, O, O, O, I, I, I, I, I, I, I },
+ { O, I, I, I, O, O, I, I, I, I, I, I, I, I, I },
+ { O, I, I, I, O, I, I, I, I, I, I, I, I, I, I },
+ { O, O, O, O, I, I, I, I, I, I, I, I, I, I, I }
+
+ },
+ {
+ { O, O, O, O, I, I, I, I, I, I, I, I, I, I, I },
+ { O, I, I, I, O, O, O, I, I, I, I, I, I, I, I },
+ { O, I, I, I, O, O, O, O, O, I, I, I, I, I, I },
+ { O, I, I, I, I, I, I, I, O, O, O, O, X, X, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, O, O, O, O, X, X, X },
+ { O, I, I, I, O, O, O, O, O, I, I, I, I, I, I },
+ { O, I, I, I, O, O, O, I, I, I, I, I, I, I, I },
+ { O, O, O, O, I, I, I, I, I, I, I, I, I, I, I }
+ },
+ {
+ { O, O, O, O, O, O, O, O, I, I, I, I, I, I, I },
+ { O, I, I, I, I, O, I, O, O, O, O, I, I, I, I },
+ { O, I, I, I, I, I, I, I, I, O, O, O, X, X, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, O, O, O, X, X, X },
+ { O, I, I, I, I, O, I, O, O, O, O, I, I, I, I },
+ { O, O, O, O, O, O, O, O, I, I, I, I, I, I, I }
+ },
+ {
+ { O, O, O, O, O, O, O, O, O, O, O, O, O, I, I },
+ { O, I, I, I, I, I, I, I, I, I, I, O, O, O, O },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, I, I, O, O, O, O },
+ { O, O, O, O, O, O, O, O, O, O, O, O, O, I, I }
+ },
+ {
+ { O, O, O, O, O, O, O, O, O, O, O, O, O, O, O },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, O },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, O },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, X },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, O },
+ { O, I, I, I, I, I, I, I, I, I, I, I, I, I, O },
+ { O, O, O, O, O, O, O, O, O, O, O, O, O, O, O }
+ }
+ };
+
+ return RailwayUtils.transpose(engine);
+ }
+
+ /**
+ * Create the base of a wagon, with an iron base and wheels.
+ *
+ * @return The requested layer.
+ */
+ private BasicBlock[][][] createWagonBase() {
+ BasicBlock O = RailwayBlocks.RAIL_IRON;
+ BasicBlock X = RailwayBlocks.EMPTY_BLOCK;
+
+ BasicBlock[][][] base = new BasicBlock[][][] {
+ {
+ { X, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, X },
+ { X, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, X },
+ { X, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, X },
+ { X, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O },
+ { O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, X },
+ { X, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O },
+ { X, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, X },
+ { X, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, X },
+ { X, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, X }
+ },
+ {
+ { X, X, O, O, X, X, X, X, X, X, X, X, X, O, O, X, X },
+ { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X },
+ { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X },
+ { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X },
+ { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X },
+ { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X },
+ { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X },
+ { X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X },
+ { X, X, O, O, X, X, X, X, X, X, X, X, X, O, O, X, X }
+
+ }
+ };
+
+ return RailwayUtils.transpose(base);
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayFloor.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayFloor.java
new file mode 100644
index 00000000..4c5fab41
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayFloor.java
@@ -0,0 +1,144 @@
+package codemetropolis.toolchain.rendering.model.building.theme.railway;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.model.primitive.WallSign;
+import codemetropolis.toolchain.rendering.util.Character;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Floor} subclass for the {@link Themes#RAILWAY} theme. Floors are represented as railway wagons.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class RailwayFloor extends Floor {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which floor type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public RailwayFloor(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * Floors are represented as railway wagons.
+ */
+ @Override
+ protected void prepareWalls() {
+ BasicBlock wall = innerBuildable.hasAttribute("character")
+ ? Character.parse(innerBuildable.getAttributeValue("character")).getBlock()
+ : RailwayBlocks.WAGON_WALL;
+ BasicBlock pillar = innerBuildable.hasAttribute("external_character")
+ ? Character.parse(innerBuildable.getAttributeValue("external_character")).getBlock()
+ : RailwayBlocks.WAGON_PILLARS[0];
+
+ primitives.add(
+ new SimpleBox(
+ position,
+ new Point(size.getX() + 2, 2, size.getZ()),
+ new RepeationPattern(RailwayUtils.createWagonBase(2, size.getZ(), size.getX() + 2)),
+ Orientation.NearY));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(1, 2, 0)),
+ new Point(size.getX(), 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { pillar } } }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(1, 3, 0)),
+ new Point(size.getX(), size.getY() - 5, size.getZ()),
+ new RepeationPattern(createSection(pillar, wall)),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(1, size.getY() - 2, 0)),
+ new Point(size.getX(), 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { pillar } } }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(1, size.getY() - 1, 1)),
+ new Point(size.getX(), 1, size.getZ() - 2),
+ new RepeationPattern(new BasicBlock[][][] { { { pillar } } }),
+ Orientation.NearX));
+ }
+
+ /**
+ * According to {@link Themes#RAILWAY} theme there are no stairs.
+ */
+ @Override
+ protected void prepareStairs() {}
+
+ /**
+ * According to {@link Themes#RAILWAY} theme there are no doors.
+ */
+ @Override
+ protected void prepareDoor() {}
+
+ /**
+ * In {@link Themes#RAILWAY} theme signs are represented on the walls, same as in the original {@link Floor}.
+ */
+ @Override
+ protected void prepareSigns() {
+ primitives.add(new WallSign(position.getX() + size.getX() / 2, position.getY() + 4, position.getZ() - 1,
+ WallSign.Orientation.NORTH, innerBuildable.getName()));
+ primitives.add(new WallSign(position.getX() + size.getX() / 2, position.getY() + 4,
+ position.getZ() + size.getZ(), WallSign.Orientation.SOUTH, innerBuildable.getName()));
+ }
+
+ /**
+ * According to {@link Themes#RAILWAY} theme there are no torches.
+ */
+ @Override
+ protected void prepareTorches() {}
+
+ /**
+ * Create a middle layer of the current wagon according to the type.
+ *
+ * @param type The type of the used blocks.
+ * @return The requested layer.
+ */
+ private BasicBlock[][][] createSection(BasicBlock pillar, BasicBlock wall) {
+ BasicBlock[][][] section = new BasicBlock[size.getX()][1][size.getZ()];
+
+ // Initialize the matrix
+ for (int i = 0; i < size.getX(); i++) {
+ for (int j = 0; j < size.getZ(); j++) {
+ section[i][0][j] = RailwayBlocks.EMPTY_BLOCK;
+ }
+ }
+
+ // Add walls
+ for (int i = 0; i < size.getX(); i++) {
+ section[i][0][0] = wall;
+ section[i][0][size.getZ() - 1] = wall;
+ }
+ for (int j = 0; j < size.getZ(); j++) {
+ section[0][0][j] = wall;
+ section[size.getX() - 1][0][j] = wall;
+ }
+
+ // Add pillars to the corners
+ section[0][0][0] = pillar;
+ section[0][0][size.getZ() - 1] = pillar;
+ section[size.getX() - 1][0][0] = pillar;
+ section[size.getX() - 1][0][size.getZ() - 1] = pillar;
+
+ return section;
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayGarden.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayGarden.java
new file mode 100644
index 00000000..43546276
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayGarden.java
@@ -0,0 +1,110 @@
+package codemetropolis.toolchain.rendering.model.building.theme.railway;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Garden;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.pattern.YSplitPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SignPost;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Garden} subclass for the {@link Themes#RAILWAY} theme. Instead of a garden it creates a rail for the trains.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class RailwayGarden extends Garden {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which garden type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public RailwayGarden(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * Instead of a garden it creates a rail for the trains.
+ */
+ @Override
+ protected void prepareBase() {
+ BasicBlock[][][] rail = new BasicBlock[1][1][size.getZ()];
+ BasicBlock[][][] railBase = new BasicBlock[3][1][size.getZ()];
+
+ for (int i = 0; i < size.getZ(); i++) {
+ railBase[0][0][i] = RailwayBlocks.RAIL_DIRT;
+ railBase[1][0][i] = RailwayBlocks.RAIL_WOOD;
+ railBase[2][0][i] = RailwayBlocks.RAIL_DIRT;
+ rail[0][0][i] = RailwayBlocks.EMPTY_BLOCK;
+ }
+
+ rail[0][0][1] = RailwayBlocks.RAIL_IRON;
+ rail[0][0][size.getZ() - 2] = RailwayBlocks.RAIL_IRON;
+
+ primitives.add(
+ new SimpleBox(
+ position, new Point(size.getX(), 2, size.getZ()),
+ new YSplitPattern(
+ 0,
+ new RepeationPattern(railBase),
+ new RepeationPattern(rail)),
+ Orientation.NearX));
+ }
+
+ /**
+ * Representing doors as bumpers.
+ */
+ @Override
+ protected void prepareDoor() {
+ BasicBlock E = RailwayBlocks.EMPTY_BLOCK;
+ BasicBlock I = RailwayBlocks.RAIL_IRON;
+ BasicBlock D = RailwayBlocks.RAIL_DIRT;
+ BasicBlock W = RailwayBlocks.RAIL_WOOD;
+
+ BasicBlock[][][] bumper = new BasicBlock[][][] {
+ {
+ { I, E },
+ { E, E },
+ { I, E }
+ },
+ {
+ { I, I },
+ { E, I },
+ { I, I }
+ },
+ {
+ { E, I },
+ { E, E },
+ { E, I }
+ },
+ {
+ { W, I },
+ { W, D },
+ { W, I }
+ }
+ };
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, 0, (size.getZ() - 3) / 2)),
+ new Point(2, 4, 3),
+ new RepeationPattern(RailwayUtils.transpose(bumper)),
+ Orientation.NearY));
+ }
+
+ /**
+ * In {@link Themes#RAILWAY} theme signs are oriented the same way in a default {@link Garden}.
+ */
+ @Override
+ protected void prepareSigns() {
+ primitives.add(new SignPost(position.getX(), position.getY() + 3, position.getZ() + size.getZ() / 2,
+ SignPost.Orientation.WEST, innerBuildable.getName()));
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayGround.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayGround.java
new file mode 100644
index 00000000..31afbdd7
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayGround.java
@@ -0,0 +1,68 @@
+package codemetropolis.toolchain.rendering.model.building.theme.railway;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Ground;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SignPost;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Ground} subclass for the {@link Themes#RAILWAY} theme. Representing grounds as gates in front of the
+ * gardens.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class RailwayGround extends Ground {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which ground type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public RailwayGround(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * Creates a gate as a representation of packages.
+ */
+ @Override
+ protected void prepareBase() {
+ BasicBlock[][][] section = new BasicBlock[1][1][size.getZ()];
+ for (int i = 0; i < size.getZ(); i++) {
+ section[0][0][i] = RailwayBlocks.EMPTY_BLOCK;
+ }
+ section[0][0][0] = RailwayBlocks.GATE;
+ section[0][0][size.getZ() - 1] = RailwayBlocks.GATE;
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, size.getY(), 0)),
+ new Point(1, 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { RailwayBlocks.GATE } } }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position,
+ new Point(1, size.getY(), size.getZ()),
+ new RepeationPattern(section),
+ Orientation.NearX));
+ }
+
+ /**
+ * Signs are on the top of the gates.
+ */
+ @Override
+ protected void prepareSigns() {
+ primitives.add(new SignPost(position.getX(), position.getY() + size.getY() + 1,
+ position.getZ() + size.getZ() / 2, SignPost.Orientation.WEST, innerBuildable.getName()));
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayUtils.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayUtils.java
new file mode 100644
index 00000000..9c102b6e
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/railway/RailwayUtils.java
@@ -0,0 +1,69 @@
+package codemetropolis.toolchain.rendering.model.building.theme.railway;
+
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * Some frequently used functions for Railway theme. So source code is clearer.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class RailwayUtils {
+
+ /**
+ * Transpose matrices which can't be handled by {@link Orientation}.
+ *
+ * @param blocks The blocks which have to be transposed.
+ * @return The transposed matrix.
+ */
+ public static BasicBlock[][][] transpose(BasicBlock[][][] blocks) {
+ int xLength = blocks.length;
+ int yLength = blocks[0][0].length;
+ int zLength = blocks[0].length;
+
+ BasicBlock[][][] transpose = new BasicBlock[xLength][yLength][zLength];
+
+ for (int x = 0; x < yLength; x++) {
+ for (int y = 0; y < zLength; y++) {
+ for (int z = 0; z < xLength; z++) {
+ transpose[z][x][y] = blocks[z][y][x];
+ }
+ }
+ }
+
+ return transpose;
+ }
+
+ /**
+ * Create the base of a wagon, with an iron base and wheels.
+ *
+ * @return The requested layer.
+ */
+ public static BasicBlock[][][] createWagonBase(int sizeX, int sizeY, int sizeZ) {
+ BasicBlock[][][] base = new BasicBlock[sizeX][sizeY][sizeZ];
+
+ for (int k = 0; k < sizeX; k++) {
+ for (int j = 0; j < sizeY; j++) {
+ for (int i = 0; i < sizeZ; i++) {
+ base[1][j][i] = RailwayBlocks.EMPTY_BLOCK;
+ base[0][j][i] = RailwayBlocks.RAIL_IRON;
+ }
+ }
+ }
+
+ for (int i = 0; i < sizeY; i++) {
+ base[0][i][0] = RailwayBlocks.EMPTY_BLOCK;
+ base[0][i][sizeZ - 1] = RailwayBlocks.EMPTY_BLOCK;
+ }
+
+ base[0][sizeY / 2][0] = RailwayBlocks.RAIL_IRON;
+ base[0][sizeY / 2][sizeZ - 1] = RailwayBlocks.RAIL_IRON;
+ base[1][0][2] = RailwayBlocks.RAIL_IRON;
+ base[1][sizeY - 1][2] = RailwayBlocks.RAIL_IRON;
+ base[1][0][sizeZ - 3] = RailwayBlocks.RAIL_IRON;
+ base[1][sizeY - 1][sizeZ - 3] = RailwayBlocks.RAIL_IRON;
+
+ return RailwayUtils.transpose(base);
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownBlocks.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownBlocks.java
new file mode 100644
index 00000000..1543ab38
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownBlocks.java
@@ -0,0 +1,31 @@
+package codemetropolis.toolchain.rendering.model.building.theme.town;
+
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+
+/**
+ * Collection of the used blocks in the {@link Themes#TOWN} theme.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class TownBlocks {
+
+ public final static BasicBlock FENCE = new BasicBlock((short) 18);
+ public final static BasicBlock EMPTY_BLOCK = BasicBlock.NonBlock;
+ public final static BasicBlock CELLAR_WALL = new BasicBlock((short) 45);
+ public final static BasicBlock ROOF = new BasicBlock((short) 112);
+ public final static BasicBlock ROOF_LEFT = new BasicBlock("minecraft:nether_brick_stairs", 2);
+ public final static BasicBlock ROOF_RIGHT = new BasicBlock("minecraft:nether_brick_stairs", 3);
+ public final static BasicBlock WINDOW = new BasicBlock((short) 95);
+ public final static BasicBlock CELLAR_DOOR = new BasicBlock((short) 42);
+ public final static BasicBlock PATH = new BasicBlock((short) 208);
+ public final static BasicBlock ROAD = new BasicBlock("minecraft:stone", 6);
+ public final static BasicBlock[] WALLS = {
+ new BasicBlock("minecraft:wool", 4),
+ new BasicBlock("minecraft:wool", 8),
+ new BasicBlock("minecraft:wool", 1),
+ new BasicBlock("minecraft:wool"),
+ new BasicBlock("minecraft:wool", 6)
+ };
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownCellar.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownCellar.java
new file mode 100644
index 00000000..7e80ae3c
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownCellar.java
@@ -0,0 +1,109 @@
+package codemetropolis.toolchain.rendering.model.building.theme.town;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Cellar;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.model.primitive.WallSign;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Cellar} subclass for the {@link Themes#TOWN} theme. Repeating {@link Floor} downwards.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class TownCellar extends Cellar {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which cellar type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public TownCellar(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * A simple wall.
+ */
+ @Override
+ protected void prepareWalls() {
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, 1, 0)),
+ new Point(size.getX(), 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.CELLAR_WALL } } }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, 1, 0)),
+ new Point(1, size.getY() - 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.CELLAR_WALL } } }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(size.getX() -1, 1, 0)),
+ new Point(1, size.getY() - 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.CELLAR_WALL } } }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, size.getY(), 0)),
+ new Point(size.getX(), 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.CELLAR_WALL } } }),
+ Orientation.NearX));
+ }
+
+ /**
+ * According to {@link Themes#TOWN} theme there are no stairs in a garage.
+ */
+ @Override
+ protected void prepareStairs() {}
+
+ /**
+ * Doors are only on opposite sides of the garage in {@link Themes#TOWN}.
+ */
+ @Override
+ protected void prepareDoor() {
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(1, 1, 0)),
+ new Point(size.getX() - 2, size.getY() - 1, 1),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.CELLAR_DOOR } } }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(1, 1, size.getZ() - 1)),
+ new Point(size.getX() - 2, size.getY() - 1, 1),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.CELLAR_DOOR } } }),
+ Orientation.NearX));
+ }
+
+ /**
+ * There are two signs on the building in {@link Themes#TOWN}.
+ */
+ @Override
+ protected void prepareSigns() {
+ primitives.add(new WallSign(position.getX() + size.getX() / 2, position.getY() + size.getY(),
+ position.getZ() - 1, WallSign.Orientation.NORTH, innerBuildable.getName()));
+ primitives.add(new WallSign(position.getX() + size.getX() / 2, position.getY() + size.getY(),
+ position.getZ() + size.getZ(), WallSign.Orientation.SOUTH, innerBuildable.getName()));
+ }
+
+ /**
+ * According to {@link Themes#TOWN} theme there are no torches in a garage.
+ */
+ @Override
+ protected void prepareTorches() {}
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownDecorationFloor.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownDecorationFloor.java
new file mode 100644
index 00000000..d1865c6f
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownDecorationFloor.java
@@ -0,0 +1,93 @@
+package codemetropolis.toolchain.rendering.model.building.theme.town;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.DecorationFloor;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.util.Character;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link DecorationFloor} subclass for the {@link Themes#TOWN} theme. Closing the top of the building with a
+ * horizontal layer, then a nice, classical, red roof.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class TownDecorationFloor extends DecorationFloor {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which decoration floor type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public TownDecorationFloor(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * Closing the top of the building with only a horizontal layer.
+ */
+ @Override
+ protected void prepareCeiling() {
+ BasicBlock houseBlock = innerBuildable.hasAttribute("external_character")
+ ? Character.parse(innerBuildable.getAttributeValue("external_character")).getBlock()
+ : TownBlocks.ROOF;
+
+ primitives.add(
+ new SimpleBox(
+ position,
+ new Point(size.getX(), 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { houseBlock } } }),
+ Orientation.NearY));
+ }
+
+ /**
+ * According to {@link Themes#TOWN} theme on the top there is a classical, red roof.
+ */
+ @Override
+ protected void prepareRoof() {
+ BasicBlock houseBlock = innerBuildable.hasAttribute("external_character")
+ ? Character.parse(innerBuildable.getAttributeValue("external_character")).getBlock()
+ : TownBlocks.ROOF;
+
+ for (int i = 0; i < (size.getZ() + 1) / 2; i++) {
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, i, i)),
+ new Point(size.getX(), 1, size.getZ() - (i * 2)),
+ new RepeationPattern(new BasicBlock[][][] { { { houseBlock } } }),
+ Orientation.NearX));
+ }
+
+ for (int i = 0; i < ((size.getZ() + 1) / 2) + 1; i++) {
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(-1, i, i - 1)),
+ new Point(size.getX() + 2, 1, 1),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.ROOF_LEFT } } }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(-1, i, size.getZ() - i)),
+ new Point(size.getX() + 2, 1, 1),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.ROOF_RIGHT } } }),
+ Orientation.NearX));
+ }
+
+ if (size.getZ() % 2 != 0) {
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(-1, (size.getZ() / 2) + 1, size.getZ() / 2)),
+ new Point(size.getX() + 2, 1, 1),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.ROOF } } }),
+ Orientation.NearX));
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownFloor.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownFloor.java
new file mode 100644
index 00000000..ec5e511a
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownFloor.java
@@ -0,0 +1,146 @@
+package codemetropolis.toolchain.rendering.model.building.theme.town;
+
+import java.util.Random;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.Door;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.model.primitive.SolidBox;
+import codemetropolis.toolchain.rendering.model.primitive.WallSign;
+import codemetropolis.toolchain.rendering.util.Character;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Floor} subclass for the {@link Themes#TOWN} theme. Nice, little houses, with windows and doors.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class TownFloor extends Floor {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which floor type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public TownFloor(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * Positioning and scaling windows.
+ */
+ private void prepareWindows() {
+ int sizeRow = 2;
+ int sizeLine = 4;
+
+ for (int i = 1; i <= (size.getY() + 1) / 5; i++) {
+ for (int j = 1; j <= size.getX() / 3; j++) {
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(j + (j - 1) * sizeRow, i + (i - 1) * sizeLine + 1, 0)),
+ new Point(1, 2, 1),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.WINDOW } } }),
+ Orientation.NearX));
+ primitives.add(
+ new SimpleBox(
+ position
+ .translate(new Point(j + (j - 1) * sizeRow, i + (i - 1) * sizeLine + 1, size.getZ() - 1)),
+ new Point(1, 2, 1),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.WINDOW } } }),
+ Orientation.NearX));
+ }
+ for (int j = 1; j <= size.getZ() / 3; j++) {
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, i + (i - 1) * sizeLine + 1, j + (j - 1) * sizeRow)),
+ new Point(1, 2, 1),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.WINDOW } } }),
+ Orientation.NearX));
+ primitives.add(
+ new SimpleBox(
+ position
+ .translate(new Point(size.getX() - 1, i + (i - 1) * sizeLine + 1, j + (j - 1) * sizeRow)),
+ new Point(1, 2, 1),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.WINDOW } } }),
+ Orientation.NearX));
+ }
+ }
+ }
+
+ /**
+ * Less doors are created, so the house looks more realistic. In this functions windows are also created.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ protected void prepareDoor() {
+ prepareWindows();
+
+ // Prepare doors
+ primitives.add(
+ new Door(position.getX() + size.getX() / 2, position.getY() + 1, position.getZ(), Door.Orientation.SOUTH));
+ primitives.add(new Door(position.getX() + size.getX() / 2, position.getY() + 1,
+ position.getZ() + size.getZ() - 1, Door.Orientation.NORTH));
+ }
+
+ /**
+ * There is no need for stairs in a one floor house.
+ */
+ @Override
+ protected void prepareStairs() {}
+
+ /**
+ * Creates a simple wall of wool.
+ */
+ @Override
+ protected void prepareWalls() {
+ BasicBlock block = innerBuildable.hasAttribute("external_character")
+ ? Character.parse(innerBuildable.getAttributeValue("external_character")).getBlock()
+ : TownBlocks.WALLS[new Random().nextInt(TownBlocks.WALLS.length)];
+
+ RepeationPattern wall = new RepeationPattern(new BasicBlock[][][] { { { block } } });
+
+ primitives.add(
+ new SimpleBox(
+ position,
+ new Point(size.getX(), 1, size.getZ()),
+ wall,
+ Orientation.NearX));
+
+ for (int i = 0; i < size.getY() - 2; i++) {
+ primitives.add(
+ new SolidBox(
+ position.translate(new Point(0, i + 1, 0)),
+ new Point(size.getX(), 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.EMPTY_BLOCK } } }),
+ wall,
+ Orientation.NearX));
+ }
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, size.getY() - 1, 0)),
+ new Point(size.getX(), 1, size.getZ()),
+ wall,
+ Orientation.NearX));
+ }
+
+ /**
+ * Only one sign above every each door.
+ */
+ @Override
+ protected void prepareSigns() {
+ primitives.add(new WallSign(position.getX() + size.getX() / 2, position.getY() + 3, position.getZ() - 1,
+ WallSign.Orientation.NORTH, innerBuildable.getName()));
+ primitives.add(new WallSign(position.getX() + size.getX() / 2, position.getY() + 3,
+ position.getZ() + size.getZ(), WallSign.Orientation.SOUTH, innerBuildable.getName()));
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownGarden.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownGarden.java
new file mode 100644
index 00000000..7771b651
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownGarden.java
@@ -0,0 +1,120 @@
+package codemetropolis.toolchain.rendering.model.building.theme.town;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Garden;
+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.SimpleBox;
+import codemetropolis.toolchain.rendering.model.primitive.SolidBox;
+import codemetropolis.toolchain.rendering.model.primitive.WallSign;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Garden} subclass for the {@link Themes#TOWN} theme. A nice garden with flowers and trees, surrounded by a
+ * hedge.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class TownGarden extends Garden {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which garden type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public TownGarden(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * A nice garden with flowers and trees. It's the same as the {@link Garden}'s appearance.
+ */
+ @Override
+ protected void prepareBase() {
+ RandomPattern _flowers = new RandomPattern(
+ new RepeationPattern(new BasicBlock[][][] { { { BasicBlock.NonBlock } } }));
+
+ RandomPattern _redOrYellow = new RandomPattern(
+ new RepeationPattern(new BasicBlock[][][] { { { new BasicBlock("minecraft:yellow_flower") } } }));
+ _redOrYellow.add(new RepeationPattern(new BasicBlock[][][] { { { new BasicBlock("minecraft:red_flower") } } }),
+ 0.5);
+
+ _flowers.add(
+ _redOrYellow,
+ innerBuildable.hasAttribute("flower-ratio")
+ ? Double.parseDouble(innerBuildable.getAttributeValue("flower-ratio"))
+ : 0);
+ _flowers.add(
+ new RepeationPattern(new BasicBlock[][][] { { { new BasicBlock("minecraft:brown_mushroom") } } }),
+ innerBuildable.hasAttribute("mushroom-ratio")
+ ? Double.parseDouble(innerBuildable.getAttributeValue("mushroom-ratio"))
+ : 0);
+ _flowers.add(
+ new RepeationPattern(new BasicBlock[][][] { { { new BasicBlock("minecraft:sapling") } } }),
+ innerBuildable.hasAttribute("tree-ratio")
+ ? Double.parseDouble(innerBuildable.getAttributeValue("tree-ratio"))
+ : 0);
+
+ primitives.add(
+ new SolidBox(
+ position,
+ new Point(size.getX(), 2, size.getZ()),
+ new YSplitPattern(
+ 0,
+ new RepeationPattern(new BasicBlock[][][] { { { new BasicBlock("minecraft:grass") } } }),
+ _flowers),
+ new RepeationPattern(
+ new BasicBlock[][][] {
+ {
+ { TownBlocks.FENCE },
+ { new BasicBlock("minecraft:grass") }
+ }
+ }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SolidBox(
+ position.translate(new Point(0, 2, 0)), new Point(size.getX(), 1, size.getZ()),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.EMPTY_BLOCK } } }),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.FENCE } } }), Orientation.NearX));
+ }
+
+ /**
+ * According to {@link Themes#TOWN} theme there are no doors, just spaces in the hedge.
+ */
+ @Override
+ protected void prepareDoor() {
+ RepeationPattern space = new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.EMPTY_BLOCK } } });
+
+ primitives.add(new SimpleBox(position.translate(new Point(center.getX(), 1, 0)), new Point(1, 2, 1), space,
+ Orientation.NearX));
+ primitives.add(new SimpleBox(position.translate(new Point(center.getX(), 1, size.getZ() - 1)),
+ new Point(1, 2, 1), space, Orientation.NearX));
+ primitives.add(new SimpleBox(position.translate(new Point(0, 1, center.getZ())), new Point(1, 2, 1), space,
+ Orientation.NearX));
+ primitives.add(new SimpleBox(position.translate(new Point(size.getX() - 1, 1, center.getZ())),
+ new Point(1, 2, 1), space, Orientation.NearX));
+ }
+
+ /**
+ * Signs are added on the side of the hedge like street signs.
+ */
+ @Override
+ protected void prepareSigns() {
+ primitives.add(new WallSign(position.getX(), position.getY() + 2, position.getZ() - 1,
+ WallSign.Orientation.NORTH, innerBuildable.getName()));
+ primitives.add(new WallSign(position.getX() + size.getX() - 1, position.getY() + 2, position.getZ() - 1,
+ WallSign.Orientation.NORTH, innerBuildable.getName()));
+ primitives.add(new WallSign(position.getX(), position.getY() + 2, position.getZ() + size.getZ(),
+ WallSign.Orientation.SOUTH, innerBuildable.getName()));
+ primitives.add(new WallSign(position.getX() + size.getX() - 1, position.getY() + 2,
+ position.getZ() + size.getZ(), WallSign.Orientation.SOUTH, innerBuildable.getName()));
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownGround.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownGround.java
new file mode 100644
index 00000000..042d89a2
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/building/theme/town/TownGround.java
@@ -0,0 +1,79 @@
+package codemetropolis.toolchain.rendering.model.building.theme.town;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Ground;
+import codemetropolis.toolchain.rendering.model.pattern.RepeationPattern;
+import codemetropolis.toolchain.rendering.model.primitive.SignPost;
+import codemetropolis.toolchain.rendering.model.primitive.SimpleBox;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A {@link Ground} subclass for the {@link Themes#TOWN} theme. Creates a simple base for the buildings, using a simple
+ * block type.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class TownGround extends Ground {
+
+ /**
+ * Runs all the parent's functions.
+ *
+ * @param innerBuildable The buildable of which floor type is created.
+ * @throws BuildingTypeMismatchException Throws exception if type of {@code innerBuildable} is incorrect.
+ */
+ public TownGround(Buildable innerBuildable) throws BuildingTypeMismatchException {
+ super(innerBuildable);
+ }
+
+ /**
+ * Pattern is determined depending on which side of the street we're building.
+ */
+ @Override
+ protected void prepareBase() {
+ primitives.add(
+ new SimpleBox(
+ position,
+ new Point(size.getX(), 1, 2),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.PATH } } }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, 0, 2)),
+ new Point(size.getX(), 1, 6),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.ROAD } } }),
+ Orientation.NearX));
+
+ primitives.add(
+ new SimpleBox(
+ position.translate(new Point(0, 0, 8)),
+ new Point(size.getX(), 1, 2),
+ new RepeationPattern(new BasicBlock[][][] { { { TownBlocks.PATH } } }),
+ Orientation.NearX));
+ }
+
+ /**
+ * Signs are oriented along the sides of the road, facing the road.
+ */
+ @Override
+ protected void prepareSigns() {
+ if (innerBuildable.hasAttribute("left") && innerBuildable.getAttributeValue("left").equals("true")) {
+ // left side
+ primitives.add(new SignPost(position.getX(), position.getY() + 1, position.getZ() + 1,
+ SignPost.Orientation.SOUTH, innerBuildable.getName()));
+ primitives.add(new SignPost(position.getX() + size.getX() - 5, position.getY() + 1, position.getZ() + 1,
+ SignPost.Orientation.SOUTH, innerBuildable.getName()));
+ } else {
+ // right side
+ primitives.add(new SignPost(position.getX(), position.getY() + 1, position.getZ() + size.getZ() - 2,
+ SignPost.Orientation.NORTH, innerBuildable.getName()));
+ primitives.add(new SignPost(position.getX() + size.getX() - 5, position.getY() + 1,
+ position.getZ() + size.getZ() - 2, SignPost.Orientation.NORTH, innerBuildable.getName()));
+ }
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/SimpleBox.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/SimpleBox.java
new file mode 100644
index 00000000..9b7fcf93
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/SimpleBox.java
@@ -0,0 +1,42 @@
+package codemetropolis.toolchain.rendering.model.primitive;
+
+import java.io.File;
+
+import codemetropolis.toolchain.commons.cmxml.Point;
+import codemetropolis.toolchain.rendering.model.BasicBlock;
+import codemetropolis.toolchain.rendering.model.pattern.Pattern;
+import codemetropolis.toolchain.rendering.util.Orientation;
+
+/**
+ * A simpler version of {@link SolidBox}. It gets rid of the unnecessary stroke.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class SimpleBox extends SolidBox {
+
+ public SimpleBox(Point basePoint, Point size, Pattern fill, Orientation orientation) {
+ super(basePoint, size, fill, null, orientation);
+ }
+
+ /**
+ * Same as the one in {@link SolidBox}, just without stroke.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public int toCSVFile(File directory) {
+ for (int x = 0; x < size.getX(); x++) {
+ for (int y = 0; y < size.getY(); y++) {
+ for (int z = 0; z < size.getZ(); z++) {
+ new Boxel(
+ new BasicBlock(fill.applyTo(new Point(x, y, z), this::flipPattern)),
+ new Point(basePoint.getX() + x, basePoint.getY() + y, basePoint.getZ() + z))
+ .toCSVFile(directory);
+ }
+ }
+ }
+
+ return getNumberOfBlocks();
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/SolidBox.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/SolidBox.java
index 46729449..102d75c9 100644
--- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/SolidBox.java
+++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/SolidBox.java
@@ -21,7 +21,7 @@ public SolidBox(Point basePoint, Point size, Pattern fill, Pattern stroke, Orien
this.orientation = orientation;
}
- private Point flipPattern(Point original, Point size) {
+ protected Point flipPattern(Point original, Point size) {
switch ( orientation ) {
case NearX:
return original;
diff --git a/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/CellarFactoryTest.java b/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/CellarFactoryTest.java
new file mode 100644
index 00000000..60e67d4a
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/CellarFactoryTest.java
@@ -0,0 +1,270 @@
+package codemetropolis.toolchain.rendering.model.building.factory;
+
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Cellar;
+import codemetropolis.toolchain.rendering.model.building.DecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.building.Garden;
+import codemetropolis.toolchain.rendering.model.building.Ground;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGround;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGround;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGround;
+
+/**
+ * Test class for {@link CellarFactory} for properly handling {@link Buildable.Type} and {@link Themes}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class CellarFactoryTest {
+
+ private Buildable decorationBuildable;
+ private Buildable floorBuildable;
+ private Buildable cellarBuildable;
+ private Buildable gardenBuildable;
+ private Buildable groundBuildable;
+
+ /**
+ * Initializes the buildables used in the tests.
+ */
+ @Before
+ public void init() {
+ decorationBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.DECORATION_FLOOR);
+ floorBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.FLOOR);
+ cellarBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.CELLAR);
+ gardenBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.GARDEN);
+ groundBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.GROUND);
+ }
+
+ /**
+ * Checks if {@link Cellar} was created properly.
+ */
+ @Test
+ public void testCreateBasicCellar() {
+ try {
+ Cellar cellar = CellarFactory.createCellar(cellarBuildable, Themes.BASIC);
+ Assert.assertEquals(cellar.getClass(), Cellar.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link MinimalistCellar} was created properly.
+ */
+ @Test
+ public void testCreateMinimalistCellar() {
+ try {
+ Cellar cellar = CellarFactory.createCellar(cellarBuildable, Themes.MINIMALIST);
+ Assert.assertEquals(cellar.getClass(), MinimalistCellar.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@linkRailwayCellar} was created properly.
+ */
+ @Test
+ public void testCreateRailwayCellar() {
+ try {
+ Cellar cellar = CellarFactory.createCellar(cellarBuildable, Themes.RAILWAY);
+ Assert.assertEquals(cellar.getClass(), RailwayCellar.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@linkTownCellar} was created properly.
+ */
+ @Test
+ public void testCreateTownCellar() {
+ try {
+ Cellar cellar = CellarFactory.createCellar(cellarBuildable, Themes.TOWN);
+ Assert.assertEquals(cellar.getClass(), TownCellar.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link Floor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicFloorAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(floorBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistFloorAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(floorBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayFloorAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(floorBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownFloorAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(floorBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link DecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicDecorationFloorAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(decorationBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistDecorationFloorAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(decorationBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayDecorationFloorAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(decorationBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownDecorationFloorAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(decorationBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Garden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicGardenAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(gardenBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistGardenAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(gardenBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayGardenAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(gardenBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownGardenAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(gardenBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Ground} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicGroundAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(groundBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistGroundAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(groundBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayGroundAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(groundBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a cellar of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownGroundAsCellar() throws BuildingTypeMismatchException {
+ CellarFactory.createCellar(groundBuildable, Themes.TOWN);
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/DecorationFloorFactoryTest.java b/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/DecorationFloorFactoryTest.java
new file mode 100644
index 00000000..771927b3
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/DecorationFloorFactoryTest.java
@@ -0,0 +1,271 @@
+package codemetropolis.toolchain.rendering.model.building.factory;
+
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Cellar;
+import codemetropolis.toolchain.rendering.model.building.DecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.building.Garden;
+import codemetropolis.toolchain.rendering.model.building.Ground;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGround;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGround;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGround;
+
+/**
+ * Test class for {@link DecorationFactory} for properly handling {@link Buildable.Type} and {@link Themes}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class DecorationFloorFactoryTest {
+
+ private Buildable decorationBuildable;
+ private Buildable floorBuildable;
+ private Buildable cellarBuildable;
+ private Buildable gardenBuildable;
+ private Buildable groundBuildable;
+
+ /**
+ * Initializes the buildables used in the tests.
+ */
+ @Before
+ public void init() {
+ decorationBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.DECORATION_FLOOR);
+ floorBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.FLOOR);
+ cellarBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.CELLAR);
+ gardenBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.GARDEN);
+ groundBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.GROUND);
+ }
+
+ /**
+ * Checks if {@link DecorationFloor} was created properly.
+ */
+ @Test
+ public void testCreateBasicDecorationFloor() {
+ try {
+ DecorationFloor floor = DecorationFloorFactory.createDecorationFloor(decorationBuildable, Themes.BASIC);
+ Assert.assertEquals(floor.getClass(), DecorationFloor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link MinimalistDecorationFloor} was created properly.
+ */
+ @Test
+ public void testCreateMinimalistDecorationFloor() {
+ try {
+ DecorationFloor floor = DecorationFloorFactory.createDecorationFloor(decorationBuildable,
+ Themes.MINIMALIST);
+ Assert.assertEquals(floor.getClass(), MinimalistDecorationFloor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@linkRailwayDecorationFloor} was created properly.
+ */
+ @Test
+ public void testCreateRailwayDecorationFloor() {
+ try {
+ DecorationFloor floor = DecorationFloorFactory.createDecorationFloor(decorationBuildable, Themes.RAILWAY);
+ Assert.assertEquals(floor.getClass(), RailwayDecorationFloor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@linkTownDecorationFloor} was created properly.
+ */
+ @Test
+ public void testCreateTownDecorationFloor() {
+ try {
+ DecorationFloor floor = DecorationFloorFactory.createDecorationFloor(decorationBuildable, Themes.TOWN);
+ Assert.assertEquals(floor.getClass(), TownDecorationFloor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link Cellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicCellarAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(cellarBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistCellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistCellarAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(cellarBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayCellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayCellarAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(cellarBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownCellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownCellarAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(cellarBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Floor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicFloorAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(floorBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistFloorAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(floorBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayFloorAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(floorBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownFloorAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(floorBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Garden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicGardenAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(gardenBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistGardenAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(gardenBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayGardenAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(gardenBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownGardenAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(gardenBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Ground} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicGroundAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(groundBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistGroundAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(groundBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayGroundAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(groundBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a decorationFloor of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownGroundAsDecorationFloor() throws BuildingTypeMismatchException {
+ DecorationFloorFactory.createDecorationFloor(groundBuildable, Themes.TOWN);
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/FloorFactoryTest.java b/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/FloorFactoryTest.java
new file mode 100644
index 00000000..99d4a235
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/FloorFactoryTest.java
@@ -0,0 +1,280 @@
+package codemetropolis.toolchain.rendering.model.building.factory;
+
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Cellar;
+import codemetropolis.toolchain.rendering.model.building.DecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.building.Garden;
+import codemetropolis.toolchain.rendering.model.building.Ground;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGround;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGround;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGround;
+
+/**
+ * Test class for {@link FloorFactory} for properly handling {@link Buildable.Type} and {@link Themes}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class FloorFactoryTest {
+
+ private Buildable decorationBuildable;
+ private Buildable floorBuildable;
+ private Buildable cellarBuildable;
+ private Buildable gardenBuildable;
+ private Buildable groundBuildable;
+
+ /**
+ * Initializes the buildables used in the tests.
+ */
+ @Before
+ public void init() {
+ decorationBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.DECORATION_FLOOR);
+ floorBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.FLOOR);
+ cellarBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.CELLAR);
+ gardenBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.GARDEN);
+ groundBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.GROUND);
+ }
+
+ /**
+ * Checks if {@link Floor} was created properly.
+ */
+ @Test
+ public void testCreateBasicFloor() {
+ try {
+ Floor floor = FloorFactory.createFloor(floorBuildable, Themes.BASIC);
+ Assert.assertEquals(floor.getClass(), Floor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link MinimalistFloor} was created properly.
+ */
+ @Test
+ public void testCreateMinimalistFloor() {
+ try {
+ Floor floor = FloorFactory.createFloor(floorBuildable, Themes.MINIMALIST);
+ Assert.assertEquals(floor.getClass(), MinimalistFloor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@linkRailwayFloor} was created properly.
+ */
+ @Test
+ public void testCreateRailwayFloor() {
+ try {
+ Floor floor = FloorFactory.createFloor(floorBuildable, Themes.RAILWAY);
+ Assert.assertEquals(floor.getClass(), RailwayFloor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@linkTownFloor} was created properly.
+ */
+ @Test
+ public void testCreateTownFloor() {
+ try {
+ Floor floor = FloorFactory.createFloor(floorBuildable, Themes.TOWN);
+ Assert.assertEquals(floor.getClass(), TownFloor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link Cellar} was created properly.
+ */
+ @Test
+ public void testCreateBasicCellarAsFloor() throws BuildingTypeMismatchException {
+ try {
+ Floor floor = FloorFactory.createFloor(cellarBuildable, Themes.BASIC);
+ Assert.assertEquals(floor.getClass(), Floor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link MinimalistCellar} was created properly.
+ */
+ @Test
+ public void testCreateMinimalistCellarAsFloor() {
+ try {
+ Floor floor = FloorFactory.createFloor(cellarBuildable, Themes.MINIMALIST);
+ Assert.assertEquals(floor.getClass(), MinimalistFloor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link RailwayFloor} was created properly.
+ */
+ @Test
+ public void testCreateRailwayCellarAsFloor() {
+ try {
+ Floor floor = FloorFactory.createFloor(cellarBuildable, Themes.RAILWAY);
+ Assert.assertEquals(floor.getClass(), RailwayFloor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link TownFloor} was created properly.
+ */
+ @Test
+ public void testCreateTownCellarAsFloor() throws BuildingTypeMismatchException {
+ try {
+ Floor floor = FloorFactory.createFloor(cellarBuildable, Themes.TOWN);
+ Assert.assertEquals(floor.getClass(), TownFloor.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link DecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicDecorationFloorAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(decorationBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistDecorationFloorAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(decorationBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayDecorationFloorAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(decorationBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownDecorationFloorAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(decorationBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Garden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicGardenAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(gardenBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistGardenAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(gardenBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayGardenAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(gardenBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownGardenAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(gardenBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Ground} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicGroundAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(groundBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistGroundAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(groundBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayGroundAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(groundBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a floor of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownGroundAsFloor() throws BuildingTypeMismatchException {
+ FloorFactory.createFloor(groundBuildable, Themes.TOWN);
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/GardenFactoryTest.java b/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/GardenFactoryTest.java
new file mode 100644
index 00000000..f09c8d58
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/GardenFactoryTest.java
@@ -0,0 +1,270 @@
+package codemetropolis.toolchain.rendering.model.building.factory;
+
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Cellar;
+import codemetropolis.toolchain.rendering.model.building.DecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.building.Garden;
+import codemetropolis.toolchain.rendering.model.building.Ground;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGround;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGround;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGround;
+
+/**
+ * Test class for {@link GardenFactory} for properly handling {@link Buildable.Type} and {@link Themes}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class GardenFactoryTest {
+
+ private Buildable decorationBuildable;
+ private Buildable floorBuildable;
+ private Buildable cellarBuildable;
+ private Buildable gardenBuildable;
+ private Buildable groundBuildable;
+
+ /**
+ * Initializes the buildables used in the tests.
+ */
+ @Before
+ public void init() {
+ decorationBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.DECORATION_FLOOR);
+ floorBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.FLOOR);
+ cellarBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.CELLAR);
+ gardenBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.GARDEN);
+ groundBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.GROUND);
+ }
+
+ /**
+ * Checks if {@link Garden} was created properly.
+ */
+ @Test
+ public void testCreateBasicGarden() {
+ try {
+ Garden garden = GardenFactory.createGarden(gardenBuildable, Themes.BASIC);
+ Assert.assertEquals(garden.getClass(), Garden.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link MinimalistGarden} was created properly.
+ */
+ @Test
+ public void testCreateMinimalistGarden() {
+ try {
+ Garden garden = GardenFactory.createGarden(gardenBuildable, Themes.MINIMALIST);
+ Assert.assertEquals(garden.getClass(), MinimalistGarden.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@linkRailwayGarden} was created properly.
+ */
+ @Test
+ public void testCreateRailwayGarden() {
+ try {
+ Garden garden = GardenFactory.createGarden(gardenBuildable, Themes.RAILWAY);
+ Assert.assertEquals(garden.getClass(), RailwayGarden.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@linkTownGarden} was created properly.
+ */
+ @Test
+ public void testCreateTownGarden() {
+ try {
+ Garden garden = GardenFactory.createGarden(gardenBuildable, Themes.TOWN);
+ Assert.assertEquals(garden.getClass(), TownGarden.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link Cellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicCellarAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(cellarBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistCellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistCellarAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(cellarBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayCellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayCellarAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(cellarBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownCellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownCellarAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(cellarBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Floor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicFloorAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(floorBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistFloorAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(floorBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayFloorAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(floorBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownFloorAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(floorBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link DecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicDecorationFloorAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(decorationBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistDecorationFloorAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(decorationBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayDecorationFloorAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(decorationBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownDecorationFloorAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(decorationBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Ground} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicGroundAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(groundBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistGroundAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(groundBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayGroundAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(groundBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownGround} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a garden of ground.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownGroundAsGarden() throws BuildingTypeMismatchException {
+ GardenFactory.createGarden(groundBuildable, Themes.TOWN);
+ }
+
+}
diff --git a/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/GroundFactoryTest.java b/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/GroundFactoryTest.java
new file mode 100644
index 00000000..c2acc8c7
--- /dev/null
+++ b/sources/codemetropolis-toolchain-rendering/src/test/java/codemetropolis/toolchain/rendering/model/building/factory/GroundFactoryTest.java
@@ -0,0 +1,270 @@
+package codemetropolis.toolchain.rendering.model.building.factory;
+
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import codemetropolis.toolchain.commons.cmxml.Buildable;
+import codemetropolis.toolchain.rendering.exceptions.BuildingTypeMismatchException;
+import codemetropolis.toolchain.rendering.model.Themes;
+import codemetropolis.toolchain.rendering.model.building.Cellar;
+import codemetropolis.toolchain.rendering.model.building.DecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.Floor;
+import codemetropolis.toolchain.rendering.model.building.Garden;
+import codemetropolis.toolchain.rendering.model.building.Ground;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.minimalist.MinimalistGround;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.railway.RailwayGround;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownCellar;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownDecorationFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownFloor;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGarden;
+import codemetropolis.toolchain.rendering.model.building.theme.town.TownGround;
+
+/**
+ * Test class for {@link GroundFactory} for properly handling {@link Buildable.Type} and {@link Themes}.
+ *
+ * @author Abigel Mester {@literal }
+ */
+public class GroundFactoryTest {
+
+ private Buildable decorationBuildable;
+ private Buildable floorBuildable;
+ private Buildable cellarBuildable;
+ private Buildable gardenBuildable;
+ private Buildable groundBuildable;
+
+ /**
+ * Initializes the buildables used in the tests.
+ */
+ @Before
+ public void init() {
+ decorationBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.DECORATION_FLOOR);
+ floorBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.FLOOR);
+ cellarBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.CELLAR);
+ gardenBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.GARDEN);
+ groundBuildable = new Buildable(UUID.randomUUID().toString(), "test", Buildable.Type.GROUND);
+ }
+
+ /**
+ * Checks if {@link Ground} was created properly.
+ */
+ @Test
+ public void testCreateBasicGround() {
+ try {
+ Ground ground = GroundFactory.createGround(groundBuildable, Themes.BASIC);
+ Assert.assertEquals(ground.getClass(), Ground.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link MinimalistGround} was created properly.
+ */
+ @Test
+ public void testCreateMinimalistGround() {
+ try {
+ Ground ground = GroundFactory.createGround(groundBuildable, Themes.MINIMALIST);
+ Assert.assertEquals(ground.getClass(), MinimalistGround.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@linkRailwayGround} was created properly.
+ */
+ @Test
+ public void testCreateRailwayGround() {
+ try {
+ Ground ground = GroundFactory.createGround(groundBuildable, Themes.RAILWAY);
+ Assert.assertEquals(ground.getClass(), RailwayGround.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@linkTownGround} was created properly.
+ */
+ @Test
+ public void testCreateTownGround() {
+ try {
+ Ground ground = GroundFactory.createGround(groundBuildable, Themes.TOWN);
+ Assert.assertEquals(ground.getClass(), TownGround.class);
+ } catch (BuildingTypeMismatchException e) {
+ Assert.fail("Shouldn't throw exception.");
+ }
+ }
+
+ /**
+ * Checks if {@link Floor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicFloorAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(floorBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistFloorAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(floorBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayFloorAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(floorBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of floor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownFloorAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(floorBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link DecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicDecorationFloorAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(decorationBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistDecorationFloorAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(decorationBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayDecorationFloorAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(decorationBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownDecorationFloor} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of decorationFloor.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownDecorationFloorAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(decorationBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Garden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicGardenAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(gardenBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistGardenAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(gardenBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayGardenAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(gardenBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownGarden} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of garden.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownGardenAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(gardenBuildable, Themes.TOWN);
+ }
+
+ /**
+ * Checks if {@link Cellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateBasicCellarAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(cellarBuildable, Themes.BASIC);
+ }
+
+ /**
+ * Checks if {@link MinimalistCellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateMinimalistCellarAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(cellarBuildable, Themes.MINIMALIST);
+ }
+
+ /**
+ * Checks if {@link RailwayCellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateRailwayCellarAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(cellarBuildable, Themes.RAILWAY);
+ }
+
+ /**
+ * Checks if {@link TownCellar} was filtered properly.
+ *
+ * @throws BuildingTypeMismatchException if testing is okay. So couldn't create a ground of cellar.
+ */
+ @Test(expected = BuildingTypeMismatchException.class)
+ public void testCreateTownCellarAsGround() throws BuildingTypeMismatchException {
+ GroundFactory.createGround(cellarBuildable, Themes.TOWN);
+ }
+
+}
diff --git a/sources/pom.xml b/sources/pom.xml
index 37cb03b2..37fa9907 100644
--- a/sources/pom.xml
+++ b/sources/pom.xml
@@ -29,6 +29,7 @@
codemetropolis-toolchain-mapping
codemetropolis-toolchain-placing
codemetropolis-toolchain-rendering
+ codemetropolis-toolchain-metrics
codemetropolis-toolchain-commons
codemetropolis-toolchain-converter
codemetropolis-toolchain-gui