mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-05-20 08:40:26 +00:00
Compare commits
262 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6bac82da25 | |||
| a51727b636 | |||
| ec722014e6 | |||
| 256761eb5b | |||
| 07731c06c0 | |||
| 556584f9f5 | |||
| 61c93b47ca | |||
| 044aa738a3 | |||
| 8da2b63f31 | |||
| ce033b0956 | |||
| a9df684b80 | |||
| 356771bcea | |||
| 166c0f7dfb | |||
| aa41cc4d3d | |||
| 0c3e3f2bc6 | |||
| 792b6efd12 | |||
| 122fbd841c | |||
| ad5823055d | |||
| 92afe1c9ab | |||
| 1826adf1c2 | |||
| 97f6cda4ad | |||
| bccfcdf9a1 | |||
| 8049824170 | |||
| 99acadaf59 | |||
| 2be4b36d1a | |||
| c283f37390 | |||
| d16c28aebd | |||
| ce45bacc6f | |||
| a68b85c522 | |||
| 7d0149b59d | |||
| 447c82f74a | |||
| 8db263e19b | |||
| 7cf34dbd8a | |||
| 283495832f | |||
| f6312a01d7 | |||
| c7d43142f2 | |||
| c4da858095 | |||
| 5ff47bad18 | |||
| 18819ae53d | |||
| ddc2cea427 | |||
| bc17597923 | |||
| 49f3c16a38 | |||
| 5db1494341 | |||
| cccb706ad5 | |||
| c6d7d1a947 | |||
| 9685dbbb9d | |||
| a18d459343 | |||
| 4b5013231c | |||
| a04bcf5b23 | |||
| 1c579e8e5b | |||
| bbab6e39ff | |||
| 2e68a0db5d | |||
| abc59901c1 | |||
| aaa0c99524 | |||
| 0780539326 | |||
| c8434e73ef | |||
| 058ec9f24d | |||
| 7127943298 | |||
| 9adc03d56b | |||
| 5d6b060dee | |||
| fc82eff93b | |||
| 1c316e52a9 | |||
| 76afd54d3c | |||
| 7fe7dac57a | |||
| 63e59692e2 | |||
| 405a96034c | |||
| e9dc7428b8 | |||
| b4342a36aa | |||
| 1158ae958a | |||
| 062c9b5efb | |||
| 66e8647517 | |||
| f47b975fe7 | |||
| e5d9ae62fa | |||
| 9c1eab04b9 | |||
| 72d4370878 | |||
| 88da796923 | |||
| 2ab4ed871c | |||
| 0ecd275c56 | |||
| 4f40bcbe5e | |||
| cb7b3de48c | |||
| 13fbb9bf54 | |||
| be8ed913e5 | |||
| fe17683d27 | |||
| 7d72a91bb7 | |||
| 7a75f20a2c | |||
| 8a7499d874 | |||
| adc5f0becc | |||
| 6d710ca442 | |||
| 7cbf8dffbe | |||
| e1cb46c8fd | |||
| 8b97d74e0a | |||
| c4f927e72c | |||
| 2880c29f8c | |||
| 474962db39 | |||
| f970838ecf | |||
| 29e2746e72 | |||
| 1ce884d1c7 | |||
| 24697ae60f | |||
| 53c554f25c | |||
| d1af8c1224 | |||
| 9ac098f1ca | |||
| 300fe10da5 | |||
| b33c8d6b77 | |||
| b06a755154 | |||
| 817b962c4a | |||
| 56c52e860d | |||
| fd89c1128a | |||
| beec1a97d4 | |||
| b955e3d9b9 | |||
| b12079694c | |||
| 7a83584317 | |||
| 1c4cc090af | |||
| a614d7dddd | |||
| ae21b8305a | |||
| 6f6767ab86 | |||
| ee35c371ec | |||
| 4d59c27a13 | |||
| 0dc0742e81 | |||
| 3b0abb7a20 | |||
| 42231cf319 | |||
| 11c8025ef4 | |||
| eda976bb5d | |||
| 49c445d0f7 | |||
| 875e1feafe | |||
| 5f5504100b | |||
| 2215c8a98c | |||
| ebe887def0 | |||
| 1dded41311 | |||
| 6db4755109 | |||
| a01dee9a27 | |||
| 582bde8d0e | |||
| f609727afb | |||
| a058f1c58b | |||
| 70abf69dc7 | |||
| 269ec257b5 | |||
| 2c15a9fc0c | |||
| 0826246cbe | |||
| a3add9b20f | |||
| 6c20b5911f | |||
| d779b3ea27 | |||
| 618e7ed12e | |||
| d84dd3a526 | |||
| 27dbd494bd | |||
| 15100caf32 | |||
| 4e9c7e0b91 | |||
| 0261ecdcbb | |||
| 5bf699cba9 | |||
| 7ee1d2c391 | |||
| 5c9c47d078 | |||
| af5309ff21 | |||
| c7539dc5dd | |||
| 4b2c2d8ba2 | |||
| ee529a5973 | |||
| 3e04dc6b46 | |||
| dbf4b4dd3b | |||
| 560fdf17fa | |||
| 7a61a2548b | |||
| 31361286b5 | |||
| abd29c1cb4 | |||
| 9f4e120283 | |||
| d9f585e4b2 | |||
| f4456f46a7 | |||
| 3dc27f2b0a | |||
| 95e39324c7 | |||
| 392ba59741 | |||
| 26228d2c71 | |||
| 8f58ba17a8 | |||
| 75f39640b0 | |||
| 42dcc159e9 | |||
| 791faa6dfd | |||
| aea2b23fc3 | |||
| 47438b7db9 | |||
| df3d3c6398 | |||
| 1457a10b0b | |||
| 2b6e8eb67c | |||
| 11cb11bc2b | |||
| bb5552c8bc | |||
| 8f5a9b7b8e | |||
| 7e365c351d | |||
| a0f0206ed8 | |||
| 554628c486 | |||
| 37c2d945ec | |||
| 59a24ef37f | |||
| ad58a1efeb | |||
| 682b155deb | |||
| 0e0d84fea7 | |||
| 4ceb4e22d4 | |||
| 2ae2801058 | |||
| 5189aa5003 | |||
| 87cc2d01cb | |||
| f86fe4db32 | |||
| 1940309954 | |||
| d946ea9b15 | |||
| 0f8ce8966a | |||
| c9b2c83dc4 | |||
| 2d24a7bf00 | |||
| 4c80a71bca | |||
| 264f1df172 | |||
| 5b17d87a97 | |||
| 0e4df43ddb | |||
| 3d7796d8c3 | |||
| 4e647620f0 | |||
| a38fcef6f1 | |||
| b5fdeef535 | |||
| 5d3ae11374 | |||
| 7db75ab21b | |||
| 3d12af6b21 | |||
| 601eb3e7ff | |||
| 5754a95f48 | |||
| b3e76f6485 | |||
| 47b3278f96 | |||
| 27e31fef9f | |||
| 3807b8c277 | |||
| 7db83c1dee | |||
| 496cd486b1 | |||
| 034f1072bf | |||
| b5c99c87e1 | |||
| c5fe86272e | |||
| 15840302e0 | |||
| 0f526ca616 | |||
| bc3d694f7f | |||
| 7f880c23b8 | |||
| 7c6aa3a425 | |||
| 9636c808fe | |||
| f49ba88cb4 | |||
| 0cbc225408 | |||
| f85d047ee6 | |||
| f033b8219c | |||
| 1357e7f84e | |||
| 3eaab219f1 | |||
| ce97732da7 | |||
| 7fe2fa493e | |||
| 78acf59f98 | |||
| 1c0954d0cf | |||
| fe6ea9511b | |||
| 1c9c183d66 | |||
| 67ff426894 | |||
| 6eb5c0e0ec | |||
| 4e11d5c1cf | |||
| 155b293b61 | |||
| 282bfe9c5d | |||
| 4ddace2a92 | |||
| 4b7b0ee7e9 | |||
| af6ba33921 | |||
| 622e65e7a5 | |||
| 2f9f89042c | |||
| 538000ed32 | |||
| fe676db0ce | |||
| 30e89a0b69 | |||
| 8e49f7ec26 | |||
| 86088d1dcd | |||
| 5c6ea59d30 | |||
| f364420007 | |||
| 96ff875d2b | |||
| 717ece9d1f | |||
| 013216ad8c | |||
| 16d8d56832 | |||
| 06d9fa1d98 | |||
| 59141f99bd | |||
| dbbe7dbd0d | |||
| c46161fc87 | |||
| 70ec483581 |
+1
-1
@@ -6,7 +6,7 @@ end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
max_line_length = 120
|
||||
max_line_length = 140
|
||||
tab_width = 4
|
||||
ij_continuation_indent_size = 8
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
|
||||
@@ -34,6 +34,7 @@ jobs:
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
prerelease: false
|
||||
files: |
|
||||
build/libs/Terra-*-shaded.jar
|
||||
files: |
|
||||
build/libs/Terra-*.jar
|
||||
LICENSE
|
||||
|
||||
@@ -137,3 +137,5 @@ build
|
||||
|
||||
!lib/*.jar
|
||||
.idea/Terra.iml
|
||||
/run/
|
||||
.idea/**.iml
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="1.8" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-18
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleHome" value="/usr/share/java/gradle" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<Languages>
|
||||
<language minSize="54" name="Java" />
|
||||
</Languages>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="NonSerializableObjectPassedToObjectStream" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SerialVersionUIDNotStaticFinal" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SerializableHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreAnonymousInnerClasses" value="false" />
|
||||
<option name="superClassString" value="java.awt.Component" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SerializableInnerClassHasSerialVersionUIDField" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoreAnonymousInnerClasses" value="false" />
|
||||
<option name="superClassString" value="java.awt.Component" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SerializableStoresNonSerializable" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TransientFieldInNonSerializableClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="TransientFieldNotInitialized" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
Generated
-85
@@ -1,85 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="BintrayJCenter" />
|
||||
<option name="name" value="BintrayJCenter" />
|
||||
<option name="url" value="https://jcenter.bintray.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="papermc" />
|
||||
<option name="name" value="papermc" />
|
||||
<option name="url" value="https://papermc.io/repo/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="parsii.local" />
|
||||
<option name="name" value="parsii" />
|
||||
<option name="url" value="file:$PROJECT_DIR$/../parsii/repo" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="local" />
|
||||
<option name="name" value="local" />
|
||||
<option name="url" value="file:lib" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="aikar" />
|
||||
<option name="name" value="aikar" />
|
||||
<option name="url" value="https://repo.aikar.co/content/groups/aikar/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="enginehub-maven" />
|
||||
<option name="name" value="enginehub-maven" />
|
||||
<option name="url" value="http://maven.enginehub.org/repo/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="spigotmc-repo" />
|
||||
<option name="name" value="spigotmc-repo" />
|
||||
<option name="url" value="https://hub.spigotmc.org/nexus/content/repositories/snapshots/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="enginehub" />
|
||||
<option name="name" value="enginehub" />
|
||||
<option name="url" value="https://maven.enginehub.org/repo/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="minecraft-repo" />
|
||||
<option name="name" value="minecraft-repo" />
|
||||
<option name="url" value="https://libraries.minecraft.net/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="gaea.local" />
|
||||
<option name="name" value="gaea" />
|
||||
<option name="url" value="file:$PROJECT_DIR$/../Gaea/repo" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="gaea.local" />
|
||||
<option name="name" value="gaea-local" />
|
||||
<option name="url" value="file:$PROJECT_DIR$/../Gaea/repo" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="CodeMC" />
|
||||
<option name="name" value="CodeMC" />
|
||||
<option name="url" value="https://repo.codemc.org/repository/maven-public" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenLocal" />
|
||||
<option name="name" value="MavenLocal" />
|
||||
<option name="url" value="file:$MAVEN_REPOSITORY$/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-25
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0">
|
||||
<entry_point TYPE="field" FQNAME="com.dfsek.terra.util.StructureTypeEnum NETHER_FORTRESS" />
|
||||
</entry_points>
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
|
||||
</list>
|
||||
</component>
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-124
@@ -1,124 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="CheckStyle-IDEA-Module">
|
||||
<option name="configuration">
|
||||
<map />
|
||||
</option>
|
||||
</component>
|
||||
<component name="FacetManager">
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>SPIGOT</platformType>
|
||||
</autoDetectTypes>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
</module>
|
||||
+6
-231
@@ -1,205 +1,11 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.net.URL
|
||||
import java.nio.channels.Channels
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.nio.file.StandardCopyOption
|
||||
//import java.util.zip.ZipFile
|
||||
import java.util.zip.ZipInputStream
|
||||
import com.dfsek.terra.getGitHash
|
||||
|
||||
plugins {
|
||||
java
|
||||
maven
|
||||
id("com.github.johnrengelman.shadow").version("6.1.0")
|
||||
val versionObj = Version("3", "0", "0", true)
|
||||
|
||||
allprojects {
|
||||
version = versionObj
|
||||
group = "com.dfsek.terra"
|
||||
}
|
||||
|
||||
repositories {
|
||||
flatDir {
|
||||
dirs("lib")
|
||||
}
|
||||
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
|
||||
maven { url = uri("http://maven.enginehub.org/repo/") }
|
||||
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
|
||||
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
|
||||
// maven { url = uri("https://maven.pkg.github.com/solonovamax/Gaea") }
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
val versionObj = Version("1", "5", "0", true)
|
||||
|
||||
version = versionObj
|
||||
|
||||
dependencies {
|
||||
val gaeaVersion = "1.14.3"
|
||||
compileOnly(name = "Gaea-${gaeaVersion}", group = "")
|
||||
testImplementation(name = "Gaea-${gaeaVersion}", group = "")
|
||||
|
||||
compileOnly("org.jetbrains:annotations:20.1.0")
|
||||
|
||||
implementation("commons-io:commons-io:2.4")
|
||||
implementation("org.apache.commons:commons-imaging:1.0-alpha2")
|
||||
|
||||
compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.0-SNAPSHOT")
|
||||
implementation("org.bstats:bstats-bukkit:1.7")
|
||||
|
||||
compileOnly("com.googlecode.json-simple:json-simple:1.1")
|
||||
|
||||
implementation(name = "parsii-1.2.1", group = "")
|
||||
|
||||
compileOnly("org.spigotmc:spigot-api:1.16.2-R0.1-SNAPSHOT")
|
||||
implementation("io.papermc:paperlib:1.0.5")
|
||||
|
||||
implementation("net.jafama:jafama:2.3.2")
|
||||
|
||||
|
||||
// JUnit.
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.0")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.0")
|
||||
}
|
||||
|
||||
val compileJava: JavaCompile by tasks
|
||||
val mainSourceSet: SourceSet = sourceSets["main"]
|
||||
|
||||
val tokenizeJavaSources = task<Copy>(name = "tokenizeJavaSources") {
|
||||
from(mainSourceSet.allSource) {
|
||||
include("**/plugin.yml")
|
||||
println("version: $versionObj")
|
||||
val tokens = mapOf("VERSION" to versionObj.toString())
|
||||
|
||||
filter(org.apache.tools.ant.filters.ReplaceTokens::class, "tokens" to tokens)
|
||||
}
|
||||
into("build/tokenizedSources")
|
||||
includeEmptyDirs = false
|
||||
}
|
||||
|
||||
|
||||
compileJava.apply {
|
||||
dependsOn(tokenizeJavaSources)
|
||||
|
||||
options.encoding = "UTF-8"
|
||||
doFirst {
|
||||
options.compilerArgs = mutableListOf("-Xlint:all")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
|
||||
maxHeapSize = "4G"
|
||||
ignoreFailures = false
|
||||
failFast = true
|
||||
maxParallelForks = 12
|
||||
}
|
||||
|
||||
tasks.named<ShadowJar>("shadowJar") {
|
||||
from(tokenizeJavaSources.destinationDir)
|
||||
dependsOn(downloadDefaultPacks)
|
||||
|
||||
archiveClassifier.set("shaded")
|
||||
archiveBaseName.set("Terra")
|
||||
setVersion(project.version)
|
||||
relocate("org.apache.commons", "com.dfsek.terra.lib.commons")
|
||||
relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats")
|
||||
relocate("parsii", "com.dfsek.terra.lib.parsii")
|
||||
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
|
||||
relocate("net.jafama", "com.dfsek.terra.lib.jafama")
|
||||
minimize {
|
||||
exclude(project(":"))
|
||||
}
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.shadowJar)
|
||||
// dependsOn(testWithPaper)
|
||||
// testWithPaper.mustRunAfter(tasks.shadowJar)
|
||||
}
|
||||
|
||||
val testDir = "target/server/"
|
||||
|
||||
val setupServer = tasks.create("setupServer") {
|
||||
dependsOn(tasks.shadowJar)
|
||||
doFirst {
|
||||
// clean
|
||||
file("${testDir}/").deleteRecursively()
|
||||
file("${testDir}/plugins").mkdirs()
|
||||
|
||||
// Downloading latest paper jar.
|
||||
val paperUrl = URL("https://papermc.io/api/v1/paper/1.16.4/latest/download")
|
||||
val paperReadableByteChannel = Channels.newChannel(paperUrl.openStream())
|
||||
val paperFile = file("${testDir}/paper.jar")
|
||||
val paperFileOutputStream = paperFile.outputStream()
|
||||
val paperFileChannel = paperFileOutputStream.channel
|
||||
paperFileChannel.transferFrom(paperReadableByteChannel, 0, Long.MAX_VALUE)
|
||||
|
||||
// Cloning test setup.
|
||||
gitClone("https://github.com/PolyhedralDev/WorldGenTestServer")
|
||||
// Copying plugins
|
||||
Files.move(Paths.get("WorldGenTestServer/plugins"),
|
||||
Paths.get("$testDir/plugins"),
|
||||
StandardCopyOption.REPLACE_EXISTING)
|
||||
// Copying config
|
||||
val serverText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/server.properties").readText()
|
||||
file("${testDir}/server.properties").writeText(serverText)
|
||||
val bukkitText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/bukkit.yml").readText()
|
||||
file("${testDir}/bukkit.yml").writeText(bukkitText.replace("\${world}", "world").replace("\${gen}", "Terra:DEFAULT"))
|
||||
|
||||
File("${testDir}/eula.txt").writeText("eula=true")
|
||||
|
||||
// clean up
|
||||
file("WorldGenTestServer").deleteRecursively()
|
||||
}
|
||||
}
|
||||
|
||||
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
|
||||
doFirst {
|
||||
// Downloading latest paper jar.
|
||||
// if (file("${buildDir}/resources/main/packs/default").exists() && file("${buildDir}/resources/main/packs/nether").exists())
|
||||
// return@doFirst
|
||||
// else
|
||||
file("${buildDir}/resources/main/packs/").deleteRecursively()
|
||||
|
||||
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/default.zip")
|
||||
downloadAndUnzipPack(defaultPackUrl)
|
||||
val netherPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/nether.zip")
|
||||
downloadAndUnzipPack(netherPackUrl)
|
||||
}
|
||||
}
|
||||
tasks.processResources {
|
||||
dependsOn(downloadDefaultPacks)
|
||||
}
|
||||
|
||||
val testWithPaper = task<JavaExec>(name = "testWithPaper") {
|
||||
standardInput = System.`in`
|
||||
dependsOn(tasks.shadowJar)
|
||||
// Copy Terra into dir
|
||||
doFirst {
|
||||
copy {
|
||||
from("${buildDir}/libs/Terra-${versionObj}.jar")
|
||||
into("${testDir}/plugins/")
|
||||
}
|
||||
}
|
||||
|
||||
main = "io.papermc.paperclip.Paperclip"
|
||||
jvmArgs = listOf("-XX:+UseG1GC", "-XX:+ParallelRefProcEnabled", "-XX:MaxGCPauseMillis=200",
|
||||
"-XX:+UnlockExperimentalVMOptions", "-XX:+DisableExplicitGC", "-XX:+AlwaysPreTouch",
|
||||
"-XX:G1NewSizePercent=30", "-XX:G1MaxNewSizePercent=40", "-XX:G1HeapRegionSize=8M",
|
||||
"-XX:G1ReservePercent=20", "-XX:G1HeapWastePercent=5", "-XX:G1MixedGCCountTarget=4",
|
||||
"-XX:InitiatingHeapOccupancyPercent=15", "-XX:G1MixedGCLiveThresholdPercent=90",
|
||||
"-XX:G1RSetUpdatingPauseTimePercent=5", "-XX:SurvivorRatio=32", "-XX:+PerfDisableSharedMem",
|
||||
"-XX:MaxTenuringThreshold=1", "-Dusing.aikars.flags=https://mcflags.emc.gs",
|
||||
"-Daikars.new.flags=true", "-DIReallyKnowWhatIAmDoingISwear")
|
||||
maxHeapSize = "2G"
|
||||
args = listOf("nogui")
|
||||
workingDir = file("${testDir}/")
|
||||
classpath = files("${testDir}/paper.jar")
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Version class that does version stuff.
|
||||
*/
|
||||
@@ -212,35 +18,4 @@ class Version(val major: String, val minor: String, val revision: String, val pr
|
||||
else //Only use git hash if it's a prerelease.
|
||||
"$major.$minor.$revision-BETA+${getGitHash()}"
|
||||
}
|
||||
}
|
||||
|
||||
fun getGitHash(): String {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
|
||||
fun gitClone(name: String) {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = mutableListOf("git", "clone", name)
|
||||
standardOutput = stdout
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadAndUnzipPack(packUrl: URL) {
|
||||
ZipInputStream(packUrl.openStream()).use { zip ->
|
||||
while (true) {
|
||||
val entry = zip.nextEntry ?: break
|
||||
if (entry.isDirectory)
|
||||
file("${buildDir}/resources/main/packs/${entry.name}").mkdirs()
|
||||
else
|
||||
file("${buildDir}/resources/main/packs/${entry.name}").outputStream().use { output ->
|
||||
output.write(zip.readBytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
kotlin("jvm") version embeddedKotlinVersion
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
"implementation"("com.github.jengelman.gradle.plugins:shadow:+")
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.dfsek.terra
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.gradle.kotlin.dsl.withType
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
fun Project.configureCommon() {
|
||||
apply(plugin = "java-library")
|
||||
apply(plugin = "maven-publish")
|
||||
apply(plugin = "idea")
|
||||
|
||||
configureDependencies()
|
||||
configureCompilation()
|
||||
configureDistribution()
|
||||
|
||||
version = rootProject.version
|
||||
|
||||
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
useJUnitPlatform()
|
||||
|
||||
maxHeapSize = "2G"
|
||||
ignoreFailures = false
|
||||
failFast = true
|
||||
maxParallelForks = 12
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.getGitHash(): String {
|
||||
val stdout = java.io.ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
|
||||
fun Project.gitClone(name: String) {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = mutableListOf("git", "clone", name)
|
||||
standardOutput = stdout
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.dfsek.terra
|
||||
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.gradle.api.tasks.javadoc.Javadoc
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.withType
|
||||
|
||||
fun Project.configureCompilation() {
|
||||
configure<JavaPluginConvention> {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = "UTF-8"
|
||||
doFirst {
|
||||
options.compilerArgs = mutableListOf("-Xlint:all")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Javadoc> {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.dfsek.terra
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.repositories
|
||||
|
||||
fun Project.configureDependencies() {
|
||||
|
||||
repositories {
|
||||
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
|
||||
maven { url = uri("http://maven.enginehub.org/repo/") }
|
||||
maven { url = uri("https://repo.codemc.org/repository/maven-public") }
|
||||
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
|
||||
maven { url = uri("https://maven.fabricmc.net/") }
|
||||
gradlePluginPortal()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.7.0")
|
||||
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.7.0")
|
||||
"compileOnly"("org.jetbrains:annotations:20.1.0")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.dfsek.terra
|
||||
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.BasePluginConvention
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.gradle.api.tasks.javadoc.Javadoc
|
||||
import org.gradle.kotlin.dsl.*
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
fun Project.configureDistribution() {
|
||||
apply(plugin = "java-library")
|
||||
apply(plugin = "com.github.johnrengelman.shadow")
|
||||
|
||||
|
||||
// configurations.create("shaded")
|
||||
|
||||
configurations {
|
||||
val shaded = create("shaded")
|
||||
getByName("compile").extendsFrom(shaded)
|
||||
// shaded.extendsFrom(getByName("compile"))
|
||||
val shadedApi = create("shadedApi")
|
||||
shaded.extendsFrom(shadedApi)
|
||||
getByName("api").extendsFrom(shadedApi)
|
||||
val shadedImplementation = create("shadedImplementation")
|
||||
shaded.extendsFrom(shadedImplementation)
|
||||
getByName("implementation").extendsFrom(shadedImplementation)
|
||||
}
|
||||
|
||||
// tasks.withType<JavaCompile> {
|
||||
// classpath +=
|
||||
// }
|
||||
|
||||
val downloadDefaultPacks = tasks.create("downloadDefaultPacks") {
|
||||
doFirst {
|
||||
file("${buildDir}/resources/main/packs/").deleteRecursively()
|
||||
|
||||
val defaultPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/default.zip")
|
||||
downloadPack(defaultPackUrl, project)
|
||||
val netherPackUrl = URL("https://github.com/PolyhedralDev/TerraDefaultConfig/releases/download/latest/nether.zip")
|
||||
downloadPack(netherPackUrl, project)
|
||||
}
|
||||
}
|
||||
tasks["processResources"].dependsOn(downloadDefaultPacks)
|
||||
|
||||
tasks.register<Jar>("sourcesJar") {
|
||||
archiveClassifier.set("sources")
|
||||
}
|
||||
|
||||
tasks.withType<Jar> {
|
||||
from("../LICENSE", "../../LICENSE")
|
||||
}
|
||||
|
||||
tasks.register<Jar>("javadocJar") {
|
||||
dependsOn("javadoc")
|
||||
archiveClassifier.set("javadoc")
|
||||
from(tasks.getByName<Javadoc>("javadoc").destinationDir)
|
||||
}
|
||||
|
||||
tasks.named<ShadowJar>("shadowJar") {
|
||||
// Tell shadow to download the packs
|
||||
dependsOn(downloadDefaultPacks)
|
||||
|
||||
configurations = listOf(project.configurations["shaded"])
|
||||
|
||||
archiveClassifier.set("shaded")
|
||||
setVersion(project.version)
|
||||
relocate("org.apache.commons", "com.dfsek.terra.lib.commons")
|
||||
relocate("parsii", "com.dfsek.terra.lib.parsii")
|
||||
relocate("net.jafama", "com.dfsek.terra.lib.jafama")
|
||||
minimize()
|
||||
}
|
||||
convention.getPlugin<BasePluginConvention>().archivesBaseName = project.name
|
||||
|
||||
tasks.named<DefaultTask>("build") {
|
||||
dependsOn(tasks["shadowJar"])
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadPack(packUrl: URL, project: Project) {
|
||||
val fileName = packUrl.file.substring(packUrl.file.lastIndexOf("/"))
|
||||
val file = File("${project.buildDir}/resources/main/packs/${fileName}")
|
||||
file.parentFile.mkdirs()
|
||||
file.outputStream().write(packUrl.readBytes())
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import com.dfsek.terra.configureCommon
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
configureCommon()
|
||||
|
||||
group = "com.dfsek.terra.common"
|
||||
|
||||
dependencies {
|
||||
"shadedApi"("org.apache.commons:commons-rng-core:1.3")
|
||||
"shadedApi"("commons-io:commons-io:2.4")
|
||||
|
||||
"shadedApi"("com.scireum:parsii:1.2.1")
|
||||
"shadedApi"("com.dfsek:Tectonic:1.0.3")
|
||||
"shadedApi"("net.jafama:jafama:2.3.2")
|
||||
"shadedApi"("org.yaml:snakeyaml:1.27")
|
||||
|
||||
"compileOnly"("com.googlecode.json-simple:json-simple:1.1")
|
||||
|
||||
"shadedApi"("com.google.guava:guava:30.0-jre")
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.dfsek.terra;
|
||||
|
||||
public interface CommandHandler {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.dfsek.terra;
|
||||
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import com.dfsek.terra.api.profiler.DataType;
|
||||
import com.dfsek.terra.api.profiler.Measurement;
|
||||
import com.dfsek.terra.api.profiler.WorldProfiler;
|
||||
|
||||
public class TerraProfiler extends WorldProfiler {
|
||||
public TerraProfiler(World w) {
|
||||
super(w);
|
||||
this
|
||||
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "FloraTime")
|
||||
.addMeasurement(new Measurement(10000000, DataType.PERIOD_MILLISECONDS), "TreeTime")
|
||||
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "OreTime")
|
||||
.addMeasurement(new Measurement(5000000, DataType.PERIOD_MILLISECONDS), "CaveTime")
|
||||
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "StructureTime")
|
||||
.addMeasurement(new Measurement(1500000, DataType.PERIOD_MILLISECONDS), "ElevationTime");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.dfsek.terra;
|
||||
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.generator.GeneratorWrapper;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import com.dfsek.terra.biome.BiomeZone;
|
||||
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
|
||||
import com.dfsek.terra.config.base.ConfigPack;
|
||||
|
||||
public class TerraWorld {
|
||||
private final TerraBiomeGrid grid;
|
||||
private final BiomeZone zone;
|
||||
private final ConfigPack config;
|
||||
private final boolean safe;
|
||||
private final TerraProfiler profiler;
|
||||
private final World world;
|
||||
|
||||
|
||||
public TerraWorld(World w, ConfigPack c, TerraPlugin main) {
|
||||
config = c;
|
||||
profiler = new TerraProfiler(w);
|
||||
this.grid = new TerraBiomeGrid.TerraBiomeGridBuilder(w.getSeed(), c, main).build();
|
||||
this.zone = grid.getZone();
|
||||
this.world = w;
|
||||
safe = true;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public static boolean isTerraWorld(World w) {
|
||||
return w.getGenerator().getHandle() instanceof GeneratorWrapper;
|
||||
}
|
||||
|
||||
public TerraBiomeGrid getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public ConfigPack getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public BiomeZone getZone() {
|
||||
return zone;
|
||||
}
|
||||
|
||||
public boolean isSafe() {
|
||||
return safe;
|
||||
}
|
||||
|
||||
public TerraProfiler getProfiler() {
|
||||
return profiler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.dfsek.terra.api;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Entity extends Handle {
|
||||
Location getLocation();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.dfsek.terra.api;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class Gaea {
|
||||
private static boolean debug;
|
||||
|
||||
public static File getGaeaFolder(World w) {
|
||||
File f = new File(w.getWorldFolder(), "gaea");
|
||||
f.mkdirs();
|
||||
return f;
|
||||
}
|
||||
|
||||
public static boolean isDebug() {
|
||||
return debug;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.dfsek.terra.api;
|
||||
|
||||
import com.dfsek.tectonic.loading.TypeRegistry;
|
||||
import com.dfsek.terra.api.math.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.math.Range;
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.biome.grid.master.TerraBiomeGrid;
|
||||
import com.dfsek.terra.biome.palette.PaletteHolder;
|
||||
import com.dfsek.terra.biome.palette.PaletteLayer;
|
||||
import com.dfsek.terra.carving.CarverPalette;
|
||||
import com.dfsek.terra.config.loaders.ImageLoaderLoader;
|
||||
import com.dfsek.terra.config.loaders.MaterialSetLoader;
|
||||
import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader;
|
||||
import com.dfsek.terra.config.loaders.RangeLoader;
|
||||
import com.dfsek.terra.config.loaders.config.FloraLayerLoader;
|
||||
import com.dfsek.terra.config.loaders.config.GridSpawnLoader;
|
||||
import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader;
|
||||
import com.dfsek.terra.config.loaders.config.OreConfigLoader;
|
||||
import com.dfsek.terra.config.loaders.config.OreHolderLoader;
|
||||
import com.dfsek.terra.config.loaders.config.TreeLayerLoader;
|
||||
import com.dfsek.terra.config.loaders.palette.CarverPaletteLoader;
|
||||
import com.dfsek.terra.config.loaders.palette.PaletteHolderLoader;
|
||||
import com.dfsek.terra.config.loaders.palette.PaletteLayerLoader;
|
||||
import com.dfsek.terra.generation.config.NoiseBuilder;
|
||||
import com.dfsek.terra.generation.items.flora.FloraLayer;
|
||||
import com.dfsek.terra.generation.items.flora.TerraFlora;
|
||||
import com.dfsek.terra.generation.items.ores.Ore;
|
||||
import com.dfsek.terra.generation.items.ores.OreConfig;
|
||||
import com.dfsek.terra.generation.items.ores.OreHolder;
|
||||
import com.dfsek.terra.generation.items.tree.TreeLayer;
|
||||
import com.dfsek.terra.image.ImageLoader;
|
||||
import com.dfsek.terra.procgen.GridSpawn;
|
||||
import com.dfsek.terra.util.MaterialSet;
|
||||
|
||||
public class GenericLoaders implements LoaderRegistrar {
|
||||
private final TerraPlugin main;
|
||||
|
||||
public GenericLoaders(TerraPlugin main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(TypeRegistry registry) {
|
||||
registry.registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader())
|
||||
.registerLoader(Range.class, new RangeLoader())
|
||||
.registerLoader(CarverPalette.class, new CarverPaletteLoader())
|
||||
.registerLoader(GridSpawn.class, new GridSpawnLoader())
|
||||
.registerLoader(PaletteHolder.class, new PaletteHolderLoader())
|
||||
.registerLoader(PaletteLayer.class, new PaletteLayerLoader())
|
||||
.registerLoader(FloraLayer.class, new FloraLayerLoader())
|
||||
.registerLoader(Ore.Type.class, (t, o, l) -> Ore.Type.valueOf((String) o))
|
||||
.registerLoader(OreConfig.class, new OreConfigLoader())
|
||||
.registerLoader(NoiseBuilder.class, new NoiseBuilderLoader())
|
||||
.registerLoader(TreeLayer.class, new TreeLayerLoader(main))
|
||||
.registerLoader(MaterialSet.class, new MaterialSetLoader())
|
||||
.registerLoader(OreHolder.class, new OreHolderLoader())
|
||||
.registerLoader(ImageLoader.class, new ImageLoaderLoader())
|
||||
.registerLoader(TerraBiomeGrid.Type.class, (t, o, l) -> TerraBiomeGrid.Type.valueOf((String) o))
|
||||
.registerLoader(ImageLoader.Channel.class, (t, o, l) -> ImageLoader.Channel.valueOf((String) o))
|
||||
.registerLoader(ImageLoader.Align.class, (t, o, l) -> ImageLoader.Align.valueOf((String) o))
|
||||
.registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf((String) o));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dfsek.terra.api;
|
||||
|
||||
import com.dfsek.tectonic.loading.TypeRegistry;
|
||||
|
||||
public interface LoaderRegistrar {
|
||||
void register(TypeRegistry registry);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.dfsek.terra.api;
|
||||
|
||||
public interface Player extends Entity {
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.dfsek.terra.api.lang;
|
||||
|
||||
|
||||
import com.dfsek.tectonic.config.Configuration;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class Language {
|
||||
private final Configuration configuration;
|
||||
public Language(File file) throws IOException {
|
||||
configuration = new Configuration(new FileInputStream(file));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public Message getMessage(String id) {
|
||||
Message temp = null;
|
||||
if(configuration.contains(id)) {
|
||||
Object m = configuration.get(id);
|
||||
|
||||
if(m instanceof List) {
|
||||
temp = new MultiLineMessage((List<String>) m);
|
||||
} else if(m instanceof String) {
|
||||
temp = new SingleLineMessage((String) m);
|
||||
} else return new SingleLineMessage("message:" + id + ":translation_undefined");
|
||||
}
|
||||
if(temp == null || temp.isEmpty()) return new SingleLineMessage("message:" + id + ":translation_undefined");
|
||||
return temp;
|
||||
}
|
||||
public void log(String messageID, Level level, Logger logger, String... args) {
|
||||
getMessage(messageID).log(logger, level, args);
|
||||
}
|
||||
public void send(String messageID, CommandSender sender, String... args) {
|
||||
getMessage(messageID).send(sender, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.api.lang;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public interface Message {
|
||||
void log(Logger logger, Level level, String... args);
|
||||
void send(CommandSender sender, String... args);
|
||||
boolean isEmpty();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.dfsek.terra.api.lang;
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class MultiLineMessage implements Message {
|
||||
private final List<String> message;
|
||||
public MultiLineMessage(List<String> message) {
|
||||
this.message = message;
|
||||
}
|
||||
@Override
|
||||
public void log(Logger logger, Level level, String... args) {
|
||||
for(String line: message) {
|
||||
logger.log(level, String.format(line, Arrays.asList(args).toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(CommandSender sender, String... args) {
|
||||
for(String line: message) {
|
||||
sender.sendMessage(String.format(line, Arrays.asList(args).toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return message == null || message.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.dfsek.terra.api.lang;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class SingleLineMessage implements Message {
|
||||
private final String message;
|
||||
public SingleLineMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
@Override
|
||||
public void log(Logger logger, Level level, String... args) {
|
||||
logger.log(level, String.format(message, Arrays.asList(args).toArray()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(CommandSender sender, String... args) {
|
||||
sender.sendMessage(String.format(message, Arrays.asList(args).toArray()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return message == null || message.equals("");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,71 @@
|
||||
package com.dfsek.terra.api.math;
|
||||
|
||||
import com.dfsek.terra.api.util.FastRandom;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Utility class for mathematical functions.
|
||||
*/
|
||||
public final class MathUtil {
|
||||
private static final double EPSILON = 0.1E-5;
|
||||
|
||||
/**
|
||||
* Gets the standard deviation of an array of doubles.
|
||||
*
|
||||
* @param numArray The array of numbers to calculate the standard deviation of.
|
||||
* @return double - The standard deviation.
|
||||
*/
|
||||
public static double standardDeviation(double[] numArray) {
|
||||
double sum = 0.0, standardDeviation = 0.0;
|
||||
int length = numArray.length;
|
||||
|
||||
for(double num : numArray) {
|
||||
sum += num;
|
||||
}
|
||||
|
||||
double mean = sum / length;
|
||||
|
||||
for(double num : numArray) {
|
||||
standardDeviation += FastMath.pow(num - mean, 2);
|
||||
}
|
||||
|
||||
return FastMath.sqrt(standardDeviation / length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the carver seed for a chunk.
|
||||
*
|
||||
* @param chunkX Chunk's X coordinate
|
||||
* @param chunkZ Chunk's Z coordinate
|
||||
* @param seed World seed
|
||||
* @return long - The carver seed.
|
||||
*/
|
||||
public static long getCarverChunkSeed(int chunkX, int chunkZ, long seed) {
|
||||
Random r = new FastRandom(seed);
|
||||
return chunkX * r.nextLong() ^ chunkZ * r.nextLong() ^ seed;
|
||||
}
|
||||
|
||||
public static long hashToLong(String s) {
|
||||
if(s == null) {
|
||||
return 0;
|
||||
}
|
||||
long hash = 0;
|
||||
for(char c : s.toCharArray()) {
|
||||
hash = 31L * hash + c;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare 2 floating-point values with epsilon to account for rounding errors
|
||||
*
|
||||
* @param a Value 1
|
||||
* @param b Value 2
|
||||
* @return Whether these values are equal
|
||||
*/
|
||||
public static boolean equals(double a, double b) {
|
||||
return a == b || FastMath.abs(a - b) < EPSILON;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.dfsek.terra.api.math;
|
||||
|
||||
import com.dfsek.terra.api.world.biome.NormalizationUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ProbabilityCollection<E> {
|
||||
private final Set<Object> cont = new HashSet<>();
|
||||
private Object[] array = new Object[0];
|
||||
private int size;
|
||||
|
||||
public com.dfsek.terra.api.math.ProbabilityCollection<E> add(E item, int probability) {
|
||||
if(!cont.contains(item)) size++;
|
||||
cont.add(item);
|
||||
int oldLength = array.length;
|
||||
Object[] newArray = new Object[array.length + probability];
|
||||
System.arraycopy(array, 0, newArray, 0, array.length); // Expand array.
|
||||
array = newArray;
|
||||
for(int i = oldLength; i < array.length; i++) array[i] = item;
|
||||
return this;
|
||||
}
|
||||
|
||||
public E get() {
|
||||
if(array.length == 0) return null;
|
||||
return (E) array[ThreadLocalRandom.current().nextInt(array.length)];
|
||||
}
|
||||
|
||||
public E get(Random r) {
|
||||
if(array.length == 0) return null;
|
||||
return (E) array[r.nextInt(array.length)];
|
||||
}
|
||||
|
||||
public E get(FastNoiseLite n, double x, double z) {
|
||||
if(array.length == 0) return null;
|
||||
return (E) array[NormalizationUtil.normalize(n.getNoise(x, z), array.length, 1)];
|
||||
}
|
||||
|
||||
public int getTotalProbability() {
|
||||
return array.length;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.dfsek.terra.api.math;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Random;
|
||||
|
||||
public class Range implements Iterable<Integer> {
|
||||
private int min;
|
||||
private int max;
|
||||
|
||||
public Range(int min, int max) {
|
||||
if(min > max) throw new IllegalArgumentException("Minimum must not be grater than maximum!");
|
||||
this.max = max;
|
||||
this.min = min;
|
||||
}
|
||||
|
||||
public boolean isInRange(int test) {
|
||||
return test >= min && test < max;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range setMax(int max) {
|
||||
this.max = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range setMin(int min) {
|
||||
this.min = min;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getRange() {
|
||||
return max - min;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range multiply(int mult) {
|
||||
min *= mult;
|
||||
max *= mult;
|
||||
return this;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range reflect(int pt) {
|
||||
return new com.dfsek.terra.api.math.Range(2 * pt - this.getMax(), 2 * pt - this.getMin());
|
||||
}
|
||||
|
||||
public int get(Random r) {
|
||||
return r.nextInt((max - min) + 1) + min;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range intersects(com.dfsek.terra.api.math.Range other) {
|
||||
try {
|
||||
return new com.dfsek.terra.api.math.Range(FastMath.max(this.getMin(), other.getMin()), FastMath.min(this.getMax(), other.getMax()));
|
||||
} catch(IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range add(int add) {
|
||||
this.min += add;
|
||||
this.max += add;
|
||||
return this;
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.math.Range sub(int sub) {
|
||||
this.min -= sub;
|
||||
this.max -= sub;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Min: " + getMin() + ", Max:" + getMax();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return min * 31 + max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof com.dfsek.terra.api.math.Range)) return false;
|
||||
com.dfsek.terra.api.math.Range other = (com.dfsek.terra.api.math.Range) obj;
|
||||
return other.getMin() == this.getMin() && other.getMax() == this.getMax();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<Integer> iterator() {
|
||||
return new RangeIterator(this);
|
||||
}
|
||||
|
||||
private static class RangeIterator implements Iterator<Integer> {
|
||||
private final com.dfsek.terra.api.math.Range m;
|
||||
private Integer current;
|
||||
|
||||
public RangeIterator(com.dfsek.terra.api.math.Range m) {
|
||||
this.m = m;
|
||||
current = m.getMin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return current < m.getMax();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer next() {
|
||||
current++;
|
||||
return current - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
package com.dfsek.terra.api.math.vector;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Location implements Cloneable {
|
||||
private World world;
|
||||
private Vector3 vector;
|
||||
private double pitch;
|
||||
private double yaw;
|
||||
|
||||
public Location(World w, double x, double y, double z) {
|
||||
this.world = w;
|
||||
this.vector = new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
public Location(World w, Vector3 vector) {
|
||||
this.world = w;
|
||||
this.vector = vector;
|
||||
}
|
||||
|
||||
public void setWorld(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public Vector3 getVector() {
|
||||
return vector;
|
||||
}
|
||||
|
||||
public void setVector(Vector3 vector) {
|
||||
this.vector = vector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location clone() {
|
||||
try {
|
||||
Location other = (Location) super.clone();
|
||||
other.setVector(other.getVector().clone());
|
||||
return other;
|
||||
} catch(CloneNotSupportedException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getBlockX() {
|
||||
return vector.getBlockX();
|
||||
}
|
||||
|
||||
public int getBlockY() {
|
||||
return vector.getBlockY();
|
||||
}
|
||||
|
||||
public int getBlockZ() {
|
||||
return vector.getBlockZ();
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return vector.getY();
|
||||
}
|
||||
|
||||
public Location setY(double y) {
|
||||
vector.setY(y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return vector.getX();
|
||||
}
|
||||
|
||||
public Location setX(double x) {
|
||||
vector.setX(x);
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return vector.getZ();
|
||||
}
|
||||
|
||||
public Location setZ(double z) {
|
||||
vector.setZ(z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public Location add(double x, double y, double z) {
|
||||
vector.add(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return world.getBlockAt(this);
|
||||
}
|
||||
|
||||
public Location subtract(int x, int y, int z) {
|
||||
vector.subtract(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Location add(Vector3 add) {
|
||||
vector.add(add);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof Location)) {
|
||||
return false;
|
||||
}
|
||||
final Location other = (Location) obj;
|
||||
|
||||
World world = this.world;
|
||||
World otherWorld = other.world;
|
||||
if(!Objects.equals(world, otherWorld)) {
|
||||
return false;
|
||||
}
|
||||
if(Double.doubleToLongBits(this.vector.getX()) != Double.doubleToLongBits(other.vector.getX())) {
|
||||
return false;
|
||||
}
|
||||
if(Double.doubleToLongBits(this.vector.getY()) != Double.doubleToLongBits(other.vector.getY())) {
|
||||
return false;
|
||||
}
|
||||
return Double.doubleToLongBits(this.vector.getZ()) == Double.doubleToLongBits(other.vector.getZ());
|
||||
}
|
||||
|
||||
public double getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public void setPitch(double pitch) {
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public double getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
public void setYaw(double yaw) {
|
||||
this.yaw = yaw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
|
||||
World world = (this.world == null) ? null : this.world;
|
||||
hash = 19 * hash + (world != null ? world.hashCode() : 0);
|
||||
hash = 19 * hash + (int) (Double.doubleToLongBits(this.vector.getX()) ^ (Double.doubleToLongBits(this.vector.getX()) >>> 32));
|
||||
hash = 19 * hash + (int) (Double.doubleToLongBits(this.vector.getY()) ^ (Double.doubleToLongBits(this.vector.getY()) >>> 32));
|
||||
hash = 19 * hash + (int) (Double.doubleToLongBits(this.vector.getZ()) ^ (Double.doubleToLongBits(this.vector.getZ()) >>> 32));
|
||||
hash = 19 * hash + (int) (Double.doubleToLongBits(this.pitch) ^ Double.doubleToLongBits(this.pitch) >>> 32);
|
||||
hash = 19 * hash + (int) (Double.doubleToLongBits(this.yaw) ^ Double.doubleToLongBits(this.yaw) >>> 32);
|
||||
return hash;
|
||||
}
|
||||
|
||||
public Vector3 toVector() {
|
||||
return vector.clone();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.dfsek.terra.procgen.math;
|
||||
package com.dfsek.terra.api.math.vector;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
package com.dfsek.terra.api.math.vector;
|
||||
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import net.jafama.FastMath;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class Vector3 implements Cloneable {
|
||||
|
||||
/**
|
||||
* Threshold for fuzzy equals().
|
||||
*/
|
||||
private static final double epsilon = 0.000001;
|
||||
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
|
||||
public Vector3(double x, double y, double z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the threshold used for equals().
|
||||
*
|
||||
* @return The epsilon.
|
||||
*/
|
||||
public static double getEpsilon() {
|
||||
return epsilon;
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public Vector3 setZ(double z) {
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public Vector3 setX(double x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector3 setY(double y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getBlockX() {
|
||||
return FastMath.floorToInt(x);
|
||||
}
|
||||
|
||||
public int getBlockY() {
|
||||
return FastMath.floorToInt(y);
|
||||
}
|
||||
|
||||
public int getBlockZ() {
|
||||
return FastMath.floorToInt(z);
|
||||
}
|
||||
|
||||
public Vector3 multiply(double m) {
|
||||
x *= m;
|
||||
y *= m;
|
||||
z *= m;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3 add(double x, double y, double z) {
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
this.z += z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3 add(Vector3 other) {
|
||||
this.x += other.getX();
|
||||
this.y += other.getY();
|
||||
this.z += other.getZ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3 add(Vector2 other) {
|
||||
this.x += other.getX();
|
||||
this.z += other.getZ();
|
||||
return this;
|
||||
}
|
||||
|
||||
public double lengthSquared() {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3 clone() {
|
||||
try {
|
||||
return (Vector3) super.clone();
|
||||
} catch(CloneNotSupportedException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public double length() {
|
||||
return FastMath.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a vector is normalized
|
||||
*
|
||||
* @return whether the vector is normalised
|
||||
*/
|
||||
public boolean isNormalized() {
|
||||
return Math.abs(this.lengthSquared() - 1) < getEpsilon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the vector around the x axis.
|
||||
* <p>
|
||||
* This piece of math is based on the standard rotation matrix for vectors
|
||||
* in three dimensional space. This matrix can be found here:
|
||||
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
|
||||
* Matrix</a>.
|
||||
*
|
||||
* @param angle the angle to rotate the vector about. This angle is passed
|
||||
* in radians
|
||||
* @return the same vector
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 rotateAroundX(double angle) {
|
||||
double angleCos = Math.cos(angle);
|
||||
double angleSin = Math.sin(angle);
|
||||
|
||||
double y = angleCos * getY() - angleSin * getZ();
|
||||
double z = angleSin * getY() + angleCos * getZ();
|
||||
return setY(y).setZ(z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the vector around the y axis.
|
||||
* <p>
|
||||
* This piece of math is based on the standard rotation matrix for vectors
|
||||
* in three dimensional space. This matrix can be found here:
|
||||
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
|
||||
* Matrix</a>.
|
||||
*
|
||||
* @param angle the angle to rotate the vector about. This angle is passed
|
||||
* in radians
|
||||
* @return the same vector
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 rotateAroundY(double angle) {
|
||||
double angleCos = Math.cos(angle);
|
||||
double angleSin = Math.sin(angle);
|
||||
|
||||
double x = angleCos * getX() + angleSin * getZ();
|
||||
double z = -angleSin * getX() + angleCos * getZ();
|
||||
return setX(x).setZ(z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the vector around the z axis
|
||||
* <p>
|
||||
* This piece of math is based on the standard rotation matrix for vectors
|
||||
* in three dimensional space. This matrix can be found here:
|
||||
* <a href="https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations">Rotation
|
||||
* Matrix</a>.
|
||||
*
|
||||
* @param angle the angle to rotate the vector about. This angle is passed
|
||||
* in radians
|
||||
* @return the same vector
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 rotateAroundZ(double angle) {
|
||||
double angleCos = Math.cos(angle);
|
||||
double angleSin = Math.sin(angle);
|
||||
|
||||
double x = angleCos * getX() - angleSin * getY();
|
||||
double y = angleSin * getX() + angleCos * getY();
|
||||
return setX(x).setY(y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance between this vector and another. The value of this
|
||||
* method is not cached and uses a costly square-root function, so do not
|
||||
* repeatedly call this method to get the vector's magnitude. NaN will be
|
||||
* returned if the inner result of the sqrt() function overflows, which
|
||||
* will be caused if the distance is too long.
|
||||
*
|
||||
* @param o The other vector
|
||||
* @return the distance
|
||||
*/
|
||||
public double distance(@NotNull Vector3 o) {
|
||||
return FastMath.sqrt(FastMath.pow2(x - o.x) + FastMath.pow2(y - o.y) + FastMath.pow2(z - o.z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the squared distance between this vector and another.
|
||||
*
|
||||
* @param o The other vector
|
||||
* @return the distance
|
||||
*/
|
||||
public double distanceSquared(@NotNull Vector3 o) {
|
||||
return FastMath.pow2(x - o.x) + FastMath.pow2(y - o.y) + FastMath.pow2(z - o.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the vector around a given arbitrary axis in 3 dimensional space.
|
||||
*
|
||||
* <p>
|
||||
* Rotation will follow the general Right-Hand-Rule, which means rotation
|
||||
* will be counterclockwise when the axis is pointing towards the observer.
|
||||
* <p>
|
||||
* This method will always make sure the provided axis is a unit vector, to
|
||||
* not modify the length of the vector when rotating.
|
||||
*
|
||||
* @param axis the axis to rotate the vector around. If the passed vector is
|
||||
* not of length 1, it gets copied and normalized before using it for the
|
||||
* rotation. Please use {@link Vector3#normalize()} on the instance before
|
||||
* passing it to this method
|
||||
* @param angle the angle to rotate the vector around the axis
|
||||
* @return the same vector
|
||||
* @throws IllegalArgumentException if the provided axis vector instance is
|
||||
* null
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 rotateAroundAxis(@NotNull Vector3 axis, double angle) throws IllegalArgumentException {
|
||||
return rotateAroundNonUnitAxis(axis.isNormalized() ? axis : axis.clone().normalize(), angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the vector around a given arbitrary axis in 3 dimensional space.
|
||||
*
|
||||
* <p>
|
||||
* Rotation will follow the general Right-Hand-Rule, which means rotation
|
||||
* will be counterclockwise when the axis is pointing towards the observer.
|
||||
* <p>
|
||||
* Note that the vector length will change accordingly to the axis vector
|
||||
* length. If the provided axis is not a unit vector, the rotated vector
|
||||
* will not have its previous length. The scaled length of the resulting
|
||||
* vector will be related to the axis vector.
|
||||
*
|
||||
* @param axis the axis to rotate the vector around.
|
||||
* @param angle the angle to rotate the vector around the axis
|
||||
* @return the same vector
|
||||
* @throws IllegalArgumentException if the provided axis vector instance is
|
||||
* null
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 rotateAroundNonUnitAxis(@NotNull Vector3 axis, double angle) throws IllegalArgumentException {
|
||||
double x = getX(), y = getY(), z = getZ();
|
||||
double x2 = axis.getX(), y2 = axis.getY(), z2 = axis.getZ();
|
||||
|
||||
double cosTheta = Math.cos(angle);
|
||||
double sinTheta = Math.sin(angle);
|
||||
double dotProduct = this.dot(axis);
|
||||
|
||||
double xPrime = x2 * dotProduct * (1d - cosTheta)
|
||||
+ x * cosTheta
|
||||
+ (-z2 * y + y2 * z) * sinTheta;
|
||||
double yPrime = y2 * dotProduct * (1d - cosTheta)
|
||||
+ y * cosTheta
|
||||
+ (z2 * x - x2 * z) * sinTheta;
|
||||
double zPrime = z2 * dotProduct * (1d - cosTheta)
|
||||
+ z * cosTheta
|
||||
+ (-y2 * x + x2 * y) * sinTheta;
|
||||
|
||||
return setX(xPrime).setY(yPrime).setZ(zPrime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the dot product of this vector with another. The dot product
|
||||
* is defined as x1*x2+y1*y2+z1*z2. The returned value is a scalar.
|
||||
*
|
||||
* @param other The other vector
|
||||
* @return dot product
|
||||
*/
|
||||
public double dot(@NotNull Vector3 other) {
|
||||
return x * other.x + y * other.y + z * other.z;
|
||||
}
|
||||
|
||||
public Location toLocation(World world) {
|
||||
return new Location(world, this.clone());
|
||||
}
|
||||
|
||||
public Vector3 normalize() {
|
||||
return this.multiply(1D / this.length());
|
||||
}
|
||||
|
||||
public Vector3 subtract(int x, int y, int z) {
|
||||
this.x -= x;
|
||||
this.y -= y;
|
||||
this.z -= z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Vector3 subtract(Vector3 end) {
|
||||
x -= end.x;
|
||||
y -= end.y;
|
||||
z -= end.z;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code for this vector
|
||||
*
|
||||
* @return hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
|
||||
hash = 79 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
|
||||
hash = 79 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
|
||||
hash = 79 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32));
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if two objects are equal.
|
||||
* <p>
|
||||
* Only two Vectors can ever return true. This method uses a fuzzy match
|
||||
* to account for floating point errors. The epsilon can be retrieved
|
||||
* with epsilon.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(!(obj instanceof Vector3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3 other = (Vector3) obj;
|
||||
|
||||
return Math.abs(x - other.x) < epsilon && Math.abs(y - other.y) < epsilon && Math.abs(z - other.z) < epsilon && (this.getClass().equals(obj.getClass()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.dfsek.terra.api.platform;
|
||||
|
||||
public interface CommandSender extends Handle {
|
||||
void sendMessage(String message);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.dfsek.terra.api.platform;
|
||||
|
||||
/**
|
||||
* An interface that contains a platform delegate.
|
||||
*/
|
||||
public interface Handle {
|
||||
Object getHandle();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.dfsek.terra.api.platform;
|
||||
|
||||
import com.dfsek.terra.TerraWorld;
|
||||
import com.dfsek.terra.api.LoaderRegistrar;
|
||||
import com.dfsek.terra.api.lang.Language;
|
||||
import com.dfsek.terra.api.platform.handle.ItemHandle;
|
||||
import com.dfsek.terra.api.platform.handle.WorldHandle;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import com.dfsek.terra.config.base.PluginConfig;
|
||||
import com.dfsek.terra.registry.ConfigRegistry;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public interface TerraPlugin extends LoaderRegistrar {
|
||||
WorldHandle getWorldHandle();
|
||||
|
||||
boolean isEnabled();
|
||||
|
||||
TerraWorld getWorld(World world);
|
||||
|
||||
Logger getLogger();
|
||||
|
||||
PluginConfig getTerraConfig();
|
||||
|
||||
File getDataFolder();
|
||||
|
||||
boolean isDebug();
|
||||
|
||||
Language getLanguage();
|
||||
|
||||
ConfigRegistry getRegistry();
|
||||
|
||||
void reload();
|
||||
|
||||
ItemHandle getItemHandle();
|
||||
|
||||
void saveDefaultConfig();
|
||||
|
||||
String platformName();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.dfsek.terra.api.platform.block;
|
||||
|
||||
public enum Axis {
|
||||
X, Y, Z
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.dfsek.terra.api.platform.block;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.state.BlockState;
|
||||
|
||||
public interface Block extends Handle {
|
||||
void setBlockData(BlockData data, boolean physics);
|
||||
|
||||
BlockData getBlockData();
|
||||
|
||||
BlockState getState();
|
||||
|
||||
Block getRelative(BlockFace face);
|
||||
|
||||
Block getRelative(BlockFace face, int len);
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
Location getLocation();
|
||||
|
||||
MaterialData getType();
|
||||
|
||||
int getX();
|
||||
|
||||
int getZ();
|
||||
|
||||
int getY();
|
||||
|
||||
boolean isPassable();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.block;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface BlockData extends Cloneable, Handle {
|
||||
MaterialData getMaterial();
|
||||
|
||||
boolean matches(MaterialData materialData);
|
||||
|
||||
BlockData clone();
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.dfsek.terra.api.platform.block;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public enum BlockFace {
|
||||
NORTH(0, 0, -1),
|
||||
EAST(1, 0, 0),
|
||||
SOUTH(0, 0, 1),
|
||||
WEST(-1, 0, 0),
|
||||
UP(0, 1, 0),
|
||||
DOWN(0, -1, 0),
|
||||
NORTH_EAST(NORTH, EAST),
|
||||
NORTH_WEST(NORTH, WEST),
|
||||
SOUTH_EAST(SOUTH, EAST),
|
||||
SOUTH_WEST(SOUTH, WEST),
|
||||
WEST_NORTH_WEST(WEST, NORTH_WEST),
|
||||
NORTH_NORTH_WEST(NORTH, NORTH_WEST),
|
||||
NORTH_NORTH_EAST(NORTH, NORTH_EAST),
|
||||
EAST_NORTH_EAST(EAST, NORTH_EAST),
|
||||
EAST_SOUTH_EAST(EAST, SOUTH_EAST),
|
||||
SOUTH_SOUTH_EAST(SOUTH, SOUTH_EAST),
|
||||
SOUTH_SOUTH_WEST(SOUTH, SOUTH_WEST),
|
||||
WEST_SOUTH_WEST(WEST, SOUTH_WEST),
|
||||
SELF(0, 0, 0);
|
||||
|
||||
private final int modX;
|
||||
private final int modY;
|
||||
private final int modZ;
|
||||
|
||||
BlockFace(final int modX, final int modY, final int modZ) {
|
||||
this.modX = modX;
|
||||
this.modY = modY;
|
||||
this.modZ = modZ;
|
||||
}
|
||||
|
||||
BlockFace(final BlockFace face1, final BlockFace face2) {
|
||||
this.modX = face1.getModX() + face2.getModX();
|
||||
this.modY = face1.getModY() + face2.getModY();
|
||||
this.modZ = face1.getModZ() + face2.getModZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of X-coordinates to modify to get the represented block
|
||||
*
|
||||
* @return Amount of X-coordinates to modify
|
||||
*/
|
||||
public int getModX() {
|
||||
return modX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of Y-coordinates to modify to get the represented block
|
||||
*
|
||||
* @return Amount of Y-coordinates to modify
|
||||
*/
|
||||
public int getModY() {
|
||||
return modY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of Z-coordinates to modify to get the represented block
|
||||
*
|
||||
* @return Amount of Z-coordinates to modify
|
||||
*/
|
||||
public int getModZ() {
|
||||
return modZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the normal vector corresponding to this block face.
|
||||
*
|
||||
* @return the normal vector
|
||||
*/
|
||||
@NotNull
|
||||
public Vector3 getDirection() {
|
||||
Vector3 direction = new Vector3(modX, modY, modZ);
|
||||
if(modX != 0 || modY != 0 || modZ != 0) {
|
||||
direction.normalize();
|
||||
}
|
||||
return direction;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public BlockFace getOppositeFace() {
|
||||
switch(this) {
|
||||
case NORTH:
|
||||
return BlockFace.SOUTH;
|
||||
|
||||
case SOUTH:
|
||||
return BlockFace.NORTH;
|
||||
|
||||
case EAST:
|
||||
return BlockFace.WEST;
|
||||
|
||||
case WEST:
|
||||
return BlockFace.EAST;
|
||||
|
||||
case UP:
|
||||
return BlockFace.DOWN;
|
||||
|
||||
case DOWN:
|
||||
return BlockFace.UP;
|
||||
|
||||
case NORTH_EAST:
|
||||
return BlockFace.SOUTH_WEST;
|
||||
|
||||
case NORTH_WEST:
|
||||
return BlockFace.SOUTH_EAST;
|
||||
|
||||
case SOUTH_EAST:
|
||||
return BlockFace.NORTH_WEST;
|
||||
|
||||
case SOUTH_WEST:
|
||||
return BlockFace.NORTH_EAST;
|
||||
|
||||
case WEST_NORTH_WEST:
|
||||
return BlockFace.EAST_SOUTH_EAST;
|
||||
|
||||
case NORTH_NORTH_WEST:
|
||||
return BlockFace.SOUTH_SOUTH_EAST;
|
||||
|
||||
case NORTH_NORTH_EAST:
|
||||
return BlockFace.SOUTH_SOUTH_WEST;
|
||||
|
||||
case EAST_NORTH_EAST:
|
||||
return BlockFace.WEST_SOUTH_WEST;
|
||||
|
||||
case EAST_SOUTH_EAST:
|
||||
return BlockFace.WEST_NORTH_WEST;
|
||||
|
||||
case SOUTH_SOUTH_EAST:
|
||||
return BlockFace.NORTH_NORTH_WEST;
|
||||
|
||||
case SOUTH_SOUTH_WEST:
|
||||
return BlockFace.NORTH_NORTH_EAST;
|
||||
|
||||
case WEST_SOUTH_WEST:
|
||||
return BlockFace.EAST_NORTH_EAST;
|
||||
|
||||
case SELF:
|
||||
return BlockFace.SELF;
|
||||
}
|
||||
|
||||
return BlockFace.SELF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.dfsek.terra.api.platform.block;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface MaterialData extends Handle {
|
||||
boolean matches(MaterialData other);
|
||||
|
||||
boolean matches(BlockData other);
|
||||
|
||||
boolean isSolid();
|
||||
|
||||
boolean isAir();
|
||||
|
||||
double getMaxDurability();
|
||||
|
||||
BlockData createBlockData();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
public interface AnaloguePowerable extends BlockData {
|
||||
int getMaximumPower();
|
||||
int getPower();
|
||||
void setPower(int power);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
public interface Bisected extends BlockData {
|
||||
Half getHalf();
|
||||
|
||||
void setHalf(Half half);
|
||||
|
||||
enum Half {
|
||||
/**
|
||||
* The top half of the block, normally with the higher y coordinate.
|
||||
*/
|
||||
TOP,
|
||||
/**
|
||||
* The bottom half of the block, normally with the lower y coordinate.
|
||||
*/
|
||||
BOTTOM
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.BlockFace;
|
||||
|
||||
public interface Directional extends BlockData {
|
||||
BlockFace getFacing();
|
||||
|
||||
void setFacing(BlockFace facing);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.BlockFace;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface MultipleFacing extends BlockData {
|
||||
Set<BlockFace> getFaces();
|
||||
|
||||
void setFace(BlockFace face, boolean facing);
|
||||
|
||||
Set<BlockFace> getAllowedFaces();
|
||||
|
||||
boolean hasFace(BlockFace f);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.Axis;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface Orientable extends BlockData {
|
||||
Set<Axis> getAxes();
|
||||
|
||||
Axis getAxis();
|
||||
|
||||
void setAxis(Axis axis);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
public interface Rail extends BlockData {
|
||||
Shape getShape();
|
||||
|
||||
void setShape(Shape newShape);
|
||||
|
||||
enum Shape {
|
||||
ASCENDING_EAST,
|
||||
ASCENDING_NORTH,
|
||||
ASCENDING_SOUTH,
|
||||
ASCENDING_WEST,
|
||||
EAST_WEST,
|
||||
NORTH_EAST,
|
||||
NORTH_SOUTH,
|
||||
NORTH_WEST,
|
||||
SOUTH_EAST,
|
||||
SOUTH_WEST
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.BlockFace;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface RedstoneWire extends BlockData, AnaloguePowerable {
|
||||
Set<BlockFace> getAllowedFaces();
|
||||
Connection getFace(BlockFace face);
|
||||
void setFace(BlockFace face, Connection connection);
|
||||
enum Connection {
|
||||
NONE, SIDE, UP
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.BlockFace;
|
||||
|
||||
public interface Rotatable extends BlockData {
|
||||
BlockFace getRotation();
|
||||
|
||||
void setRotation(BlockFace face);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
public interface Slab extends Waterlogged {
|
||||
Type getType();
|
||||
|
||||
void setType(Type type);
|
||||
|
||||
enum Type {
|
||||
TOP, BOTTOM, DOUBLE
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
public interface Stairs extends Waterlogged, Directional, Bisected {
|
||||
Shape getShape();
|
||||
|
||||
void setShape(Shape shape);
|
||||
|
||||
enum Shape {
|
||||
/**
|
||||
* Regular stair block.
|
||||
*/
|
||||
STRAIGHT,
|
||||
/**
|
||||
* Inner corner stair block with higher left side.
|
||||
*/
|
||||
INNER_LEFT,
|
||||
/**
|
||||
* Inner corner stair block with higher right side.
|
||||
*/
|
||||
INNER_RIGHT,
|
||||
/**
|
||||
* Outer corner stair block with higher left side.
|
||||
*/
|
||||
OUTER_LEFT,
|
||||
/**
|
||||
* Outer corner stair block with higher right side.
|
||||
*/
|
||||
OUTER_RIGHT
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.BlockFace;
|
||||
|
||||
public interface Wall extends BlockData, Waterlogged {
|
||||
boolean isUp();
|
||||
void setHeight(BlockFace face, Height height);
|
||||
Height getHeight(BlockFace face);
|
||||
void setUp(boolean up);
|
||||
|
||||
enum Height {
|
||||
LOW, NONE, TALL
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.dfsek.terra.api.platform.block.data;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
public interface Waterlogged extends BlockData {
|
||||
boolean isWaterlogged();
|
||||
|
||||
void setWaterlogged(boolean waterlogged);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.dfsek.terra.api.platform.block.state;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
|
||||
public interface BlockState extends Handle {
|
||||
Block getBlock();
|
||||
|
||||
int getX();
|
||||
|
||||
int getY();
|
||||
|
||||
int getZ();
|
||||
|
||||
BlockData getBlockData();
|
||||
|
||||
boolean update(boolean applyPhysics);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.block.state;
|
||||
|
||||
import com.dfsek.terra.api.platform.inventory.BlockInventoryHolder;
|
||||
|
||||
public interface Container extends BlockState, BlockInventoryHolder {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.generator;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.world.Chunk;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public interface BlockPopulator extends Handle {
|
||||
void populate(World world, Random random, Chunk chunk);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.dfsek.terra.api.platform.generator;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.world.BiomeGrid;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import com.dfsek.terra.api.world.generation.TerraChunkGenerator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public interface ChunkGenerator extends Handle {
|
||||
boolean isParallelCapable();
|
||||
|
||||
boolean shouldGenerateCaves();
|
||||
|
||||
boolean shouldGenerateDecorations();
|
||||
|
||||
boolean shouldGenerateMobs();
|
||||
|
||||
boolean shouldGenerateStructures();
|
||||
|
||||
ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome);
|
||||
|
||||
|
||||
List<BlockPopulator> getDefaultPopulators(World world);
|
||||
|
||||
@Nullable
|
||||
TerraChunkGenerator getTerraGenerator();
|
||||
|
||||
interface ChunkData {
|
||||
Object getHandle();
|
||||
|
||||
/**
|
||||
* Get the maximum height for the chunk.
|
||||
* <p>
|
||||
* Setting blocks at or above this height will do nothing.
|
||||
*
|
||||
* @return the maximum height
|
||||
*/
|
||||
int getMaxHeight();
|
||||
|
||||
|
||||
/**
|
||||
* Set the block at x,y,z in the chunk data to material.
|
||||
* <p>
|
||||
* Setting blocks outside the chunk's bounds does nothing.
|
||||
*
|
||||
* @param x the x location in the chunk from 0-15 inclusive
|
||||
* @param y the y location in the chunk from 0 (inclusive) - maxHeight (exclusive)
|
||||
* @param z the z location in the chunk from 0-15 inclusive
|
||||
* @param blockData the type to set the block to
|
||||
*/
|
||||
void setBlock(int x, int y, int z, @NotNull BlockData blockData);
|
||||
|
||||
|
||||
/**
|
||||
* Get the type and data of the block at x, y, z.
|
||||
* <p>
|
||||
* Getting blocks outside the chunk's bounds returns air.
|
||||
*
|
||||
* @param x the x location in the chunk from 0-15 inclusive
|
||||
* @param y the y location in the chunk from 0 (inclusive) - maxHeight (exclusive)
|
||||
* @param z the z location in the chunk from 0-15 inclusive
|
||||
* @return the data of the block or the BlockData for air if x, y or z are outside the chunk's bounds
|
||||
*/
|
||||
@NotNull BlockData getBlockData(int x, int y, int z);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.generator;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface GeneratorWrapper extends Handle {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.dfsek.terra.api.platform.handle;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.MaterialData;
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
|
||||
public interface ItemHandle {
|
||||
ItemStack newItemStack(MaterialData material, int amount);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.dfsek.terra.api.platform.handle;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.MaterialData;
|
||||
import com.dfsek.terra.api.platform.world.Tree;
|
||||
import com.dfsek.terra.api.platform.world.entity.EntityType;
|
||||
|
||||
/**
|
||||
* Interface to be implemented for world manipulation.
|
||||
*/
|
||||
public interface WorldHandle {
|
||||
void setBlockData(Block block, BlockData data, boolean physics);
|
||||
|
||||
BlockData getBlockData(Block block);
|
||||
|
||||
MaterialData getType(Block block);
|
||||
|
||||
BlockData createBlockData(String data);
|
||||
|
||||
MaterialData createMaterialData(String data);
|
||||
|
||||
Tree getTree(String id);
|
||||
|
||||
EntityType getEntity(String id);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dfsek.terra.api.platform.inventory;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
|
||||
public interface BlockInventoryHolder extends InventoryHolder {
|
||||
Block getBlock();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.inventory;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Inventory extends Handle {
|
||||
int getSize();
|
||||
|
||||
ItemStack getItem(int slot);
|
||||
|
||||
void setItem(int slot, ItemStack newStack);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dfsek.terra.api.platform.inventory;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface InventoryHolder extends Handle {
|
||||
Inventory getInventory();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.dfsek.terra.api.platform.inventory;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.MaterialData;
|
||||
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
|
||||
|
||||
public interface ItemStack extends Handle, Cloneable {
|
||||
int getAmount();
|
||||
|
||||
void setAmount(int i);
|
||||
|
||||
MaterialData getType();
|
||||
|
||||
ItemStack clone();
|
||||
|
||||
ItemMeta getItemMeta();
|
||||
|
||||
void setItemMeta(ItemMeta meta);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.dfsek.terra.api.platform.inventory.item;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Damageable extends Handle {
|
||||
int getDamage();
|
||||
|
||||
void setDamage(int damage);
|
||||
|
||||
boolean hasDamage();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.inventory.item;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface ItemMeta extends Handle {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* API for platform implementations. Mostly interfaces to be implemented by platform delegates.
|
||||
*/
|
||||
package com.dfsek.terra.api.platform;
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.world;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Biome extends Handle {
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.dfsek.terra.api.platform.world;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface BiomeGrid extends Handle {
|
||||
/**
|
||||
* Get biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param z - 0-15
|
||||
* @return Biome value
|
||||
*/
|
||||
@NotNull
|
||||
Biome getBiome(int x, int z);
|
||||
|
||||
/**
|
||||
* Get biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param y - 0-255
|
||||
* @param z - 0-15
|
||||
* @return Biome value
|
||||
*/
|
||||
@NotNull
|
||||
Biome getBiome(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param z - 0-15
|
||||
* @param bio - Biome value
|
||||
*/
|
||||
void setBiome(int x, int z, @NotNull Biome bio);
|
||||
|
||||
/**
|
||||
* Set biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param y - 0-255
|
||||
* @param z - 0-15
|
||||
* @param bio - Biome value
|
||||
*/
|
||||
void setBiome(int x, int y, int z, @NotNull Biome bio);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.api.platform.world;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
|
||||
public interface Chunk extends Handle {
|
||||
int getX();
|
||||
|
||||
int getZ();
|
||||
|
||||
World getWorld();
|
||||
|
||||
Block getBlock(int x, int y, int z);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.world;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Tree extends Handle, com.dfsek.terra.api.world.tree.Tree {
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.dfsek.terra.api.platform.world;
|
||||
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
import com.dfsek.terra.api.platform.generator.ChunkGenerator;
|
||||
import com.dfsek.terra.api.platform.world.entity.Entity;
|
||||
import com.dfsek.terra.api.platform.world.entity.EntityType;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface World extends Handle {
|
||||
long getSeed();
|
||||
|
||||
int getMaxHeight();
|
||||
|
||||
ChunkGenerator getGenerator();
|
||||
|
||||
String getName();
|
||||
|
||||
UUID getUID();
|
||||
|
||||
boolean isChunkGenerated(int x, int z);
|
||||
|
||||
Chunk getChunkAt(int x, int z);
|
||||
|
||||
File getWorldFolder();
|
||||
|
||||
Block getBlockAt(int x, int y, int z);
|
||||
|
||||
Block getBlockAt(Location l);
|
||||
|
||||
boolean generateTree(Location l, Tree vanillaTreeType);
|
||||
|
||||
Entity spawnEntity(Location location, EntityType entityType);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.world.entity;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface Entity extends Handle {
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.dfsek.terra.api.platform.world.entity;
|
||||
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
|
||||
public interface EntityType extends Handle {
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.dfsek.terra.api.profiler;
|
||||
|
||||
/**
|
||||
* Class to hold a profiler data value. Contains formatting method to highlight value based on desired range.
|
||||
*/
|
||||
public class DataHolder {
|
||||
private final long desired;
|
||||
private final DataType type;
|
||||
private final double desiredRangePercent;
|
||||
|
||||
/**
|
||||
* Constructs a DataHolder with a DataType and a desired value, including a percentage around the desired value considered acceptable
|
||||
*
|
||||
* @param type The type of data held in this instance.
|
||||
* @param desired The desired value. This should be the average value of whatever is being measured.
|
||||
* @param desiredRangePercent The percentage around the desired value to be considered acceptable.
|
||||
*/
|
||||
public DataHolder(DataType type, long desired, double desiredRangePercent) {
|
||||
this.desired = desired;
|
||||
this.type = type;
|
||||
this.desiredRangePercent = desiredRangePercent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String, formatted with Bungee ChatColors.<br>
|
||||
* GREEN if the value is better than desired and outside of acceptable range.<br>
|
||||
* YELLOW if the value is better or worse than desired, and within acceptable range.<br>
|
||||
* RED if the value is worse than desired and outside of acceptable range.<br>
|
||||
*
|
||||
* @param data The data to format.
|
||||
* @return String - The formatted data.
|
||||
*/
|
||||
public String getFormattedData(long data) {
|
||||
return type.getFormatted(data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.dfsek.terra.api.profiler;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
|
||||
public enum DataType {
|
||||
PERIOD_MILLISECONDS(Desire.LOW, 1000000, "ms"), PERIOD_NANOSECONDS(Desire.LOW, 1, "ns");
|
||||
private final Desire desire;
|
||||
private final long divisor;
|
||||
private final String unit;
|
||||
|
||||
DataType(Desire d, long divisor, String unit) {
|
||||
this.desire = d;
|
||||
this.divisor = divisor;
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
public String getFormatted(long value) {
|
||||
return (double) FastMath.round(((double) value / divisor) * 100D) / 100D + unit;
|
||||
}
|
||||
|
||||
public Desire getDesire() {
|
||||
return desire;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dfsek.terra.api.profiler;
|
||||
|
||||
|
||||
/**
|
||||
* Enum to represent the "goal" of a value, whether it is desirable for the value to be high (e.g. Frequency), or low (e.g. Period)
|
||||
*/
|
||||
public enum Desire {
|
||||
LOW, HIGH
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.dfsek.terra.api.profiler;
|
||||
|
||||
import com.dfsek.terra.api.math.MathUtil;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class to record and hold all data for a single type of measurement performed by the profiler.
|
||||
*/
|
||||
public class Measurement {
|
||||
private final List<Long> measurements;
|
||||
private final long desirable;
|
||||
private final DataType type;
|
||||
private long min = Long.MAX_VALUE;
|
||||
private long max = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* Constructs a new Measurement with a desired value and DataType.
|
||||
*
|
||||
* @param desirable The desired value of the measurement.
|
||||
* @param type The type of data the measurement is holding.
|
||||
*/
|
||||
public Measurement(long desirable, DataType type) {
|
||||
this.desirable = desirable;
|
||||
this.type = type;
|
||||
measurements = new GlueList<>();
|
||||
}
|
||||
|
||||
public void record(long value) {
|
||||
max = FastMath.max(value, max);
|
||||
min = FastMath.min(value, min);
|
||||
measurements.add(value);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return measurements.size();
|
||||
}
|
||||
|
||||
public ProfileFuture beginMeasurement() {
|
||||
ProfileFuture future = new ProfileFuture();
|
||||
long current = System.nanoTime();
|
||||
future.thenRun(() -> record(System.nanoTime() - current));
|
||||
return future;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
min = Long.MAX_VALUE;
|
||||
max = Long.MIN_VALUE;
|
||||
measurements.clear();
|
||||
}
|
||||
|
||||
public DataHolder getDataHolder() {
|
||||
return new DataHolder(type, desirable, 0.25);
|
||||
}
|
||||
|
||||
public long getMin() {
|
||||
if(min == Long.MAX_VALUE) return 0;
|
||||
return min;
|
||||
}
|
||||
|
||||
public long getMax() {
|
||||
if(max == Long.MIN_VALUE) return 0;
|
||||
return max;
|
||||
}
|
||||
|
||||
public long average() {
|
||||
BigInteger running = new BigInteger("0");
|
||||
List<Long> mTemp = new GlueList<>(measurements);
|
||||
for(Long l : mTemp) {
|
||||
running = running.add(BigInteger.valueOf(l));
|
||||
}
|
||||
if(measurements.size() == 0) return 0;
|
||||
return running.divide(BigInteger.valueOf(measurements.size())).longValue();
|
||||
}
|
||||
|
||||
public double getStdDev() {
|
||||
List<Long> mTemp = new GlueList<>(measurements);
|
||||
double[] vals = new double[mTemp.size()];
|
||||
for(int i = 0; i < mTemp.size(); i++) {
|
||||
vals[i] = mTemp.get(i);
|
||||
}
|
||||
return MathUtil.standardDeviation(vals);
|
||||
}
|
||||
|
||||
public int entries() {
|
||||
return measurements.size();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.dfsek.terra.api.profiler;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ProfileFuture extends CompletableFuture<Boolean> implements AutoCloseable {
|
||||
public ProfileFuture() {
|
||||
super();
|
||||
}
|
||||
|
||||
public boolean complete() {
|
||||
return super.complete(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.complete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.dfsek.terra.api.profiler;
|
||||
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class WorldProfiler {
|
||||
private final BiMap<String, Measurement> measures = HashBiMap.create();
|
||||
private final World world;
|
||||
private boolean isProfiling;
|
||||
|
||||
public WorldProfiler(World w) {
|
||||
if(w.getGenerator().getTerraGenerator() == null)
|
||||
throw new IllegalArgumentException("Attempted to instantiate profiler on non-Gaea managed world!");
|
||||
this.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "TotalChunkGenTime")
|
||||
.addMeasurement(new Measurement(2500000, DataType.PERIOD_MILLISECONDS), "ChunkBaseGenTime")
|
||||
.addMeasurement(new Measurement(2000000, DataType.PERIOD_MILLISECONDS), "BiomeApplyTime")
|
||||
.addMeasurement(new Measurement(2000000, DataType.PERIOD_MILLISECONDS), "PopulationManagerTime");
|
||||
isProfiling = false;
|
||||
this.world = w;
|
||||
}
|
||||
|
||||
public String getResultsFormatted() {
|
||||
if(! isProfiling) return "Profiler is not currently running.";
|
||||
StringBuilder result = new StringBuilder("Gaea World Profiler Results (Min / Avg / Max / Std Dev): \n");
|
||||
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
|
||||
result
|
||||
.append(e.getKey())
|
||||
.append(": ")
|
||||
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMin()))
|
||||
.append(" / ")
|
||||
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().average()))
|
||||
.append(" / ")
|
||||
.append(e.getValue().getDataHolder().getFormattedData(e.getValue().getMax()))
|
||||
.append(" / ")
|
||||
.append((double) FastMath.round((e.getValue().getStdDev() / 1000000) * 100D) / 100D)
|
||||
.append("ms")
|
||||
.append(" (x").append(e.getValue().size()).append(")\n");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
for(Map.Entry<String, Measurement> e : measures.entrySet()) {
|
||||
e.getValue().reset();
|
||||
}
|
||||
}
|
||||
|
||||
public com.dfsek.terra.api.profiler.WorldProfiler addMeasurement(Measurement m, String name) {
|
||||
measures.put(name, m);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setMeasurement(String id, long value) {
|
||||
if(isProfiling) measures.get(id).record(value);
|
||||
}
|
||||
|
||||
public ProfileFuture measure(String id) {
|
||||
if(isProfiling) return measures.get(id).beginMeasurement();
|
||||
else return null;
|
||||
}
|
||||
|
||||
public String getID(Measurement m) {
|
||||
return measures.inverse().get(m);
|
||||
}
|
||||
|
||||
public boolean isProfiling() {
|
||||
return isProfiling;
|
||||
}
|
||||
|
||||
public void setProfiling(boolean enabled) {
|
||||
this.isProfiling = enabled;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.dfsek.terra.api.structures.loot;
|
||||
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.block.MaterialData;
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.structures.loot.functions.AmountFunction;
|
||||
import com.dfsek.terra.api.structures.loot.functions.DamageFunction;
|
||||
import com.dfsek.terra.api.structures.loot.functions.Function;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import net.jafama.FastMath;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Representation of a single item entry within a Loot Table pool.
|
||||
*/
|
||||
public class Entry {
|
||||
private final MaterialData item;
|
||||
private final long weight;
|
||||
private final List<Function> functions = new GlueList<>();
|
||||
private final TerraPlugin main;
|
||||
|
||||
/**
|
||||
* Instantiates an Entry from a JSON representation.
|
||||
*
|
||||
* @param entry The JSON Object to instantiate from.
|
||||
*/
|
||||
public Entry(JSONObject entry, TerraPlugin main) {
|
||||
this.main = main;
|
||||
String id = entry.get("name").toString();
|
||||
this.item = main.getWorldHandle().createMaterialData(id);
|
||||
|
||||
long weight1;
|
||||
try {
|
||||
weight1 = (long) entry.get("weight");
|
||||
} catch(NullPointerException e) {
|
||||
weight1 = 1;
|
||||
}
|
||||
|
||||
this.weight = weight1;
|
||||
if(entry.containsKey("functions")) {
|
||||
for(Object function : (JSONArray) entry.get("functions")) {
|
||||
switch(((String) ((JSONObject) function).get("function"))) {
|
||||
case "minecraft:set_count":
|
||||
case "set_count":
|
||||
Object loot = ((JSONObject) function).get("count");
|
||||
long max, min;
|
||||
if(loot instanceof Long) {
|
||||
max = (Long) loot;
|
||||
min = (Long) loot;
|
||||
} else {
|
||||
max = (long) ((JSONObject) loot).get("max");
|
||||
min = (long) ((JSONObject) loot).get("min");
|
||||
}
|
||||
functions.add(new AmountFunction(FastMath.toIntExact(min), FastMath.toIntExact(max)));
|
||||
break;
|
||||
case "minecraft:set_damage":
|
||||
case "set_damage":
|
||||
long maxDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("max");
|
||||
long minDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("min");
|
||||
functions.add(new DamageFunction(FastMath.toIntExact(minDamage), FastMath.toIntExact(maxDamage)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a single ItemStack from the Entry, applying all functions to it.
|
||||
*
|
||||
* @param r The Random instance to apply functions with
|
||||
* @return ItemStack - The ItemStack with all functions applied.
|
||||
*/
|
||||
public ItemStack getItem(Random r) {
|
||||
ItemStack item = main.getItemHandle().newItemStack(this.item, 1);
|
||||
for(Function f : functions) {
|
||||
item = f.apply(item, r);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the weight attribute of the Entry.
|
||||
*
|
||||
* @return long - The weight of the Entry.
|
||||
*/
|
||||
public long getWeight() {
|
||||
return this.weight;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.dfsek.terra.api.structures.loot;
|
||||
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.inventory.Inventory;
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Class representation of a Loot Table to populate chest loot.
|
||||
*/
|
||||
public class LootTable {
|
||||
private final List<Pool> pools = new GlueList<>();
|
||||
|
||||
/**
|
||||
* Instantiates a LootTable from a JSON String.
|
||||
*
|
||||
* @param json The JSON String representing the loot table.
|
||||
* @throws ParseException if malformed JSON is passed.
|
||||
*/
|
||||
public LootTable(String json, TerraPlugin main) throws ParseException {
|
||||
JSONParser jsonParser = new JSONParser();
|
||||
Object tableJSON = jsonParser.parse(json);
|
||||
JSONArray poolArray = (JSONArray) ((JSONObject) tableJSON).get("pools");
|
||||
for(Object pool : poolArray) {
|
||||
pools.add(new Pool((JSONObject) pool, main));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of ItemStacks from the loot table using the given Random instance.
|
||||
*
|
||||
* @param r The Random instance to use.
|
||||
* @return List<ItemStack> - The list of loot fetched.
|
||||
*/
|
||||
public List<ItemStack> getLoot(Random r) {
|
||||
List<ItemStack> itemList = new GlueList<>();
|
||||
for(Pool pool : pools) {
|
||||
itemList.addAll(pool.getItems(r));
|
||||
}
|
||||
return itemList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills an Inventory with loot.
|
||||
*
|
||||
* @param i The Inventory to fill.
|
||||
* @param r The The Random instance to use.
|
||||
*/
|
||||
public void fillInventory(Inventory i, Random r) {
|
||||
List<ItemStack> loot = getLoot(r);
|
||||
for(ItemStack stack : loot) {
|
||||
int attempts = 0;
|
||||
while(stack.getAmount() != 0 && attempts < 10) {
|
||||
ItemStack newStack = stack.clone();
|
||||
newStack.setAmount(1);
|
||||
int slot = r.nextInt(i.getSize());
|
||||
ItemStack slotItem = i.getItem(slot);
|
||||
if(slotItem == null) {
|
||||
i.setItem(slot, newStack);
|
||||
stack.setAmount(stack.getAmount() - 1);
|
||||
} else if(slotItem.getType().equals(newStack.getType())) {
|
||||
ItemStack dep = newStack.clone();
|
||||
dep.setAmount(newStack.getAmount() + slotItem.getAmount());
|
||||
i.setItem(slot, dep);
|
||||
stack.setAmount(stack.getAmount() - 1);
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.dfsek.terra.api.structures.loot;
|
||||
|
||||
import com.dfsek.terra.api.math.ProbabilityCollection;
|
||||
import com.dfsek.terra.api.platform.TerraPlugin;
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import net.jafama.FastMath;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Representation of a Loot Table pool, or a set of items to be fetched independently.
|
||||
*/
|
||||
public class Pool {
|
||||
private final int max;
|
||||
private final int min;
|
||||
private final ProbabilityCollection<Entry> entries;
|
||||
|
||||
/**
|
||||
* Instantiates a Pool from a JSON representation.
|
||||
*
|
||||
* @param pool The JSON Object to instantiate from.
|
||||
*/
|
||||
public Pool(JSONObject pool, TerraPlugin main) {
|
||||
entries = new ProbabilityCollection<>();
|
||||
Object amount = pool.get("rolls");
|
||||
if(amount instanceof Long) {
|
||||
max = FastMath.toIntExact((Long) amount);
|
||||
min = FastMath.toIntExact((Long) amount);
|
||||
} else {
|
||||
max = FastMath.toIntExact((Long) ((JSONObject) amount).get("max"));
|
||||
min = FastMath.toIntExact((Long) ((JSONObject) amount).get("min"));
|
||||
}
|
||||
|
||||
for(Object entryJSON : (JSONArray) pool.get("entries")) {
|
||||
Entry entry = new Entry((JSONObject) entryJSON, main);
|
||||
entries.add(entry, FastMath.toIntExact(entry.getWeight()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of items from the pool using the provided Random instance.
|
||||
*
|
||||
* @param r The Random instance to use.
|
||||
* @return List<ItemStack> - The list of items fetched.
|
||||
*/
|
||||
public List<ItemStack> getItems(Random r) {
|
||||
|
||||
int rolls = r.nextInt(max - min + 1) + min;
|
||||
List<ItemStack> items = new GlueList<>();
|
||||
for(int i = 0; i < rolls; i++) {
|
||||
items.add(entries.get(r).getItem(r));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.dfsek.terra.api.structures.loot.functions;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Loot Function fot setting the amount of an item.
|
||||
*/
|
||||
public class AmountFunction implements Function {
|
||||
private final int max;
|
||||
private final int min;
|
||||
|
||||
/**
|
||||
* Instantiates an AmountFunction.
|
||||
*
|
||||
* @param min Minimum amount.
|
||||
* @param max Maximum amount.
|
||||
*/
|
||||
public AmountFunction(int min, int max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the function to an ItemStack.
|
||||
*
|
||||
* @param original The ItemStack on which to apply the function.
|
||||
* @param r The Random instance to use.
|
||||
* @return - ItemStack - The mutated ItemStack.
|
||||
*/
|
||||
@Override
|
||||
public ItemStack apply(ItemStack original, Random r) {
|
||||
original.setAmount(r.nextInt(max - min + 1) + min);
|
||||
return original;
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.dfsek.terra.api.structures.loot.functions;
|
||||
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.platform.inventory.item.Damageable;
|
||||
import com.dfsek.terra.api.platform.inventory.item.ItemMeta;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Loot Function for setting the damage on items in Loot Tables
|
||||
*/
|
||||
public class DamageFunction implements Function {
|
||||
private final int max;
|
||||
private final int min;
|
||||
|
||||
/**
|
||||
* Instantiates a DamageFunction.
|
||||
*
|
||||
* @param min Minimum amount of damage (percentage, out of 100)
|
||||
* @param max Maximum amount of damage (percentage, out of 100)
|
||||
*/
|
||||
public DamageFunction(int min, int max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the function to an ItemStack.
|
||||
*
|
||||
* @param original The ItemStack on which to apply the function.
|
||||
* @param r The Random instance to use.
|
||||
* @return - ItemStack - The mutated ItemStack.
|
||||
*/
|
||||
@Override
|
||||
public ItemStack apply(ItemStack original, Random r) {
|
||||
double itemDurability = (r.nextDouble() * (max - min)) + min;
|
||||
Damageable damage = (Damageable) original.getItemMeta();
|
||||
damage.setDamage((int) (original.getType().getMaxDurability() - (itemDurability / 100) * original.getType().getMaxDurability()));
|
||||
original.setItemMeta((ItemMeta) damage);
|
||||
return original;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.dfsek.terra.api.structures.loot.functions;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.platform.inventory.ItemStack;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Interface for mutating items in Loot Tables.
|
||||
*/
|
||||
public interface Function {
|
||||
/**
|
||||
* Applies the function to an ItemStack.
|
||||
*
|
||||
* @param original The ItemStack on which to apply the function.
|
||||
* @param r The Random instance to use.
|
||||
* @return - ItemStack - The mutated ItemStack.
|
||||
*/
|
||||
ItemStack apply(ItemStack original, Random r);
|
||||
}
|
||||
@@ -0,0 +1,477 @@
|
||||
package com.dfsek.terra.api.structures.parser;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Block;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Item;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Keyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.parser.lang.constants.BooleanConstant;
|
||||
import com.dfsek.terra.api.structures.parser.lang.constants.ConstantExpression;
|
||||
import com.dfsek.terra.api.structures.parser.lang.constants.NumericConstant;
|
||||
import com.dfsek.terra.api.structures.parser.lang.constants.StringConstant;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.AbsFunction;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.PowFunction;
|
||||
import com.dfsek.terra.api.structures.parser.lang.functions.builtin.SqrtFunction;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.BreakKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.ContinueKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.FailKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.flow.ReturnKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.looplike.ForKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.looplike.IfKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.keywords.looplike.WhileKeyword;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.BinaryOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanAndOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanNotOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.BooleanOrOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.ConcatenationOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.DivisionOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.MultiplicationOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.NumberAdditionOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.SubtractionOperation;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.statements.EqualsStatement;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.statements.GreaterOrEqualsThanStatement;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.statements.GreaterThanStatement;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.statements.LessThanOrEqualsStatement;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.statements.LessThanStatement;
|
||||
import com.dfsek.terra.api.structures.parser.lang.operations.statements.NotEqualsStatement;
|
||||
import com.dfsek.terra.api.structures.parser.lang.variables.Assignment;
|
||||
import com.dfsek.terra.api.structures.parser.lang.variables.BooleanVariable;
|
||||
import com.dfsek.terra.api.structures.parser.lang.variables.Getter;
|
||||
import com.dfsek.terra.api.structures.parser.lang.variables.NumberVariable;
|
||||
import com.dfsek.terra.api.structures.parser.lang.variables.StringVariable;
|
||||
import com.dfsek.terra.api.structures.parser.lang.variables.Variable;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Token;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Tokenizer;
|
||||
import com.dfsek.terra.api.structures.tokenizer.exceptions.TokenizerException;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class Parser {
|
||||
private final String data;
|
||||
private final Map<String, FunctionBuilder<? extends Function<?>>> functions = new HashMap<>();
|
||||
private final Set<String> builtinFunctions = Sets.newHashSet("abs", "sqrt", "pow");
|
||||
|
||||
private String id;
|
||||
|
||||
public Parser(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Parser addFunction(String name, FunctionBuilder<? extends Function<?>> functionBuilder) {
|
||||
functions.put(name, functionBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse input
|
||||
*
|
||||
* @return executable {@link Block}
|
||||
* @throws ParseException If parsing fails.
|
||||
*/
|
||||
public Block parse() throws ParseException {
|
||||
Tokenizer tokenizer = new Tokenizer(data);
|
||||
|
||||
TokenHolder tokens = new TokenHolder();
|
||||
try {
|
||||
Token t = tokenizer.fetch();
|
||||
while(t != null) {
|
||||
tokens.add(t);
|
||||
t = tokenizer.fetch();
|
||||
}
|
||||
} catch(TokenizerException e) {
|
||||
throw new ParseException("Failed to tokenize input", new Position(0, 0), e);
|
||||
}
|
||||
|
||||
// Parse ID
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.ID); // First token must be ID
|
||||
Token idToken = tokens.get();
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STRING); // Second token must be string literal containing ID
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
this.id = idToken.getContent();
|
||||
|
||||
// Check for dangling brackets
|
||||
int blockLevel = 0;
|
||||
for(Token t : tokens.getTokens()) {
|
||||
if(t.getType().equals(Token.Type.BLOCK_BEGIN)) blockLevel++;
|
||||
else if(t.getType().equals(Token.Type.BLOCK_END)) blockLevel--;
|
||||
if(blockLevel < 0) throw new ParseException("Dangling closing brace", t.getPosition());
|
||||
}
|
||||
if(blockLevel != 0)
|
||||
throw new ParseException("Dangling opening brace", tokens.getTokens().get(tokens.getTokens().size() - 1).getPosition());
|
||||
|
||||
return parseBlock(tokens, new HashMap<>(), false);
|
||||
}
|
||||
|
||||
|
||||
private Keyword<?> parseLoopLike(TokenHolder tokens, Map<String, Variable<?>> variableMap, boolean loop) throws ParseException {
|
||||
|
||||
Token identifier = tokens.consume();
|
||||
ParserUtil.checkType(identifier, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
|
||||
|
||||
switch(identifier.getType()) {
|
||||
case FOR_LOOP:
|
||||
return parseForLoop(tokens, variableMap, identifier.getPosition());
|
||||
case IF_STATEMENT:
|
||||
return parseIfStatement(tokens, variableMap, identifier.getPosition(), loop);
|
||||
case WHILE_LOOP:
|
||||
return parseWhileLoop(tokens, variableMap, identifier.getPosition());
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
private WhileKeyword parseWhileLoop(TokenHolder tokens, Map<String, Variable<?>> variableMap, Position start) throws ParseException {
|
||||
Returnable<?> first = parseExpression(tokens, true, variableMap);
|
||||
ParserUtil.checkReturnType(first, Returnable.ReturnType.BOOLEAN);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
|
||||
return new WhileKeyword(parseStatementBlock(tokens, variableMap, true), (Returnable<Boolean>) first, start); // While loop
|
||||
}
|
||||
|
||||
private IfKeyword parseIfStatement(TokenHolder tokens, Map<String, Variable<?>> variableMap, Position start, boolean loop) throws ParseException {
|
||||
Returnable<?> condition = parseExpression(tokens, true, variableMap);
|
||||
ParserUtil.checkReturnType(condition, Returnable.ReturnType.BOOLEAN);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
|
||||
Block elseBlock = null;
|
||||
Block statement = parseStatementBlock(tokens, variableMap, loop);
|
||||
|
||||
List<IfKeyword.Pair<Returnable<Boolean>, Block>> elseIf = new GlueList<>();
|
||||
|
||||
while(tokens.hasNext() && tokens.get().getType().equals(Token.Type.ELSE)) {
|
||||
tokens.consume(); // Consume else.
|
||||
if(tokens.get().getType().equals(Token.Type.IF_STATEMENT)) {
|
||||
tokens.consume(); // Consume if.
|
||||
Returnable<?> elseCondition = parseExpression(tokens, true, variableMap);
|
||||
ParserUtil.checkReturnType(elseCondition, Returnable.ReturnType.BOOLEAN);
|
||||
elseIf.add(new IfKeyword.Pair<>((Returnable<Boolean>) elseCondition, parseStatementBlock(tokens, variableMap, loop)));
|
||||
} else {
|
||||
elseBlock = parseStatementBlock(tokens, variableMap, loop);
|
||||
break; // Else must be last.
|
||||
}
|
||||
}
|
||||
|
||||
return new IfKeyword(statement, (Returnable<Boolean>) condition, elseIf, elseBlock, start); // If statement
|
||||
}
|
||||
|
||||
private Block parseStatementBlock(TokenHolder tokens, Map<String, Variable<?>> variableMap, boolean loop) throws ParseException {
|
||||
|
||||
if(tokens.get().getType().equals(Token.Type.BLOCK_BEGIN)) {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN);
|
||||
Block block = parseBlock(tokens, variableMap, loop);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_END);
|
||||
return block;
|
||||
} else {
|
||||
Position position = tokens.get().getPosition();
|
||||
Block block = new Block(Collections.singletonList(parseItem(tokens, variableMap, loop)), position);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
private ForKeyword parseForLoop(TokenHolder tokens, Map<String, Variable<?>> old, Position start) throws ParseException {
|
||||
Map<String, Variable<?>> variableMap = new HashMap<>(old); // New scope
|
||||
Token f = tokens.get();
|
||||
ParserUtil.checkType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER);
|
||||
Item<?> initializer;
|
||||
if(f.isVariableDeclaration()) {
|
||||
Variable<?> forVar = parseVariableDeclaration(tokens, ParserUtil.getVariableReturnType(f));
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
|
||||
Token name = tokens.get();
|
||||
|
||||
if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
|
||||
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
|
||||
|
||||
initializer = parseAssignment(forVar, tokens, variableMap);
|
||||
variableMap.put(name.getContent(), forVar);
|
||||
} else initializer = parseExpression(tokens, true, variableMap);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
Returnable<?> conditional = parseExpression(tokens, true, variableMap);
|
||||
ParserUtil.checkReturnType(conditional, Returnable.ReturnType.BOOLEAN);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
|
||||
Item<?> incrementer;
|
||||
Token token = tokens.get();
|
||||
if(variableMap.containsKey(token.getContent())) { // Assume variable assignment
|
||||
Variable<?> variable = variableMap.get(token.getContent());
|
||||
incrementer = parseAssignment(variable, tokens, variableMap);
|
||||
} else incrementer = parseFunction(tokens, true, variableMap);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
|
||||
return new ForKeyword(parseStatementBlock(tokens, variableMap, true), initializer, (Returnable<Boolean>) conditional, incrementer, start);
|
||||
}
|
||||
|
||||
private Returnable<?> parseExpression(TokenHolder tokens, boolean full, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||
boolean booleanInverted = false; // Check for boolean not operator
|
||||
if(tokens.get().getType().equals(Token.Type.BOOLEAN_NOT)) {
|
||||
booleanInverted = true;
|
||||
tokens.consume();
|
||||
}
|
||||
|
||||
Token id = tokens.get();
|
||||
|
||||
ParserUtil.checkType(id, Token.Type.IDENTIFIER, Token.Type.BOOLEAN, Token.Type.STRING, Token.Type.NUMBER, Token.Type.GROUP_BEGIN);
|
||||
|
||||
Returnable<?> expression;
|
||||
if(id.isConstant()) {
|
||||
expression = parseConstantExpression(tokens);
|
||||
} else if(id.getType().equals(Token.Type.GROUP_BEGIN)) { // Parse grouped expression
|
||||
expression = parseGroup(tokens, variableMap);
|
||||
} else {
|
||||
if(functions.containsKey(id.getContent()) || builtinFunctions.contains(id.getContent()))
|
||||
expression = parseFunction(tokens, false, variableMap);
|
||||
else if(variableMap.containsKey(id.getContent())) {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER);
|
||||
expression = new Getter(variableMap.get(id.getContent()));
|
||||
} else throw new ParseException("Unexpected token \" " + id.getContent() + "\"", id.getPosition());
|
||||
}
|
||||
|
||||
if(booleanInverted) { // Invert operation if boolean not detected
|
||||
ParserUtil.checkReturnType(expression, Returnable.ReturnType.BOOLEAN);
|
||||
expression = new BooleanNotOperation((Returnable<Boolean>) expression, expression.getPosition());
|
||||
}
|
||||
|
||||
if(full && tokens.get().isBinaryOperator()) { // Parse binary operations
|
||||
return parseBinaryOperation(expression, tokens, variableMap);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
private ConstantExpression<?> parseConstantExpression(TokenHolder tokens) throws ParseException {
|
||||
Token constantToken = tokens.consume();
|
||||
Position position = constantToken.getPosition();
|
||||
switch(constantToken.getType()) {
|
||||
case NUMBER:
|
||||
String content = constantToken.getContent();
|
||||
return new NumericConstant(content.contains(".") ? Double.parseDouble(content) : Integer.parseInt(content), position);
|
||||
case STRING:
|
||||
return new StringConstant(constantToken.getContent(), position);
|
||||
case BOOLEAN:
|
||||
return new BooleanConstant(Boolean.parseBoolean(constantToken.getContent()), position);
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported constant token: " + constantToken.getType() + " at position: " + position);
|
||||
}
|
||||
}
|
||||
|
||||
private Returnable<?> parseGroup(TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
|
||||
Returnable<?> expression = parseExpression(tokens, true, variableMap); // Parse inside of group as a separate expression
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
return expression;
|
||||
}
|
||||
|
||||
|
||||
private BinaryOperation<?, ?> parseBinaryOperation(Returnable<?> left, TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||
Token binaryOperator = tokens.consume();
|
||||
ParserUtil.checkBinaryOperator(binaryOperator);
|
||||
|
||||
Returnable<?> right = parseExpression(tokens, false, variableMap);
|
||||
|
||||
Token other = tokens.get();
|
||||
if(ParserUtil.hasPrecedence(binaryOperator.getType(), other.getType())) {
|
||||
return assemble(left, parseBinaryOperation(right, tokens, variableMap), binaryOperator);
|
||||
} else if(other.isBinaryOperator()) {
|
||||
return parseBinaryOperation(assemble(left, right, binaryOperator), tokens, variableMap);
|
||||
}
|
||||
return assemble(left, right, binaryOperator);
|
||||
}
|
||||
|
||||
private BinaryOperation<?, ?> assemble(Returnable<?> left, Returnable<?> right, Token binaryOperator) throws ParseException {
|
||||
if(binaryOperator.isStrictNumericOperator())
|
||||
ParserUtil.checkArithmeticOperation(left, right, binaryOperator); // Numeric type checking
|
||||
if(binaryOperator.isStrictBooleanOperator()) ParserUtil.checkBooleanOperation(left, right, binaryOperator); // Boolean type checking
|
||||
switch(binaryOperator.getType()) {
|
||||
case ADDITION_OPERATOR:
|
||||
if(left.returnType().equals(Returnable.ReturnType.NUMBER) && right.returnType().equals(Returnable.ReturnType.NUMBER)) {
|
||||
return new NumberAdditionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
}
|
||||
return new ConcatenationOperation((Returnable<Object>) left, (Returnable<Object>) right, binaryOperator.getPosition());
|
||||
case SUBTRACTION_OPERATOR:
|
||||
return new SubtractionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case MULTIPLICATION_OPERATOR:
|
||||
return new MultiplicationOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case DIVISION_OPERATOR:
|
||||
return new DivisionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case EQUALS_OPERATOR:
|
||||
return new EqualsStatement((Returnable<Object>) left, (Returnable<Object>) right, binaryOperator.getPosition());
|
||||
case NOT_EQUALS_OPERATOR:
|
||||
return new NotEqualsStatement((Returnable<Object>) left, (Returnable<Object>) right, binaryOperator.getPosition());
|
||||
case GREATER_THAN_OPERATOR:
|
||||
return new GreaterThanStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case LESS_THAN_OPERATOR:
|
||||
return new LessThanStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case GREATER_THAN_OR_EQUALS_OPERATOR:
|
||||
return new GreaterOrEqualsThanStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case LESS_THAN_OR_EQUALS_OPERATOR:
|
||||
return new LessThanOrEqualsStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case BOOLEAN_AND:
|
||||
return new BooleanAndOperation((Returnable<Boolean>) left, (Returnable<Boolean>) right, binaryOperator.getPosition());
|
||||
case BOOLEAN_OR:
|
||||
return new BooleanOrOperation((Returnable<Boolean>) left, (Returnable<Boolean>) right, binaryOperator.getPosition());
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported binary operator: " + binaryOperator.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private Variable<?> parseVariableDeclaration(TokenHolder tokens, Returnable.ReturnType type) throws ParseException {
|
||||
ParserUtil.checkVarType(tokens.get(), type); // Check for type mismatch
|
||||
switch(type) {
|
||||
case NUMBER:
|
||||
return new NumberVariable(0d, tokens.get().getPosition());
|
||||
case STRING:
|
||||
return new StringVariable("", tokens.get().getPosition());
|
||||
case BOOLEAN:
|
||||
return new BooleanVariable(false, tokens.get().getPosition());
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported variable type: " + type);
|
||||
}
|
||||
|
||||
private Block parseBlock(TokenHolder tokens, Map<String, Variable<?>> superVars, boolean loop) throws ParseException {
|
||||
List<Item<?>> parsedItems = new GlueList<>();
|
||||
|
||||
Map<String, Variable<?>> parsedVariables = new HashMap<>(superVars); // New hashmap as to not mutate parent scope's declarations.
|
||||
|
||||
Token first = tokens.get();
|
||||
|
||||
while(tokens.hasNext()) {
|
||||
Token token = tokens.get();
|
||||
if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
|
||||
parsedItems.add(parseItem(tokens, parsedVariables, loop));
|
||||
if(tokens.hasNext() && !token.isLoopLike()) ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
}
|
||||
return new Block(parsedItems, first.getPosition());
|
||||
}
|
||||
|
||||
private Item<?> parseItem(TokenHolder tokens, Map<String, Variable<?>> variableMap, boolean loop) throws ParseException {
|
||||
Token token = tokens.get();
|
||||
if(loop) ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
|
||||
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL);
|
||||
else ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
|
||||
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN, Token.Type.FAIL);
|
||||
|
||||
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc)
|
||||
return parseLoopLike(tokens, variableMap, loop);
|
||||
} else if(token.isIdentifier()) { // Parse identifiers
|
||||
if(variableMap.containsKey(token.getContent())) { // Assume variable assignment
|
||||
Variable<?> variable = variableMap.get(token.getContent());
|
||||
return parseAssignment(variable, tokens, variableMap);
|
||||
} else return parseFunction(tokens, true, variableMap);
|
||||
} else if(token.isVariableDeclaration()) {
|
||||
Variable<?> temp = parseVariableDeclaration(tokens, ParserUtil.getVariableReturnType(token));
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
|
||||
Token name = tokens.get();
|
||||
ParserUtil.checkType(name, Token.Type.IDENTIFIER); // Name must be an identifier.
|
||||
|
||||
if(functions.containsKey(name.getContent()) || variableMap.containsKey(name.getContent()) || builtinFunctions.contains(name.getContent()))
|
||||
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
|
||||
|
||||
variableMap.put(name.getContent(), temp);
|
||||
|
||||
|
||||
return parseAssignment(temp, tokens, variableMap);
|
||||
} else if(token.getType().equals(Token.Type.RETURN)) return new ReturnKeyword(tokens.consume().getPosition());
|
||||
else if(token.getType().equals(Token.Type.BREAK)) return new BreakKeyword(tokens.consume().getPosition());
|
||||
else if(token.getType().equals(Token.Type.CONTINUE)) return new ContinueKeyword(tokens.consume().getPosition());
|
||||
else if(token.getType().equals(Token.Type.FAIL)) return new FailKeyword(tokens.consume().getPosition());
|
||||
else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
|
||||
}
|
||||
|
||||
private Assignment<?> parseAssignment(Variable<?> variable, TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||
Token name = tokens.get();
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT);
|
||||
|
||||
Returnable<?> expression = parseExpression(tokens, true, variableMap);
|
||||
|
||||
ParserUtil.checkReturnType(expression, variable.getType());
|
||||
|
||||
return new Assignment<>((Variable<Object>) variable, (Returnable<Object>) expression, name.getPosition());
|
||||
}
|
||||
|
||||
private Function<?> parseFunction(TokenHolder tokens, boolean fullStatement, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||
Token identifier = tokens.consume();
|
||||
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
|
||||
|
||||
if(!functions.containsKey(identifier.getContent()) && !builtinFunctions.contains(identifier.getContent()))
|
||||
throw new ParseException("No such function \"" + identifier.getContent() + "\"", identifier.getPosition());
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); // Second is body begin
|
||||
|
||||
|
||||
List<Returnable<?>> args = getArgs(tokens, variableMap); // Extract arguments, consume the rest.
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); // Remove body end
|
||||
|
||||
if(fullStatement) ParserUtil.checkType(tokens.get(), Token.Type.STATEMENT_END);
|
||||
|
||||
if(functions.containsKey(identifier.getContent())) {
|
||||
FunctionBuilder<?> builder = functions.get(identifier.getContent());
|
||||
|
||||
if(builder.argNumber() != -1 && args.size() != builder.argNumber())
|
||||
throw new ParseException("Expected " + builder.argNumber() + " arguments, found " + args.size(), identifier.getPosition());
|
||||
|
||||
for(int i = 0; i < args.size(); i++) {
|
||||
Returnable<?> argument = args.get(i);
|
||||
if(builder.getArgument(i) == null)
|
||||
throw new ParseException("Unexpected argument at position " + i + " in function " + identifier.getContent(), identifier.getPosition());
|
||||
ParserUtil.checkReturnType(argument, builder.getArgument(i));
|
||||
}
|
||||
return builder.build(args, identifier.getPosition());
|
||||
} else {
|
||||
switch(identifier.getContent()) {
|
||||
case "abs":
|
||||
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
|
||||
if(args.size() != 1)
|
||||
throw new ParseException("Expected 1 argument; found " + args.size(), identifier.getPosition());
|
||||
return new AbsFunction(identifier.getPosition(), (Returnable<Number>) args.get(0));
|
||||
case "sqrt":
|
||||
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
|
||||
if(args.size() != 1)
|
||||
throw new ParseException("Expected 1 argument; found " + args.size(), identifier.getPosition());
|
||||
return new SqrtFunction(identifier.getPosition(), (Returnable<Number>) args.get(0));
|
||||
case "pow":
|
||||
ParserUtil.checkReturnType(args.get(0), Returnable.ReturnType.NUMBER);
|
||||
ParserUtil.checkReturnType(args.get(1), Returnable.ReturnType.NUMBER);
|
||||
if(args.size() != 2)
|
||||
throw new ParseException("Expected 1 argument; found " + args.size(), identifier.getPosition());
|
||||
return new PowFunction(identifier.getPosition(), (Returnable<Number>) args.get(0), (Returnable<Number>) args.get(1));
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<Returnable<?>> getArgs(TokenHolder tokens, Map<String, Variable<?>> variableMap) throws ParseException {
|
||||
List<Returnable<?>> args = new GlueList<>();
|
||||
|
||||
while(!tokens.get().getType().equals(Token.Type.GROUP_END)) {
|
||||
args.add(parseExpression(tokens, true, variableMap));
|
||||
ParserUtil.checkType(tokens.get(), Token.Type.SEPARATOR, Token.Type.GROUP_END);
|
||||
if(tokens.get().getType().equals(Token.Type.SEPARATOR)) tokens.consume();
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.dfsek.terra.api.structures.parser;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.api.structures.parser.lang.Returnable;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Token;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ParserUtil {
|
||||
|
||||
private static final Map<Token.Type, List<Token.Type>> PRECEDENCE = new HashMap<>();
|
||||
private static final List<Token.Type> ARITHMETIC = Arrays.asList(Token.Type.ADDITION_OPERATOR, Token.Type.SUBTRACTION_OPERATOR, Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR);
|
||||
private static final List<Token.Type> COMPARISON = Arrays.asList(Token.Type.EQUALS_OPERATOR, Token.Type.NOT_EQUALS_OPERATOR, Token.Type.LESS_THAN_OPERATOR, Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, Token.Type.GREATER_THAN_OPERATOR, Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR);
|
||||
|
||||
static { // Setup precedence
|
||||
PRECEDENCE.put(Token.Type.ADDITION_OPERATOR, Arrays.asList(Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR));
|
||||
PRECEDENCE.put(Token.Type.SUBTRACTION_OPERATOR, Arrays.asList(Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR));
|
||||
PRECEDENCE.put(Token.Type.EQUALS_OPERATOR, ARITHMETIC);
|
||||
PRECEDENCE.put(Token.Type.NOT_EQUALS_OPERATOR, ARITHMETIC);
|
||||
PRECEDENCE.put(Token.Type.GREATER_THAN_OPERATOR, ARITHMETIC);
|
||||
PRECEDENCE.put(Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR, ARITHMETIC);
|
||||
PRECEDENCE.put(Token.Type.LESS_THAN_OPERATOR, ARITHMETIC);
|
||||
PRECEDENCE.put(Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, ARITHMETIC);
|
||||
PRECEDENCE.put(Token.Type.BOOLEAN_AND, COMPARISON);
|
||||
PRECEDENCE.put(Token.Type.BOOLEAN_OR, COMPARISON);
|
||||
}
|
||||
|
||||
public static void checkType(Token token, Token.Type... expected) throws ParseException {
|
||||
for(Token.Type type : expected) if(token.getType().equals(type)) return;
|
||||
throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType(), token.getPosition());
|
||||
}
|
||||
|
||||
public static void checkReturnType(Returnable<?> returnable, Returnable.ReturnType... types) throws ParseException {
|
||||
for(Returnable.ReturnType type : types) if(returnable.returnType().equals(type)) return;
|
||||
throw new ParseException("Expected " + Arrays.toString(types) + " but found " + returnable.returnType(), returnable.getPosition());
|
||||
}
|
||||
|
||||
public static void checkArithmeticOperation(Returnable<?> left, Returnable<?> right, Token operation) throws ParseException {
|
||||
if(!left.returnType().equals(Returnable.ReturnType.NUMBER) || !right.returnType().equals(Returnable.ReturnType.NUMBER)) {
|
||||
throw new ParseException("Operation " + operation.getType() + " not supported between " + left.returnType() + " and " + right.returnType(), operation.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkBooleanOperation(Returnable<?> left, Returnable<?> right, Token operation) throws ParseException {
|
||||
if(!left.returnType().equals(Returnable.ReturnType.BOOLEAN) || !right.returnType().equals(Returnable.ReturnType.BOOLEAN)) {
|
||||
throw new ParseException("Operation " + operation.getType() + " not supported between " + left.returnType() + " and " + right.returnType(), operation.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkVarType(Token token, Returnable.ReturnType returnType) throws ParseException {
|
||||
if(returnType.equals(Returnable.ReturnType.STRING) && token.getType().equals(Token.Type.STRING_VARIABLE)) return;
|
||||
if(returnType.equals(Returnable.ReturnType.NUMBER) && token.getType().equals(Token.Type.NUMBER_VARIABLE)) return;
|
||||
if(returnType.equals(Returnable.ReturnType.BOOLEAN) && token.getType().equals(Token.Type.BOOLEAN_VARIABLE)) return;
|
||||
throw new ParseException("Type mismatch, cannot convert from " + returnType + " to " + token.getType(), token.getPosition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if token is a binary operator
|
||||
*
|
||||
* @param token Token to check
|
||||
* @throws ParseException If token isn't a binary operator
|
||||
*/
|
||||
public static void checkBinaryOperator(Token token) throws ParseException {
|
||||
if(!token.isBinaryOperator())
|
||||
throw new ParseException("Expected binary operator, found " + token.getType(), token.getPosition());
|
||||
}
|
||||
|
||||
public static Returnable.ReturnType getVariableReturnType(Token varToken) throws ParseException {
|
||||
switch(varToken.getType()) {
|
||||
case NUMBER_VARIABLE:
|
||||
return Returnable.ReturnType.NUMBER;
|
||||
case STRING_VARIABLE:
|
||||
return Returnable.ReturnType.STRING;
|
||||
case BOOLEAN_VARIABLE:
|
||||
return Returnable.ReturnType.BOOLEAN;
|
||||
default:
|
||||
throw new ParseException("Unexpected token " + varToken.getType() + "; expected variable declaration", varToken.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasPrecedence(Token.Type first, Token.Type second) {
|
||||
if(!PRECEDENCE.containsKey(first)) return false;
|
||||
return PRECEDENCE.get(first).contains(second);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.dfsek.terra.api.structures.parser;
|
||||
|
||||
import com.dfsek.terra.api.structures.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Token;
|
||||
import com.dfsek.terra.api.util.GlueList;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Data structure to hold tokens, where items are inserted at the top and removed from the bottom.
|
||||
*/
|
||||
public class TokenHolder {
|
||||
private final List<Token> tokens = new GlueList<>();
|
||||
private Position last;
|
||||
|
||||
/**
|
||||
* Add a token to the top of the stack.
|
||||
*
|
||||
* @param token Token to add
|
||||
*/
|
||||
public void add(Token token) {
|
||||
tokens.add(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token at the bottom of the stack.
|
||||
*
|
||||
* @return First token
|
||||
* @throws ParseException If stack is empty
|
||||
*/
|
||||
public Token get() throws ParseException {
|
||||
if(!hasNext()) throw new ParseException("Unexpected end of input", last);
|
||||
Token token = tokens.get(0);
|
||||
last = token.getPosition();
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume (get and remove) the token at the bottom of the stack.
|
||||
*
|
||||
* @return First token
|
||||
* @throws ParseException If stack is empty
|
||||
*/
|
||||
public Token consume() throws ParseException {
|
||||
if(!hasNext()) throw new ParseException("Unexpected end of input", last);
|
||||
Token token = tokens.remove(0);
|
||||
last = token.getPosition();
|
||||
return token;
|
||||
}
|
||||
|
||||
public List<Token> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return tokens.size() > 0;
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.dfsek.terra.api.structures.parser.exceptions;
|
||||
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
public class ParseException extends Exception {
|
||||
private final Position position;
|
||||
|
||||
public ParseException(String message, Position position) {
|
||||
super(message);
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public ParseException(String message, Position position, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return super.getMessage() + ": " + position;
|
||||
}
|
||||
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
import com.dfsek.terra.api.structures.structure.Rotation;
|
||||
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class Block implements Item<Block.ReturnInfo<?>> {
|
||||
private final List<Item<?>> items;
|
||||
private final Position position;
|
||||
|
||||
public Block(List<Item<?>> items, Position position) {
|
||||
this.items = items;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public List<Item<?>> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ReturnInfo<?> apply(Buffer buffer, Rotation rotation, Random random, int recursions) {
|
||||
for(Item<?> item : items) {
|
||||
Object result = item.apply(buffer, rotation, random, recursions);
|
||||
if(result instanceof ReturnInfo) {
|
||||
ReturnInfo<?> level = (ReturnInfo<?>) result;
|
||||
if(!level.getLevel().equals(ReturnLevel.NONE)) return level;
|
||||
}
|
||||
}
|
||||
return new ReturnInfo<>(ReturnLevel.NONE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public static class ReturnInfo<T> {
|
||||
private final ReturnLevel level;
|
||||
private final T data;
|
||||
|
||||
public ReturnInfo(ReturnLevel level, T data) {
|
||||
this.level = level;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public ReturnLevel getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ReturnLevel {
|
||||
NONE(false), BREAK(false), CONTINUE(false), RETURN(true), FAIL(true);
|
||||
|
||||
private final boolean returnFast;
|
||||
|
||||
ReturnLevel(boolean returnFast) {
|
||||
this.returnFast = returnFast;
|
||||
}
|
||||
|
||||
public boolean isReturnFast() {
|
||||
return returnFast;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
import com.dfsek.terra.api.structures.structure.Rotation;
|
||||
import com.dfsek.terra.api.structures.structure.buffer.Buffer;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public interface Item<T> {
|
||||
T apply(Buffer buffer, Rotation rotation, Random random, int recursions);
|
||||
|
||||
Position getPosition();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
public interface Keyword<T> extends Returnable<T> {
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.dfsek.terra.api.structures.parser.lang;
|
||||
|
||||
public interface Returnable<T> extends Item<T> {
|
||||
ReturnType returnType();
|
||||
|
||||
enum ReturnType {
|
||||
NUMBER(true), STRING(true), BOOLEAN(false), VOID(false), OBJECT(false);
|
||||
|
||||
private final boolean comparable;
|
||||
|
||||
ReturnType(boolean comparable) {
|
||||
this.comparable = comparable;
|
||||
}
|
||||
|
||||
public boolean isComparable() {
|
||||
return comparable;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user