├── .gitignore
├── .idea
├── .name
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── fileTemplates
│ ├── code
│ │ └── New Kotlin Function Body.kt
│ └── includes
│ │ └── File Header.java
├── gradle.xml
├── inspectionProfiles
│ └── Project_Default.xml
└── runConfigurations
│ └── io_github_sof3_graphmine_cli_MainKt.xml
├── .travis.yml
├── LICENSE
├── Makefile
├── README.md
├── build.gradle.kts
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── graphmine-cli
├── build.gradle.kts
├── module.md
├── settings.gradle.kts
└── src
│ └── main
│ ├── kotlin
│ └── io
│ │ └── github
│ │ └── sof3
│ │ └── graphmine
│ │ └── cli
│ │ ├── ConsoleReceiver.kt
│ │ ├── ConsoleSender.kt
│ │ ├── TerminalSignal.kt
│ │ └── main.kt
│ └── resources
│ ├── config.kts
│ ├── log4j2.component.properties
│ └── log4j2.yml
├── graphmine-core
├── build.gradle.kts
├── module.md
├── settings.gradle.kts
└── src
│ └── main
│ └── kotlin
│ └── io
│ └── github
│ └── sof3
│ └── graphmine
│ ├── HasLogger.kt
│ ├── Server.kt
│ ├── VersionInfo.kt
│ ├── client
│ ├── Client.kt
│ └── ClientAttachable.kt
│ ├── command
│ ├── Command.kt
│ ├── CommandExecutor.kt
│ ├── CommandMap.kt
│ ├── CommandReceiver.kt
│ ├── CommandSender.kt
│ ├── EmptyOverload.kt
│ ├── Overload.kt
│ ├── RegisteredOverload.kt
│ ├── args
│ │ ├── ClientArg.kt
│ │ ├── CommandArg.kt
│ │ ├── EnumArg.kt
│ │ ├── number.kt
│ │ └── string.kt
│ ├── exception.kt
│ ├── impl
│ │ ├── HelpCommand.kt
│ │ ├── SayCommand.kt
│ │ ├── VersionCommand.kt
│ │ └── package.md
│ └── package.md
│ ├── config
│ ├── ConfigEntryDelegate.kt
│ ├── ConfigGroupSpec.kt
│ ├── ConfigSpec.kt
│ ├── SimpleConfigEntry.kt
│ ├── exception.kt
│ └── spec.kt
│ ├── entity
│ ├── Entity.kt
│ ├── EntityController.kt
│ ├── EntityState.kt
│ ├── EntityViewEvent.kt
│ ├── ExternalView.kt
│ ├── ExternalViewer.kt
│ └── InternalViewer.kt
│ ├── feature
│ ├── FeatureEdge.kt
│ ├── FeatureEvent.kt
│ ├── FeatureGraph.kt
│ ├── FeatureNode.kt
│ └── FeatureNodeInstance.kt
│ ├── scope
│ ├── BaseScope.kt
│ └── Scope.kt
│ └── world
│ ├── Block.kt
│ ├── BlockLocation.kt
│ ├── Blocks.kt
│ ├── Location.kt
│ ├── World.kt
│ ├── WorldPartition.kt
│ ├── WorldUser.kt
│ └── WorldView.kt
├── graphmine-i18n-core
├── build.gradle.kts
├── module.md
├── settings.gradle.kts
└── src
│ ├── main
│ ├── kotlin
│ │ └── io
│ │ │ └── github
│ │ │ └── sof3
│ │ │ └── graphmine
│ │ │ └── i18n
│ │ │ └── core
│ │ │ ├── CoreLang.kt
│ │ │ └── CoreLangLoader.kt
│ └── resources
│ │ └── io
│ │ └── github
│ │ └── sof3
│ │ └── graphmine
│ │ └── i18n
│ │ └── core
│ │ └── en_US.lang.kts
│ └── test
│ └── kotlin
│ └── io
│ └── github
│ └── sof3
│ └── graphmine
│ └── i18n
│ └── core
│ └── TranslationTest_en_US.kt
├── graphmine-i18n
├── build.gradle.kts
├── module.md
├── settings.gradle.kts
└── src
│ └── main
│ └── kotlin
│ └── io
│ └── github
│ └── sof3
│ └── graphmine
│ └── i18n
│ ├── Declaration.kt
│ ├── GroupSpec.kt
│ ├── I18n.kt
│ ├── I18nable.kt
│ ├── LangSpec.kt
│ ├── LiteralI18N.kt
│ └── SpecI18N.kt
├── graphmine-util
├── build.gradle.kts
├── module.md
├── settings.gradle.kts
└── src
│ ├── main
│ ├── kotlin
│ │ └── io
│ │ │ └── github
│ │ │ └── sof3
│ │ │ └── graphmine
│ │ │ └── util
│ │ │ ├── DataUtil.kt
│ │ │ ├── DelegateProvider.kt
│ │ │ ├── KtsBin.kt
│ │ │ ├── KtsLoader.kt
│ │ │ ├── VarDelegateProvider.kt
│ │ │ ├── arrayMaps.kt
│ │ │ ├── error.kt
│ │ │ ├── misc.kt
│ │ │ ├── qualifier
│ │ │ ├── Qualifier.kt
│ │ │ ├── QualifierClashException.kt
│ │ │ ├── QualifierMap.kt
│ │ │ └── package.md
│ │ │ ├── ranges.kt
│ │ │ ├── ref.kt
│ │ │ └── string
│ │ │ └── FormattedStringReader.kt
│ └── resources
│ │ └── META-INF
│ │ └── services
│ │ └── javax.script.ScriptEngineFactory
│ └── test
│ └── kotlin
│ └── io
│ └── github
│ └── sof3
│ └── graphmine
│ └── util
│ ├── string
│ └── FormattedStringReaderSpec.kt
│ └── testUtil.kt
├── settings.gradle.kts
├── util-math
├── build.gradle.kts
├── module.md
├── settings.gradle.kts
└── src
│ └── main
│ └── kotlin
│ └── io
│ └── github
│ └── sof3
│ └── graphmine
│ └── util
│ └── math
│ ├── IntVector3.kt
│ ├── IntVector3Range.kt
│ ├── Side.kt
│ ├── Vector3.kt
│ ├── annotations.kt
│ └── math.kt
└── util-reflect-io
├── build.gradle.kts
├── module.md
├── settings.gradle.kts
└── src
└── main
└── kotlin
└── io
└── github
└── sof3
└── graphmine
└── util
└── reflectio
└── Persistable.kt
/.gitignore:
--------------------------------------------------------------------------------
1 | /data/
2 | /logs/
3 | /graphmine-cli/data/
4 | /graphmine-cli/logs/
5 | /*/out
6 | .idea/*
7 | !.idea/fileTemplates
8 | !.idea/inspectionProfiles
9 | !.idea/.name
10 | !.idea/codeStyles
11 | !.idea/runConfigurations
12 | !.idea/gradle.xml
13 | *.class
14 | *.log
15 | *.ctxt
16 | .mtj.tmp/
17 | *.jar
18 | *.war
19 | *.nar
20 | *.ear
21 | *.zip
22 | *.tar.gz
23 | *.rar
24 | hs_err_pid*
25 | *~
26 | .fuse_hidden*
27 | .directory
28 | .Trash-*
29 | .nfs*
30 | .DS_Store
31 | .AppleDouble
32 | .LSOverride
33 | Icon
34 | ._*
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 | .com.apple.timemachine.donotpresent
42 | .AppleDB
43 | .AppleDesktop
44 | Network Trash Folder
45 | Temporary Items
46 | .apdisk
47 | *.bak
48 | Thumbs.db
49 | ehthumbs.db
50 | ehthumbs_vista.db
51 | *.stackdump
52 | [Dd]esktop.ini
53 | $RECYCLE.BIN/
54 | *.cab
55 | *.msi
56 | *.msix
57 | *.msm
58 | *.msp
59 | *.lnk
60 | .gradle
61 | /build/
62 | /*/build/
63 | gradle-app.setting
64 | !gradle-wrapper.jar
65 | .gradletasknamecache
66 | [._]*.s[a-v][a-z]
67 | [._]*.sw[a-p]
68 | [._]s[a-rt-v][a-z]
69 | [._]ss[a-gi-z]
70 | [._]sw[a-p]
71 | Session.vim
72 | .netrwhist
73 | tags
74 | [._]*.un~
75 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | graphmine
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | GETTERS_AND_SETTERS
84 | KEEP
85 |
86 |
87 | OVERRIDDEN_METHODS
88 | KEEP
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/fileTemplates/code/New Kotlin Function Body.kt:
--------------------------------------------------------------------------------
1 | TODO("not implemented")
--------------------------------------------------------------------------------
/.idea/fileTemplates/includes/File Header.java:
--------------------------------------------------------------------------------
1 | /*
2 | * GraphMine
3 | * Copyright (C) 2018 SOFe
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/io_github_sof3_graphmine_cli_MainKt.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - openjdk8
4 | - oraclejdk8
5 | #- oraclejdk9
6 | env:
7 | global:
8 | - secure: "SuMHzb/Ua8UOH9ayTRyJ1H5xERrZq6pFG0kM8i1nvQcHmKTkfYcP/J/SaXYLhEueCch4m0OVeBCgSKZUxAFEhvTino2ULPpebGHUAtmeBzMIn2jIyOM3qY6oEXfQ6OXV1O3xXp2m/Q7WQXyrnGCiGTBNKJ4uEwvWzaMyocvw0g4RFRrGuhJT8xsceMrxKzyhqDr/Um/c7E2xD58nCc8OmfHXwAlJa1yOzcWwNAdU2jfAF/jFQIfFE/u2OmeT4sNkTgzrsGstiphhIQsUyLglwQrhQvqgaU5Bp//iRAAq0inreVjaA2HJAiU41ZhrYUjOEFa2S6z8JWicT8dsbCKDgspp7+u1NSHUs4k9mxhHhCo/1npbw5e/Uyr78Qin5fLYVEWUwdRDby0q6kJZgjVpbf+LtKMd1nNcDerSf4cI4wRORI0afAZ4mRQC7Fs13JjnUdJs+7ly8QB6/IF4pwziuVwXeBufQzj0VEF4jf7I83F0LWGUENh/98rknQB2UjI5EujLQLT6bU7TWdjXCqLH6QAp8ljGVMJKCXE3hODkXnye+hqjbUH2uYhJwCQjiFTTWOUtlWXnTNRQdOsFG+X6DmC8yi8otHt6Qz4s1/ZCTB78Gl1wSKgf01q+3HPoHrdVmoJFPxMEqo+UPwV6A5ScBRPwt+aLV8WW0xYHXW1jGFA="
9 | before_cache:
10 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
11 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
12 | cache:
13 | directories:
14 | - $HOME/.gradle/caches/
15 | - $HOME/.gradle/wrapper/
16 | script:
17 | - ./gradlew check
18 | after_script:
19 | - cd $TRAVIS_BUILD_DIR && ./gradlew codeCoverageReport
20 | - bash <(curl -s https://codecov.io/bash)
21 | before_deploy:
22 | - ./gradlew graphmine-cli:fatJar dokka generateDependencyGraph
23 | - wget -O ../gh-pages.tar.gz https://github.com/SOF3/GraphMine/archive/gh-pages.tar.gz
24 | - tar xzf ../gh-pages.tar.gz -C ..
25 | - cd ../GraphMine-gh-pages && rm -r api && mkdir api
26 | - cp -r $TRAVIS_BUILD_DIR/*/build/javadoc/* api
27 | - cp $TRAVIS_BUILD_DIR/build/reports/dependency-graph/dependency-graph.png depGraph.png
28 | - cp $TRAVIS_BUILD_DIR/graphmine-cli/build/libs/graphmine-cli-fat-*.jar latestMaster.jar
29 | deploy:
30 | skip-cleanup: true
31 | on:
32 | branch: master
33 | jdk: openjdk8
34 | provider: pages
35 | github-token: $GITHUB_TOKEN
36 | local-dir: $TRAVIS_BUILD_DIR/../GraphMine-gh-pages
37 | keep-history: true
38 | committer-from-gh: true
39 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: clean
2 |
3 | clean:
4 | rm -r build \
5 | graphmine-cli/build \
6 | graphmine-core/build \
7 | graphmine-i18n/build \
8 | graphmine-i18n-core/build \
9 | graphmine-util/build \
10 | util-math/build \
11 | util-reflect-io/build \
12 | 2>/dev/null
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GraphMine
2 | An experimental server software project. DO NOT TRY TO USE THIS. This is just a proof of concept.
3 |
4 | [](https://travis-ci.org/SOF3/GraphMine)
5 |
6 | ## What is this?
7 | This is just yet another of SOFe's useless projects where he just writes the code and never tests it. **Do not expect a
8 | working server software from someone who doesn't even have a client.**
9 |
10 | Yes, there are unit tests, but there are no integration tests.
11 |
12 | ## So why is this here?
13 | Often, I have some cool ideas for PocketMine, but the idea is too big, complicated or impractical to be implemented on
14 | PocketMine. Since I am addicted in implementing crazy stuff, I created this repo to satisfy my own desires for
15 | sophistication. Most ideas here are probably too impractical, e.g. a lot of effort is put into making sure multiple
16 | players can control the same entity at the same time but see different things. And some effort is put into making sure
17 | the server can run fluently as a pure proxy, and the server can also run fluently as a pure backend without actual
18 | connecting players. Sound confusing and pointless? Yes, pointlessness is the point of this project.
19 |
20 | In addition, Kotlin is a cool language that I want to master, but I don't have cool ideas to work on, so I resorted to
21 | Minecraft server software again. I am too stupid to learn to make anything other than Minecraft-related stuff.
22 |
23 | No project is perfect, but I hope this one is going to *look* better than PocketMine.
24 |
25 | ## How to run the project?
26 | Development jar executables can be found in https://sof3.github.io/GraphMine/latestMaster.jar (but make sure you
27 | actually want to run it -- it doesn't do anything useful!)
28 |
29 | Oracle JDK 9 is not supported, but Oracle JDK 8 and OpenJDK 8 are both OK.
30 |
31 | #### Project dependency graph
32 |
33 | 
34 |
35 | ## Why is it called GraphMine?
36 | GraphMine organizes features in a graph model. Features can be appended to or removed from the graph with a more
37 | intuitive approach. However, the exact modelling of this graph is still yet to be defined.
38 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension
2 | import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension.Generator
3 | import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorPlugin
4 | import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorTask
5 | import guru.nidi.graphviz.attribute.Color
6 | import guru.nidi.graphviz.attribute.Style
7 | import guru.nidi.graphviz.model.MutableNode
8 | import java.nio.file.Files
9 | import org.gradle.api.tasks.testing.logging.TestLogEvent
10 | import org.gradle.internal.impldep.org.testng.reporters.XMLUtils.xml
11 | import org.gradle.testing.jacoco.tasks.JacocoReport
12 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
13 | import org.jetbrains.dokka.gradle.DokkaTask
14 |
15 | /*
16 | * GraphMine
17 | * Copyright (C) 2018 SOFe
18 | *
19 | * This program is free software: you can redistribute it and/or modify
20 | * it under the terms of the GNU Affero General Public License as published
21 | * by the Free Software Foundation, either version 3 of the License, or
22 | * (at your option) any later version.
23 | *
24 | * This program is distributed in the hope that it will be useful,
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 | * GNU Affero General Public License for more details.
28 | *
29 | * You should have received a copy of the GNU Affero General Public License
30 | * along with this program. If not, see .
31 | */
32 |
33 | group = "io.github.sof3.graphmine"
34 | version = "1.0.0-SNAPSHOT"
35 |
36 | buildscript {
37 | repositories {
38 | jcenter()
39 | }
40 | dependencies {
41 | classpath("org.jetbrains.dokka:dokka-gradle-plugin:0.9.17")
42 | classpath("com.vanniktech:gradle-dependency-graph-generator-plugin:0.5.0")
43 | }
44 | }
45 |
46 | plugins {
47 | java
48 | kotlin("jvm") version "1.3.0"
49 | jacoco
50 | id("com.vanniktech.dependency.graph.generator") version "0.5.0"
51 | }
52 |
53 | allprojects {
54 | repositories {
55 | jcenter()
56 | }
57 | }
58 |
59 | subprojects {
60 | apply(plugin = "org.jetbrains.dokka")
61 |
62 | repositories {
63 | maven(url = "https://dl.bintray.com/spekframework/spek-dev")
64 | }
65 |
66 | tasks.withType {
67 | kotlinOptions.jvmTarget = "1.8"
68 | }
69 |
70 | tasks.withType {
71 | useJUnitPlatform {
72 | includeEngines("spek2")
73 | }
74 | testLogging {
75 | showStandardStreams = true
76 | showExceptions = true
77 | showCauses = true
78 | showStackTraces = true
79 | events(TestLogEvent.FAILED, TestLogEvent.STANDARD_OUT, TestLogEvent.STANDARD_ERROR)
80 | }
81 | }
82 |
83 | tasks.withType {
84 | outputFormat = "jekyll"
85 | outputDirectory = "$buildDir/javadoc"
86 |
87 | File(project.projectDir, "module.md").takeIf { it.isFile }?.let { includes += it }
88 | Files.walk(File(project.projectDir, "src").toPath())
89 | .filter { it.toFile().isDirectory }
90 | .map { it.resolve("package.md").toFile() }
91 | .filter { it.isFile }
92 | .forEach { includes += it.absolutePath }
93 | }
94 | }
95 |
96 | fun colorNode(node: MutableNode, name: String): MutableNode {
97 | val rgb = name.hashCode()
98 | node.add(Style.FILLED, Color.rgb(rgb))
99 | val R = rgb shr 16 and 0xFF
100 | val G = rgb shr 8 and 0xFF
101 | val B = rgb and 0xFF
102 | val light = 0.299 * R + 0.587 * G + 0.114 * B
103 | if (light <= 152.0) {
104 | node.add("fontcolor", "#ffffff")
105 | }
106 | return node
107 | }
108 |
109 | val graphMineDepGraphGenerator = Generator(
110 | dependencyNode = { node, dependency -> colorNode(node, dependency.moduleGroup) },
111 | projectNode = { node, project -> colorNode(node, project.group.toString()) }
112 | )
113 |
114 | configure {
115 | generators = listOf(graphMineDepGraphGenerator)
116 | }
117 |
118 | tasks.withType {
119 | reports {
120 | xml.isEnabled = true
121 | xml.destination = File("build/reports/jacoco.xml")
122 | executionData(tasks.withType())
123 | }
124 | }
125 |
126 | tasks {
127 | task("codeCoverageReport", type = JacocoReport::class) {
128 | subprojects.forEach {
129 | dependsOn(":${it.name}:test")
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SOF3/GraphMine/ae7c3599e8d327c0077fa798adeaed8dbbf0577f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Nov 06 21:36:00 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/graphmine-cli/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * GraphMine
3 | * Copyright (C) 2018 SOFe
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | plugins {
20 | java
21 | kotlin("jvm")
22 | application
23 | }
24 |
25 | group = "io.github.sof3.graphmine"
26 | version = "1.0.0-SNAPSHOT"
27 |
28 | dependencies {
29 | implementation(project(":graphmine-core"))
30 | implementation(kotlin("stdlib-jdk8"))
31 | implementation("commons-cli", "commons-cli", "1.4")
32 | implementation("commons-io", "commons-io", "2.6")
33 | testImplementation(kotlin("test"))
34 | testImplementation("org.spekframework.spek2:spek-dsl-jvm:2.0.0-alpha.2")
35 | testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:2.0.0-alpha.2")
36 | }
37 |
38 | application {
39 | mainClassName = "io.github.sof3.graphmine.cli.MainKt"
40 | }
41 |
42 | val fatJar = task("fatJar", type = Jar::class) {
43 | baseName = "${project.name}-fat"
44 | manifest {
45 | attributes["Implementation-Title"] = "GraphMine"
46 | attributes["Implementation-Version"] = version
47 | attributes["Main-Class"] = "io.github.sof3.graphmine.cli.MainKt"
48 | }
49 | from(configurations.runtime.map { if (it.isDirectory) it else zipTree(it) })
50 | with(tasks["jar"] as CopySpec)
51 | }
52 |
--------------------------------------------------------------------------------
/graphmine-cli/module.md:
--------------------------------------------------------------------------------
1 | # Module graphmine-cli
2 | An executable project that wraps the core and exposes a user interface through standard I/O (command line interface for terminal users)
3 |
4 | ## Threading
5 | ### Main thread
6 | This module contains a `fun main` entry point. The Server object is constructed from this thread. This thread exits after the server has been fully initialized.
7 |
8 | ### Stdin thread
9 | This module starts a thread for reading input from stdin.
10 |
11 | ### Shutdown thread
12 | A thread is started when the user sends a shutdown signal e.g. SIGINT. The thread exits as soon as the signal has been
13 | sent to the server's corresponding handlers.
14 |
--------------------------------------------------------------------------------
/graphmine-cli/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "graphmine-cli"
2 |
--------------------------------------------------------------------------------
/graphmine-cli/src/main/kotlin/io/github/sof3/graphmine/cli/ConsoleReceiver.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.cli
2 |
3 | import io.github.sof3.graphmine.command.CommandReceiver
4 | import io.github.sof3.graphmine.i18n.I18n
5 | import org.apache.logging.log4j.LogManager
6 |
7 | /*
8 | * GraphMine
9 | * Copyright (C) 2018 SOFe
10 | *
11 | * This program is free software: you can redistribute it and/or modify
12 | * it under the terms of the GNU Affero General Public License as published
13 | * by the Free Software Foundation, either version 3 of the License, or
14 | * (at your option) any later version.
15 | *
16 | * This program is distributed in the hope that it will be useful,
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | * GNU Affero General Public License for more details.
20 | *
21 | * You should have received a copy of the GNU Affero General Public License
22 | * along with this program. If not, see .
23 | */
24 |
25 | internal class ConsoleReceiver(private val prefix: String, private val locale: String) : CommandReceiver {
26 | override fun receiveMessage(message: I18n) {
27 | LogManager.getLogger(prefix).info(message[locale])
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/graphmine-cli/src/main/kotlin/io/github/sof3/graphmine/cli/ConsoleSender.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.cli
2 |
3 | import io.github.sof3.graphmine.command.CommandSender
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | internal object ConsoleSender : CommandSender {
24 | }
25 |
--------------------------------------------------------------------------------
/graphmine-cli/src/main/kotlin/io/github/sof3/graphmine/cli/TerminalSignal.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.cli
2 |
3 | /**
4 | * Any signals received from the abstract console are expressed as a [TerminalSignal].
5 | */
6 | sealed class TerminalSignal {
7 | /**
8 | * Represents an EOD (end of data) signal, implying that the input is closed
9 | */
10 | object Eod : TerminalSignal()
11 |
12 | /**
13 | * Represents a SIGINT or otherwise force-shutdown signal.
14 | */
15 | object Int : TerminalSignal()
16 |
17 | /**
18 | * Represents a line of command
19 | * @property line the command line with line endings trimmed
20 | */
21 | class Cmd(val line: String) : TerminalSignal()
22 | }
23 |
--------------------------------------------------------------------------------
/graphmine-cli/src/main/kotlin/io/github/sof3/graphmine/cli/main.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.cli
2 |
3 | import io.github.sof3.graphmine.Server
4 | import io.github.sof3.graphmine.VersionInfo
5 | import io.github.sof3.graphmine.config.CoreConfig
6 | import io.github.sof3.graphmine.util.BooleanRef
7 | import io.github.sof3.graphmine.util.KtsLoader
8 | import org.apache.commons.cli.CommandLine
9 | import org.apache.commons.cli.DefaultParser
10 | import org.apache.commons.cli.HelpFormatter
11 | import org.apache.commons.cli.Options
12 | import org.apache.commons.io.IOUtils
13 | import org.apache.logging.log4j.LogManager
14 | import reactor.core.publisher.Flux
15 | import reactor.core.scheduler.Schedulers
16 | import java.io.File
17 | import java.io.FileOutputStream
18 | import java.io.FileReader
19 | import java.io.IOException
20 | import java.text.DateFormat
21 |
22 | /*
23 | * GraphMine
24 | * Copyright (C) 2018 SOFe
25 | *
26 | * This program is free software: you can redistribute it and/or modify
27 | * it under the terms of the GNU Affero General Public License as published
28 | * by the Free Software Foundation, either version 3 of the License, or
29 | * (at your option) any later version.
30 | *
31 | * This program is distributed in the hope that it will be useful,
32 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 | * GNU Affero General Public License for more details.
35 | *
36 | * You should have received a copy of the GNU Affero General Public License
37 | * along with this program. If not, see .
38 | */
39 |
40 | internal lateinit var options: Options
41 | internal lateinit var cmd: CommandLine
42 | internal val logger = LogManager.getLogger()!!
43 |
44 | internal fun main(args: Array) {
45 | options = Options().apply {
46 | addOption("v", "version", false, "GraphMine version")
47 | addOption("h", "help", false, "Overload line description")
48 | addOption("d", "data", true, "Path to data directory")
49 | }
50 | cmd = DefaultParser().parse(options, args)
51 |
52 | if (metaArgs()) return
53 |
54 | val initNano = System.nanoTime()
55 |
56 | logger.debug("Setting up data directory...")
57 | val (dataDir, config) = setupDataDir()
58 |
59 | val server = Server(
60 | dataDir = dataDir,
61 | config = config,
62 | initNano = initNano
63 | )
64 |
65 | logger.debug("Initializing stdin")
66 | val (signalFlux, shutdown) = createStdinFlux()
67 | signalFlux.subscribe {
68 | when (it) {
69 | is TerminalSignal.Cmd -> {
70 | val name = it.line.substringBefore(" ")
71 | server.commandMap.dispatch(it.line, ConsoleSender, ConsoleReceiver("Command:$name", server.locale))
72 | }
73 | TerminalSignal.Eod -> server.shutdown()
74 | TerminalSignal.Int -> server.shutdown()
75 | }
76 | }
77 | server.shutdownHandlers += shutdown
78 | }
79 |
80 | private fun metaArgs() = when {
81 | cmd.hasOption("h") -> {
82 | HelpFormatter().printHelp("graphmine", options)
83 | true
84 | }
85 | cmd.hasOption("v") -> {
86 | println("GraphMine v${VersionInfo.VERSION}, built on ${DateFormat.getDateTimeInstance().format(VersionInfo.BUILD_DATE)}")
87 | true
88 | }
89 | else -> false
90 | }
91 |
92 | private fun setupDataDir(): Pair {
93 | val dataDir = File(cmd.getOptionValue("data", "data"))
94 | if (!dataDir.exists()) dataDir.mkdirs()
95 |
96 | val configFile = File(dataDir, "config.kts")
97 | if (!configFile.exists()) {
98 | logger.debug("Copying default config.kts")
99 | val default = object {}.javaClass.classLoader.getResourceAsStream("config.kts")
100 | FileOutputStream(configFile).use { IOUtils.copy(default, it) }
101 | }
102 |
103 | logger.debug("Loading CoreConfig classes")
104 | CoreConfig {}
105 | logger.debug("Loading ${configFile.canonicalPath}")
106 | val config = KtsLoader.load(FileReader(configFile))
107 | logger.debug("Loaded ${configFile.canonicalPath}")
108 | return dataDir to config
109 | }
110 |
111 | private fun createStdinFlux(): Pair, () -> Unit> {
112 | var closing by BooleanRef(false)
113 |
114 | val flux = Flux.create { sink ->
115 | Runtime.getRuntime().addShutdownHook(Thread { sink.next(TerminalSignal.Int) })
116 |
117 | try {
118 | while (!closing) {
119 | val line = readLine() ?: break
120 | sink.next(TerminalSignal.Cmd(line))
121 | }
122 | } catch (e: IOException) {
123 | }
124 | if (!closing) sink.next(TerminalSignal.Eod)
125 | }.subscribeOn(Schedulers.newSingle("stdin"))
126 |
127 | return Pair(flux) {
128 | System.`in`.close()
129 | closing = true
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/graphmine-cli/src/main/resources/config.kts:
--------------------------------------------------------------------------------
1 | import io.github.sof3.graphmine.config.CoreConfig
2 |
3 | CoreConfig {
4 | language = "en_US"
5 | server {
6 | port = 19132
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/graphmine-cli/src/main/resources/log4j2.component.properties:
--------------------------------------------------------------------------------
1 | log4j.configurationFile=log4j2.yml
2 |
--------------------------------------------------------------------------------
/graphmine-cli/src/main/resources/log4j2.yml:
--------------------------------------------------------------------------------
1 | ---
2 | Configuration:
3 | name: GraphMineLogger
4 | status: WARN
5 | appenders:
6 | Console:
7 | name: stdout
8 | PatternLayout:
9 | Pattern: "%date{HH:mm:ss.SSS} %logger{2}@%thread %level %msg%n"
10 | RollingFile:
11 | name: file
12 | fileName: logs/server.log
13 | filePattern: "logs/archive/server.%{yyyy-MM-dd-HH-mm}.gz"
14 | PatternLayout:
15 | Pattern: "%d{MMM dd HH:mm:ss} [%thread] %level %logger - %msg%n"
16 | Filters:
17 | ThresholdFilter:
18 | level: info
19 | Policies:
20 | SizeBasedTriggeringPolicy:
21 | size: 16 KB
22 | DefaultRollOverStrategy:
23 | max: 64
24 | Loggers:
25 | # Logger:
26 | # - name: io.github.sof3.graphmine.Server
27 | Root:
28 | level: trace
29 | AppenderRef:
30 | - ref: stdout
31 | - ref: file
32 | ...
33 |
--------------------------------------------------------------------------------
/graphmine-core/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import java.io.File
2 | import java.io.FileWriter
3 | import java.text.SimpleDateFormat
4 | import java.util.Date
5 | import java.util.Properties
6 |
7 | /*
8 | * GraphMine
9 | * Copyright (C) 2018 SOFe
10 | *
11 | * This program is free software: you can redistribute it and/or modify
12 | * it under the terms of the GNU Affero General Public License as published
13 | * by the Free Software Foundation, either version 3 of the License, or
14 | * (at your option) any later version.
15 | *
16 | * This program is distributed in the hope that it will be useful,
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | * GNU Affero General Public License for more details.
20 | *
21 | * You should have received a copy of the GNU Affero General Public License
22 | * along with this program. If not, see .
23 | */
24 |
25 | plugins {
26 | java
27 | kotlin("jvm")
28 | }
29 |
30 | group = "io.github.sof3.graphmine"
31 | version = "1.0.0-SNAPSHOT"
32 |
33 | dependencies {
34 | api(project(":graphmine-util"))
35 | api(project(":util-math"))
36 | api(project(":graphmine-i18n"))
37 | api(project(":graphmine-i18n-core"))
38 |
39 | api("org.apache.logging.log4j", "log4j-api", "2.11.1")
40 | runtimeOnly("org.apache.logging.log4j", "log4j-core", "2.11.1")
41 |
42 | api(kotlin("stdlib-jdk8"))
43 | api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.1")
44 | api(kotlin("reflect"))
45 |
46 | api("io.projectreactor:reactor-core:3.2.3.RELEASE")
47 |
48 | implementation("com.fasterxml.jackson.module", "jackson-module-kotlin", "2.9.7")
49 | implementation("com.fasterxml.jackson.dataformat", "jackson-dataformat-yaml", "2.9.7")
50 | implementation("com.fasterxml.jackson.core", "jackson-databind", "2.9.4")
51 | implementation("com.fasterxml.jackson.core", "jackson-annotations", "2.9.7")
52 |
53 | testImplementation(kotlin("test"))
54 | testImplementation("org.spekframework.spek2:spek-dsl-jvm:2.0.0-alpha.2")
55 | testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:2.0.0-alpha.2")
56 | }
57 |
58 | open class CreateVersionProperties : DefaultTask() {
59 | @TaskAction
60 | fun create() {
61 | }
62 | }
63 |
64 | tasks {
65 | "createVersionProperties"(CreateVersionProperties::class) {
66 | dependsOn("processResources")
67 | doLast {
68 | val resDir = File(project.buildDir, "resources/main")
69 | resDir.mkdirs()
70 | FileWriter(File(resDir, "build.properties")).use {
71 | Properties().apply {
72 | this["version"] = project.version
73 | this["build-date"] = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'").format(Date())
74 | }.store(it, "Generated by gradle build script")
75 | }
76 | }
77 | }
78 | "classes"{
79 | dependsOn("createVersionProperties")
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/graphmine-core/module.md:
--------------------------------------------------------------------------------
1 | # Module graphmine-core
2 | Main GraphMine code. All public classes and functions are stable API.
3 |
4 | ## Threading
5 |
--------------------------------------------------------------------------------
/graphmine-core/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "graphmine-core"
2 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/HasLogger.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine
2 |
3 | import io.github.sof3.graphmine.i18n.I18n
4 | import org.apache.logging.log4j.Logger
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * This interface only exists to avoid the boilerplate of calling the logger.
26 | */
27 | interface HasLogger {
28 | /**
29 | * The logger for this object
30 | */
31 | val logger: Logger
32 | /**
33 | * @return the default locale to use
34 | */
35 | val locale: String
36 |
37 | /**
38 | * Logs a DEBUG-level message
39 | */
40 | fun debug(i18n: I18n) = logger.debug(i18n[locale])
41 |
42 | /**
43 | * Logs a ERROR-level message
44 | */
45 | fun error(i18n: I18n) = logger.error(i18n[locale])
46 |
47 | /**
48 | * Logs a FATAL-level message
49 | */
50 | fun fatal(i18n: I18n) = logger.fatal(i18n[locale])
51 |
52 | /**
53 | * Logs a INFO-level message
54 | */
55 | fun info(i18n: I18n) = logger.info(i18n[locale])
56 |
57 | /**
58 | * Logs a WARN-level message
59 | */
60 | fun warn(i18n: I18n) = logger.warn(i18n[locale])
61 | }
62 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/Server.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine
2 |
3 | import io.github.sof3.graphmine.command.CommandMap
4 | import io.github.sof3.graphmine.command.impl.VersionCommand
5 | import io.github.sof3.graphmine.config.CoreConfig
6 | import io.github.sof3.graphmine.i18n.core.*
7 | import io.github.sof3.graphmine.i18n.core.CoreLang.Startup.LockedArg
8 | import io.github.sof3.graphmine.scope.BaseScope
9 | import io.github.sof3.graphmine.scope.Scope
10 | import org.apache.logging.log4j.LogManager
11 | import java.io.File
12 | import java.io.RandomAccessFile
13 | import java.nio.channels.FileLock
14 |
15 | /*
16 | * GraphMine
17 | * Copyright (C) 2018 SOFe
18 | *
19 | * This program is free software: you can redistribute it and/or modify
20 | * it under the terms of the GNU Affero General Public License as published
21 | * by the Free Software Foundation, either version 3 of the License, or
22 | * (at your option) any later version.
23 | *
24 | * This program is distributed in the hope that it will be useful,
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 | * GNU Affero General Public License for more details.
28 | *
29 | * You should have received a copy of the GNU Affero General Public License
30 | * along with this program. If not, see .
31 | */
32 |
33 | /**
34 | * The Server should be the object that links up different components of the server.
35 | *
36 | * To prevent cyclic dependency, instead of passing the Server object around, pass the objects that will actually be used, e.g. the logger, the config, etc.
37 | *
38 | * @property dataDir the server data directory
39 | * @property config the server config
40 | * @param initNano System.nanoTime() when the server start command was created
41 | * @param scope internal value, do not override
42 | */
43 | class Server(
44 | val dataDir: File,
45 | val config: CoreConfig,
46 |
47 | initNano: Long = System.nanoTime(),
48 |
49 | private val scope: BaseScope = BaseScope(Server::class)
50 | ) : Scope by scope, HasLogger {
51 | /**
52 | * the logger used for the server scope. Plugins should use their own logger instead of this one.
53 | */
54 | override val logger = LogManager.getLogger()!!
55 | /**
56 | * the default locale of the server.
57 | */
58 | override val locale get() = config.language
59 |
60 | init {
61 | logger.debug("Checking config")
62 | config.checkAll()
63 | logger.debug("Loading en_US.lang.kts")
64 | loadCoreLang()
65 | logger.debug("Loaded en_US.lang.kts")
66 |
67 | lockDataDir()
68 | info(CoreLang.startup.version(CoreLang.Startup.VersionArg(version = VersionInfo.VERSION, ip = config.server.ip, port = config.server.port)))
69 | }
70 |
71 | private fun lockDataDir() {
72 | val file = File(dataDir, "server.lock")
73 | val ra = RandomAccessFile(file, "rw")
74 | val lock: FileLock? = ra.channel.tryLock()
75 | if (lock == null) {
76 | fatal(CoreLang.startup.locked(LockedArg(file)))
77 | throw RuntimeException("Server is already running")
78 | }
79 | }
80 |
81 |
82 | /**
83 | * List of [Runnable]s that are called when the server shuts down
84 | */
85 | val shutdownHandlers = mutableListOf<() -> Unit>().apply {
86 | this += scope::dispose
87 | }
88 |
89 |
90 | /**
91 | * Stores the list of server-wide commands
92 | */
93 | val commandMap = CommandMap().apply {
94 | // default commands
95 | addCommand(VersionCommand, this@Server)
96 | }
97 |
98 |
99 | init {
100 | info(CoreLang.startup.complete(CoreLang.Startup.CompleteArg(nano = System.nanoTime() - initNano)))
101 | }
102 |
103 | fun shutdown() {
104 | shutdownHandlers.forEach { it() }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/VersionInfo.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine
2 |
3 | import java.text.SimpleDateFormat
4 | import java.util.*
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * Holds the static version information for this build
26 | */
27 | object VersionInfo {
28 | /**
29 | * the API version from build.gradle
30 | */
31 | val VERSION: String
32 |
33 | /**
34 | * the date the Gradle build for the API module was created
35 | */
36 | val BUILD_DATE: Date
37 |
38 | init {
39 | val properties = javaClass.classLoader.getResourceAsStream("build.properties")?.use {
40 | Properties().apply { load(it) }
41 | }
42 | if (properties != null) {
43 | VERSION = properties["version"].toString()
44 | BUILD_DATE = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'").parse(properties["build-date"].toString())
45 | } else {
46 | VERSION = "NO_GRADLE"
47 | BUILD_DATE = Date()
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/client/Client.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.client
2 |
3 | import io.github.sof3.graphmine.feature.FeatureNode
4 | import io.github.sof3.graphmine.feature.FeatureNodeInstance
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | interface Client : FeatureNodeInstance {
25 | var attached: ClientAttachable
26 |
27 | companion object Node : FeatureNode
28 |
29 | override val node get() = Node
30 | }
31 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/client/ClientAttachable.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.client
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | interface ClientAttachable {
22 | }
23 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/Command.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command
2 |
3 | import io.github.sof3.graphmine.i18n.I18n
4 | import io.github.sof3.graphmine.i18n.i18n
5 | import io.github.sof3.graphmine.scope.Scope
6 | import io.github.sof3.graphmine.util.qualifier.Qualifier
7 | import io.github.sof3.graphmine.util.string.FormattedStringReader
8 | import kotlinx.coroutines.launch
9 |
10 | /*
11 | * GraphMine
12 | * Copyright (C) 2018 SOFe
13 | *
14 | * This program is free software: you can redistribute it and/or modify
15 | * it under the terms of the GNU Affero General Public License as published
16 | * by the Free Software Foundation, either version 3 of the License, or
17 | * (at your option) any later version.
18 | *
19 | * This program is distributed in the hope that it will be useful,
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | * GNU Affero General Public License for more details.
23 | *
24 | * You should have received a copy of the GNU Affero General Public License
25 | * along with this program. If not, see .
26 | */
27 |
28 | /**
29 | * This class represents a command type. Each instance of Command should represent one registered command.
30 | *
31 | * Subclasses must initialize the [name] property.
32 | *
33 | * @param fn A lambda to initialize the command.
34 | *
35 | * @sample io.github.sof3.graphmine.command.impl.VersionCommand
36 | */
37 | abstract class Command(fn: Command.() -> Unit) {
38 | /**
39 | * The scope that owns the command
40 | */
41 | lateinit var scope: C
42 | internal set
43 |
44 | /**
45 | * The qualified name of the command.
46 | *
47 | * This property is intentionally not made as a delegation as string so as to remind command developers that the
48 | * name needs to be qualified.
49 | *
50 | * @see Qualifier
51 | */
52 | lateinit var name: Qualifier
53 | /**
54 | * The description of the command, shown in action lists like /help.
55 | */
56 | var description: I18n = "".i18n
57 | /**
58 | * The list of aliases
59 | */
60 | var aliases = listOf()
61 |
62 | /** @suppress */
63 | val overloads = mutableListOf()
64 | /** @suppress */
65 | val handlers = mutableListOf) -> Unit>()
66 |
67 | /**
68 | * Executes the command.
69 | *
70 | * The command is run as a new coroutine in [the command's owner scope][scope].
71 | *
72 | * @param reader the reader containing the command arguments. The reader pointer should start at the first character
73 | * of the command arguments.
74 | * @param sender the [CommandSender] that sent the command
75 | * @param receiver the object that accepts the command output and presents it to the sender.
76 | */
77 | fun dispatch(reader: FormattedStringReader, sender: CommandSender, receiver: CommandReceiver) = scope.launch {
78 | try {
79 | for (overload in overloads) {
80 | val arg = overload.accept(reader)
81 | if (arg != null) {
82 | val executor = CommandExecutor(arg, sender, receiver, scope)
83 | handlers.forEach { it(executor) }
84 | return@launch
85 | }
86 | }
87 | throw WrongSyntaxException(name.toString(), overloads.map { it.i18n })
88 | } catch (ex: CommandException) {
89 | receiver.receiveMessage(ex.i18n)
90 | }
91 | }
92 |
93 | /**
94 | * Adds a handler to the command.
95 | *
96 | * Type parameters [A] and [S] are explicitly specified to filter the overloads and sender types.
97 | *
98 | * If the command does not require any parameters, [EmptyOverload] can be used.
99 | *
100 | * @param A the restricted [Overload] type
101 | * @param S the restricted [CommandSender] type
102 | *
103 | * @param fn the handler function
104 | */
105 | inline fun handle(crossinline fn: suspend CommandExecutor.() -> Unit) {
106 | overloads += RegisteredOverload(A::class)
107 |
108 | handlers += {
109 | val special = it.specialize ()
110 | if (special != null) fn(special)
111 | }
112 | }
113 |
114 | init {
115 | fn()
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/CommandExecutor.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command
2 |
3 | import io.github.sof3.graphmine.i18n.I18n
4 | import io.github.sof3.graphmine.scope.Scope
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * The `this` context of command handlers.
26 | *
27 | * Other modules are encouraged to create extension functions on this class for more convenient handling.
28 | *
29 | * @param A the type of overload. Can be any supertype of the actual overload.
30 | * @param S the type of command sender. Can be any supertype of the actual sender.
31 | * @param C the [scope][Scope] of the command execution.
32 | *
33 | * @property args the parsed overload instance
34 | * @property sender the sender that sent the command
35 | * @property receiver the object to send command output into
36 | * @property scope the scope that owns the command
37 | */
38 | class CommandExecutor internal constructor(
39 | val args: A,
40 | val sender: S,
41 | val receiver: CommandReceiver,
42 | val scope: C
43 | ) {
44 | /**
45 | * Restricts the command executor to its subtypes.
46 | *
47 | * [SubA] and [SubS] are intentionally not forced to be subtypes of [A] and [S] because it is possible that [SubA]
48 | * is another interface that does not extend [A].
49 | *
50 | * @param SubA the new expected overload type
51 | * @param SubS the new expected sender type
52 | * @return `this` if the types can be narrowed for this instance, `null` if types are incompatible
53 | */
54 | @Suppress("UNCHECKED_CAST")
55 | inline fun specialize() =
56 | if (args is SubA && sender is SubS) this as CommandExecutor
57 | else null
58 |
59 | /**
60 | * Responds to the command sender. A shortcut for `receiver.receiveMessage`.
61 | *
62 | * @param message the i18nized message to be sent.
63 | */
64 | fun respond(message: I18n) = receiver.receiveMessage(message)
65 | }
66 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/CommandMap.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command
2 |
3 | import io.github.sof3.graphmine.i18n.core.*
4 | import io.github.sof3.graphmine.i18n.core.CoreLang.Commands.Generic.NotFoundArg
5 | import io.github.sof3.graphmine.scope.Scope
6 | import io.github.sof3.graphmine.util.qualifier.QualifierMap
7 | import io.github.sof3.graphmine.util.string.FormattedStringReader
8 |
9 | /*
10 | * GraphMine
11 | * Copyright (C) 2018 SOFe
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU Affero General Public License as published
15 | * by the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU Affero General Public License for more details.
22 | *
23 | * You should have received a copy of the GNU Affero General Public License
24 | * along with this program. If not, see .
25 | */
26 |
27 | /**
28 | * Stores a list of commands. This class can also be instantiated at individual commands to provide a sub-command list.
29 | */
30 | class CommandMap {
31 | private val map = QualifierMap>()
32 |
33 | /**
34 | * Adds a command to the map.
35 | *
36 | * @param command the command to be added
37 | * @param scope the [scope][Scope] that owns the command
38 | */
39 | fun addCommand(command: Command, scope: C) = apply {
40 | command.scope = scope
41 | map[command.name] = command
42 | }
43 |
44 | /**
45 | * Dispatches a command. This function should only be used when the command name is unknown.
46 | *
47 | * @param
48 | */
49 | fun dispatch(string: String, by: CommandSender, to: CommandReceiver) {
50 | val reader = FormattedStringReader(string)
51 | val (name) = reader.nextDelimiter() ?: return
52 | val command = map[name]
53 | if (command != null) {
54 | command.dispatch(reader, by, to)
55 | } else {
56 | to.receiveMessage(CoreLang.commands.generic.notFound(NotFoundArg(name)))
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/CommandReceiver.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command
2 |
3 | import io.github.sof3.graphmine.i18n.I18n
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * Accepts output from a command.
25 | */
26 | interface CommandReceiver {
27 | /**
28 | * Receives a message from the command output and presents it to the client
29 | */
30 | fun receiveMessage(message: I18n)
31 |
32 | // TODO add receiver-specific configurations here, similar to how tty detection works on Linux
33 | }
34 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/CommandSender.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Represents an object that sends the command.
23 | */
24 | interface CommandSender
25 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/EmptyOverload.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * An empty overload, reused for commands that do not require arguments.
23 | */
24 | class EmptyOverload : Overload()
25 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/Overload.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command
2 |
3 | import io.github.sof3.graphmine.client.Client
4 | import io.github.sof3.graphmine.command.args.*
5 | import kotlin.reflect.KClass
6 |
7 | /*
8 | * GraphMine
9 | * Copyright (C) 2018 SOFe
10 | *
11 | * This program is free software: you can redistribute it and/or modify
12 | * it under the terms of the GNU Affero General Public License as published
13 | * by the Free Software Foundation, either version 3 of the License, or
14 | * (at your option) any later version.
15 | *
16 | * This program is distributed in the hope that it will be useful,
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | * GNU Affero General Public License for more details.
20 | *
21 | * You should have received a copy of the GNU Affero General Public License
22 | * along with this program. If not, see .
23 | */
24 |
25 | /**
26 | * Defines the parameters of a command.
27 | *
28 | * Commands that have parameters should create classes extending Overload. The subclass should contain backing
29 | * properties delegated to one of the [CommandArg] factory methods like [string], [integer], etc.
30 | *
31 | * If another module wants to implement its own [CommandArg] types, it can create extension functions on [Overload] that
32 | * constructs the CommandArg, calls the [addArg] function and returns the new CommandArg instance.
33 | */
34 | abstract class Overload {
35 | internal val args = mutableListOf>()
36 |
37 | /**
38 | * @see StringArg
39 | */
40 | fun string(): CommandArg = addArg(StringArg())
41 |
42 | /**
43 | * @see IntegerArg
44 | */
45 | fun integer(): CommandArg = addArg(IntegerArg())
46 |
47 | /**
48 | * @see NumberArg
49 | */
50 | fun number(): CommandArg = addArg(NumberArg())
51 |
52 | /**
53 | * @see ClientArg
54 | */
55 | fun client(): CommandArg = addArg(ClientArg())
56 |
57 | /**
58 | * @see EnumArg
59 | */
60 | inline fun > enum() = enum(E::class)
61 |
62 | /**
63 | * @see EnumArg
64 | */
65 | fun > enum(enumClass: KClass): CommandArg = addArg(EnumArg(enumClass))
66 |
67 | /**
68 | * @see RawTextArg
69 | */
70 | fun rawText(): CommandArg = addArg(RawTextArg())
71 |
72 | /**
73 | * CommandArg factory extension functions must call this function before returning the argument
74 | */
75 | fun addArg(arg: CommandArg): CommandArg {
76 | args += arg
77 | return arg
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/RegisteredOverload.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command
2 |
3 | import io.github.sof3.graphmine.command.args.CommandArg
4 | import io.github.sof3.graphmine.i18n.I18n
5 | import io.github.sof3.graphmine.i18n.I18nable
6 | import io.github.sof3.graphmine.util.string.FormattedStringReader
7 | import kotlin.reflect.KClass
8 | import kotlin.reflect.full.createInstance
9 |
10 | /*
11 | * GraphMine
12 | * Copyright (C) 2018 SOFe
13 | *
14 | * This program is free software: you can redistribute it and/or modify
15 | * it under the terms of the GNU Affero General Public License as published
16 | * by the Free Software Foundation, either version 3 of the License, or
17 | * (at your option) any later version.
18 | *
19 | * This program is distributed in the hope that it will be useful,
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | * GNU Affero General Public License for more details.
23 | *
24 | * You should have received a copy of the GNU Affero General Public License
25 | * along with this program. If not, see .
26 | */
27 |
28 | /**
29 | * A factory that creates a new instance of a known command overload for each command execution.
30 | */
31 | class RegisteredOverload(private val klass: KClass) : I18nable {
32 | override val i18n: I18n
33 | get() = TODO("not implemented")
34 |
35 | /**
36 | * The arguments applicable to this overload
37 | */
38 | val args: List>
39 |
40 | init {
41 | val instance = klass.createInstance()
42 | args = instance.args
43 | }
44 |
45 | /**
46 | * Accepts a command and tries to parse it.
47 | */
48 | fun accept(parser: FormattedStringReader): Overload? {
49 | val command = klass.createInstance()
50 | for (arg in command.args) {
51 | if (!arg.accept(parser)) return null // TODO use parser.exec{}
52 | }
53 |
54 | return command
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/args/ClientArg.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command.args
2 |
3 | import io.github.sof3.graphmine.client.Client
4 | import io.github.sof3.graphmine.util.string.FormattedStringReader
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * Accepts a client name
26 | */
27 | class ClientArg : CommandArg() {
28 | override fun parse(parser: FormattedStringReader): Client? {
29 | TODO("not implemented")
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/args/CommandArg.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command.args
2 |
3 | import io.github.sof3.graphmine.command.Overload
4 | import io.github.sof3.graphmine.util.DelegateProvider
5 | import io.github.sof3.graphmine.util.string.FormattedStringReader
6 | import kotlin.properties.ReadOnlyProperty
7 | import kotlin.reflect.KProperty
8 |
9 | /*
10 | * GraphMine
11 | * Copyright (C) 2018 SOFe
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU Affero General Public License as published
15 | * by the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU Affero General Public License for more details.
22 | *
23 | * You should have received a copy of the GNU Affero General Public License
24 | * along with this program. If not, see .
25 | */
26 |
27 | /**
28 | * Superclass of a command argument.
29 | */
30 | abstract class CommandArg : DelegateProvider {
31 | /**
32 | * Reads the next value in the parser into the value for the argument.
33 | * @return whether the value is valid for this argument
34 | */
35 | fun accept(parser: FormattedStringReader): Boolean {
36 | value = parse(parser) ?: return false
37 | return true
38 | }
39 |
40 | /**
41 | * Reads the next value in the parser into the value for the argument
42 | *
43 | * @return the parsed value, or `null` if it is missing or cannot be parsed
44 | */
45 | abstract fun parse(parser: FormattedStringReader): T?
46 |
47 |
48 | override fun provideDelegate(thisRef: Overload, property: KProperty<*>) = object : ReadOnlyProperty {
49 | override fun getValue(thisRef: Overload, property: KProperty<*>) = value
50 | }
51 |
52 | /**
53 | * Whether the command arg can be skipped
54 | */
55 | var optional = false
56 | /**
57 | * Sets the default value of the command. Implicitly sets [optional] to `true` (even if the set value is `null`)
58 | */
59 | var default: T? = null
60 | set(value) {
61 | field = value
62 | optional = true
63 | }
64 |
65 | /**
66 | * Sets the default value of the command. Implicitly sets [optional] to `true` (even if the set value is `null`)
67 | */
68 | fun default(value: T) = apply { default = value }
69 |
70 | /**
71 | * The received value of the argument
72 | */
73 | lateinit var value: T
74 | protected set
75 | }
76 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/args/EnumArg.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command.args
2 |
3 | import io.github.sof3.graphmine.util.string.FormattedStringReader
4 | import kotlin.reflect.KClass
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * Accepts a value that names one of the constants in the enum class
26 | */
27 | class EnumArg>(private val enumClass: KClass) : CommandArg() {
28 | /**
29 | * Match enum constant names case-insensitively.
30 | *
31 | * This may cause problems if multiple enum constants have the same name with different cases. (However this is not
32 | * encouraged in Java coding style anyway)
33 | */
34 | var ignoreCase = true
35 |
36 | /**
37 | * The policy for comparing symbols in enum names
38 | */
39 | var symbolPolicy = SymbolPolicy.ANY
40 |
41 | override fun parse(parser: FormattedStringReader): E? {
42 | val name = parser.nextDelimiter()?.content ?: return null
43 | val given = symbolPolicy.fn(name)
44 | for (enum in enumClass.java.enumConstants!!) {
45 | val actual = symbolPolicy.fn(enum.name)
46 | if (actual.equals(given, ignoreCase)) return enum
47 | }
48 | return null
49 | }
50 |
51 | /**
52 | * The policy to use for comparing symbols in enum names
53 | */
54 | enum class SymbolPolicy(internal val fn: (String) -> String) {
55 | /**
56 | * Compares names as-is
57 | */
58 | AS_IS({ it }),
59 | /**
60 | * Any strings of one or more non-alphanumeric symbols are considered the same, and leading and trailing symbols are always
61 | * ignored
62 | */
63 | ANY({ it.replace(Regex("[^A-Za-z0-9]+"), "_").trim('_') }),
64 | /**
65 | * Any non-alphanumeric symbols are ignored
66 | */
67 | IGNORE({ it.replace(Regex("[^A-Za-z0-9]+"), "") }),
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/args/number.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command.args
2 |
3 | import io.github.sof3.graphmine.util.string.FormattedStringReader
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * Accepts integer arguments.
25 | */
26 | class IntegerArg : CommandArg() {
27 | override fun parse(parser: FormattedStringReader) = try {
28 | parser.nextDelimiter()?.content?.toInt()
29 | } catch (e: NumberFormatException) {
30 | null
31 | }
32 | }
33 |
34 | /**
35 | * Accepts any finite real-numeric arguments.
36 | */
37 | class NumberArg : CommandArg() {
38 | override fun parse(parser: FormattedStringReader) = try {
39 | parser.nextDelimiter()?.content?.toDouble()
40 | } catch (e: NumberFormatException) {
41 | null
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/args/string.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command.args
2 |
3 | import io.github.sof3.graphmine.util.string.FormattedStringReader
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * Accepts the next value in the line. Multi-word arguments can be quoted by `""` or their spaces escaped by `\` before.
25 | */
26 | class StringArg : CommandArg() {
27 | override fun parse(parser: FormattedStringReader) = parser.nextQuoted()?.inner
28 | }
29 |
30 | /**
31 | * Accepts the rest of the whole line literally
32 | */
33 | class RawTextArg : CommandArg() {
34 | override fun parse(parser: FormattedStringReader) = parser.remaining
35 | }
36 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/exception.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command
2 |
3 | import io.github.sof3.graphmine.i18n.I18n
4 | import io.github.sof3.graphmine.i18n.I18nable
5 | import io.github.sof3.graphmine.i18n.core.*
6 | import io.github.sof3.graphmine.i18n.core.CoreLang.Commands.Generic.WrongSyntaxArg
7 |
8 | /*
9 | * GraphMine
10 | * Copyright (C) 2018 SOFe
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU Affero General Public License as published
14 | * by the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU Affero General Public License for more details.
21 | *
22 | * You should have received a copy of the GNU Affero General Public License
23 | * along with this program. If not, see .
24 | */
25 |
26 | /**
27 | * Represents any user-friendly errors reported from commands.
28 | *
29 | * Commands are not required to use this exception. It is only here for more convenient control flow (e.g. can throw
30 | * exception directly instead of calling response() then return)
31 | */
32 | abstract class CommandException : Exception(), I18nable {
33 | /**
34 | * A user-friendly [I18n] describing the problem
35 | */
36 | abstract override val i18n: I18n
37 | }
38 |
39 | /**
40 | * Thrown when a command with wrong syntax is sent.
41 | * @param name command name
42 | * @param syntax list of syntax possible for this command
43 | */
44 | class WrongSyntaxException(private val name: String, private val syntax: List) : CommandException() {
45 | override val i18n get() = CoreLang.commands.generic.wrongSyntax(WrongSyntaxArg(name, syntax))
46 | }
47 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/impl/HelpCommand.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command.impl
2 |
3 | import io.github.sof3.graphmine.Server
4 | import io.github.sof3.graphmine.command.Command
5 | import io.github.sof3.graphmine.command.CommandSender
6 | import io.github.sof3.graphmine.command.Overload
7 | import io.github.sof3.graphmine.i18n.i18n
8 | import io.github.sof3.graphmine.util.qualifier.qualify
9 |
10 | /*
11 | * GraphMine
12 | * Copyright (C) 2018 SOFe
13 | *
14 | * This program is free software: you can redistribute it and/or modify
15 | * it under the terms of the GNU Affero General Public License as published
16 | * by the Free Software Foundation, either version 3 of the License, or
17 | * (at your option) any later version.
18 | *
19 | * This program is distributed in the hope that it will be useful,
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | * GNU Affero General Public License for more details.
23 | *
24 | * You should have received a copy of the GNU Affero General Public License
25 | * along with this program. If not, see .
26 | */
27 |
28 | internal object HelpCommand : Command({
29 | name = "graphmine.help".qualify()
30 |
31 | description = "Shows help information".i18n // TODO localize
32 |
33 | aliases += "h"
34 | aliases += "?"
35 |
36 | class ByPage : Overload() {
37 | val page by integer().default(1)
38 | }
39 | handle {
40 | TODO("implement")
41 | }
42 |
43 | class ByName : Overload() {
44 | val name by string()
45 | }
46 | handle {
47 | TODO("implement")
48 | }
49 | })
50 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/impl/SayCommand.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command.impl
2 |
3 | import io.github.sof3.graphmine.Server
4 | import io.github.sof3.graphmine.command.Command
5 | import io.github.sof3.graphmine.command.CommandSender
6 | import io.github.sof3.graphmine.command.Overload
7 | import io.github.sof3.graphmine.i18n.i18n
8 | import io.github.sof3.graphmine.util.qualifier.qualify
9 |
10 | /*
11 | * GraphMine
12 | * Copyright (C) 2018 SOFe
13 | *
14 | * This program is free software: you can redistribute it and/or modify
15 | * it under the terms of the GNU Affero General Public License as published
16 | * by the Free Software Foundation, either version 3 of the License, or
17 | * (at your option) any later version.
18 | *
19 | * This program is distributed in the hope that it will be useful,
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | * GNU Affero General Public License for more details.
23 | *
24 | * You should have received a copy of the GNU Affero General Public License
25 | * along with this program. If not, see .
26 | */
27 |
28 | internal class SayCommand : Overload() {
29 | companion object : Command({
30 | name = "graphmine.say".qualify()
31 | aliases += "announce"
32 |
33 | description = "".i18n // TODO
34 |
35 | handle {
36 | TODO("Implement")
37 | }
38 | })
39 |
40 | val message by rawText()
41 | }
42 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/impl/VersionCommand.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.command.impl
2 |
3 | import io.github.sof3.graphmine.Server
4 | import io.github.sof3.graphmine.VersionInfo
5 | import io.github.sof3.graphmine.command.Command
6 | import io.github.sof3.graphmine.command.CommandSender
7 | import io.github.sof3.graphmine.command.EmptyOverload
8 | import io.github.sof3.graphmine.i18n.core.*
9 | import io.github.sof3.graphmine.i18n.core.CoreLang.Commands.Version.VersionResponse
10 | import io.github.sof3.graphmine.util.qualifier.qualify
11 |
12 | /*
13 | * GraphMine
14 | * Copyright (C) 2018 SOFe
15 | *
16 | * This program is free software: you can redistribute it and/or modify
17 | * it under the terms of the GNU Affero General Public License as published
18 | * by the Free Software Foundation, either version 3 of the License, or
19 | * (at your option) any later version.
20 | *
21 | * This program is distributed in the hope that it will be useful,
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 | * GNU Affero General Public License for more details.
25 | *
26 | * You should have received a copy of the GNU Affero General Public License
27 | * along with this program. If not, see .
28 | */
29 |
30 | /**
31 | * Implements the /version command
32 | */
33 | object VersionCommand : Command({
34 | name = "graphmine.version".qualify()
35 | aliases += "v"
36 |
37 | description = CoreLang.commands.version.description(Unit)
38 |
39 | handle {
40 | respond(CoreLang.commands.version.response(VersionResponse(VersionInfo.VERSION)))
41 | }
42 | })
43 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/impl/package.md:
--------------------------------------------------------------------------------
1 | # Package io.github.sof3.graphmine.command.impl
2 | This package implements the default commands in GraphMine. Except for [VersionCommand] that serves as the example command, all other commands are internal.
3 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/command/package.md:
--------------------------------------------------------------------------------
1 | # Package io.github.sof3.graphmine.command
2 | This package contains the API for declaring commands.
3 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/config/ConfigEntryDelegate.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.config
2 |
3 | import kotlin.properties.ReadWriteProperty
4 | import kotlin.reflect.KProperty
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * The delegate class to a config entry
26 | * @see ConfigSpec.entry
27 | */
28 | class ConfigEntryDelegate internal constructor(internal var validator: (T) -> String?) : ReadWriteProperty {
29 | internal lateinit var name: () -> String
30 | internal var set = false
31 | internal var value: T? = null
32 |
33 | /**
34 | * Validates the config value.
35 | *
36 | * This method assumes that the value is sufficiently set.
37 | */
38 | internal fun validate() = validator(value!!)
39 |
40 | override operator fun getValue(thisRef: ConfigSpec, property: KProperty<*>) = value!!
41 |
42 | override operator fun setValue(thisRef: ConfigSpec, property: KProperty<*>, value: T) {
43 | set = true
44 | val err = validator(value)
45 | if (err != null) throw IllegalArgumentException("Config entry ${name()} is missing")
46 | this.value = value
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/config/ConfigGroupSpec.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.config
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Superclass of type specifications of groups in a [ConfigSpec]
23 | *
24 | * @see ConfigSpec.group
25 | */
26 | abstract class ConfigGroupSpec> : ConfigSpec() {
27 | internal lateinit var parent: ConfigSpec
28 | internal lateinit var groupName: String
29 |
30 | override val path get() = parent.path + groupName
31 |
32 | /**
33 | * @see Any.run
34 | */
35 | @Suppress("UNCHECKED_CAST")
36 | operator fun invoke(fn: Self.() -> Unit) = (this as Self).run(fn)
37 | }
38 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/config/ConfigSpec.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.config
2 |
3 | import io.github.sof3.graphmine.util.Ref
4 | import io.github.sof3.graphmine.util.notNull
5 | import kotlin.reflect.KProperty
6 |
7 | /*
8 | * GraphMine
9 | * Copyright (C) 2018 SOFe
10 | *
11 | * This program is free software: you can redistribute it and/or modify
12 | * it under the terms of the GNU Affero General Public License as published
13 | * by the Free Software Foundation, either version 3 of the License, or
14 | * (at your option) any later version.
15 | *
16 | * This program is distributed in the hope that it will be useful,
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | * GNU Affero General Public License for more details.
20 | *
21 | * You should have received a copy of the GNU Affero General Public License
22 | * along with this program. If not, see .
23 | */
24 |
25 | /**
26 | * Superclass for type specifications of .kts config files
27 | */
28 | abstract class ConfigSpec {
29 | internal open var entries = mutableMapOf>()
30 | internal val groups = mutableMapOf>()
31 | internal open val path = emptyList()
32 |
33 | /**
34 | * Declares a required entry
35 | * @param T type of entry
36 | * @param validator returns an error string if the config value is incorrect, `null` otherwise
37 | */
38 | protected fun entry(validator: (T) -> String? = { null }) = SimpleConfigEntry(validator)
39 |
40 | /**
41 | * Declares an entry with a default value
42 | * @param T type of entry
43 | * @param default default value to use if the config does not specify this entry.
44 | * @param validator returns an error string if the config value is incorrect, `null` otherwise
45 | * @sample CoreConfig.language
46 | */
47 | protected fun entry(default: T, validator: (T) -> String? = { null }): SimpleConfigEntry = entry(validator).apply {
48 | delegate.set = true
49 | delegate.value = default
50 | }
51 |
52 | /**
53 | * Used in property delegation. Config groups are included in the parent group by property delegation.
54 | * @param G the actual group spec class
55 | * @see ConfigSpec.group
56 | */
57 | protected inner class GroupDelegate>(private val group: G) {
58 | /**
59 | * Provides delegation to the backing group.
60 | */
61 | operator fun provideDelegate(thisRef: ConfigSpec, property: KProperty<*>): Ref {
62 | groups[property.name] = group
63 | group.groupName = property.name
64 | return Ref(group)
65 | }
66 | }
67 |
68 | /**
69 | * Config groups should be included by delegation to this call
70 | * @param group the config to be added
71 | * @return the delegate that can be included by property delegation
72 | * @sample CoreConfig.server
73 | */
74 | protected fun > group(group: G) = GroupDelegate(group.also {
75 | group.parent = this
76 | entries.putAll(group.entries)
77 | group.entries = entries
78 | })
79 |
80 | /**
81 | * Validates the whole config
82 | * @throws ConfigMissingException if a config value is not set
83 | * @throws ConfigValidationException if a config value is invalid
84 | */
85 | fun checkAll() {
86 | for ((_, entry) in entries) {
87 | if (!entry.set) throw ConfigMissingException("The config entry ${entry.name} is required but is not set")
88 | entry.validate().notNull { err ->
89 | throw ConfigValidationException("The config entry ${entry.name} is invalid: $err")
90 | }
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/config/SimpleConfigEntry.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.config
2 |
3 | import kotlin.reflect.KProperty
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * @see ConfigSpec.entry
25 | */
26 | class SimpleConfigEntry internal constructor(validator: (T) -> String?) {
27 | internal val delegate = ConfigEntryDelegate(validator)
28 |
29 | operator fun provideDelegate(thisRef: ConfigSpec, property: KProperty<*>): ConfigEntryDelegate {
30 | thisRef.entries[property.name] = delegate
31 | delegate.name = { (thisRef.path + property.name).joinToString(".") }
32 | return delegate
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/config/exception.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.config
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Thrown when a config has some problems
23 | * @param message the detailed exception message
24 | */
25 | open class ConfigException(message: String) : RuntimeException(message)
26 |
27 | /**
28 | * Thrown when a required entry is missing from a config
29 | * @param message the detailed exception message
30 | */
31 | open class ConfigMissingException(message: String) : ConfigException(message)
32 |
33 | /**
34 | * Thrown when an entry from a config is invalid
35 | * @param message the detailed exception message
36 | */
37 | open class ConfigValidationException(message: String) : ConfigException(message)
38 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/config/spec.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.config
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Model for the server config.yml
23 | */
24 | class CoreConfig(fn: CoreConfig.() -> Unit) : ConfigSpec() {
25 | companion object {
26 | const val VERSION = 1
27 | }
28 |
29 | /**
30 | * The default language to use
31 | */
32 | var language by entry("en_US")
33 |
34 | /**
35 | * Settings for the server
36 | */
37 | val server by group(ServerConfig())
38 |
39 | init {
40 | apply(fn)
41 | }
42 | }
43 |
44 | /**
45 | * Settings for the server
46 | */
47 | class ServerConfig : ConfigGroupSpec() {
48 | /**
49 | * The IP to listen on
50 | *
51 | * Keep this as `0.0.0.0` unless the server has multiple networks.
52 | */
53 | var ip by entry("0.0.0.0")
54 | /**
55 | * The port to listen on
56 | */
57 | var port by entry(19132) { if (it !in 0..65535) "Port must be between 0 and 65535" else null }
58 | }
59 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/entity/Entity.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.entity
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * An entity is a mobile object that exists in a world
23 | *
24 | * An entity follows the ICES structure:
25 | * - a set of Internal viewers that sees what the entity sees
26 | * - a set of Controllers that controls the behaviour of the entity
27 | * - a nullable External viewer that exposes the entity to other viewers
28 | */
29 | class Entity {
30 | /**
31 | * The list of viewers that can view the world from the entity's perspective, i.e. using the entity as a camera
32 | */
33 | val internalViewers = mutableSetOf()
34 | /**
35 | * The list of objects that control the entity's motion and behaviour. They may gain or lose control on the entity,
36 | * or co-work with other controllers to control the entity.
37 | */
38 | val controllers = mutableSetOf()
39 | /**
40 | * The adapter that determines how this entity looks to other viewers, e.g. which model to look like.
41 | */
42 | var externalViewer: ExternalViewer? = null
43 | /**
44 | * Stores the entity-specific information. Can be directly written to or read from disk.
45 | */
46 | var state: EntityState? = null
47 | }
48 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/entity/EntityController.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.entity
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Controls the actions of an entity.
23 | *
24 | * Each instance of EntityController should only be applied on one entity.
25 | */
26 | interface EntityController {
27 | /**
28 | * Invoked when the controller is added to the entity
29 | */
30 | fun onGainControl()
31 |
32 | /**
33 | * Invoked when the controller is removed from the entity
34 | */
35 | fun onLoseControl()
36 | }
37 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/entity/EntityState.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.entity
2 |
3 | import io.github.sof3.graphmine.util.math.Vector3
4 | import io.github.sof3.graphmine.world.World
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * Contains the savable data of an entity
26 | * @property world the world that the entity belongs to
27 | * @param vector the entity's initial position
28 | * @property vector the position of the entity
29 | */
30 | open class EntityState(
31 | var world: World,
32 | var vector: Vector3
33 | )
34 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/entity/EntityViewEvent.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.entity
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Events that an entity's view changes. This may be due to changes in entity external views, blocks in world views, or
23 | * other reasons.
24 | */
25 | interface EntityViewEvent
26 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/entity/ExternalView.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.entity
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Represents one of the appearances of an entity.
23 | */
24 | interface ExternalView
25 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/entity/ExternalViewer.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.entity
2 |
3 | import io.github.sof3.graphmine.world.WorldView
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * Provides an adapter that determines how this entity looks to other entities.
25 | */
26 | interface ExternalViewer {
27 | /**
28 | *
29 | * @param worldView the world view that views the entity
30 | */
31 | fun provideView(worldView: WorldView): ExternalView
32 | }
33 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/entity/InternalViewer.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.entity
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Acts like the receiver to the camera signals of an entity
23 | */
24 | interface InternalViewer {
25 | /**
26 | * Handles a change in what the entity sees.
27 | */
28 | fun receiveEvent(event: EntityViewEvent)
29 | }
30 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/feature/FeatureEdge.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.feature
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Represents the implementation of a feature.
23 | *
24 | * FeatureGraph.handle() provides a convenience inline function for implementing this.
25 | * @see FeatureGraph.handle
26 | */
27 | interface FeatureEdge<
28 | Node1 : FeatureNode,
29 | Node2 : FeatureNode,
30 | Inst1 : FeatureNodeInstance,
31 | Inst2 : FeatureNodeInstance
32 | > {
33 | /**
34 | * Represents one of the endpoint FeatureNodes. Swapping node1 and node2 does not matter.
35 | */
36 | val node1: Node1
37 | /**
38 | * Represents one of the endpoint FeatureNodes. Swapping node1 and node2 does not matter.
39 | */
40 | val node2: Node2
41 |
42 | /**
43 | * The implementation to handle the FeatureEvent.
44 | */
45 | fun handle(inst1: Inst1, inst2: Inst2, event: FeatureEvent)
46 | }
47 |
48 | /**
49 | * Convenience implementation of self-looping FeatureEdge
50 | */
51 | interface SingleFeatureEdge<
52 | Node : FeatureNode,
53 | Inst : FeatureNodeInstance>
54 | : FeatureEdge {
55 | /**
56 | * the node that the edge incidents with
57 | */
58 | val node: Node
59 | override val node1 get() = node
60 | override val node2 get() = node
61 |
62 | override fun handle(inst1: Inst, inst2: Inst, event: FeatureEvent) {
63 | assert(inst1 === inst2)
64 | return handle(inst1, event)
65 | }
66 |
67 | /**
68 | * The implementation to handle the FeatureEvent.
69 | */
70 | fun handle(inst: Inst, event: FeatureEvent)
71 | }
72 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/feature/FeatureEvent.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.feature
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Represents an event on some node(s). Implementations shall contain mutable and immutable properties for FeatureEdges
23 | * to read and modify, except the FeatureNodeInstances do not need to be in the event since
24 | * they are passed to the event in a different way.
25 | */
26 | interface FeatureEvent
27 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/feature/FeatureGraph.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.feature
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * The Feature Graph is the main registry of features in the server. It is an undirected multi-graph that allows
23 | * FeatureEdges (the features themselves) to handle interaction events (FeatureEvent) between FeatureNodes (the objects
24 | * of features, e.g. entities, blocks, or abstract concepts like commands), or self-loop edges that handle events on
25 | * a single object (e.g. player join).
26 | */
27 | class FeatureGraph {
28 | /**
29 | * the features registered on this server
30 | */
31 | val edges: MutableMap,
32 | MutableMap,
33 | MutableSet>>> = hashMapOf()
34 |
35 | /**
36 | * Registers a FeatureNode so that edges can be added upon it
37 | */
38 | fun addNode(node: FeatureNode<*, *>) {
39 | edges[node] = mutableMapOf()
40 | }
41 |
42 | /**
43 | * Registers a FeatureEdge
44 | */
45 | fun addEdge(edge: FeatureEdge<
46 | out FeatureNode<*, *>,
47 | out FeatureNode<*, *>,
48 | out FeatureNodeInstance<*, *>,
49 | out FeatureNodeInstance<*, *>>
50 | ) {
51 | edges[edge.node1]!![edge.node2]!!.add(edge)
52 | edges[edge.node2]!![edge.node1]!!.add(edge)
53 | }
54 |
55 | /**
56 | * Dispatch a single-node event
57 | */
58 | fun , Inst2 : FeatureNodeInstance>
59 | dispatch(inst1: Inst1, inst2: Inst2, event: FeatureEvent) {
60 | getEdges(inst1, inst1)?.forEach { it.handle(inst1, inst1, event) }
61 | getEdges(inst1, inst2)?.forEach { it.handle(inst1, inst2, event) }
62 | // getEdges(inst2, inst1)?.forEach { it.handle(inst2, inst1, event) } // edges should have been registered bidirectionally
63 | getEdges(inst2, inst2)?.forEach { it.handle(inst2, inst2, event) }
64 | }
65 |
66 | /**
67 | * Dispatch a two-node event
68 | */
69 | fun > dispatch(inst: Inst, event: FeatureEvent) {
70 | getEdges(inst, inst)?.forEach { it.handle(inst, inst, event) }
71 | }
72 |
73 | @Suppress("UNCHECKED_CAST")
74 | private fun , Inst2 : FeatureNodeInstance> getEdges(inst1: Inst1, inst2: Inst2):
75 | MutableSet, out FeatureNode<*, Inst2>, Inst1, Inst2>>? =
76 | edges[inst1.node]!![inst2.node] as MutableSet, out FeatureNode<*, Inst2>, Inst1, Inst2>>?
77 | }
78 |
79 | /**
80 | * A convenient wrapper for FeatureGraph.addEdge and SingleFeatureEdge construction (for one node)
81 | */
82 | inline fun , Inst : FeatureNodeInstance, reified Ev : FeatureEvent>
83 | FeatureGraph.handle(node: Node, crossinline fn: (inst: Inst, event: Ev) -> Unit) {
84 | addEdge(SingleFeatureHandler(node) { inst, event -> if (event is Ev) fn(inst, event) })
85 | }
86 |
87 | /** @internal */
88 | class SingleFeatureHandler, Inst : FeatureNodeInstance>(
89 | override val node: Node,
90 | private val fn: (inst: Inst, event: FeatureEvent) -> Unit
91 | ) : SingleFeatureEdge {
92 | override fun handle(inst: Inst, event: FeatureEvent) = fn(inst, event)
93 | }
94 |
95 | /**
96 | * A convenient wrapper for FeatureGraph.addEdge and FeatureEdge construction (for two nodes)
97 | */
98 | inline fun , Inst1 : FeatureNodeInstance,
99 | Node2 : FeatureNode, Inst2 : FeatureNodeInstance,
100 | reified Ev : FeatureEvent>
101 | FeatureGraph.handle(node1: Node1, node2: Node2, crossinline fn: (inst1: Inst1, inst2: Inst2, event: Ev) -> Unit) {
102 | addEdge(DoubleFeatureHandler(node1, node2) { inst1, inst2, event -> if (event is Ev) fn(inst1, inst2, event) })
103 | }
104 |
105 | /** @internal */
106 | class DoubleFeatureHandler, Inst1 : FeatureNodeInstance,
107 | Node2 : FeatureNode, Inst2 : FeatureNodeInstance>(
108 | override val node1: Node1,
109 | override val node2: Node2,
110 | private val fn: (Inst1, Inst2, FeatureEvent) -> Unit
111 | ) : FeatureEdge {
112 | override fun handle(inst1: Inst1, inst2: Inst2, event: FeatureEvent) = fn(inst1, inst2, event)
113 | }
114 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/feature/FeatureNode.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.feature
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Represents a concrete or abstract concept that can interact with itself or other FeatureNodes, such as an entity,
23 | * a block, a client or a command.
24 | *
25 | * If the implementation is a singleton, it is recommended that FeatureNode be implemented in the companion object of
26 | * the corresponding FeatureNodeInstance.
27 | *
28 | * @param Self the actual class implementing FeatureNode. It is not mandatory to pass the actual instance type, but it
29 | * is recommended if possible to improve type prediction
30 | * @param Inst the FeatureNodeInstance class corresponding to Self.
31 | */
32 | interface FeatureNode, Inst : FeatureNodeInstance>
33 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/feature/FeatureNodeInstance.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.feature
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Represents an instance of FeatureNode. The FeatureNode represents the type in general, while FeatureNodeInstance
23 | * represents each instance of the type. It is valid for FeatureNodeInstance to be singleton or even same as the
24 | * FeatureNode. For example, each instance of the Client class represents one client, while the singleton Client.Node
25 | * companion object represents the client type.
26 | */
27 | interface FeatureNodeInstance, Node : FeatureNode> {
28 | /**
29 | * the corresponding node for the instance.
30 | */
31 | val node: Node
32 | }
33 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/scope/BaseScope.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.scope
2 |
3 | import kotlinx.coroutines.Job
4 | import kotlin.coroutines.CoroutineContext
5 | import kotlin.reflect.KClass
6 |
7 | /**
8 | * Basic implementation of BaseScope
9 | *
10 | * @property name the scope name
11 | * @property parent the parent scope (if any)
12 | */
13 | open class BaseScope(final override val name: String, val parent: BaseScope? = null) : Scope {
14 | /**
15 | * @param klass the class to be used in the scope name
16 | * @param name the scope name
17 | * @param parent the parent scope (if any)
18 | */
19 | constructor(klass: KClass, name: String, parent: BaseScope? = null) : this("${klass.qualifiedName}:$name", parent)
20 |
21 | /**
22 | * @param klass the class to be used in the scope name
23 | * @param parent the parent scope (if any)
24 | */
25 | constructor(klass: KClass, parent: BaseScope? = null) : this(klass.qualifiedName!!, parent)
26 |
27 | override var isDisposed = false
28 | protected set
29 |
30 | private var disposalHooks = mutableListOf<() -> Unit>()
31 |
32 | override val coroutineContext: CoroutineContext
33 | get() = if (parent != null) parent.coroutineContext + Job() else Job()
34 |
35 | @Suppress("OVERRIDE_BY_INLINE")
36 | override fun addOnDispose(fn: () -> Unit) {
37 | disposalHooks.add(fn)
38 | }
39 |
40 | /**
41 | * Marks the scope as disposed.
42 | */
43 | open fun dispose() {
44 | isDisposed = true
45 |
46 | disposalHooks.forEach { it() }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/scope/Scope.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.scope
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * A Scope represents some period of persistence. Features are enabled only during the scope is not disposed. Builtin
25 | * scopes include:
26 | *
27 | * - Server scope: Until the server is stopped
28 | * - Player scope: Until the player leaves the server
29 | * - Plugin scope: While the plugin is enabled
30 | * - World scope: While the world is loaded
31 | * - World partition scope: While the world partition is loaded
32 | *
33 | * Plugins may create their own scopes too, e.g. a Hunger Games plugin may create a scope that lasts during the Hunger Games tournament
34 | *
35 | * A scope is also a coroutine scope. Coroutines may be started from the scope.
36 | */
37 | interface Scope : CoroutineScope {
38 | val name: String
39 |
40 | /**
41 | * whether the scope has been disposed
42 | */
43 | val isDisposed: Boolean
44 |
45 | /**
46 | * Adds an action to execute when the scope is disposed
47 | */
48 | fun addOnDispose(fn: () -> Unit)
49 | }
50 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/world/Block.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.world
2 |
3 | import io.github.sof3.graphmine.feature.FeatureNode
4 | import io.github.sof3.graphmine.feature.FeatureNodeInstance
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * Represents a block type.
26 | *
27 | * This class is only used as a wrapper for the block ID along with FeatureNode identification. In other words, it can
28 | * be said that this class only exists for documentation purpose.
29 | */
30 | data class Block(
31 | /**
32 | * The block ID. This may be changed in the future.
33 | */
34 | val id: Int
35 | ) : FeatureNode
36 |
37 | /**
38 | * Represents a block type at a certain location. The existence persistence of this block is irrelevant to whether the
39 | * block is really at the location, ever at the location or has been removed. This is a pure value class.
40 | */
41 | data class BlockInstance(
42 | /**
43 | * the block type
44 | */
45 | val block: Block,
46 | /**
47 | * the expected location of the block
48 | */
49 | val location: BlockLocation
50 | ) : FeatureNodeInstance {
51 | override val node get() = block
52 | }
53 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/world/BlockLocation.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.world
2 |
3 | import io.github.sof3.graphmine.util.math.IntVector3
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * A unique identifier for an integer location.
25 | *
26 | * Out-of-bounds block locations are intentionally allowed, because normally out-of-bounds locations like negative
27 | * locations may be valid for certain world formats. While they are not valid for the client, the World implementation
28 | * is responsible for translating coordinates to something the client can see. This should not interfere with plugins'
29 | * ability to interpret the world in a sensible manner.
30 | */
31 | data class BlockLocation(
32 | /**
33 | * The positional vector of the location
34 | */
35 | val vector: IntVector3,
36 | /**
37 | * The world that the location is in
38 | */
39 | val world: World
40 | )
41 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/world/Blocks.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.world
2 |
3 | /**
4 | * The list of default Block instances. Plugins are not expected to add custom block types to this list
5 | */
6 | object Blocks {
7 | /***/
8 | val AIR = Block(0)
9 | /***/
10 | val STONE = Block(1)
11 | // TODO generate more block types
12 | }
13 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/world/Location.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.world
2 |
3 | import io.github.sof3.graphmine.util.math.Vector3
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * Represents a point in the 3D space of a world.
25 | */
26 | data class Location(
27 | /**
28 | * The position vector for the location
29 | */
30 | val vector: Vector3,
31 | /**
32 | * The world that the location is in
33 | */
34 | val world: World
35 | )
36 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/world/World.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.world
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Each world has its set of 3D space. Usually, this is implemented as one saved map, but plugins may create virtual
23 | * worlds, remote worlds or anything that features the characteristics as required by the interface.
24 | *
25 | * As the World object itself is used as the identifier, implementations should not override the equals() and hashCode()
26 | * methods.
27 | */
28 | interface World {
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/world/WorldPartition.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.world
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Represents a partition of a World. World partitioning is controlled by the server based on WorldUser activity.
23 | */
24 | interface WorldPartition {
25 | }
26 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/world/WorldUser.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.world
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Represents a user of a world that holds resources from being freed.
23 | */
24 | interface WorldUser {
25 | }
26 |
--------------------------------------------------------------------------------
/graphmine-core/src/main/kotlin/io/github/sof3/graphmine/world/WorldView.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.world
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * An adapter that intercepts between a world viewer and the actual world.
23 | */
24 | interface WorldView {
25 | }
26 |
--------------------------------------------------------------------------------
/graphmine-i18n-core/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * GraphMine
3 | * Copyright (C) 2018 SOFe
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | plugins {
20 | java
21 | kotlin("jvm")
22 | }
23 |
24 | group = "io.github.sof3.graphmine"
25 | version = "1.0.0-SNAPSHOT"
26 |
27 | dependencies {
28 | implementation(kotlin("stdlib-jdk8"))
29 | implementation(project(":graphmine-i18n"))
30 | implementation(project(":graphmine-util"))
31 | testImplementation(kotlin("test"))
32 | testImplementation("org.spekframework.spek2:spek-dsl-jvm:2.0.0-alpha.2")
33 | testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:2.0.0-alpha.2")
34 | }
35 |
--------------------------------------------------------------------------------
/graphmine-i18n-core/module.md:
--------------------------------------------------------------------------------
1 | # Module graphmine-i18n-core
2 | This module is an implementation of graphmine-i18n that contains the declarations required for the core.
3 |
--------------------------------------------------------------------------------
/graphmine-i18n-core/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "graphmine-i18n-core"
2 |
3 |
--------------------------------------------------------------------------------
/graphmine-i18n-core/src/main/kotlin/io/github/sof3/graphmine/i18n/core/CoreLang.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.i18n.core
2 |
3 | import io.github.sof3.graphmine.i18n.GroupSpec
4 | import io.github.sof3.graphmine.i18n.I18n
5 | import io.github.sof3.graphmine.i18n.LangSpec
6 | import java.io.File
7 |
8 | /*
9 | * GraphMine
10 | * Copyright (C) 2018 SOFe
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU Affero General Public License as published
14 | * by the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU Affero General Public License for more details.
21 | *
22 | * You should have received a copy of the GNU Affero General Public License
23 | * along with this program. If not, see .
24 | */
25 |
26 | object CoreLang : LangSpec() {
27 | val serverName by accept()
28 |
29 | val startup by group(Startup)
30 |
31 | object Startup : GroupSpec() {
32 | val locked by accept()
33 |
34 | data class LockedArg(val file: File)
35 |
36 | val version by accept()
37 |
38 | data class VersionArg(val version: String, val ip: String, val port: Int)
39 |
40 | val complete by accept()
41 |
42 | data class CompleteArg(val nano: Long)
43 | }
44 |
45 | val commands by group(Commands)
46 |
47 | object Commands : GroupSpec() {
48 | val generic by group(Generic)
49 |
50 | object Generic : GroupSpec() {
51 | val notFound by accept()
52 |
53 | data class NotFoundArg(val command: String)
54 |
55 | val wrongSyntax by accept()
56 |
57 | data class WrongSyntaxArg(val command: String, val syntax: List)
58 | }
59 |
60 | val version by group(Version)
61 |
62 | object Version : GroupSpec() {
63 | val description by accept()
64 | val response by accept()
65 |
66 | data class VersionResponse(val version: String)
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/graphmine-i18n-core/src/main/kotlin/io/github/sof3/graphmine/i18n/core/CoreLangLoader.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.i18n.core
2 |
3 | import io.github.sof3.graphmine.i18n.loadLangScript
4 |
5 | val availableLocales = listOf(
6 | "en_US"
7 | )
8 |
9 | fun loadCoreLang() {
10 | loadLangScript(availableLocales)
11 | }
12 |
--------------------------------------------------------------------------------
/graphmine-i18n-core/src/main/resources/io/github/sof3/graphmine/i18n/core/en_US.lang.kts:
--------------------------------------------------------------------------------
1 | import io.github.sof3.graphmine.i18n.core.*
2 | import kotlin.math.round
3 |
4 | /*
5 | * GraphMine
6 | * Copyright (C) 2018 SOFe
7 | *
8 | * This program is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU Affero General Public License as published
10 | * by the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU Affero General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU Affero General Public License
19 | * along with this program. If not, see .
20 | */
21 |
22 | CoreLang("en_US") {
23 | serverName { "GraphMine" }
24 | startup {
25 | locked { "Another server is already running in the data directory $file" }
26 | version { "Starting GraphMine version $version on $ip:$port" }
27 | complete { "Startup completed in ${round(nano / 1e+6) / 1e+3}s" }
28 | }
29 | commands {
30 | generic {
31 | notFound { """Command "$command" not found""" }
32 | wrongSyntax {
33 | """Wrong format for "$command". """ +
34 | if (syntax.size == 1) "Correct format: ${syntax[0]}"
35 | else syntax.joinToString("\n", "Possible format:\n")
36 | }
37 | }
38 | version {
39 | description { "Shows the server version" }
40 | response { "The server is running GraphMine version $version" }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/graphmine-i18n-core/src/test/kotlin/io/github/sof3/graphmine/i18n/core/TranslationTest_en_US.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.i18n.core
2 |
3 | import io.github.sof3.graphmine.i18n.Declaration
4 | import org.spekframework.spek2.Spek
5 | import org.spekframework.spek2.style.gherkin.Feature
6 | import org.spekframework.spek2.style.gherkin.ScenarioBody
7 | import kotlin.test.assertEquals
8 |
9 | /*
10 | * GraphMine
11 | * Copyright (C) 2018 SOFe
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU Affero General Public License as published
15 | * by the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU Affero General Public License for more details.
22 | *
23 | * You should have received a copy of the GNU Affero General Public License
24 | * along with this program. If not, see .
25 | */
26 |
27 | object TranslationTest_en_US : Spek({
28 | fun ScenarioBody.expect(decl: Declaration, arg: Arg, expected: String) {
29 | lateinit var actual: String
30 | Given("${decl.pathJoined} with ${arg.toString()}") { actual = decl(arg)["en_US"] }
31 | Then("Translation should be \"$expected\"") { assertEquals(expected, actual) }
32 | }
33 |
34 | Feature("GraphMine en_US translation") {
35 | val lang by memoized { loadCoreLang(); CoreLang }
36 |
37 | fun ScenarioBody.expect(decl: Declaration, s: String) = expect(decl, Unit, s)
38 |
39 | Scenario("serverName") { expect(lang.serverName, "GraphMine") }
40 | }
41 | })
42 |
43 |
--------------------------------------------------------------------------------
/graphmine-i18n/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * GraphMine
3 | * Copyright (C) 2018 SOFe
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | plugins {
20 | java
21 | kotlin("jvm")
22 | }
23 |
24 | group = "io.github.sof3.graphmine"
25 | version = "1.0.0-SNAPSHOT"
26 |
27 | dependencies {
28 | api(project(":graphmine-util"))
29 | implementation(kotlin("stdlib-jdk8"))
30 | }
31 |
--------------------------------------------------------------------------------
/graphmine-i18n/module.md:
--------------------------------------------------------------------------------
1 | # Module graphmine-i18n
2 | This module provides a kotlin-flavoured i18n (internationalization) framework.
3 |
4 | ## Main Concepts
5 | ### Locale
6 | A locale refers to a human language. It does not need to be an ISO-639 language code; the convention should be determined by the user of this module based on its context, as long as it can be represented in a simple `kotlin.String`.
7 |
8 | ### i18n
9 | An i18n object represents a text displayed differently given different locales. In code, it is represented with the `I18n` interface
10 |
11 | Logically, i18n is the conversion `(locale: String) -> (humanReadable: String)`
12 |
13 | ### Declaration
14 | A declaration is the specification that a dynamic i18n is required by a module based on an argument of type `Arg`. This `Arg` type should either be `Unit` or a kotlin `data class`.
15 |
16 | Logically, a declaration has the conversions:
17 | - `(arg: Arg) -> i18n`
18 | - `(arg: Arg, locale: String) -> (humanReadable: String)`
19 | - `(locale: Locale) -> Translation` (in the next section)
20 |
21 | ### Translation
22 | A translation is the specialization of a declaration in a particular locale. In code, it is represented with the lambda function `(arg: Arg) -> (humanReadable: String)`.
23 |
24 | Translations may perform any memoryless operations, i.e. given the same `Arg` and the same current timestamp, a translation should always return the same string.
25 |
26 | ### Path
27 | A path is the unique identifier of a declaration within a module, composed of one or multiple valid JVM identifier (including those that require the `backtick` syntax in kotlin) strings. In code, a path is represented as an `Array`.
28 |
29 | ## Usage
30 | A module may require translations by declaring a LangSpec class:
31 |
32 | ```kotlin
33 | class MySpecName : LangSpec() {
34 | val declOne by accept() // creates the declaration with path "declOne" and arg type "Unit", i.e. it does not require an argument.
35 |
36 | val declTwo by accept() // creates the declaration with path "declTwo" and arg type "ArgTwo"
37 | data class ArgTwo(val one: String, val two: Int) // translations can reference them as $one and $two
38 |
39 | val groupThree by group(GroupThree())
40 | class GroupThree : GroupSpec() {
41 | val subFour by accept() // creates the declaration with path "groupThree.subFour"
42 | val subFive by accept() // arg types may be reused.
43 | }
44 | }
45 | ```
46 |
47 | Also create a convenience infix function:
48 |
49 | ```kotlin
50 | infix fun String.translatesMySpecName (fn: MySpecName.() -> Unit) = MySpecName().apply {
51 | locale = this@translatesMySpecName
52 | fn()
53 | }
54 | ```
55 |
56 | Translations scripts can then invoke strings with lambdas on this class:
57 |
58 | ```kotlin
59 | "en_US" translatesMySpecName { // provides translations in the locale "en_US"
60 | declOne { "Hello world!" }
61 | declTwo { "arg1 is $one and arg2 is half of ${two * 2}" }
62 | groupThree {
63 | subFour = "this is an inner translation"
64 | subFive = "I don't actually need to use all the args provided, because I only like $two but not one."
65 | }
66 | }
67 | ```
68 |
69 | Not all messages need to be translated. If it is not provided in one locale, it fallbacks to the first locale registered, then the second one, vice versa. If it is not found in any locales, the message path will be used..
70 |
71 | ```kotlin
72 | "zh_HK" translatesMySpecName {
73 | declOne { "你好,世界!" }
74 | declTwo { "第一個參數是$one,而第二個參數是${two}的一半" }
75 | groupThree {
76 | // we skipped subFour, and this is OK
77 | subFive = "英文翻譯中沒有用${one},但是在其他語言中也可以用。"
78 | }
79 | }
80 | ```
81 |
82 | Note that in locales without spaces, translations may need to wrap variable references with `${}`. In this zh_HK example, normal Chinese characters like `的一半` are parsed as part of the variable name without the `{}`, while Chinese punctuation characters are not. Since the translator may be unsure whether a character is a valid JVM identifier, it is recommended that variables always be quoted (even unnecessarily).
83 |
84 | Scripts should be placed in the spec class resource path, i.e. if the LangSpec subclass is `io.github.sof3.graphmine.i18n.core.CoreSpec`, the lang scripts should be placed in `io/github/sof3/graphmine/i18n/core/{locale}.lang.kts` of the corresponding resources directory.
85 |
86 | To load the scripts into a `LangSpec` object, call `io.github.sof3.graphmine.i18n.loadLangScript` with the `LangSpec` subclass as the type parameter and a list of locale names as the argument:
87 |
88 | ```kotlin
89 | val spec = loadLangScript(listOf(
90 | "en_US",
91 | "zh_HK"
92 | ))
93 | ```
94 |
95 | One of the instances of `MySpecName` will be returned (it is undefined which one is returned). Whichever instance it returns, the API is the same: To retrieve the I18nable representation of a message `path.to.decl`, simply call `spec.path.to.decl.i18n()` (or `spec.path.to.decl.i18n(arg)` if it requires an argument).
96 |
97 | Note: Although a `LangSpec` object is created for every locale, the `.i18n` accessor works the same in any locale of `LangSpec`, so just take any `LangSpec` returned by the translation scripts.
98 |
99 |
--------------------------------------------------------------------------------
/graphmine-i18n/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "graphmine-i18n"
2 |
--------------------------------------------------------------------------------
/graphmine-i18n/src/main/kotlin/io/github/sof3/graphmine/i18n/Declaration.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.i18n
2 |
3 | import kotlin.properties.ReadOnlyProperty
4 | import kotlin.reflect.KProperty
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | typealias Translation = T.() -> String
25 |
26 | class Declaration(private val spec: () -> LangSpec<*>, private val pathGet: () -> List) : ReadOnlyProperty, Declaration> {
27 | val translations = linkedMapOf>()
28 | val path by lazy { pathGet() }
29 | val pathJoined by lazy { path.joinToString(".") }
30 |
31 | /**
32 | * Dummy function to satisfy the ReadOnlyProperty interface
33 | */
34 | override fun getValue(thisRef: LangSpec<*>, property: KProperty<*>) = this
35 |
36 | /**
37 | * To be called by translation scripts to provide a translation.
38 | */
39 | operator fun invoke(fn: Translation) {
40 | translations[spec().locale!!] = fn
41 | }
42 |
43 | /**
44 | * To be called by translation users to obtain a specific I18n for this declaration.
45 | */
46 | operator fun invoke(arg: Arg): I18n {
47 | return SpecI18N(arg, this)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/graphmine-i18n/src/main/kotlin/io/github/sof3/graphmine/i18n/GroupSpec.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.i18n
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | abstract class GroupSpec> : LangSpec() {
22 | lateinit var parent: LangSpec<*>
23 | lateinit var name: String
24 |
25 | override val rootSpec: LangSpec<*> get() = parent
26 | override var locale: String?
27 | get() = parent.locale
28 | set(_) = throw RuntimeException("Cannot set locale on group spec")
29 | override val path get() = parent.path + name
30 |
31 | operator fun invoke(fn: Self.() -> Unit) {
32 | @Suppress("UNCHECKED_CAST") fn(this as Self)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/graphmine-i18n/src/main/kotlin/io/github/sof3/graphmine/i18n/I18n.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.i18n
2 |
3 | import io.github.sof3.graphmine.util.KtsLoader
4 | import java.io.InputStreamReader
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | interface I18n {
25 | operator fun get(locale: String): String
26 | }
27 |
28 | inline fun > loadLangScript(locales: Iterable) {
29 | for (locale in locales) {
30 | val url = T::class.java.getResource("$locale.lang.kts")!!
31 |
32 | KtsLoader.load(InputStreamReader(url.openStream()!!)) // no caching for singletons :(
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/graphmine-i18n/src/main/kotlin/io/github/sof3/graphmine/i18n/I18nable.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.i18n
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * An object that can be expressed i18nly
23 | */
24 | interface I18nable {
25 | /**
26 | * the i18nized expression of the object
27 | */
28 | val i18n: I18n
29 | }
30 |
--------------------------------------------------------------------------------
/graphmine-i18n/src/main/kotlin/io/github/sof3/graphmine/i18n/LangSpec.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.i18n
2 |
3 | import io.github.sof3.graphmine.util.DelegateProvider
4 | import io.github.sof3.graphmine.util.Ref
5 | import kotlin.properties.ReadOnlyProperty
6 | import kotlin.reflect.KProperty
7 |
8 | /*
9 | * GraphMine
10 | * Copyright (C) 2018 SOFe
11 | *
12 | * This program is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU Affero General Public License as published
14 | * by the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * This program is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU Affero General Public License for more details.
21 | *
22 | * You should have received a copy of the GNU Affero General Public License
23 | * along with this program. If not, see .
24 | */
25 |
26 | abstract class LangSpec> {
27 | open val rootSpec: LangSpec<*> get() = this
28 | open var locale: String? = null
29 | open val path = emptyList()
30 |
31 | val declarations = hashMapOf>()
32 | val groups = hashMapOf>()
33 |
34 | // to be invoked from translation
35 | inline operator fun invoke(locale: String, fn: Self.() -> Unit): LangSpec {
36 | if (this.locale != null) throw ConcurrentModificationException("Concurrent calls to forLocale()")
37 | try {
38 | this.locale = locale
39 | @Suppress("UNCHECKED_CAST") fn(this as Self)
40 | } finally {
41 | this.locale = null
42 | }
43 | return this
44 | }
45 |
46 | /**
47 | * Invoked by declaration subclasses to create a single declaration
48 | */
49 | fun accept() = object : DelegateProvider> {
50 | override fun provideDelegate(thisRef: Self, property: KProperty<*>): ReadOnlyProperty> {
51 | val declaration = Declaration({ rootSpec }, { path + property.name })
52 | declarations[property.name] = declaration
53 | return declaration
54 | }
55 | }
56 |
57 | /**
58 | * Invoked by declaration subclasses to create a declaration group
59 | */
60 | fun > group(group: Grp) = object : DelegateProvider {
61 | override fun provideDelegate(thisRef: Self, property: KProperty<*>): ReadOnlyProperty {
62 | group.parent = this@LangSpec
63 | group.name = property.name
64 | groups[property.name] = group
65 | return Ref(group)
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/graphmine-i18n/src/main/kotlin/io/github/sof3/graphmine/i18n/LiteralI18N.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.i18n
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | class LiteralI18N(val string: String) : I18n {
22 | override fun get(locale: String) = string
23 | }
24 |
25 | val String.i18n get() = LiteralI18N(this)
26 |
--------------------------------------------------------------------------------
/graphmine-i18n/src/main/kotlin/io/github/sof3/graphmine/i18n/SpecI18N.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.i18n
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | class SpecI18N internal constructor(private val arg: Arg, private val declaration: Declaration) : I18n {
22 | override fun get(locale: String): String {
23 | val best = declaration.translations[locale]
24 | if (best != null) return best(arg)
25 |
26 | val iter = declaration.translations.iterator()
27 | if (iter.hasNext()) return iter.next().value(arg)
28 |
29 | return declaration.pathJoined
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/graphmine-util/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * GraphMine
3 | * Copyright (C) 2018 SOFe
4 | *
5 | * This program is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU Affero General Public License as published
7 | * by the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * This program is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU Affero General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU Affero General Public License
16 | * along with this program. If not, see .
17 | */
18 |
19 | plugins {
20 | java
21 | kotlin("jvm")
22 | }
23 |
24 | group = "io.github.sof3.graphmine"
25 | version = "1.0.0-SNAPSHOT"
26 |
27 | dependencies {
28 | implementation(kotlin("stdlib-jdk8"))
29 | implementation(kotlin("reflect"))
30 |
31 | implementation("commons-io:commons-io:2.6")
32 |
33 | runtimeOnly(kotlin("compiler-embeddable"))
34 | runtimeOnly(kotlin("script-util"))
35 |
36 | testImplementation(kotlin("test"))
37 | testImplementation("org.spekframework.spek2:spek-dsl-jvm:2.0.0-alpha.2")
38 | testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:2.0.0-alpha.2")
39 | }
40 |
--------------------------------------------------------------------------------
/graphmine-util/module.md:
--------------------------------------------------------------------------------
1 | # Module graphmine-util
2 | This module provides general-purpose that cannot be classified. Most of them are to supplement the Kotlin language API.
3 |
--------------------------------------------------------------------------------
/graphmine-util/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "graphmine-util"
2 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/DataUtil.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util
2 |
3 | import java.io.DataInputStream
4 | import java.io.DataOutputStream
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | fun DataInputStream.readString(): String {
25 | val length = readInt()
26 | val buf = ByteArray(length)
27 | read(buf)
28 | return String(buf)
29 | }
30 |
31 | fun DataOutputStream.writeString(string: String) {
32 | val buf = string.toByteArray()
33 | writeInt(buf.size)
34 | write(buf)
35 | }
36 |
37 | inline fun DataInputStream.readMap(keyFn: (DataInputStream) -> K, valueFn: (DataInputStream) -> V) = readMap(mutableMapOf(), keyFn, valueFn)
38 | inline fun DataInputStream.readMap(map: MutableMap, keyFn: (DataInputStream) -> K, valueFn: (DataInputStream) -> V): MutableMap {
39 | val size = readInt()
40 | repeat(size) {
41 | val key = keyFn(this)
42 | val value = valueFn(this)
43 | map[key] = value
44 | }
45 | return map
46 | }
47 |
48 | inline fun DataOutputStream.writeMap(map: MutableMap, keyFn: (DataOutputStream, K) -> Unit, valueFn: (DataOutputStream, V) -> Unit): MutableMap {
49 | writeInt(map.size)
50 | for ((k, v) in map) {
51 | keyFn(this, k)
52 | valueFn(this, v)
53 | }
54 | return map
55 | }
56 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/DelegateProvider.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util
2 |
3 | import kotlin.properties.ReadOnlyProperty
4 | import kotlin.reflect.KProperty
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * An interface to help completing the `provideDelegate` operator function for `val` property delegation.
26 | */
27 | interface DelegateProvider {
28 | /**
29 | * Provide the [ReadOnlyProperty] for delegation. Could use [Ref] if no special logic is required.
30 | */
31 | operator fun provideDelegate(thisRef: R, property: KProperty<*>): ReadOnlyProperty
32 | }
33 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/KtsBin.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util
2 |
3 | import java.io.DataInputStream
4 | import java.io.DataOutputStream
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | interface KtsBin, F : KtsBin.Factory> {
25 | fun write(dis: DataOutputStream)
26 |
27 | interface Factory, F : Factory> {
28 | fun read(dis: DataInputStream): T
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/KtsLoader.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util
2 |
3 | import org.apache.commons.io.IOUtils
4 | import org.apache.commons.io.input.TeeInputStream
5 | import java.io.*
6 | import java.security.DigestOutputStream
7 | import java.security.MessageDigest
8 | import javax.script.ScriptEngineManager
9 |
10 | /*
11 | * GraphMine
12 | * Copyright (C) 2018 SOFe
13 | *
14 | * This program is free software: you can redistribute it and/or modify
15 | * it under the terms of the GNU Affero General Public License as published
16 | * by the Free Software Foundation, either version 3 of the License, or
17 | * (at your option) any later version.
18 | *
19 | * This program is distributed in the hope that it will be useful,
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | * GNU Affero General Public License for more details.
23 | *
24 | * You should have received a copy of the GNU Affero General Public License
25 | * along with this program. If not, see .
26 | */
27 |
28 | /**
29 | * State object to ensure system properties are set before loading a script
30 | */
31 | object KtsLoader {
32 | init {
33 | System.setProperty("idea.io.use.fallback", "true")
34 | }
35 |
36 | /**
37 | * Loads a .kts file, optionally from cache and stores to cache
38 | *
39 | * @param T the type
40 | */
41 | inline fun , F : KtsBin.Factory> loadSerializable(factory: F, fis: InputStream, path: String, cacheDir: File, rVersion: Int): T {
42 | cacheDir.mkdirs()
43 | val cacheFile = File(cacheDir, "kts-" + path.hashCode().toString(16))
44 |
45 | val digestBuf = ByteArrayOutputStream()
46 | val digest = DigestOutputStream(digestBuf, MessageDigest.getInstance("MD5")!!)
47 | val tee = TeeInputStream(fis, digest)
48 |
49 | val raw = ByteArrayOutputStream()
50 | tee.use { IOUtils.copy(tee, raw) }
51 |
52 | val md5 = digestBuf.toByteArray()!!
53 | assert(md5.size == 16)
54 | val load = loadCache(md5, cacheFile, rVersion) { factory.read(it) }
55 | if (load != null) return load
56 | val loaded = load(StringReader(String(raw.toByteArray())))
57 | writeCache(cacheFile, md5, rVersion, loaded)
58 | return loaded
59 | }
60 |
61 | fun loadCache(md5: ByteArray, cacheFile: File, rVersion: Int, read: (DataInputStream) -> T): T? {
62 | if (!cacheFile.isFile) return null
63 | return DataInputStream(FileInputStream(cacheFile)).use {
64 | val buffer = ByteArray(16)
65 | it.read(buffer)
66 | if (!buffer.contentEquals(md5)) return null
67 | val version = it.readInt()
68 | if (version != rVersion) return null
69 | read(it)
70 | }
71 | }
72 |
73 | fun writeCache(cacheFile: File, md5: ByteArray, rVersion: Int, value: KtsBin<*, *>) {
74 | return DataOutputStream(FileOutputStream(cacheFile)).use {
75 | it.write(md5)
76 | it.writeInt(rVersion)
77 | value.write(it)
78 | }
79 | }
80 |
81 | /**
82 | * Loads a script from a reader
83 | *
84 | * @param R the expected return type from the script
85 | * @return the value in the script
86 | */
87 | inline fun load(reader: Reader): R {
88 | val engine = ScriptEngineManager().getEngineByExtension("kts")
89 | return reader.use { engine.eval(it) as R }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/VarDelegateProvider.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util
2 |
3 | import kotlin.properties.ReadWriteProperty
4 | import kotlin.reflect.KProperty
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * An interface to help completing the `provideDelegate` operator function for `var` property delegation.
26 | */
27 | interface VarDelegateProvider {
28 | /**
29 | * Provide the [ReadWriteProperty] for delegation. Could use [Ref] if no special logic is required.
30 | */
31 | operator fun provideDelegate(thisRef: R, property: KProperty<*>): ReadWriteProperty
32 | }
33 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/error.kt:
--------------------------------------------------------------------------------
1 | @file:Suppress("NOTHING_TO_INLINE")
2 |
3 | package io.github.sof3.graphmine.util
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * Always throws [AssertionError] stating that control flow should never reach this point. Useful in `when` blocks when
25 | * Kotlin is unable to detect that the conditions are exhaustive
26 | */
27 | inline val DEADCODE: Nothing get() = DEADCODE()
28 |
29 | /**
30 | * Always throws [AssertionError] stating that control flow should never reach this point. Useful in `when` blocks when
31 | * Kotlin is unable to detect that the conditions are exhaustive
32 | * @param message a string to use as the error message
33 | */
34 | inline fun DEADCODE(message: String = "Control flow error"): Nothing = throw AssertionError(message)
35 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/misc.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Executes [fn] if [this] is not null
23 | */
24 | inline fun T?.notNull(fn: (T) -> Unit) {
25 | if (this != null) fn(this)
26 | }
27 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/qualifier/Qualifier.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util.qualifier
2 |
3 | import io.github.sof3.graphmine.util.get
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * Represents a qualified identifier.
25 | *
26 | * @param string the dot-delimited qualified identifier
27 | */
28 | class Qualifier(string: String) {
29 | /**
30 | * The string parts of the qualifier
31 | */
32 | val parts = string.split(".")
33 |
34 | /**
35 | * The last part of the qualifier, which is also the most frequently used one
36 | */
37 | val simple get() = parts.last()
38 |
39 | /**
40 | * Executes [fn] on each possible representation of this qualifier
41 | */
42 | inline fun forEachPermutation(fn: (List) -> Unit) {
43 | for (i in 0 until parts.size) {
44 | fn(parts[i, parts.size])
45 | }
46 | }
47 |
48 | /**
49 | * Returns the dot-delimited representation of the qualifier
50 | */
51 | override fun toString() = parts.joinToString(".")
52 |
53 | private val hashCode by lazy { parts.map(String::hashCode).reduce { a, b -> a * 31 + b } }
54 | /**
55 | * Returns the lazily-evaluated hash code of the qualifier only based on the contents of [parts]
56 | */
57 | override fun hashCode() = hashCode
58 |
59 | /**
60 | * Checks if two identifiers are fully equal based on the contents of [parts]
61 | */
62 | override fun equals(other: Any?) = other is Qualifier && parts == other.parts
63 | }
64 |
65 | /**
66 | * Converts a dot-delimited string to a qualifier
67 | *
68 | * @receiver a dot-delimited string
69 | */
70 | fun String.qualify() = Qualifier(this)
71 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/qualifier/QualifierClashException.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util.qualifier
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Thrown when there is a qualifier clash
23 | * @property values a map of [Qualifier]s to their respective values. The value type of the map can be safely assumed to be
24 | * the type T in the [QualifierMap] that throws the exception.
25 | */
26 | class QualifierClashException(val values: Map) : Exception()
27 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/qualifier/QualifierMap.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util.qualifier
2 |
3 | import java.util.*
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * A thread-safe store for qualified entries allowing search by qualified name
25 | */
26 | class QualifierMap {
27 | private val map = hashMapOf>()
28 |
29 | /**
30 | * Adds a qualified entry to the map
31 | * @param qualifier the qualified name
32 | * @param value the value to add
33 | */
34 | operator fun set(qualifier: Qualifier, value: T) {
35 | qualifier.forEachPermutation { slice ->
36 | val key = slice.joinToString(".")
37 | lateinit var map: MutableMap
38 | synchronized(this.map) {
39 | if (key !in this.map) this.map[key] = hashMapOf()
40 | map = this.map[key]!!
41 | }
42 | synchronized(map) { map[qualifier] = value }
43 | }
44 | }
45 |
46 | /**
47 | * Gets an entry using a qualified key
48 | * @param key any qualified key
49 | */
50 | operator fun get(key: String): T? {
51 | val map = synchronized(map) { map[key] } ?: return null
52 | val clone: Map = synchronized(map) {
53 | if (map.size == 1) return map.iterator().next().value
54 | Collections.unmodifiableMap(map)
55 | }
56 | throw QualifierClashException(clone)
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/qualifier/package.md:
--------------------------------------------------------------------------------
1 | # Package io.github.sof3.graphmine.util.qualifier
2 | This package provides the Qualifier API, which is used to resolve name clashes.
3 |
4 | When multiple modules add to the same registry with the same name, a name clash occurs. The module identifier can be
5 | used to distinguish others from multiple modules. On the other hand, it is inconvenient if users have to type the whole
6 | name from the module identifier. Therefore, a gradual approach is used: If the base name does not have a clash, only
7 | typing the base name is enough. Otherwise, the user has to add one more part of the qualifier. This process repeats
8 | until there is no longer any ambiguity.
9 |
10 | The qualifier string should be dot-separated. By convention, it starts with the module identifier (usually the module
11 | package), then the object name. Since the same module should not register two objects with the same name, it is not
12 | necessary to subdivide under the package. Moreover, to make the second part of the object name (which usually
13 | distinguishes most of the collision) more intuitive, it should be the module name.
14 |
15 | For example, if there is a plugin called "ChestLock" and two plugins called "PortKey" that implement a "key" command,
16 | they might have qualified command names like this:
17 |
18 | ```
19 | io.github.foo.ChestLock.key
20 | com.gmail.bar.PortKey.key
21 | com.example.qux.PortKey.key
22 | ```
23 |
24 | When the user uses the "key" command, there are three possibilities, so typing "ChestLock.key" instead (or usually the
25 | case-insensitive situation) would distinguish that the user wants to run the key command from ChestLock. Otherwise, the
26 | user wants to run the key command from the PortKey plugin, but there are two PortKey plugins (which is quite strange
27 | and unlikely), so the user types the full package name of the PortKey plugin to specify which plugin to use.
28 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/ranges.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Syntactic sugar for [CharSequence.substring] so that it looks like `string[start:end]` in Python
23 | */
24 | operator fun CharSequence.get(start: Int, end: Int) = substring(start, end)
25 |
26 | /**
27 | * Syntactic sugar for [CharSequence.substring] so that it looks like `list[start:end]` in Python
28 | */
29 | operator fun List.get(start: Int, end: Int) = slice(start until end)
30 |
31 | /**
32 | * A more intuitive way of checking if an offset is in bounds of a string
33 | */
34 | fun String.hasOffset(offset: Int) = offset in 0 until length
35 |
36 | /**
37 | * A more intuitive way of checking if an offset is in bounds of a list
38 | */
39 | fun List<*>.hasOffset(offset: Int) = offset in 0 until size
40 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/kotlin/io/github/sof3/graphmine/util/ref.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util
2 |
3 | import kotlin.properties.ReadOnlyProperty
4 | import kotlin.properties.ReadWriteProperty
5 | import kotlin.reflect.KProperty
6 |
7 | /*
8 | * GraphMine
9 | * Copyright (C) 2018 SOFe
10 | *
11 | * This program is free software: you can redistribute it and/or modify
12 | * it under the terms of the GNU Affero General Public License as published
13 | * by the Free Software Foundation, either version 3 of the License, or
14 | * (at your option) any later version.
15 | *
16 | * This program is distributed in the hope that it will be useful,
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | * GNU Affero General Public License for more details.
20 | *
21 | * You should have received a copy of the GNU Affero General Public License
22 | * along with this program. If not, see .
23 | */
24 |
25 | /**
26 | * Useful for passing by reference or as return value in delegation providers [DelegateProvider] and
27 | * [VarDelegateProvider]
28 | * @property value the backing value
29 | */
30 | class Ref(var value: T) : ReadWriteProperty, ReadOnlyProperty {
31 | /** Used for delegation to the backing [value] */
32 | override operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
33 |
34 | /** Used for delegation to the backing [value] */
35 | override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
36 | this.value = value
37 | }
38 | }
39 |
40 | /**
41 | * Useful for passing by reference or as return value in delegation providers [DelegateProvider] and
42 | * [VarDelegateProvider]
43 | * @property value the backing value
44 | */
45 | class ByteRef(var value: Byte) : ReadWriteProperty, ReadOnlyProperty {
46 | /** Used for delegation to the backing [value] */
47 | override operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
48 |
49 | /** Used for delegation to the backing [value] */
50 | override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Byte) {
51 | this.value = value
52 | }
53 | }
54 |
55 | /**
56 | * Useful for passing by reference or as return value in delegation providers [DelegateProvider] and
57 | * [VarDelegateProvider]
58 | * @property value the backing value
59 | */
60 | class CharRef(var value: Char) : ReadWriteProperty, ReadOnlyProperty {
61 | /** Used for delegation to the backing [value] */
62 | override operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
63 |
64 | /** Used for delegation to the backing [value] */
65 | override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Char) {
66 | this.value = value
67 | }
68 | }
69 |
70 | /**
71 | * Useful for passing by reference or as return value in delegation providers [DelegateProvider] and
72 | * [VarDelegateProvider]
73 | * @property value the backing value
74 | */
75 | class ShortRef(var value: Short) : ReadWriteProperty, ReadOnlyProperty {
76 | /** Used for delegation to the backing [value] */
77 | override operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
78 |
79 | /** Used for delegation to the backing [value] */
80 | override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Short) {
81 | this.value = value
82 | }
83 | }
84 |
85 | /**
86 | * Useful for passing by reference or as return value in delegation providers [DelegateProvider] and
87 | * [VarDelegateProvider]
88 | * @property value the backing value
89 | */
90 | class IntRef(var value: Int) : ReadWriteProperty, ReadOnlyProperty {
91 | /** Used for delegation to the backing [value] */
92 | override operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
93 |
94 | /** Used for delegation to the backing [value] */
95 | override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
96 | this.value = value
97 | }
98 | }
99 |
100 | /**
101 | * Useful for passing by reference or as return value in delegation providers [DelegateProvider] and
102 | * [VarDelegateProvider]
103 | * @property value the backing value
104 | */
105 | class LongRef(var value: Long) : ReadWriteProperty, ReadOnlyProperty {
106 | /** Used for delegation to the backing [value] */
107 | override operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
108 |
109 | /** Used for delegation to the backing [value] */
110 | override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Long) {
111 | this.value = value
112 | }
113 | }
114 |
115 | /**
116 | * Useful for passing by reference or as return value in delegation providers [DelegateProvider] and
117 | * [VarDelegateProvider]
118 | * @property value the backing value
119 | */
120 | class FloatRef(var value: Float) : ReadWriteProperty, ReadOnlyProperty {
121 | /** Used for delegation to the backing [value] */
122 | override operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
123 |
124 | /** Used for delegation to the backing [value] */
125 | override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Float) {
126 | this.value = value
127 | }
128 | }
129 |
130 | /**
131 | * Useful for passing by reference or as return value in delegation providers [DelegateProvider] and
132 | * [VarDelegateProvider]
133 | * @property value the backing value
134 | */
135 | class DoubleRef(var value: Double) : ReadWriteProperty, ReadOnlyProperty {
136 | /** Used for delegation to the backing [value] */
137 | override operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
138 |
139 | /** Used for delegation to the backing [value] */
140 | override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Double) {
141 | this.value = value
142 | }
143 | }
144 |
145 | /**
146 | * Useful for passing by reference or as return value in delegation providers [DelegateProvider] and
147 | * [VarDelegateProvider]
148 | * @property value the backing value
149 | */
150 | class BooleanRef(var value: Boolean) : ReadWriteProperty, ReadOnlyProperty {
151 | /** Used for delegation to the backing [value] */
152 | override operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
153 |
154 | /** Used for delegation to the backing [value] */
155 | override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
156 | this.value = value
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/graphmine-util/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory:
--------------------------------------------------------------------------------
1 | org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory
2 |
--------------------------------------------------------------------------------
/graphmine-util/src/test/kotlin/io/github/sof3/graphmine/util/testUtil.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util
2 |
3 | import org.spekframework.spek2.dsl.TestBody
4 | import org.spekframework.spek2.style.gherkin.ScenarioBody
5 | import kotlin.random.Random
6 | import kotlin.test.assertEquals
7 | import kotlin.test.assertNotEquals
8 |
9 | /*
10 | * GraphMine
11 | * Copyright (C) 2018 SOFe
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU Affero General Public License as published
15 | * by the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope that it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU Affero General Public License for more details.
22 | *
23 | * You should have received a copy of the GNU Affero General Public License
24 | * along with this program. If not, see .
25 | */
26 |
27 | infix fun Ref.shouldBe(expected: T) = assertEquals(expected, value)
28 | infix fun Ref.shouldNotBe(expected: T) = assertNotEquals(expected, value)
29 | infix fun T.shouldBe(expected: T) = assertEquals(expected, this)
30 | infix fun T.shouldNotBe(expected: T) = assertNotEquals(expected, this)
31 |
32 | private typealias InScenarioBody = ScenarioBody.() -> Unit
33 |
34 | //inline fun ScenarioBody.If(condition: String, boolean: Boolean, then: InScenarioBody, or: InScenarioBody) {
35 | // if (boolean) {
36 | // When("\"$condition\" is true") {}
37 | // then(this)
38 | // } else {
39 | // When("\"$condition\" is false", {})
40 | // or(this)
41 | // }
42 | //}
43 |
44 | inline fun ScenarioBody.GivenRandom(
45 | lengths: IntRange,
46 | crossinline stringToParam: (String) -> T,
47 | crossinline ctx: () -> C,
48 | name: String = "random strings of length [${lengths.start}, ${lengths.endInclusive}]",
49 | eachTimes: Int = 10,
50 | charset: List = ALPHA_NUMERAL,
51 | crossinline then: RandomContext.() -> Unit
52 | ) {
53 | val list = mutableListOf>>()
54 | Given(name) {
55 | randomRegularStrings(lengths, eachTimes, charset) { list += Triple(it, stringToParam(it), Ref(ctx())) }
56 | }
57 | val context = RandomContext().apply(then)
58 | context.runs.forEach { it(this, list) }
59 | }
60 |
61 | typealias RandomTest = TestBody.(String, T, Ref) -> Unit
62 | private typealias RandomContextParam = List>>
63 |
64 | class RandomContext {
65 | val runs = mutableListOf) -> Unit>()
66 |
67 | inline fun When(description: String, crossinline fn: RandomTest) {
68 | runs.add { list -> When(description) { list.forEach { fn(it.first, it.second, it.third) } } }
69 | }
70 |
71 | inline fun Then(description: String, crossinline fn: RandomTest) {
72 | runs.add { list -> Then(description) { list.forEach { fn(it.first, it.second, it.third) } } }
73 | }
74 |
75 | inline fun And(description: String, crossinline fn: RandomTest) {
76 | runs.add { list -> And(description) { list.forEach { fn(it.first, it.second, it.third) } } }
77 | }
78 |
79 | inline fun If(
80 | condition: String, crossinline predicate: (String) -> Boolean,
81 | thenMessage: String, crossinline then: RandomTest,
82 | orMessage: String, crossinline or: RandomTest) {
83 | runs.add { list ->
84 | lateinit var t: RandomContextParam
85 | lateinit var f: RandomContextParam
86 | When("\"$condition\" is true") {
87 | val pair = list.partition { predicate(it.first) }
88 | t = pair.first
89 | f = pair.second
90 | }
91 | Then(thenMessage) { t.forEach { then(it.first, it.second, it.third) } }
92 | When("\"$condition\" is false") {}
93 | Then(orMessage) { f.forEach { or(it.first, it.second, it.third) } }
94 | }
95 | }
96 | }
97 |
98 | val ALPHA_UPPER = ('A'..'Z').toList()
99 | val ALPHA_LOWER = ('a'..'z').toList()
100 | val NUMERAL = ('0'..'9').toList()
101 | val ALPHA_NUMERAL = ALPHA_UPPER + ALPHA_LOWER + NUMERAL
102 | val ALPHA_NUMERAL_SPACE = ALPHA_NUMERAL + ' '
103 |
104 | inline fun randomRegularStrings(
105 | lengths: IntRange,
106 | eachTimes: Int,
107 | charset: List = ALPHA_NUMERAL,
108 | fn: (String) -> Unit
109 | ) {
110 | for (length in lengths) {
111 | repeat(eachTimes) {
112 | fn(randomRegularString(length, charset))
113 | }
114 | }
115 | }
116 |
117 | fun randomRegularString(length: Int, charset: List = ALPHA_NUMERAL): String {
118 | val chars = CharArray(length)
119 | repeat(length) { chars[it] = charset[Random.nextInt(charset.size)] }
120 | return String(chars)
121 | }
122 |
123 | fun allPermutations(vararg values: T, yields: Int = values.size, fn: (List) -> Unit) = allPermutations(emptyList(), values.toList(), yields, fn)
124 | fun allPermutations(front: List, values: List, levels: Int, fn: (List) -> Unit) {
125 | if (levels == 0) {
126 | fn(front)
127 | return
128 | }
129 |
130 | for (i in 0 until values.size) {
131 | val clone = values.toMutableList()
132 | val rem = clone.removeAt(i)
133 | allPermutations(front + rem, clone, levels - 1, fn)
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "graphmine"
2 |
3 | include("graphmine-util")
4 | include("graphmine-i18n")
5 | include("graphmine-i18n-core")
6 | include("graphmine-core")
7 | include("graphmine-cli")
8 | include("util-math")
9 | include("util-reflect-io")
10 |
--------------------------------------------------------------------------------
/util-math/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | plugins {
22 | java
23 | kotlin("jvm")
24 | }
25 |
26 | group = "io.github.sof3.graphmine"
27 | version = "1.0.0-SNAPSHOT"
28 |
29 | dependencies {
30 | implementation(kotlin("stdlib-jdk8"))
31 | implementation(kotlin("reflect"))
32 | api(project(":graphmine-util"))
33 | testImplementation(kotlin("test"))
34 | testImplementation("org.spekframework.spek2:spek-dsl-jvm:2.0.0-alpha.2")
35 | testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:2.0.0-alpha.2")
36 | }
37 |
38 | tasks.withType {
39 | kotlinOptions.freeCompilerArgs += "-XXLanguage:+InlineClasses"
40 | }
41 |
--------------------------------------------------------------------------------
/util-math/module.md:
--------------------------------------------------------------------------------
1 | # Module util-math
2 | This module provides a math library that targets at world geometry management.
3 |
--------------------------------------------------------------------------------
/util-math/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "util-math"
2 |
--------------------------------------------------------------------------------
/util-math/src/main/kotlin/io/github/sof3/graphmine/util/math/IntVector3.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util.math
2 |
3 | import io.github.sof3.graphmine.util.mapDoubleArray
4 | import io.github.sof3.graphmine.util.mapIntArray
5 | import kotlin.math.abs
6 | import kotlin.math.max
7 | import kotlin.math.min
8 | import kotlin.math.sqrt
9 |
10 | /*
11 | * GraphMine
12 | * Copyright (C) 2018 SOFe
13 | *
14 | * This program is free software: you can redistribute it and/or modify
15 | * it under the terms of the GNU Affero General Public License as published
16 | * by the Free Software Foundation, either version 3 of the License, or
17 | * (at your option) any later version.
18 | *
19 | * This program is distributed in the hope that it will be useful,
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | * GNU Affero General Public License for more details.
23 | *
24 | * You should have received a copy of the GNU Affero General Public License
25 | * along with this program. If not, see .
26 | */
27 |
28 | /**
29 | * A 3-dimensional vector in integers. Intended to store aligned positions e.g. block positions.
30 | *
31 | * The class is a value class. Values in this class cannot be changed. Therefore, no copy method is present.
32 | */
33 | inline class IntVector3(internal val values: IntArray) {
34 | /**
35 | * This object caches some common instances for efficient reuse
36 | */
37 | companion object Common {
38 | /** A zero vector */
39 | val ZERO = IntVector3(0, 0, 0)
40 | /** A unit vector in the direction of *x* (east) */
41 | val UNIT_X = IntVector3(1, 0, 0)
42 | /** A unit vector in the direction of *-x* (west) */
43 | val UNIT_X_NEG = IntVector3(-1, 0, 0)
44 | /** A unit vector in the direction of *y* (up) */
45 | val UNIT_Y = IntVector3(0, 1, 0)
46 | /** A unit vector in the direction of *-y* (up) */
47 | val UNIT_Y_NEG = IntVector3(0, -1, 0)
48 | /** A unit vector in the direction of *z* (south) */
49 | val UNIT_Z = IntVector3(0, 0, 1)
50 | /** A unit vector in the direction of *-z* (north) */
51 | val UNIT_Z_NEG = IntVector3(0, 0, -1)
52 | }
53 |
54 | /**
55 | * Consrtucts a [Vector3] by specifying all coordinates
56 | */
57 | constructor(x: Int, y: Int, z: Int) : this(intArrayOf(x, y, z))
58 |
59 | /** The *x*-component value */
60 | val x get() = values[0]
61 | /** The *y*-component value, which is orthogonal to *x* */
62 | val y get() = values[1]
63 | /** The *z*-component value, which is in the direction of *x*×*y* */
64 | val z get() = values[2]
65 |
66 | /**
67 | * Converts to a [Vector3] with approximately equivalent positions
68 | */
69 | fun toDouble() = Vector3(values.mapDoubleArray(Int::toDouble))
70 |
71 | /**
72 | * Calculates the squared length of this vector
73 | */
74 | val lengthSquared get() = values.mapIntArray { it * it }.sum()
75 | /**
76 | * Calculates the length (a.k.a. norm or modulus) of this vector.
77 | *
78 | * Use [lengthSquared] if only comparison is needed for less computation.
79 | */
80 | val length get() = sqrt(lengthSquared.toDouble())
81 |
82 | /**
83 | * @return a unit vector (length = 1) in the same direction as this vector
84 | */
85 | val unit get() = if (lengthSquared == 0) Vector3.ZERO else toDouble() / length
86 |
87 | /**
88 | * Calculates the dot product of `this` and [v]
89 | */
90 | infix fun dot(v: IntVector3) = biMap(v) { a, b -> a * b }.values.sum()
91 |
92 | /**
93 | * Calculates the cross product of `this` and [v]
94 | */
95 | infix fun cross(v: IntVector3) = IntVector3(
96 | y * v.z - z * v.y,
97 | z * v.x - x * v.z,
98 | x * v.y - y * v.x
99 | )
100 |
101 | /** Calculates `this` + [that]*/
102 | operator fun plus(that: IntVector3) = biMap(that) { a, b -> a + b }
103 |
104 | /** Calculates `this` - [that] */
105 | operator fun minus(that: IntVector3) = biMap(that) { a, b -> a + b }
106 |
107 | /**
108 | * Multiplies the components of `this` by [scalar]
109 | *
110 | * Use `this.toDouble() * scalar` if [scalar] is a double.
111 | *
112 | * Use `this.toDouble() / scalar` if division is intended.
113 | */
114 | operator fun times(scalar: Int) = map { it * scalar }
115 |
116 | /** @return this vector */
117 | operator fun unaryPlus() = this
118 |
119 | /** @return this vector in the opposite direction and same length */
120 | operator fun unaryMinus() = map(Int::unaryMinus)
121 |
122 | /** @return this vector with all components flipped if negative */
123 | fun abs(): IntVector3 = map(::abs)
124 |
125 | /**
126 | * Calculates the squared distance between `this` and [that]
127 | */
128 | fun distanceSquared(that: IntVector3) = (this - that).lengthSquared
129 |
130 | /**
131 | * Calculates the distance between `this` and [that].
132 | *
133 | * Use [distanceSquared] if only comparison is needed for less computation.
134 | */
135 | infix fun distanceTo(that: IntVector3) = (this - that).length
136 |
137 | /**
138 | * Returns the minimum [IntVector3Range] that inclusively contains both `this` and [that]
139 | */
140 | operator fun rangeTo(that: IntVector3) = IntVector3Range(biMap(that, ::min), biMap(that, ::max))
141 |
142 | /** @return the neighbour of `this` on the side [side] */
143 | fun side(side: Side) = this + side.intVector
144 |
145 | /** @return `this` moved towards [side] by [steps] steps */
146 | fun side(side: Side, steps: Int) = this + side.intVector * steps
147 |
148 | /** @return executes [fn] on each of the 6 neighbours of `this` */
149 | fun eachSide(fn: (IntVector3) -> Unit) = Side.ALL.forEach { fn(side(it)) }
150 |
151 | internal inline fun map(fn: (Int) -> Int) = IntVector3(values.mapIntArray(fn))
152 |
153 | internal inline fun biMap(that: IntVector3, fn: (Int, Int) -> Int): IntVector3 {
154 | val new = IntArray(3)
155 | for (i in 0 until values.size) new[i] = fn(values[i], that.values[i])
156 | return IntVector3(new)
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/util-math/src/main/kotlin/io/github/sof3/graphmine/util/math/IntVector3Range.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util.math
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * A unit-aligned cuboid region in the 3D space.
23 | *
24 | * In integer-aligned space, this is a closed range [[min], [max]] such that the region joined with another region at
25 | * [max] + 1 on any axis will be fully continuous.
26 | *
27 | * In non-integer-aligned space, this is a semi-open range [[min], [max] + 1) such that the same rule applies. It can be
28 | * thought as the vector at `(x, y, z)` covering the range `([x, x + 1), [y, y + 1), [z, z + 1))`.
29 | *
30 | * @property min the minimum possible point in the region
31 | * @property max the maximum possible point in the region
32 | */
33 | class IntVector3Range internal constructor(val min: IntVector3, val max: IntVector3) : Iterable {
34 | /**
35 | * Specifies the iteration order.
36 | * @property a the first axis to iterate over (increments when [b] resets, stops iteration after reaching [max])
37 | * @property b the second axis to iterate over (increments when [c] resets, resets after reaching [max])
38 | * @property c the third axis to iterate over (increments every time, resets after reaching [max])
39 | */
40 | enum class IterationOrder(val a: Int, val b: Int, val c: Int) {
41 | /** Iterate bottom-up, for each column from west to east, yields from north to south */
42 | YXZ(1, 0, 2),
43 | /** Iterate from west to east, for each row from north to south, yields bottom-up */
44 | XZY(0, 2, 1),
45 | /** Iterate bottom-up, for each column from north to south, yields from west to east */
46 | YZX(1, 2, 0),
47 | /** Iterate from morth to south, for each row from west to east, yields bottom-up */
48 | ZXY(2, 0, 1),
49 | }
50 |
51 | /**
52 | * Specifies the iteration order before using as an iterable.
53 | *
54 | * Example ues: `for(vector in range with IterationOrder.ZXY) { ... }`
55 | */
56 | infix fun with(order: IterationOrder) = object : Iterable {
57 | override fun iterator(): Iterator = kotlin.sequences.iterator {
58 | for (a in min.values[order.a]..max.values[order.a]) {
59 | for (b in min.values[order.b]..max.values[order.b]) {
60 | for (c in min.values[order.c]..max.values[order.c]) {
61 | val array = intArrayOf(3, 3, 3)
62 | array[order.a] = a
63 | array[order.b] = b
64 | array[order.c] = c
65 | }
66 | }
67 | }
68 | }
69 | }
70 |
71 | /**
72 | * Iterates over every integer-aligned point in this range.
73 | */
74 | override fun iterator() = with(IterationOrder.YXZ).iterator()
75 |
76 | /**
77 | * Checks if a vector is inside the range in integer-aligned space.
78 | */
79 | operator fun contains(vector: IntVector3) = (0..2).all { vector.values[it] in min.values[it]..max.values[it] }
80 |
81 | /**
82 | * Checks if a vector is inside the range in non-integer-aligned space.
83 | *
84 | * See the [IntVector3Range] definition of the range in non-integer-aligned space.
85 | */
86 | operator fun contains(vector: Vector3) = (0..2).all {
87 | vector.values[it] >= min.values[it].toDouble() &&
88 | vector.values[it] < max.values[it].toDouble() + 1.0
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/util-math/src/main/kotlin/io/github/sof3/graphmine/util/math/Side.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util.math
2 |
3 | import io.github.sof3.graphmine.util.DEADCODE
4 |
5 | /*
6 | * GraphMine
7 | * Copyright (C) 2018 SOFe
8 | *
9 | * This program is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU Affero General Public License as published
11 | * by the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * This program is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU Affero General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU Affero General Public License
20 | * along with this program. If not, see .
21 | */
22 |
23 | /**
24 | * Represents one of the 6 directions in a 3D space.
25 | *
26 | * @property id the ID of the direction
27 | */
28 | class Side private constructor(val id: Int) {
29 | /**
30 | * Contains the default sides
31 | */
32 | companion object Sides {
33 | /** The DOWN side */
34 | val DOWN = Side(0)
35 | /** The UP side */
36 | val UP = Side(1)
37 | /** The NORTH side */
38 | val NORTH = Side(2)
39 | /** The SOUTH side */
40 | val SOUTH = Side(3)
41 | /** The WEST side */
42 | val WEST = Side(4)
43 | /** The EAST side */
44 | val EAST = Side(5)
45 |
46 | /** A list of all sides */
47 | val ALL = (0..5).map { Side(it) }
48 |
49 | /** Access a side by ID */
50 | operator fun get(id: Int) = ALL[id]
51 | }
52 |
53 | /**
54 | * Expresses the side as an [IntVector3]
55 | */
56 | val intVector = when (id) {
57 | 0 -> IntVector3(0, -1, 0)
58 | 1 -> IntVector3(0, 1, 0)
59 | 2 -> IntVector3(0, 0, -1)
60 | 3 -> IntVector3(0, 0, 1)
61 | 4 -> IntVector3(-1, 0, 0)
62 | 5 -> IntVector3(1, 0, 0)
63 | else -> DEADCODE
64 | }
65 |
66 | /**
67 | * Expresses the side as a [Vector3]
68 | */
69 | val vector = when (id) {
70 | 0 -> Vector3(0.0, -1.0, 0.0)
71 | 1 -> Vector3(0.0, 1.0, 0.0)
72 | 2 -> Vector3(0.0, 0.0, -1.0)
73 | 3 -> Vector3(0.0, 0.0, 1.0)
74 | 4 -> Vector3(-1.0, 0.0, 0.0)
75 | 5 -> Vector3(1.0, 0.0, 0.0)
76 | else -> DEADCODE
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/util-math/src/main/kotlin/io/github/sof3/graphmine/util/math/Vector3.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util.math
2 |
3 | import io.github.sof3.graphmine.util.mapDoubleArray
4 | import io.github.sof3.graphmine.util.mapIntArray
5 | import kotlin.Double.Companion.NEGATIVE_INFINITY
6 | import kotlin.Double.Companion.POSITIVE_INFINITY
7 | import kotlin.math.*
8 |
9 | /*
10 | * GraphMine
11 | * Copyright (C) 2018 SOFe
12 | *
13 | * This program is free software: you can redistribute it and/or modify
14 | * it under the terms of the GNU Affero General Public License as published
15 | * by the Free Software Foundation, either version 3 of the License, or
16 | * (at your option) any later version.
17 | *
18 | * This program is distributed in the hope v it will be useful,
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | * GNU Affero General Public License for more details.
22 | *
23 | * You should have received a copy of the GNU Affero General Public License
24 | * along with this program. If not, see .
25 | */
26 |
27 | /**
28 | * A 3-dimensional vector in floating point precision. Intended to store non-aligned positions, e.g. entity positions.
29 | *
30 | * The class is a value class. Values in this class cannot be changed. Therefore, no copy method is present.
31 | */
32 | inline class Vector3(internal val values: DoubleArray) {
33 | /**
34 | * This object caches some common instances for efficient reuse
35 | */
36 | companion object Common {
37 | /** A zero vector */
38 | val ZERO = Vector3(0.0, 0.0, 0.0)
39 | /** A unit vector in the direction of *x* (east) */
40 | val UNIT_X = Vector3(1.0, 0.0, 0.0)
41 | /** A unit vector in the direction of *y* (up) */
42 | val UNIT_Y = Vector3(0.0, 1.0, 0.0)
43 | /** A unit vector in the direction of *z* (south) */
44 | val UNIT_Z = Vector3(0.0, 0.0, 1.0)
45 | /** A unit vector in the direction of *-x* (west) */
46 | val UNIT_X_NEG = Vector3(-1.0, 0.0, 0.0)
47 | /** A unit vector in the direction of *-y* (down) */
48 | val UNIT_Y_NEG = Vector3(0.0, -1.0, 0.0)
49 | /** A unit vector in the direction of *-z* (north) */
50 | val UNIT_Z_NEG = Vector3(0.0, 0.0, -1.0)
51 | /** A vector pointing to the infinity in the (+,+,+) octant */
52 | val INF = Vector3(POSITIVE_INFINITY, POSITIVE_INFINITY, POSITIVE_INFINITY)
53 | /** A vector pointing to the infinity in the (-,-,-) octant */
54 | val INF_NEG = Vector3(NEGATIVE_INFINITY, NEGATIVE_INFINITY, NEGATIVE_INFINITY)
55 | }
56 |
57 | /**
58 | * Constructs a [Vector3] by specifying all coordinates
59 | */
60 | constructor(x: Double, y: Double, z: Double) : this(doubleArrayOf(x, y, z))
61 |
62 | /** The *x*-component value */
63 | val x get() = values[0]
64 | /** The *y*-component value, which is orthogonal to *x* */
65 | val y get() = values[1]
66 | /** The *z*-component value, which is in the direction of *x*×*y* */
67 | val z get() = values[2]
68 |
69 | /**
70 | * Rounds this vector to an [IntVector3]
71 | */
72 | fun round() = IntVector3(values.mapIntArray(Double::roundToInt))
73 |
74 | /**
75 | * Rounds this vector to [dp] decimal places
76 | */
77 | fun round(dp: Int): Vector3 {
78 | val factor = dp.pow10()
79 | return map { round(it * factor) / factor }
80 | }
81 |
82 | /**
83 | * Rounds down this vector to an [IntVector3]
84 | */
85 | fun floor() = IntVector3(values.mapIntArray { floor(it).toInt() })
86 |
87 | /**
88 | * Rounds up this vector to an [IntVector3]
89 | */
90 | fun ceil() = IntVector3(values.mapIntArray { ceil(it).toInt() })
91 |
92 | /**
93 | * Calculates the squared length of this vector
94 | */
95 | val lengthSquared get() = values.mapDoubleArray { it * it }.sum()
96 | /**
97 | * Calculates the length (a.k.a. norm or modulus) of this vector.
98 | *
99 | * Use [lengthSquared] if only comparison is needed for less computation.
100 | */
101 | val length get() = sqrt(lengthSquared.toDouble())
102 |
103 | /**
104 | * @return a unit vector (length = 1) in the same direction as this vector
105 | */
106 | val unit get() = this / length
107 |
108 | /**
109 | * Calculates the dot product of `this` and [v]
110 | */
111 | infix fun dot(v: Vector3) = biMap(v) { a, b -> a * b }.values.sum()
112 |
113 | /**
114 | * Calculates the cross product of `this` and [v]
115 | */
116 | infix fun cross(v: Vector3) = Vector3(
117 | y * v.z - z * v.y,
118 | z * v.x - x * v.z,
119 | x * v.y - y * v.x
120 | )
121 |
122 | /** Calculates `this` + [that] */
123 | operator fun plus(that: Vector3) = biMap(that) { a, b -> a + b }
124 |
125 | /** Calculates `this` - [that] */
126 | operator fun minus(that: Vector3) = biMap(that) { a, b -> a + b }
127 |
128 | /** Multiplies the components of `this` by [scalar] */
129 | operator fun times(scalar: Double) = map { it * scalar }
130 |
131 | /**
132 | * Divides the components of `this` by [scalar]
133 | *
134 | * @throws ArithmeticException if [scalar] is zero
135 | */
136 | operator fun div(scalar: Double) = map { it / scalar }
137 |
138 | /** @return this vector */
139 | operator fun unaryPlus() = this
140 |
141 | /** @return this vector in the opposite direction and same length */
142 | operator fun unaryMinus() = map(Double::unaryMinus)
143 |
144 | /** @return this vector with all components flipped if negative */
145 | fun abs(): Vector3 = map(::abs)
146 |
147 | /**
148 | * Calculates the squared distance between `this` and [that]
149 | */
150 | fun distanceSquared(that: Vector3) = (this - that).lengthSquared
151 |
152 | /**
153 | * Calculates the distance between `this` and [that].
154 | *
155 | * Use [distanceSquared] if only comparison is needed for less computation.
156 | */
157 | infix fun distanceTo(that: Vector3) = (this - that).length
158 |
159 | /** @return this vector moved towards the side [side] by one unit */
160 | fun side(side: Side) = this + side.vector
161 |
162 | /** @return this vector moved towards the side [side] by [steps] units */
163 | fun side(side: Side, steps: Double) = this + side.vector * steps
164 |
165 | private inline fun map(fn: (Double) -> Double): Vector3 {
166 | val new = DoubleArray(values.size)
167 | for (i in 0 until values.size) new[i] = fn(values[i])
168 | return Vector3(new)
169 | }
170 |
171 | private inline fun biMap(v: Vector3, fn: (Double, Double) -> Double): Vector3 {
172 | val new = DoubleArray(3)
173 | for (i in 0 until values.size) new[i] = fn(values[i], v.values[i])
174 | return Vector3(new)
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/util-math/src/main/kotlin/io/github/sof3/graphmine/util/math/annotations.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util.math
2 |
3 | import kotlin.annotation.AnnotationRetention.BINARY
4 | import kotlin.annotation.AnnotationTarget.*
5 |
6 | /*
7 | * GraphMine
8 | * Copyright (C) 2018 SOFe
9 | *
10 | * This program is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Affero General Public License as published
12 | * by the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * This program is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU Affero General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU Affero General Public License
21 | * along with this program. If not, see .
22 | */
23 |
24 | /**
25 | * Applied on a [Vector3] or [IntVector3] to indicate that it represents a positional vector, e.g. the position of an
26 | * object
27 | */
28 | @Target(PROPERTY, LOCAL_VARIABLE, VALUE_PARAMETER, FUNCTION)
29 | @Retention(BINARY)
30 | @MustBeDocumented
31 | annotation class Positional
32 |
33 | /**
34 | * Applied on a [Vector3] or [IntVector3] to indicate that it represents a relative vector, e.g. the distance between
35 | * two vectors
36 | */
37 | @Target(PROPERTY, LOCAL_VARIABLE, VALUE_PARAMETER, FUNCTION)
38 | @Retention(BINARY)
39 | @MustBeDocumented
40 | annotation class Relative
41 |
--------------------------------------------------------------------------------
/util-math/src/main/kotlin/io/github/sof3/graphmine/util/math/math.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util.math
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * Calculates 10 raised to the power of this
23 | */
24 | fun Int.pow10() = Math.pow(10.0, toDouble())
25 |
--------------------------------------------------------------------------------
/util-reflect-io/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | plugins {
22 | java
23 | kotlin("jvm")
24 | }
25 |
26 | group = "io.github.sof3.graphmine"
27 | version = "1.0.0-SNAPSHOT"
28 |
29 | dependencies {
30 | api(project(":graphmine-util"))
31 | implementation(kotlin("stdlib-jdk8"))
32 | implementation(kotlin("reflect"))
33 | testImplementation(kotlin("test"))
34 | testImplementation("org.spekframework.spek2:spek-dsl-jvm:2.0.0-alpha.2")
35 | testRuntimeOnly("org.spekframework.spek2:spek-runner-junit5:2.0.0-alpha.2")
36 | }
37 |
--------------------------------------------------------------------------------
/util-reflect-io/module.md:
--------------------------------------------------------------------------------
1 | # Module util-reflect-io
2 | This module enables persisting data using a reflection-based API.
3 |
--------------------------------------------------------------------------------
/util-reflect-io/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "util-reflect-io"
2 |
--------------------------------------------------------------------------------
/util-reflect-io/src/main/kotlin/io/github/sof3/graphmine/util/reflectio/Persistable.kt:
--------------------------------------------------------------------------------
1 | package io.github.sof3.graphmine.util.reflectio
2 |
3 | /*
4 | * GraphMine
5 | * Copyright (C) 2018 SOFe
6 | *
7 | * This program is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published
9 | * by the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | interface Persistable
22 |
--------------------------------------------------------------------------------